patchright-core 1.49.2 → 1.50.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/ThirdPartyNotices.txt +380 -12
  2. package/bin/reinstall_msedge_beta_linux.sh +6 -0
  3. package/bin/reinstall_msedge_dev_linux.sh +6 -0
  4. package/bin/reinstall_msedge_stable_linux.sh +6 -0
  5. package/browsers.json +17 -16
  6. package/lib/androidServerImpl.js +1 -1
  7. package/lib/cli/program.js +6 -30
  8. package/lib/client/channelOwner.js +35 -55
  9. package/lib/client/clientInstrumentation.js +2 -0
  10. package/lib/client/connection.js +3 -3
  11. package/lib/client/network.js +3 -1
  12. package/lib/client/waiter.js +1 -1
  13. package/lib/generated/consoleApiSource.js +1 -1
  14. package/lib/generated/injectedScriptSource.js +1 -1
  15. package/lib/generated/pollingRecorderSource.js +1 -1
  16. package/lib/inProcessFactory.js +2 -0
  17. package/lib/protocol/debug.js +1 -1
  18. package/lib/protocol/validator.js +2 -2
  19. package/lib/remote/playwrightConnection.js +4 -3
  20. package/lib/remote/playwrightServer.js +2 -1
  21. package/lib/server/bidi/bidiBrowser.js +9 -6
  22. package/lib/server/bidi/bidiExecutionContext.js +20 -1
  23. package/lib/server/bidi/bidiInput.js +7 -5
  24. package/lib/server/bidi/bidiNetworkManager.js +8 -9
  25. package/lib/server/bidi/bidiPage.js +9 -20
  26. package/lib/server/bidi/third_party/bidiKeyboard.js +9 -7
  27. package/lib/server/browserContext.js +24 -16
  28. package/lib/server/chromium/crBrowser.js +10 -10
  29. package/lib/server/chromium/crExecutionContext.js +1 -5
  30. package/lib/server/chromium/crInput.js +15 -4
  31. package/lib/server/chromium/crPage.js +17 -31
  32. package/lib/server/codegen/csharp.js +12 -2
  33. package/lib/server/codegen/java.js +14 -3
  34. package/lib/server/codegen/javascript.js +10 -2
  35. package/lib/server/codegen/jsonl.js +1 -1
  36. package/lib/server/codegen/python.js +5 -4
  37. package/lib/server/debugController.js +15 -40
  38. package/lib/server/debugger.js +1 -1
  39. package/lib/server/deviceDescriptorsSource.json +50 -50
  40. package/lib/server/dispatchers/browserContextDispatcher.js +2 -13
  41. package/lib/server/dispatchers/debugControllerDispatcher.js +4 -2
  42. package/lib/server/dispatchers/frameDispatcher.js +3 -2
  43. package/lib/server/dispatchers/pageDispatcher.js +1 -1
  44. package/lib/server/dispatchers/webSocketRouteDispatcher.js +10 -11
  45. package/lib/server/dom.js +7 -2
  46. package/lib/server/fetch.js +14 -20
  47. package/lib/server/firefox/ffBrowser.js +9 -7
  48. package/lib/server/firefox/ffInput.js +15 -4
  49. package/lib/server/firefox/ffPage.js +13 -28
  50. package/lib/server/frames.js +25 -30
  51. package/lib/server/har/harTracer.js +1 -1
  52. package/lib/server/input.js +2 -3
  53. package/lib/server/network.js +2 -2
  54. package/lib/server/page.js +23 -16
  55. package/lib/server/recorder/chat.js +177 -0
  56. package/lib/server/recorder/contextRecorder.js +6 -15
  57. package/lib/server/recorder/recorderApp.js +1 -1
  58. package/lib/server/recorder/recorderCollection.js +5 -17
  59. package/lib/server/recorder/recorderRunner.js +7 -3
  60. package/lib/server/recorder/recorderUtils.js +5 -29
  61. package/lib/server/recorder.js +12 -9
  62. package/lib/server/registry/browserFetcher.js +1 -1
  63. package/lib/server/registry/dependencies.js +5 -5
  64. package/lib/server/registry/index.js +118 -5
  65. package/lib/server/registry/nativeDeps.js +7 -4
  66. package/lib/server/socksClientCertificatesInterceptor.js +1 -1
  67. package/lib/server/trace/recorder/snapshotterInjected.js +12 -5
  68. package/lib/server/trace/viewer/traceViewer.js +6 -1
  69. package/lib/server/transport.js +1 -0
  70. package/lib/server/webkit/webkit.js +1 -1
  71. package/lib/server/webkit/wkBrowser.js +6 -6
  72. package/lib/server/webkit/wkExecutionContext.js +1 -0
  73. package/lib/server/webkit/wkInput.js +15 -5
  74. package/lib/server/webkit/wkPage.js +7 -25
  75. package/lib/utils/comparators.js +16 -10
  76. package/lib/utils/debugLogger.js +3 -1
  77. package/lib/utils/hostPlatform.js +14 -8
  78. package/lib/utils/httpServer.js +0 -4
  79. package/lib/utils/isomorphic/ariaSnapshot.js +176 -52
  80. package/lib/utils/isomorphic/cssParser.js +4 -4
  81. package/lib/utils/isomorphic/locatorGenerators.js +2 -2
  82. package/lib/utils/isomorphic/locatorParser.js +18 -12
  83. package/lib/utils/isomorphic/urlMatch.js +2 -4
  84. package/lib/utils/network.js +1 -1
  85. package/lib/utils/processLauncher.js +1 -1
  86. package/lib/utils/wsServer.js +1 -0
  87. package/lib/utils/zones.js +18 -20
  88. package/lib/utilsBundleImpl/index.js +104 -104
  89. package/lib/vite/htmlReport/index.html +14 -14
  90. package/lib/vite/{traceViewer/assets/codeMirrorModule-VZNWuWvU.js → recorder/assets/codeMirrorModule-CNAqJrkA.js} +1 -1
  91. package/lib/vite/recorder/assets/{index-CqeZmzx8.js → index-DGS0JLxS.js} +78 -78
  92. package/lib/vite/recorder/assets/{index-iA1aAGZg.css → index-eHBmevrY.css} +1 -1
  93. package/lib/vite/recorder/index.html +2 -2
  94. package/lib/vite/{recorder/assets/codeMirrorModule-DUzBrnvO.js → traceViewer/assets/codeMirrorModule-D55P_UuL.js} +10 -10
  95. package/lib/vite/traceViewer/assets/defaultSettingsView-B-uNoFsX.js +243 -0
  96. package/lib/vite/traceViewer/defaultSettingsView.2xeEXCXv.css +1 -0
  97. package/lib/vite/traceViewer/index.BfvuujqP.js +2 -0
  98. package/lib/vite/traceViewer/index.html +4 -7
  99. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  100. package/lib/vite/traceViewer/{uiMode.voC1ZiOQ.css → uiMode.BatfzHMG.css} +1 -1
  101. package/lib/vite/traceViewer/uiMode.CStJu6jo.js +5 -0
  102. package/lib/vite/traceViewer/uiMode.html +4 -7
  103. package/package.json +1 -1
  104. package/types/protocol.d.ts +269 -20
  105. package/types/types.d.ts +69 -30
  106. package/bin/PrintDeps.exe +0 -0
  107. package/bin/README.md +0 -2
  108. package/lib/server/ariaSnapshot.js +0 -33
  109. package/lib/server/recorder/recorderInTraceViewer.js +0 -144
  110. package/lib/utils/isomorphic/recorderUtils.js +0 -227
  111. package/lib/vite/traceViewer/assets/inspectorTab-BV-Uf3j9.js +0 -68
  112. package/lib/vite/traceViewer/assets/testServerConnection-DeE2kSzz.js +0 -1
  113. package/lib/vite/traceViewer/assets/workbench-B4WPcYi9.js +0 -9
  114. package/lib/vite/traceViewer/embedded.BLPSqdbm.js +0 -2
  115. package/lib/vite/traceViewer/embedded.html +0 -18
  116. package/lib/vite/traceViewer/embedded.w7WN2u1R.css +0 -1
  117. package/lib/vite/traceViewer/index.BGZfFXXF.js +0 -2
  118. package/lib/vite/traceViewer/inspectorTab.DEOUW62d.css +0 -1
  119. package/lib/vite/traceViewer/recorder.B_SY1GJM.css +0 -0
  120. package/lib/vite/traceViewer/recorder.eWs2vuTG.js +0 -2
  121. package/lib/vite/traceViewer/recorder.html +0 -17
  122. package/lib/vite/traceViewer/uiMode.CW2d9h0S.js +0 -5
  123. package/lib/vite/traceViewer/workbench.C-zR9ysA.css +0 -1
  124. /package/lib/vite/recorder/assets/{codeMirrorModule-ez37Vkbh.css → codeMirrorModule-C3UTv-Ge.css} +0 -0
  125. /package/lib/vite/traceViewer/assets/{xtermModule-BeNbaIVa.js → xtermModule-c-SNdYZy.js} +0 -0
  126. /package/lib/vite/traceViewer/{codeMirrorModule.ez37Vkbh.css → codeMirrorModule.C3UTv-Ge.css} +0 -0
  127. /package/lib/vite/traceViewer/{index.CrbWWHbf.css → index.CFOW-Ezb.css} +0 -0
  128. /package/lib/vite/traceViewer/{xtermModule.DSXBckUd.css → xtermModule.Beg8tuEN.css} +0 -0
