Skip to content

Commit 731aff7

Browse files
cursoragentP4X-ng
andcommitted
Harden CDP patch coverage
Co-authored-by: P4x-ng <P4X-ng@users.noreply.github.com>
1 parent 2140462 commit 731aff7

File tree

3 files changed

+143
-15
lines changed

3 files changed

+143
-15
lines changed

generator/generate.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -990,32 +990,26 @@ def generate_docs(docs_path, domains):
990990
def patchCDP(domains):
991991
'''Patch up CDP errors. It's easier to patch that here than it is to modify the generator code.'''
992992

993-
# 1. DOM includes an erroneous $ref that refers to itself.
994-
# 2. Page includes an event with an extraneous backtick in the description.
995-
# 3. Network.requestWillBeSent.redirectHasExtraInfo is not marked as optional but it is not present in all events
996-
# 4. Network.responseReceived.hasExtraInfo is not marked as optional but it is not present in all events
993+
# 1. Page includes an event with an extraneous backtick in the description.
994+
# 2. Network.requestWillBeSent.redirectHasExtraInfo is not marked as optional but it is not present in all events
995+
# 3. Network.responseReceived.hasExtraInfo is not marked as optional but it is not present in all events
997996
for domain in domains:
998-
if domain.domain == 'DOM':
999-
for cmd in domain.commands:
1000-
if cmd.name == 'resolveNode':
1001-
# Patch 1
1002-
cmd.parameters[1].ref = 'BackendNodeId'
1003-
elif domain.domain == 'Page':
997+
if domain.domain == 'Page':
1004998
for event in domain.events:
1005999
if event.name == 'screencastVisibilityChanged':
1006-
# Patch 2
1000+
# Patch 1
10071001
event.description = event.description.replace('`', '')
10081002
elif domain.domain == 'Network':
10091003
for event in domain.events:
10101004
if event.name == 'requestWillBeSent':
10111005
for param in event.parameters:
10121006
if param.name == 'redirectHasExtraInfo':
1013-
# Patch 3
1007+
# Patch 2
10141008
param.optional = True
10151009
if event.name == 'responseReceived':
10161010
for param in event.parameters:
10171011
if param.name == 'hasExtraInfo':
1018-
# Patch 4
1012+
# Patch 3
10191013
param.optional = True
10201014

10211015

generator/test_generate.py

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from textwrap import dedent
1414

15-
from generate import CdpCommand, CdpDomain, CdpEvent, CdpType, docstring
15+
from generate import CdpCommand, CdpDomain, CdpEvent, CdpType, docstring, patchCDP
1616

1717