@@ -66,22 +66,28 @@ function calculatePlatform() {
66
66
  // KDE Neon is ubuntu-based and has the same versions.
67
67
  // TUXEDO OS is ubuntu-based and has the same versions.
68
68
  if ((distroInfo === null || distroInfo === void 0 ? void 0 : distroInfo.id) === 'ubuntu' || (distroInfo === null || distroInfo === void 0 ? void 0 : distroInfo.id) === 'pop' || (distroInfo === null || distroInfo === void 0 ? void 0 : distroInfo.id) === 'neon' || (distroInfo === null || distroInfo === void 0 ? void 0 : distroInfo.id) === 'tuxedo') {
69
- const isOfficiallySupportedPlatform = (distroInfo === null || distroInfo === void 0 ? void 0 : distroInfo.id) === 'ubuntu';
70
- if (parseInt(distroInfo.version, 10) <= 19) return {
69
+ const isUbuntu = (distroInfo === null || distroInfo === void 0 ? void 0 : distroInfo.id) === 'ubuntu';
70
+ const version = distroInfo === null || distroInfo === void 0 ? void 0 : distroInfo.version;
71
+ const major = parseInt(distroInfo.version, 10);
72
+ if (major < 20) return {
71
73
  hostPlatform: 'ubuntu18.04' + archSuffix,
72
74
  isOfficiallySupportedPlatform: false
73
75
  };
74
- if (parseInt(distroInfo.version, 10) <= 21) return {
76
+ if (major < 22) return {
75
77
  hostPlatform: 'ubuntu20.04' + archSuffix,
76
- isOfficiallySupportedPlatform
78
+ isOfficiallySupportedPlatform: isUbuntu && version === '20.04'
77
79
  };
78
- if (parseInt(distroInfo.version, 10) <= 22) return {
80
+ if (major < 24) return {
79
81
  hostPlatform: 'ubuntu22.04' + archSuffix,
80
- isOfficiallySupportedPlatform
82
+ isOfficiallySupportedPlatform: isUbuntu && version === '22.04'
81
83
  };
82
- return {
84
+ if (major < 26) return {
83
85
  hostPlatform: 'ubuntu24.04' + archSuffix,
84
- isOfficiallySupportedPlatform
86
+ isOfficiallySupportedPlatform: isUbuntu && version === '24.04'
87
+ };
88
+ return {
89
+ hostPlatform: 'ubuntu' + distroInfo.version + archSuffix,
90
+ isOfficiallySupportedPlatform: false
85
91
  };
86
92
  }
87
93
  // Linux Mint is ubuntu-based but does not have the same versions
@@ -207,10 +207,6 @@ class HttpServer {
207
207
  readable.pipe(response);
208
208
  }
209
209
  _onRequest(request, response) {
210
- response.setHeader('Access-Control-Allow-Origin', '*');
211
- response.setHeader('Access-Control-Request-Method', '*');
212
- response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
213
- if (request.headers.origin) response.setHeader('Access-Control-Allow-Headers', request.headers.origin);
214
210
  if (request.method === 'OPTIONS') {
215
211
  response.writeHead(200);
216
212
  response.end();
@@ -3,9 +3,10 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.AriaKeyError = void 0;
7
- exports.parseAriaKey = parseAriaKey;
8
- exports.parseYamlTemplate = parseYamlTemplate;
6
+ exports.ParserError = exports.KeyParser = void 0;
7
+ exports.parseAriaSnapshot = parseAriaSnapshot;
8
+ exports.parseAriaSnapshotUnsafe = parseAriaSnapshotUnsafe;
9
+ exports.valueOrRegex = valueOrRegex;
9
10
  /**
10
11
  * Copyright (c) Microsoft Corporation.
11
12
  *
@@ -24,65 +25,191 @@ exports.parseYamlTemplate = parseYamlTemplate;
24
25
 
25
26
  // https://www.w3.org/TR/wai-aria-1.2/#role_definitions
26
27
 
27
- function parseYamlTemplate(fragment) {
28
- const result = {
29
- kind: 'role',
30
- role: 'fragment'
31
- };
32
- populateNode(result, fragment);
33
- if (result.children && result.children.length === 1) return result.children[0];
34
- return result;
28
+ // We pass parsed template between worlds using JSON, make it easy.
29
+
30
+ function parseAriaSnapshotUnsafe(yaml, text) {
31
+ const result = parseAriaSnapshot(yaml, text);
32
+ if (result.errors.length) throw new Error(result.errors[0].message);
33
+ return result.fragment;
35
34
  }
36
- function populateNode(node, container) {
37
- for (const object of container) {
38
- if (typeof object === 'string') {
39
- const childNode = KeyParser.parse(object);
40
- node.children = node.children || [];
41
- node.children.push(childNode);
42
- continue;
35
+ function parseAriaSnapshot(yaml, text, options = {}) {
36
+ var _fragment$children;
37
+ const lineCounter = new yaml.LineCounter();
38
+ const parseOptions = {
39
+ keepSourceTokens: true,
40
+ lineCounter,
41
+ ...options
42
+ };
43
+ const yamlDoc = yaml.parseDocument(text, parseOptions);
44
+ const errors = [];
45
+ const convertRange = range => {
46
+ return [lineCounter.linePos(range[0]), lineCounter.linePos(range[1])];
47
+ };
48
+ const addError = error => {
49
+ errors.push({
50
+ message: error.message,
51
+ range: [lineCounter.linePos(error.pos[0]), lineCounter.linePos(error.pos[1])]
52
+ });
53
+ };
54
+ const convertSeq = (container, seq) => {
55
+ for (const item of seq.items) {
56
+ const itemIsString = item instanceof yaml.Scalar && typeof item.value === 'string';
57
+ if (itemIsString) {
58
+ const childNode = KeyParser.parse(item, parseOptions, errors);
59
+ if (childNode) {
60
+ container.children = container.children || [];
61
+ container.children.push(childNode);
62
+ }
63
+ continue;
64
+ }
65
+ const itemIsMap = item instanceof yaml.YAMLMap;
66
+ if (itemIsMap) {
67
+ convertMap(container, item);
68
+ continue;
69
+ }
70
+ errors.push({
71
+ message: 'Sequence items should be strings or maps',
72
+ range: convertRange(item.range || seq.range)
73
+ });
43
74
  }
44
- for (const key of Object.keys(object)) {
45
- node.children = node.children || [];
46
- const value = object[key];
47
- if (key === 'text') {
48
- node.children.push({
49
- kind: 'text',
50
- text: valueOrRegex(value)
75
+ };
76
+ const convertMap = (container, map) => {
77
+ for (const entry of map.items) {
78
+ container.children = container.children || [];
79
+ // Key must by a string
80
+ const keyIsString = entry.key instanceof yaml.Scalar && typeof entry.key.value === 'string';
81
+ if (!keyIsString) {
82
+ errors.push({
83
+ message: 'Only string keys are supported',
84
+ range: convertRange(entry.key.range || map.range)
51
85
  });
52
86
  continue;
53
87
  }
54
- const childNode = KeyParser.parse(key);
55
- if (childNode.kind === 'text') {
56
- node.children.push({
88
+ const key = entry.key;
89
+ const value = entry.value;
90
+
91
+ // - text: "text"
92
+ if (key.value === 'text') {
93
+ const valueIsString = value instanceof yaml.Scalar && typeof value.value === 'string';
94
+ if (!valueIsString) {
95
+ errors.push({
96
+ message: 'Text value should be a string',
97
+ range: convertRange(entry.value.range || map.range)
98
+ });
99
+ continue;
100
+ }
101
+ container.children.push({
57
102
  kind: 'text',
58
- text: valueOrRegex(value)
103
+ text: valueOrRegex(value.value)
59
104
  });
60
105
  continue;
61
106
  }
62
- if (typeof value === 'string') {
63
- node.children.push({
107
+
108
+ // role "name": ...
109
+ const childNode = KeyParser.parse(key, parseOptions, errors);
110
+ if (!childNode) continue;
111
+
112
+ // - role "name": "text"
113
+ const valueIsScalar = value instanceof yaml.Scalar;
114
+ if (valueIsScalar) {
115
+ const type = typeof value.value;
116
+ if (type !== 'string' && type !== 'number' && type !== 'boolean') {
117
+ errors.push({
118
+ message: 'Node value should be a string or a sequence',
119
+ range: convertRange(entry.value.range || map.range)
120
+ });
121
+ continue;
122
+ }
123
+ container.children.push({
64
124
  ...childNode,
65
125
  children: [{
66
126
  kind: 'text',
67
- text: valueOrRegex(value)
127
+ text: valueOrRegex(String(value.value))
68
128
  }]
69
129
  });
70
130
  continue;
71
131
  }
72
- node.children.push(childNode);
73
- populateNode(childNode, value);
132
+
133
+ // - role "name":
134
+ // - child
135
+ const valueIsSequence = value instanceof yaml.YAMLSeq;
136
+ if (valueIsSequence) {
137
+ container.children.push(childNode);
138
+ convertSeq(childNode, value);
139
+ continue;
140
+ }
141
+ errors.push({
142
+ message: 'Map values should be strings or sequences',
143
+ range: convertRange(entry.value.range || map.range)
144
+ });
74
145
  }
146
+ };
147
+ const fragment = {
148
+ kind: 'role',
149
+ role: 'fragment'
150
+ };
151
+ yamlDoc.errors.forEach(addError);
152
+ if (errors.length) return {
153
+ errors,
154
+ fragment
155
+ };
156
+ if (!(yamlDoc.contents instanceof yaml.YAMLSeq)) {
157
+ errors.push({
158
+ message: 'Aria snapshot must be a YAML sequence, elements starting with " -"',
159
+ range: yamlDoc.contents ? convertRange(yamlDoc.contents.range) : [{
160
+ line: 0,
161
+ col: 0
162
+ }, {
163
+ line: 0,
164
+ col: 0
165
+ }]
166
+ });
75
167
  }
168
+ if (errors.length) return {
169
+ errors,
170
+ fragment
171
+ };
172
+ convertSeq(fragment, yamlDoc.contents);
173
+ if (errors.length) return {
174
+ errors,
175
+ fragment: emptyFragment
176
+ };
177
+ if (((_fragment$children = fragment.children) === null || _fragment$children === void 0 ? void 0 : _fragment$children.length) === 1) return {
178
+ fragment: fragment.children[0],
179
+ errors
180
+ };
181
+ return {
182
+ fragment,
183
+ errors
184
+ };
76
185
  }
186
+ const emptyFragment = {
187
+ kind: 'role',
188
+ role: 'fragment'
189
+ };
77
190
  function normalizeWhitespace(text) {
78
191
  return text.replace(/[\r\n\s\t]+/g, ' ').trim();
79
192
  }
80
193
  function valueOrRegex(value) {
81
- return value.startsWith('/') && value.endsWith('/') ? new RegExp(value.slice(1, -1)) : normalizeWhitespace(value);
194
+ return value.startsWith('/') && value.endsWith('/') && value.length > 1 ? {
195
+ pattern: value.slice(1, -1)
196
+ } : normalizeWhitespace(value);
82
197
  }
83
198
  class KeyParser {
84
- static parse(input) {
85
- return new KeyParser(input)._parse();
199
+ static parse(text, options, errors) {
200
+ try {
201
+ return new KeyParser(text.value)._parse();
202
+ } catch (e) {
203
+ if (e instanceof ParserError) {
204
+ const message = options.prettyErrors === false ? e.message : e.message + ':\n\n' + text.value + '\n' + ' '.repeat(e.pos) + '^\n';
205
+ errors.push({
206
+ message,
207
+ range: [options.lineCounter.linePos(text.range[0]), options.lineCounter.linePos(text.range[0] + e.pos)]
208
+ });
209
+ return null;
210
+ }
211
+ throw e;
212
+ }
86
213
  }
87
214
  constructor(input) {
88
215
  this._input = void 0;
@@ -132,8 +259,8 @@ class KeyParser {
132
259
  }
133
260
  this._throwError('Unterminated string');
134
261
  }
135
- _throwError(message, pos) {
136
- throw new AriaKeyError(message, this._input, pos || this._pos);
262
+ _throwError(message, offset = 0) {
263
+ throw new ParserError(message, offset || this._pos);
137
264
  }
138
265
  _readRegex() {
139
266
  let result = '';
@@ -148,7 +275,9 @@ class KeyParser {
148
275
  escaped = true;
149
276
  result += ch;
150
277
  } else if (ch === '/' && !insideClass) {
151
- return result;
278
+ return {
279
+ pattern: result
280
+ };
152
281
  } else if (ch === '[') {
153
282
  insideClass = true;
154
283
  result += ch;
@@ -165,11 +294,11 @@ class KeyParser {
165
294
  const ch = this._peek();
166
295
  if (ch === '"') {
167
296
  this._next();
168
- return this._readString();
297
+ return normalizeWhitespace(this._readString());
169
298
  }
170
299
  if (ch === '/') {
171
300
  this._next();
172
- return new RegExp(this._readRegex());
301
+ return this._readRegex();
173
302
  }
174
303
  return null;
175
304
  }
@@ -251,17 +380,12 @@ class KeyParser {
251
380
  if (!value) this._throwError(message || 'Assertion error', valuePos);
252
381
  }
253
382
  }
254
- function parseAriaKey(key) {
255
- return KeyParser.parse(key);
256
- }
257
- class AriaKeyError extends Error {
258
- constructor(message, input, pos) {
259
- super(message + ':\n\n' + input + '\n' + ' '.repeat(pos) + '^\n');
260
- this.shortMessage = void 0;
383
+ exports.KeyParser = KeyParser;
384
+ class ParserError extends Error {
385
+ constructor(message, pos) {
386
+ super(message);
261
387
  this.pos = void 0;
262
- this.shortMessage = message;
263
388
  this.pos = pos;
264
- this.stack = undefined;
265
389
  }
266
390
  }
267
- exports.AriaKeyError = AriaKeyError;
391
+ exports.ParserError = ParserError;
@@ -46,7 +46,7 @@ function parseCSS(selector, customNames) {
46
46
  tokens = css.tokenize(selector);
47
47
  if (!(tokens[tokens.length - 1] instanceof css.EOFToken)) tokens.push(new css.EOFToken());
48
48
  } catch (e) {
49
- const newMessage = e.message + ` while parsing selector "${selector}"`;
49
+ const newMessage = e.message + ` while parsing css selector "${selector}". Did you mean to CSS.escape it?`;
50
50
  const index = (e.stack || '').indexOf(e.message);
51
51
  if (index !== -1) e.stack = e.stack.substring(0, index) + newMessage + e.stack.substring(index + e.message.length);
52
52
  e.message = newMessage;
@@ -61,11 +61,11 @@ function parseCSS(selector, customNames) {
61
61
  // TODO: Consider treating these as strings?
62
62
  token instanceof css.URLToken || token instanceof css.PercentageToken;
63
63
  });
64
- if (unsupportedToken) throw new InvalidSelectorError(`Unsupported token "${unsupportedToken.toSource()}" while parsing selector "${selector}"`);
64
+ if (unsupportedToken) throw new InvalidSelectorError(`Unsupported token "${unsupportedToken.toSource()}" while parsing css selector "${selector}". Did you mean to CSS.escape it?`);
65
65
  let pos = 0;
66
66
  const names = new Set();
67
67
  function unexpected() {
68
- return new InvalidSelectorError(`Unexpected token "${tokens[pos].toSource()}" while parsing selector "${selector}"`);
68
+ return new InvalidSelectorError(`Unexpected token "${tokens[pos].toSource()}" while parsing css selector "${selector}". Did you mean to CSS.escape it?`);
69
69
  }
70
70
  function skipWhitespace() {
71
71
  while (tokens[pos] instanceof css.WhitespaceToken) pos++;
@@ -227,7 +227,7 @@ function parseCSS(selector, customNames) {
227
227
  }
228
228
  const result = consumeFunctionArguments();
229
229
  if (!isEOF()) throw unexpected();
230
- if (result.some(arg => typeof arg !== 'object' || !('simples' in arg))) throw new InvalidSelectorError(`Error while parsing selector "${selector}"`);
230
+ if (result.some(arg => typeof arg !== 'object' || !('simples' in arg))) throw new InvalidSelectorError(`Error while parsing css selector "${selector}". Did you mean to CSS.escape it?`);
231
231
  return {
232
232
  selector: result,
233
233
  names: Array.from(names)
@@ -25,7 +25,7 @@ var _selectorParser = require("./selectorParser");
25
25
  */
26
26
 
27
27
  function asLocator(lang, selector, isFrameLocator = false) {
28
- return asLocators(lang, selector, isFrameLocator)[0];
28
+ return asLocators(lang, selector, isFrameLocator, 1)[0];
29
29
  }
30
30
  function asLocators(lang, selector, isFrameLocator = false, maxOutputSize = 20, preferredQuote) {
31
31
  try {
@@ -235,7 +235,7 @@ function combineTokens(factory, tokens, maxOutputSize) {
235
235
  const visit = index => {
236
236
  if (index === tokens.length) {
237
237
  result.push(factory.chainLocators(currentTokens));
238
- return currentTokens.length < maxOutputSize;
238
+ return result.length < maxOutputSize;
239
239
  }
240
240
  for (const taken of tokens[index]) {
241
241
  currentTokens[index] = taken;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.locatorOrSelectorAsSelector = locatorOrSelectorAsSelector;
7
+ exports.unsafeLocatorOrSelectorAsSelector = unsafeLocatorOrSelectorAsSelector;
7
8
  var _stringUtils = require("./stringUtils");
8
9
  var _locatorGenerators = require("./locatorGenerators");
9
10
  var _selectorParser = require("./selectorParser");
@@ -66,7 +67,7 @@ function parseLocator(locator, testIdAttributeName) {
66
67
  template = template.toLowerCase().replace(/get_by_alt_text/g, 'getbyalttext').replace(/get_by_test_id/g, 'getbytestid').replace(/get_by_([\w]+)/g, 'getby$1').replace(/has_not_text/g, 'hasnottext').replace(/has_text/g, 'hastext').replace(/has_not/g, 'hasnot').replace(/frame_locator/g, 'framelocator').replace(/content_frame/g, 'contentframe').replace(/[{}\s]/g, '').replace(/new\(\)/g, '').replace(/new[\w]+\.[\w]+options\(\)/g, '').replace(/\.set/g, ',set').replace(/\.or_\(/g, 'or(') // Python has "or_" instead of "or".
67
68
  .replace(/\.and_\(/g, 'and(') // Python has "and_" instead of "and".
68
69
  .replace(/:/g, '=').replace(/,re\.ignorecase/g, 'i').replace(/,pattern.case_insensitive/g, 'i').replace(/,regexoptions.ignorecase/g, 'i').replace(/re.compile\(([^)]+)\)/g, '$1') // Python has regex strings as r"foo"
69
- .replace(/pattern.compile\(([^)]+)\)/g, 'r$1').replace(/newregex\(([^)]+)\)/g, 'r$1').replace(/string=/g, '=').replace(/regex=/g, '=').replace(/,,/g, ',');
70
+ .replace(/pattern.compile\(([^)]+)\)/g, 'r$1').replace(/newregex\(([^)]+)\)/g, 'r$1').replace(/string=/g, '=').replace(/regex=/g, '=').replace(/,,/g, ',').replace(/,\)/g, ')');
70
71
  const preferredQuote = params.map(p => p.quote).filter(quote => '\'"`'.includes(quote))[0];
71
72
  return {
72
73
  selector: transform(template, params, testIdAttributeName),
@@ -123,7 +124,7 @@ function transform(template, params, testIdAttributeName) {
123
124
  }
124
125
 
125
126
  // Transform to selector engines.
126
- template = template.replace(/\,set([\w]+)\(([^)]+)\)/g, (_, group1, group2) => ',' + group1.toLowerCase() + '=' + group2.toLowerCase()).replace(/framelocator\(([^)]+)\)/g, '$1.internal:control=enter-frame').replace(/contentframe(\(\))?/g, 'internal:control=enter-frame').replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2').replace(/locator\(([^)]+),hasnottext=([^),]+)\)/g, 'locator($1).internal:has-not-text=$2').replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2').replace(/locator\(([^)]+)\)/g, '$1').replace(/getbyrole\(([^)]+)\)/g, 'internal:role=$1').replace(/getbytext\(([^)]+)\)/g, 'internal:text=$1').replace(/getbylabel\(([^)]+)\)/g, 'internal:label=$1').replace(/getbytestid\(([^)]+)\)/g, `internal:testid=[${testIdAttributeName}=$1]`).replace(/getby(placeholder|alt|title)(?:text)?\(([^)]+)\)/g, 'internal:attr=[$1=$2]').replace(/first(\(\))?/g, 'nth=0').replace(/last(\(\))?/g, 'nth=-1').replace(/nth\(([^)]+)\)/g, 'nth=$1').replace(/filter\(,?hastext=([^)]+)\)/g, 'internal:has-text=$1').replace(/filter\(,?hasnottext=([^)]+)\)/g, 'internal:has-not-text=$1').replace(/filter\(,?has2=([^)]+)\)/g, 'internal:has=$1').replace(/filter\(,?hasnot2=([^)]+)\)/g, 'internal:has-not=$1').replace(/,exact=false/g, '').replace(/,exact=true/g, 's').replace(/\,/g, '][');
127
+ template = template.replace(/\,set([\w]+)\(([^)]+)\)/g, (_, group1, group2) => ',' + group1.toLowerCase() + '=' + group2.toLowerCase()).replace(/framelocator\(([^)]+)\)/g, '$1.internal:control=enter-frame').replace(/contentframe(\(\))?/g, 'internal:control=enter-frame').replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2').replace(/locator\(([^)]+),hasnottext=([^),]+)\)/g, 'locator($1).internal:has-not-text=$2').replace(/locator\(([^)]+),hastext=([^),]+)\)/g, 'locator($1).internal:has-text=$2').replace(/locator\(([^)]+)\)/g, '$1').replace(/getbyrole\(([^)]+)\)/g, 'internal:role=$1').replace(/getbytext\(([^)]+)\)/g, 'internal:text=$1').replace(/getbylabel\(([^)]+)\)/g, 'internal:label=$1').replace(/getbytestid\(([^)]+)\)/g, `internal:testid=[${testIdAttributeName}=$1]`).replace(/getby(placeholder|alt|title)(?:text)?\(([^)]+)\)/g, 'internal:attr=[$1=$2]').replace(/first(\(\))?/g, 'nth=0').replace(/last(\(\))?/g, 'nth=-1').replace(/nth\(([^)]+)\)/g, 'nth=$1').replace(/filter\(,?hastext=([^)]+)\)/g, 'internal:has-text=$1').replace(/filter\(,?hasnottext=([^)]+)\)/g, 'internal:has-not-text=$1').replace(/filter\(,?has2=([^)]+)\)/g, 'internal:has=$1').replace(/filter\(,?hasnot2=([^)]+)\)/g, 'internal:has-not=$1').replace(/,exact=false/g, '').replace(/,exact=true/g, 's').replace(/,includehidden=/g, ',include-hidden=').replace(/\,/g, '][');
127
128
  const parts = template.split('.');
128
129
  // Turn "internal:control=enter-frame >> nth=0" into "nth=0 >> internal:control=enter-frame"
129
130
  // because these are swapped in locators vs selectors.
@@ -157,23 +158,28 @@ function transform(template, params, testIdAttributeName) {
157
158
  }).join(' >> ');
158
159
  }
159
160
  function locatorOrSelectorAsSelector(language, locator, testIdAttributeName) {
161
+ try {
162
+ return unsafeLocatorOrSelectorAsSelector(language, locator, testIdAttributeName);
163
+ } catch (e) {
164
+ return '';
165
+ }
166
+ }
167
+ function unsafeLocatorOrSelectorAsSelector(language, locator, testIdAttributeName) {
160
168
  try {
161
169
  (0, _selectorParser.parseSelector)(locator);
162
170
  return locator;
163
171
  } catch (e) {}
164
- try {
165
- const {
166
- selector,
167
- preferredQuote
168
- } = parseLocator(locator, testIdAttributeName);
169
- const locators = (0, _locatorGenerators.asLocators)(language, selector, undefined, undefined, preferredQuote);
170
- const digest = digestForComparison(language, locator);
171
- if (locators.some(candidate => digestForComparison(language, candidate) === digest)) return selector;
172
- } catch (e) {}
172
+ const {
173
+ selector,
174
+ preferredQuote
175
+ } = parseLocator(locator, testIdAttributeName);
176
+ const locators = (0, _locatorGenerators.asLocators)(language, selector, undefined, undefined, preferredQuote);
177
+ const digest = digestForComparison(language, locator);
178
+ if (locators.some(candidate => digestForComparison(language, candidate) === digest)) return selector;
173
179
  return '';
174
180
  }