1818
def test_docstring():
@@ -491,6 +491,51 @@ def resolve_animation(
491491
assert expected == actual
492492

493493

494+
def test_cdp_command_same_domain_ref_parameter():
495+
json_cmd = {
496+
"name": "resolveNode",
497+
"description": "Resolves the JavaScript node object for a given BackendNodeId.",
498+
"parameters": [
499+
{
500+
"name": "backendNodeId",
501+
"description": "Backend identifier of the node to resolve.",
502+
"optional": True,
503+
"$ref": "DOM.BackendNodeId"
504+
}
505+
],
506+
"returns": [
507+
{
508+
"name": "object",
509+
"description": "JavaScript object wrapper for given node.",
510+
"$ref": "Runtime.RemoteObject"
511+
}
512+
]
513+
}
514+
expected = dedent("""\
515+
def resolve_node(
516+
backend_node_id: typing.Optional[BackendNodeId] = None
517+
) -> typing.Generator[T_JSON_DICT,T_JSON_DICT,runtime.RemoteObject]:
518+
r'''
519+
Resolves the JavaScript node object for a given BackendNodeId.
520+
521+
:param backend_node_id: *(Optional)* Backend identifier of the node to resolve.
522+
:returns: JavaScript object wrapper for given node.
523+
'''
524+
params: T_JSON_DICT = dict()
525+
if backend_node_id is not None:
526+
params['backendNodeId'] = backend_node_id.to_json()
527+
cmd_dict: T_JSON_DICT = {
528+
'method': 'DOM.resolveNode',
529+
'params': params,
530+
}
531+
json = yield cmd_dict
532+
return runtime.RemoteObject.from_json(json['object'])""")
533+
534+
cmd = CdpCommand.from_json(json_cmd, 'DOM')
535+
actual = cmd.generate_code()
536+
assert expected == actual
537+
538+
494539
def test_cdp_command_multiple_return():
495540
json_cmd = {
496541
"name": "getEncodedResponse",
@@ -858,6 +903,46 @@ def test_domain_shadows_builtin():
858903
assert domain.module == 'input_'
859904

860905

906+
def test_patch_cdp_marks_network_extra_info_flags_optional():
907+
json_domain = {
908+
"domain": "Network",
909+
"types": [],
910+
"commands": [],
911+
"events": [
912+
{
913+
"name": "requestWillBeSent",
914+
"parameters": [
915+
{"name": "requestId", "type": "string"},
916+
{"name": "redirectHasExtraInfo", "type": "boolean"},
917+
],
918+
},
919+
{
920+
"name": "responseReceived",
921+
"parameters": [
922+
{"name": "requestId", "type": "string"},
923+
{"name": "hasExtraInfo", "type": "boolean"},
924+
],
925+
},
926+
],
927+
}
928+
929+
domain = CdpDomain.from_json(json_domain)
930+
request_will_be_sent = next(
931+
event for event in domain.events if event.name == 'requestWillBeSent'
932+
)
933+
response_received = next(
934+
event for event in domain.events if event.name == 'responseReceived'
935+
)
936+
937+
assert request_will_be_sent.parameters[1].optional is False
938+
assert response_received.parameters[1].optional is False
939+
940+
patchCDP([domain])
941+
942+
assert request_will_be_sent.parameters[1].optional is True
943+
assert response_received.parameters[1].optional is True
944+
945+
861946
def test_cdp_domain_sphinx():
862947
json_domain = {
863948
"domain": "Animation",

test/test_cdp.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'''
22
Some basic tests for the generated CDP modules.
33
'''
4-
from cdp import dom, io, page, tracing, util
4+
from cdp import dom, io, network, page, tracing, util
55

66

77
def test_primitive_type():
@@ -71,3 +71,52 @@ def test_event_dispatch():
7171
assert event.window_name == 'Window 1'
7272
assert event.window_features == ['feature1', 'feature2']
7373
assert not event.user_gesture
74+
75+
76+
def test_request_will_be_sent_missing_redirect_has_extra_info():
77+
event = network.RequestWillBeSent.from_json({
78+
'requestId': 'request-1',
79+
'loaderId': 'loader-1',
80+
'documentURL': 'https://example.com',
81+
'request': {
82+
'url': 'https://example.com',
83+
'method': 'GET',
84+
'headers': {},
85+
'initialPriority': 'Medium',
86+
'referrerPolicy': 'strict-origin-when-cross-origin',
87+
},
88+
'timestamp': 1.25,
89+
'wallTime': 2.5,
90+
'initiator': {
91+
'type': 'parser',
92+
},
93+
})
94+
95+
assert event.request_id == network.RequestId('request-1')
96+
assert event.redirect_has_extra_info is None
97+
assert event.request.initial_priority == network.ResourcePriority.MEDIUM
98+
99+
100+
def test_response_received_missing_has_extra_info():
101+
event = network.ResponseReceived.from_json({
102+
'requestId': 'request-1',
103+
'loaderId': 'loader-1',
104+
'timestamp': 1.25,
105+
'type': 'Document',
106+
'response': {
107+
'url': 'https://example.com',
108+
'status': 200,
109+
'statusText': 'OK',
110+
'headers': {},
111+
'mimeType': 'text/html',
112+
'charset': 'utf-8',
113+
'connectionReused': False,
114+
'connectionId': 1,
115+
'encodedDataLength': 128,
116+
'securityState': 'secure',
117+
},
118+
})
119+
120+
assert event.request_id == network.RequestId('request-1')
121+
assert event.has_extra_info is None
122+
assert event.response.status == 200

0 commit comments

Comments
 (0)