175
181
  function digestForComparison(language, locator) {
176
182
  locator = locator.replace(/\s/g, '');
177
- if (language === 'javascript') locator = locator.replace(/\\?["`]/g, '\'');
183
+ if (language === 'javascript') locator = locator.replace(/\\?["`]/g, '\'').replace(/,{}/g, '');
178
184
  return locator;
179
185
  }
@@ -101,14 +101,12 @@ function urlMatches(baseURL, urlString, match) {
101
101
  }
102
102
  if ((0, _stringUtils.isString)(match)) match = globToRegex(match);
103
103
  if (isRegExp(match)) return match.test(urlString);
104
- if (typeof match === 'string' && match === urlString) return true;
105
- const url = parsedURL(urlString);
104
+ const url = parseURL(urlString);
106
105
  if (!url) return false;
107
- if (typeof match === 'string') return url.pathname === match;
108
106
  if (typeof match !== 'function') throw new Error('url parameter should be string, RegExp or function');
109
107
  return match(url);
110
108
  }
111
- function parsedURL(url) {
109
+ function parseURL(url) {
112
110
  try {
113
111
  return new URL(url);
114
112
  } catch (e) {
@@ -47,7 +47,7 @@ function httpRequest(params, onResponse, onError) {
47
47
  const timeout = (_params$timeout = params.timeout) !== null && _params$timeout !== void 0 ? _params$timeout : NET_DEFAULT_TIMEOUT;
48
48
  const proxyURL = (0, _utilsBundle.getProxyForUrl)(params.url);
49
49
  if (proxyURL) {
50
- const parsedProxyURL = new URL(proxyURL);
50
+ const parsedProxyURL = _url.default.parse(proxyURL);
51
51
  if (params.url.startsWith('http:')) {
52
52
  options = {
53
53
  path: parsedUrl.href,
@@ -149,7 +149,7 @@ async function launchProcess(options) {
149
149
  let processClosed = false;
150
150
  let fulfillCleanup = () => {};
151
151
  const waitForCleanup = new Promise(f => fulfillCleanup = f);
152
- spawnedProcess.once('exit', (exitCode, signal) => {
152
+ spawnedProcess.once('close', (exitCode, signal) => {
153
153
  options.log(`[pid=${spawnedProcess.pid}] <process did exit: exitCode=${exitCode}, signal=${signal}>`);
154
154
  processClosed = true;
155
155
  gracefullyCloseSet.delete(gracefullyClose);
@@ -26,6 +26,7 @@ var _debugLogger = require("./debugLogger");
26
26
  let lastConnectionId = 0;
27
27
  const kConnectionSymbol = Symbol('kConnection');
28
28
  const perMessageDeflate = exports.perMessageDeflate = {
29
+ serverNoContextTakeover: true,
29
30
  zlibDeflateOptions: {
30
31
  level: 3
31
32
  },
@@ -24,31 +24,24 @@ var _async_hooks = require("async_hooks");
24
24
  class ZoneManager {
25
25
  constructor() {
26
26
  this._asyncLocalStorage = new _async_hooks.AsyncLocalStorage();
27
+ this._emptyZone = Zone.createEmpty(this._asyncLocalStorage);
27
28
  }
28
29
  run(type, data, func) {
29
- const zone = Zone._createWithData(this._asyncLocalStorage, type, data);
30
- return this._asyncLocalStorage.run(zone, func);
30
+ return this.current().with(type, data).run(func);
31
31
  }
32
32
  zoneData(type) {
33
- const zone = this._asyncLocalStorage.getStore();
34
- return zone === null || zone === void 0 ? void 0 : zone.get(type);
33
+ return this.current().data(type);
35
34
  }
36
- currentZone() {
35
+ current() {
37
36
  var _this$_asyncLocalStor;
38
- return (_this$_asyncLocalStor = this._asyncLocalStorage.getStore()) !== null && _this$_asyncLocalStor !== void 0 ? _this$_asyncLocalStor : Zone._createEmpty(this._asyncLocalStorage);
37
+ return (_this$_asyncLocalStor = this._asyncLocalStorage.getStore()) !== null && _this$_asyncLocalStor !== void 0 ? _this$_asyncLocalStor : this._emptyZone;
39
38
  }
40
- exitZones(func) {
41
- return this._asyncLocalStorage.run(undefined, func);
39
+ empty() {
40
+ return this._emptyZone;
42
41
  }
43
42
  }
44
43
  class Zone {
45
- static _createWithData(asyncLocalStorage, type, data) {
46
- var _asyncLocalStorage$ge;
47
- const store = new Map((_asyncLocalStorage$ge = asyncLocalStorage.getStore()) === null || _asyncLocalStorage$ge === void 0 ? void 0 : _asyncLocalStorage$ge._data);
48
- store.set(type, data);
49
- return new Zone(asyncLocalStorage, store);
50
- }
51
- static _createEmpty(asyncLocalStorage) {
44
+ static createEmpty(asyncLocalStorage) {
52
45
  return new Zone(asyncLocalStorage, new Map());
53
46
  }
54
47
  constructor(asyncLocalStorage, store) {
@@ -57,13 +50,18 @@ class Zone {
57
50
  this._asyncLocalStorage = asyncLocalStorage;
58
51
  this._data = store;
59
52
  }
53
+ with(type, data) {
54
+ return new Zone(this._asyncLocalStorage, new Map(this._data).set(type, data));
55
+ }
56
+ without(type) {
57
+ const data = type ? new Map(this._data) : new Map();
58
+ data.delete(type);
59
+ return new Zone(this._asyncLocalStorage, data);
60
+ }
60
61
  run(func) {
61
- // Reset apiZone and expectZone, but restore stepZone.
62
- const entries = [...this._data.entries()].filter(([type]) => type !== 'apiZone' && type !== 'expectZone');
63
- const resetZone = new Zone(this._asyncLocalStorage, new Map(entries));
64
- return this._asyncLocalStorage.run(resetZone, func);
62
+ return this._asyncLocalStorage.run(this, func);
65
63
  }
66
- get(type) {
64
+ data(type) {
67
65
  return this._data.get(type);
68
66
  }
69
67
  }