chrome-devtools-frontend 1.0.1636056 → 1.0.1640418

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 (171) hide show
  1. package/front_end/core/common/Color.ts +0 -4
  2. package/front_end/core/host/AidaClientTypes.ts +8 -6
  3. package/front_end/core/root/Runtime.ts +2 -2
  4. package/front_end/core/sdk/DOMStorageModel.ts +1 -1
  5. package/front_end/core/sdk/SourceMap.ts +8 -3
  6. package/front_end/core/sdk/TargetManager.ts +14 -1
  7. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +147 -0
  8. package/front_end/generated/ARIAProperties.js +17 -4
  9. package/front_end/generated/InspectorBackendCommands.ts +13 -7
  10. package/front_end/generated/SupportedCSSProperties.js +1 -0
  11. package/front_end/generated/protocol-mapping.d.ts +7 -0
  12. package/front_end/generated/protocol-proxy-api.d.ts +14 -0
  13. package/front_end/generated/protocol.ts +120 -2
  14. package/front_end/global_typings/global_defs.d.ts +13 -0
  15. package/front_end/models/ai_assistance/AiAgent2.ts +116 -0
  16. package/front_end/models/ai_assistance/AiConversation.ts +22 -36
  17. package/front_end/models/ai_assistance/AiHistoryStorage.ts +0 -1
  18. package/front_end/models/ai_assistance/AiOrigins.ts +46 -0
  19. package/front_end/models/ai_assistance/AiUtils.ts +9 -0
  20. package/front_end/models/ai_assistance/README.md +16 -0
  21. package/front_end/models/ai_assistance/StorageItem.ts +30 -26
  22. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +12 -5
  23. package/front_end/models/ai_assistance/agents/AiAgent.ts +86 -32
  24. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +2 -2
  25. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +31 -10
  26. package/front_end/models/ai_assistance/agents/ConversationSummaryAgent.ts +1 -1
  27. package/front_end/models/ai_assistance/agents/FileAgent.ts +2 -2
  28. package/front_end/models/ai_assistance/agents/GreenDevAgent.ts +1 -3
  29. package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +19 -0
  30. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +9 -4
  31. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +2 -2
  32. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +41 -12
  33. package/front_end/models/ai_assistance/agents/StorageAgent.ts +442 -122
  34. package/front_end/models/ai_assistance/agents/StylingAgent.ts +2 -2
  35. package/front_end/models/ai_assistance/ai_assistance.ts +4 -2
  36. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +2 -2
  37. package/front_end/models/ai_assistance/performance/AIContext.ts +7 -8
  38. package/front_end/models/ai_assistance/skills/README.md +40 -0
  39. package/front_end/models/ai_assistance/skills/Skill.ts +13 -0
  40. package/front_end/models/ai_assistance/skills/SkillRegistry.ts +10 -0
  41. package/front_end/models/ai_assistance/skills/styling.md +6 -0
  42. package/front_end/models/bindings/CompilerScriptMapping.ts +12 -4
  43. package/front_end/models/breakpoints/BreakpointManager.ts +54 -2
  44. package/front_end/models/greendev/Prototypes.ts +0 -7
  45. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +20 -0
  46. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +5 -0
  47. package/front_end/models/issues_manager/EmailVerificationRequestIssue.ts +293 -0
  48. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  49. package/front_end/models/issues_manager/descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
  50. package/front_end/models/issues_manager/descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
  51. package/front_end/models/issues_manager/descriptions/emailVerificationRequestInvalidEmail.md +1 -0
  52. package/front_end/models/issues_manager/descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
  53. package/front_end/models/issues_manager/descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
  54. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
  55. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
  56. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
  57. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
  58. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
  59. package/front_end/models/issues_manager/descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
  60. package/front_end/models/issues_manager/descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
  61. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
  62. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
  63. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
  64. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
  65. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
  66. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
  67. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
  68. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
  69. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
  70. package/front_end/models/issues_manager/descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
  71. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  72. package/front_end/models/javascript_metadata/NativeFunctions.js +1748 -1739
  73. package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +1 -1
  74. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +9 -1
  75. package/front_end/models/stack_trace/StackTraceImpl.ts +29 -9
  76. package/front_end/models/stack_trace/StackTraceModel.ts +23 -11
  77. package/front_end/models/stack_trace/Trie.ts +11 -1
  78. package/front_end/models/trace/extras/TraceTree.ts +20 -1
  79. package/front_end/models/trace/insights/Common.ts +9 -0
  80. package/front_end/models/trace/lantern/core/NetworkAnalyzer.ts +21 -25
  81. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +19 -75
  82. package/front_end/panels/ai_assistance/components/AccessibilityAgentMarkdownRenderer.ts +10 -3
  83. package/front_end/panels/ai_assistance/components/ChatMessage.ts +148 -2
  84. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +2 -3
  85. package/front_end/panels/ai_assistance/components/chatMessage.css +27 -0
  86. package/front_end/panels/application/CookieItemsView.ts +24 -0
  87. package/front_end/panels/application/DOMStorageItemsView.ts +9 -4
  88. package/front_end/panels/application/preloading/components/PreloadingString.ts +6 -0
  89. package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +4 -4
  90. package/front_end/panels/console/ConsoleViewMessage.ts +13 -102
  91. package/front_end/panels/elements/StandaloneStylesContainer.ts +10 -0
  92. package/front_end/panels/elements/StylePropertiesSection.ts +6 -2
  93. package/front_end/panels/elements/StylePropertyTreeElement.ts +30 -1
  94. package/front_end/panels/elements/StylesContainer.ts +3 -0
  95. package/front_end/panels/elements/StylesSidebarPane.ts +54 -4
  96. package/front_end/panels/elements/elements-meta.ts +14 -0
  97. package/front_end/panels/layer_viewer/layerDetailsView.css +1 -1
  98. package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
  99. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +4 -4
  100. package/front_end/panels/network/NetworkDataGridNode.ts +14 -0
  101. package/front_end/panels/network/NetworkLogViewColumns.ts +2 -2
  102. package/front_end/panels/network/RequestHeadersView.ts +55 -19
  103. package/front_end/panels/network/networkTimingTable.css +2 -4
  104. package/front_end/panels/recorder/components/ReplaySection.ts +28 -16
  105. package/front_end/panels/recorder/converters/LighthouseConverter.snapshot.txt +47 -0
  106. package/front_end/panels/recorder/converters/PuppeteerConverter.snapshot.txt +49 -0
  107. package/front_end/panels/recorder/converters/PuppeteerReplayConverter.snapshot.txt +33 -0
  108. package/front_end/panels/settings/SettingsScreen.ts +1 -2
  109. package/front_end/panels/sources/BreakpointsView.ts +23 -42
  110. package/front_end/panels/sources/DebuggerPlugin.ts +12 -5
  111. package/front_end/panels/sources/ScopeChainSidebarPane.ts +169 -106
  112. package/front_end/panels/timeline/components/IgnoreListSetting.ts +1 -0
  113. package/front_end/third_party/chromium/README.chromium +1 -1
  114. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +2 -2
  115. package/front_end/third_party/marked/README.chromium +3 -6
  116. package/front_end/third_party/marked/package/README.md +5 -5
  117. package/front_end/third_party/marked/package/bin/main.js +27 -22
  118. package/front_end/third_party/marked/package/bin/marked.js +2 -1
  119. package/front_end/third_party/marked/package/lib/marked.esm.d.ts +346 -256
  120. package/front_end/third_party/marked/package/lib/marked.esm.js +67 -2698
  121. package/front_end/third_party/marked/package/lib/marked.esm.js.map +7 -1
  122. package/front_end/third_party/marked/package/lib/marked.umd.js +69 -2722
  123. package/front_end/third_party/marked/package/lib/marked.umd.js.map +7 -1
  124. package/front_end/third_party/marked/package/man/marked.1 +4 -2
  125. package/front_end/third_party/marked/package/man/marked.1.md +2 -1
  126. package/front_end/third_party/marked/package/package.json +49 -57
  127. package/front_end/third_party/puppeteer-replay/README.chromium +2 -2
  128. package/front_end/third_party/puppeteer-replay/package/lib/cli.js +84 -80
  129. package/front_end/third_party/puppeteer-replay/package/lib/cli.js.map +1 -1
  130. package/front_end/third_party/puppeteer-replay/package/lib/extension-test.js +79 -83
  131. package/front_end/third_party/puppeteer-replay/package/lib/extension-test.js.map +1 -1
  132. package/front_end/third_party/puppeteer-replay/package/lib/main.d.ts +43 -171
  133. package/front_end/third_party/puppeteer-replay/package/lib/main.js +51 -206
  134. package/front_end/third_party/puppeteer-replay/package/lib/main.js.map +1 -1
  135. package/front_end/third_party/puppeteer-replay/package/package.json +37 -67
  136. package/front_end/tsconfig.json +1 -1
  137. package/front_end/ui/components/markdown_view/CodeBlock.ts +17 -6
  138. package/front_end/ui/components/markdown_view/MarkdownView.ts +39 -3
  139. package/front_end/ui/components/markdown_view/codeBlock.css +11 -0
  140. package/front_end/ui/components/markdown_view/markdownView.css +17 -0
  141. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +0 -79
  142. package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +16 -4
  143. package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
  144. package/inspector_overlay/testing/InspectorOverlayHelpers.ts +2 -0
  145. package/mcp/mcp.ts +1 -6
  146. package/package.json +14 -16
  147. package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgent.ts +0 -1015
  148. package/front_end/models/ai_assistance/agents/BreakpointDebuggerAgentOverlay.ts +0 -87
  149. package/front_end/third_party/marked/package/bin/marked +0 -215
  150. package/front_end/third_party/marked/package/lib/marked.cjs +0 -2726
  151. package/front_end/third_party/marked/package/lib/marked.cjs.map +0 -1
  152. package/front_end/third_party/marked/package/lib/marked.d.cts +0 -670
  153. package/front_end/third_party/marked/package/lib/marked.js +0 -2780
  154. package/front_end/third_party/marked/package/man/marked.1.txt +0 -86
  155. package/front_end/third_party/marked/package/marked.min.js +0 -6
  156. package/front_end/third_party/marked/package/src/Lexer.js +0 -492
  157. package/front_end/third_party/marked/package/src/Parser.js +0 -286
  158. package/front_end/third_party/marked/package/src/Renderer.js +0 -166
  159. package/front_end/third_party/marked/package/src/Slugger.js +0 -49
  160. package/front_end/third_party/marked/package/src/TextRenderer.js +0 -42
  161. package/front_end/third_party/marked/package/src/Tokenizer.js +0 -755
  162. package/front_end/third_party/marked/package/src/defaults.js +0 -29
  163. package/front_end/third_party/marked/package/src/helpers.js +0 -249
  164. package/front_end/third_party/marked/package/src/marked.js +0 -350
  165. package/front_end/third_party/marked/package/src/rules.js +0 -285
  166. package/front_end/third_party/puppeteer-replay/package/lib/cjs/main.cjs +0 -2099
  167. package/front_end/third_party/puppeteer-replay/package/lib/cjs/main.cjs.map +0 -1
  168. package/front_end/third_party/puppeteer-replay/package/lib/cjs/main.d.cts +0 -686
  169. package/front_end/third_party/puppeteer-replay/package/lib/cjs/main.d.ts +0 -35
  170. package/mcp/HostBindings.ts +0 -319
  171. /package/front_end/third_party/marked/package/{LICENSE.md → LICENSE} +0 -0
@@ -1,2099 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- Copyright 2022 Google LLC
5
-
6
- Licensed under the Apache License, Version 2.0 (the "License");
7
- you may not use this file except in compliance with the License.
8
- You may obtain a copy of the License at
9
-
10
- https://www.apache.org/licenses/LICENSE-2.0
11
-
12
- Unless required by applicable law or agreed to in writing, software
13
- distributed under the License is distributed on an "AS IS" BASIS,
14
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- See the License for the specific language governing permissions and
16
- limitations under the License.
17
- */
18
- exports.SelectorType = void 0;
19
- (function (SelectorType) {
20
- SelectorType["CSS"] = "css";
21
- SelectorType["ARIA"] = "aria";
22
- SelectorType["Text"] = "text";
23
- SelectorType["XPath"] = "xpath";
24
- SelectorType["Pierce"] = "pierce";
25
- })(exports.SelectorType || (exports.SelectorType = {}));
26
- exports.StepType = void 0;
27
- (function (StepType) {
28
- StepType["Change"] = "change";
29
- StepType["Click"] = "click";
30
- StepType["Close"] = "close";
31
- StepType["CustomStep"] = "customStep";
32
- StepType["DoubleClick"] = "doubleClick";
33
- StepType["EmulateNetworkConditions"] = "emulateNetworkConditions";
34
- StepType["Hover"] = "hover";
35
- StepType["KeyDown"] = "keyDown";
36
- StepType["KeyUp"] = "keyUp";
37
- StepType["Navigate"] = "navigate";
38
- StepType["Scroll"] = "scroll";
39
- StepType["SetViewport"] = "setViewport";
40
- StepType["WaitForElement"] = "waitForElement";
41
- StepType["WaitForExpression"] = "waitForExpression";
42
- })(exports.StepType || (exports.StepType = {}));
43
- exports.AssertedEventType = void 0;
44
- (function (AssertedEventType) {
45
- AssertedEventType["Navigation"] = "navigation";
46
- })(exports.AssertedEventType || (exports.AssertedEventType = {}));
47
-
48
- var Schema = /*#__PURE__*/Object.freeze({
49
- __proto__: null,
50
- get AssertedEventType () { return exports.AssertedEventType; },
51
- get SelectorType () { return exports.SelectorType; },
52
- get StepType () { return exports.StepType; }
53
- });
54
-
55
- /**
56
- Copyright 2022 Google LLC
57
-
58
- Licensed under the Apache License, Version 2.0 (the "License");
59
- you may not use this file except in compliance with the License.
60
- You may obtain a copy of the License at
61
-
62
- https://www.apache.org/licenses/LICENSE-2.0
63
-
64
- Unless required by applicable law or agreed to in writing, software
65
- distributed under the License is distributed on an "AS IS" BASIS,
66
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
67
- See the License for the specific language governing permissions and
68
- limitations under the License.
69
- */
70
- function assertAllStepTypesAreHandled(s) {
71
- throw new Error(`Unknown step type: ${s.type}`);
72
- }
73
- const typeableInputTypes = new Set([
74
- 'textarea',
75
- 'text',
76
- 'url',
77
- 'tel',
78
- 'search',
79
- 'password',
80
- 'number',
81
- 'email',
82
- ]);
83
- const pointerDeviceTypes = new Set([
84
- 'mouse',
85
- 'pen',
86
- 'touch',
87
- ]);
88
- const mouseButtonMap = new Map([
89
- ['primary', 'left'],
90
- ['auxiliary', 'middle'],
91
- ['secondary', 'right'],
92
- ['back', 'back'],
93
- ['forward', 'forward'],
94
- ]);
95
- function hasProperty(data, prop) {
96
- // TODO: use Object.hasOwn once types are available https://github.com/microsoft/TypeScript/issues/44253
97
- if (!Object.prototype.hasOwnProperty.call(data, prop)) {
98
- return false;
99
- }
100
- const keyedData = data;
101
- return keyedData[prop] !== undefined;
102
- }
103
- function isObject(data) {
104
- return typeof data === 'object' && data !== null;
105
- }
106
- function isString(data) {
107
- return typeof data === 'string';
108
- }
109
- function isNumber(data) {
110
- return typeof data === 'number';
111
- }
112
- function isArray(data) {
113
- return Array.isArray(data);
114
- }
115
- function isBoolean(data) {
116
- return typeof data === 'boolean';
117
- }
118
- function isIntegerArray(data) {
119
- return isArray(data) && data.every((item) => Number.isInteger(item));
120
- }
121
- function isKnownDeviceType(data) {
122
- return typeof data === 'string' && pointerDeviceTypes.has(data);
123
- }
124
- function isKnownMouseButton(data) {
125
- return typeof data === 'string' && mouseButtonMap.has(data);
126
- }
127
- function parseTarget(step) {
128
- if (hasProperty(step, 'target') && isString(step.target)) {
129
- return step.target;
130
- }
131
- return undefined;
132
- }
133
- function parseFrame(step) {
134
- if (hasProperty(step, 'frame')) {
135
- if (isIntegerArray(step.frame)) {
136
- return step.frame;
137
- }
138
- throw new Error('Step `frame` is not an integer array');
139
- }
140
- return undefined;
141
- }
142
- function parseNumber(step, prop) {
143
- if (hasProperty(step, prop)) {
144
- const maybeNumber = step[prop];
145
- if (isNumber(maybeNumber)) {
146
- return maybeNumber;
147
- }
148
- }
149
- throw new Error(`Step.${prop} is not a number`);
150
- }
151
- function parseBoolean(step, prop) {
152
- if (hasProperty(step, prop)) {
153
- const maybeBoolean = step[prop];
154
- if (isBoolean(maybeBoolean)) {
155
- return maybeBoolean;
156
- }
157
- }
158
- throw new Error(`Step.${prop} is not a boolean`);
159
- }
160
- function parseOptionalNumber(step, prop) {
161
- if (hasProperty(step, prop)) {
162
- return parseNumber(step, prop);
163
- }
164
- return undefined;
165
- }
166
- function parseOptionalString(step, prop) {
167
- if (hasProperty(step, prop)) {
168
- return parseString(step, prop);
169
- }
170
- return undefined;
171
- }
172
- function parseOptionalBoolean(step, prop) {
173
- if (hasProperty(step, prop)) {
174
- return parseBoolean(step, prop);
175
- }
176
- return undefined;
177
- }
178
- function parseString(step, prop) {
179
- if (hasProperty(step, prop)) {
180
- const maybeString = step[prop];
181
- if (isString(maybeString)) {
182
- return maybeString;
183
- }
184
- }
185
- throw new Error(`Step.${prop} is not a string`);
186
- }
187
- function parseSelectors(step) {
188
- if (!hasProperty(step, 'selectors')) {
189
- throw new Error('Step does not have required selectors');
190
- }
191
- if (!isArray(step.selectors)) {
192
- throw new Error('Step selectors are not an array');
193
- }
194
- if (step.selectors.length === 0) {
195
- throw new Error('Step does not have required selectors');
196
- }
197
- return step.selectors.map((s) => {
198
- if (!isString(s) && !isArray(s)) {
199
- throw new Error('Selector is not an array or string');
200
- }
201
- if (isArray(s)) {
202
- return s.map((sub) => {
203
- if (!isString(sub)) {
204
- throw new Error('Selector element is not a string');
205
- }
206
- return sub;
207
- });
208
- }
209
- return s;
210
- });
211
- }
212
- function parseOptionalSelectors(step) {
213
- if (!hasProperty(step, 'selectors')) {
214
- return undefined;
215
- }
216
- return parseSelectors(step);
217
- }
218
- function parseAssertedEvent(event) {
219
- if (!isObject(event)) {
220
- throw new Error('Asserted event is not an object');
221
- }
222
- if (!hasProperty(event, 'type')) {
223
- throw new Error('Asserted event is missing type');
224
- }
225
- if (event.type === exports.AssertedEventType.Navigation) {
226
- return {
227
- type: exports.AssertedEventType.Navigation,
228
- url: parseOptionalString(event, 'url'),
229
- title: parseOptionalString(event, 'title'),
230
- };
231
- }
232
- throw new Error('Unknown assertedEvent type');
233
- }
234
- function parseAssertedEvents(events) {
235
- if (!isArray(events)) {
236
- return undefined;
237
- }
238
- return events.map(parseAssertedEvent);
239
- }
240
- function parseBaseStep(type, step) {
241
- if (hasProperty(step, 'timeout') &&
242
- isNumber(step.timeout) &&
243
- !validTimeout(step.timeout)) {
244
- throw new Error(timeoutErrorMessage);
245
- }
246
- return {
247
- type,
248
- assertedEvents: hasProperty(step, 'assertedEvents')
249
- ? parseAssertedEvents(step.assertedEvents)
250
- : undefined,
251
- timeout: hasProperty(step, 'timeout') && isNumber(step.timeout)
252
- ? step.timeout
253
- : undefined,
254
- };
255
- }
256
- function parseStepWithTarget(type, step) {
257
- return {
258
- ...parseBaseStep(type, step),
259
- target: parseTarget(step),
260
- };
261
- }
262
- function parseStepWithFrame(type, step) {
263
- return {
264
- ...parseStepWithTarget(type, step),
265
- frame: parseFrame(step),
266
- };
267
- }
268
- function parseStepWithSelectors(type, step) {
269
- return {
270
- ...parseStepWithFrame(type, step),
271
- selectors: parseSelectors(step),
272
- };
273
- }
274
- function parseClickAttributes(step) {
275
- const attributes = {
276
- offsetX: parseNumber(step, 'offsetX'),
277
- offsetY: parseNumber(step, 'offsetY'),
278
- duration: parseOptionalNumber(step, 'duration'),
279
- };
280
- const deviceType = parseOptionalString(step, 'deviceType');
281
- if (deviceType) {
282
- if (!isKnownDeviceType(deviceType)) {
283
- throw new Error(`'deviceType' for click steps must be one of the following: ${[
284
- ...pointerDeviceTypes,
285
- ].join(', ')}`);
286
- }
287
- attributes.deviceType = deviceType;
288
- }
289
- const button = parseOptionalString(step, 'button');
290
- if (button) {
291
- if (!isKnownMouseButton(button)) {
292
- throw new Error(`'button' for click steps must be one of the following: ${[
293
- ...mouseButtonMap.keys(),
294
- ].join(', ')}`);
295
- }
296
- attributes.button = button;
297
- }
298
- return attributes;
299
- }
300
- function parseClickStep(step) {
301
- return {
302
- ...parseStepWithSelectors(exports.StepType.Click, step),
303
- ...parseClickAttributes(step),
304
- type: exports.StepType.Click,
305
- };
306
- }
307
- function parseDoubleClickStep(step) {
308
- return {
309
- ...parseStepWithSelectors(exports.StepType.DoubleClick, step),
310
- ...parseClickAttributes(step),
311
- type: exports.StepType.DoubleClick,
312
- };
313
- }
314
- function parseHoverStep(step) {
315
- return {
316
- ...parseStepWithSelectors(exports.StepType.Hover, step),
317
- type: exports.StepType.Hover,
318
- };
319
- }
320
- function parseChangeStep(step) {
321
- return {
322
- ...parseStepWithSelectors(exports.StepType.Change, step),
323
- type: exports.StepType.Change,
324
- value: parseString(step, 'value'),
325
- };
326
- }
327
- function parseKeyDownStep(step) {
328
- return {
329
- ...parseStepWithTarget(exports.StepType.KeyDown, step),
330
- type: exports.StepType.KeyDown,
331
- // TODO: type-check keys.
332
- key: parseString(step, 'key'),
333
- };
334
- }
335
- function parseKeyUpStep(step) {
336
- return {
337
- ...parseStepWithTarget(exports.StepType.KeyUp, step),
338
- type: exports.StepType.KeyUp,
339
- // TODO: type-check keys.
340
- key: parseString(step, 'key'),
341
- };
342
- }
343
- function parseEmulateNetworkConditionsStep(step) {
344
- return {
345
- ...parseStepWithTarget(exports.StepType.EmulateNetworkConditions, step),
346
- type: exports.StepType.EmulateNetworkConditions,
347
- download: parseNumber(step, 'download'),
348
- upload: parseNumber(step, 'upload'),
349
- latency: parseNumber(step, 'latency'),
350
- };
351
- }
352
- function parseCloseStep(step) {
353
- return {
354
- ...parseStepWithTarget(exports.StepType.Close, step),
355
- type: exports.StepType.Close,
356
- };
357
- }
358
- function parseSetViewportStep(step) {
359
- return {
360
- ...parseStepWithTarget(exports.StepType.SetViewport, step),
361
- type: exports.StepType.SetViewport,
362
- width: parseNumber(step, 'width'),
363
- height: parseNumber(step, 'height'),
364
- deviceScaleFactor: parseNumber(step, 'deviceScaleFactor'),
365
- isMobile: parseBoolean(step, 'isMobile'),
366
- hasTouch: parseBoolean(step, 'hasTouch'),
367
- isLandscape: parseBoolean(step, 'isLandscape'),
368
- };
369
- }
370
- function parseScrollStep(step) {
371
- return {
372
- ...parseStepWithFrame(exports.StepType.Scroll, step),
373
- type: exports.StepType.Scroll,
374
- x: parseOptionalNumber(step, 'x'),
375
- y: parseOptionalNumber(step, 'y'),
376
- selectors: parseOptionalSelectors(step),
377
- };
378
- }
379
- function parseNavigateStep(step) {
380
- return {
381
- ...parseStepWithTarget(exports.StepType.Navigate, step),
382
- type: exports.StepType.Navigate,
383
- target: parseTarget(step),
384
- url: parseString(step, 'url'),
385
- };
386
- }
387
- function parseWaitForElementStep(step) {
388
- const operator = parseOptionalString(step, 'operator');
389
- if (operator && operator !== '>=' && operator !== '==' && operator !== '<=') {
390
- throw new Error("WaitForElement step's operator is not one of '>=','==','<='");
391
- }
392
- if (hasProperty(step, 'attributes')) {
393
- if (!isObject(step.attributes) ||
394
- Object.values(step.attributes).some((attribute) => typeof attribute !== 'string')) {
395
- throw new Error("WaitForElement step's attribute is not a dictionary of strings");
396
- }
397
- }
398
- if (hasProperty(step, 'properties')) {
399
- if (!isObject(step.properties)) {
400
- throw new Error("WaitForElement step's attribute is not an object");
401
- }
402
- }
403
- return {
404
- ...parseStepWithSelectors(exports.StepType.WaitForElement, step),
405
- type: exports.StepType.WaitForElement,
406
- operator: operator,
407
- count: parseOptionalNumber(step, 'count'),
408
- visible: parseOptionalBoolean(step, 'visible'),
409
- attributes: hasProperty(step, 'attributes')
410
- ? step.attributes
411
- : undefined,
412
- properties: hasProperty(step, 'properties')
413
- ? step.properties
414
- : undefined,
415
- };
416
- }
417
- function parseWaitForExpressionStep(step) {
418
- if (!hasProperty(step, 'expression')) {
419
- throw new Error('waitForExpression step is missing `expression`');
420
- }
421
- return {
422
- ...parseStepWithFrame(exports.StepType.WaitForExpression, step),
423
- type: exports.StepType.WaitForExpression,
424
- expression: parseString(step, 'expression'),
425
- };
426
- }
427
- function parseCustomStep(step) {
428
- if (!hasProperty(step, 'name')) {
429
- throw new Error('customStep is missing name');
430
- }
431
- if (!isString(step.name)) {
432
- throw new Error("customStep's name is not a string");
433
- }
434
- return {
435
- ...parseStepWithFrame(exports.StepType.CustomStep, step),
436
- type: exports.StepType.CustomStep,
437
- name: step.name,
438
- parameters: hasProperty(step, 'parameters') ? step.parameters : undefined,
439
- };
440
- }
441
- function parseStep(step, idx) {
442
- if (!isObject(step)) {
443
- throw new Error(idx ? `Step ${idx} is not an object` : 'Step is not an object');
444
- }
445
- if (!hasProperty(step, 'type')) {
446
- throw new Error(idx ? `Step ${idx} does not have a type` : 'Step does not have a type');
447
- }
448
- if (!isString(step.type)) {
449
- throw new Error(idx
450
- ? `Type of the step ${idx} is not a string`
451
- : 'Type of the step is not a string');
452
- }
453
- switch (step.type) {
454
- case exports.StepType.Click:
455
- return parseClickStep(step);
456
- case exports.StepType.DoubleClick:
457
- return parseDoubleClickStep(step);
458
- case exports.StepType.Hover:
459
- return parseHoverStep(step);
460
- case exports.StepType.Change:
461
- return parseChangeStep(step);
462
- case exports.StepType.KeyDown:
463
- return parseKeyDownStep(step);
464
- case exports.StepType.KeyUp:
465
- return parseKeyUpStep(step);
466
- case exports.StepType.EmulateNetworkConditions:
467
- return parseEmulateNetworkConditionsStep(step);
468
- case exports.StepType.Close:
469
- return parseCloseStep(step);
470
- case exports.StepType.SetViewport:
471
- return parseSetViewportStep(step);
472
- case exports.StepType.Scroll:
473
- return parseScrollStep(step);
474
- case exports.StepType.Navigate:
475
- return parseNavigateStep(step);
476
- case exports.StepType.CustomStep:
477
- return parseCustomStep(step);
478
- case exports.StepType.WaitForElement:
479
- return parseWaitForElementStep(step);
480
- case exports.StepType.WaitForExpression:
481
- return parseWaitForExpressionStep(step);
482
- default:
483
- throw new Error(`Step type ${step.type} is not supported`);
484
- }
485
- }
486
- function parseSteps(steps) {
487
- const result = [];
488
- if (!isArray(steps)) {
489
- throw new Error('Recording `steps` is not an array');
490
- }
491
- for (const [idx, step] of steps.entries()) {
492
- result.push(parseStep(step, idx));
493
- }
494
- return result;
495
- }
496
- function cleanUndefined(json) {
497
- return JSON.parse(JSON.stringify(json));
498
- }
499
- const minTimeout = 1;
500
- const maxTimeout = 30000;
501
- const timeoutErrorMessage = `Timeout is not between ${minTimeout} and ${maxTimeout} milliseconds`;
502
- function validTimeout(timeout) {
503
- return timeout >= minTimeout && timeout <= maxTimeout;
504
- }
505
- function parse(data) {
506
- if (!isObject(data)) {
507
- throw new Error('Recording is not an object');
508
- }
509
- if (!hasProperty(data, 'title')) {
510
- throw new Error('Recording is missing `title`');
511
- }
512
- if (!isString(data.title)) {
513
- throw new Error('Recording `title` is not a string');
514
- }
515
- if (hasProperty(data, 'timeout') && !isNumber(data.timeout)) {
516
- throw new Error('Recording `timeout` is not a number');
517
- }
518
- if (!hasProperty(data, 'steps')) {
519
- throw new Error('Recording is missing `steps`');
520
- }
521
- if (hasProperty(data, 'timeout') &&
522
- isNumber(data.timeout) &&
523
- !validTimeout(data.timeout)) {
524
- throw new Error(timeoutErrorMessage);
525
- }
526
- return cleanUndefined({
527
- title: data.title,
528
- timeout: hasProperty(data, 'timeout') && isNumber(data.timeout)
529
- ? data.timeout
530
- : undefined,
531
- selectorAttribute: hasProperty(data, 'selectorAttribute') && isString(data.selectorAttribute)
532
- ? data.selectorAttribute
533
- : undefined,
534
- steps: parseSteps(data.steps),
535
- });
536
- }
537
- /**
538
- * Detects what type of a selector the string contains. For example,
539
- * `aria/Label` is a SelectorType.ARIA.
540
- *
541
- * Note that CSS selectors are special and usually don't require a prefix,
542
- * therefore, SelectorType.CSS is the default type if other types didn't match.
543
- */
544
- function getSelectorType(selector) {
545
- for (const value of Object.values(exports.SelectorType)) {
546
- if (selector.startsWith(`${value}/`)) {
547
- return value;
548
- }
549
- }
550
- return exports.SelectorType.CSS;
551
- }
552
- /**
553
- * Converts a selector or an array of selector parts into a Puppeteer selector.
554
- *
555
- * @see https://pptr.dev/guides/query-selectors#p-elements
556
- */
557
- function selectorToPElementSelector(selector) {
558
- if (!Array.isArray(selector)) {
559
- selector = [selector];
560
- }
561
- function escape(input) {
562
- return input.replace(/['"()]/g, `\\$&`);
563
- }
564
- const result = selector.map((s) => {
565
- switch (getSelectorType(s)) {
566
- case exports.SelectorType.ARIA:
567
- return `::-p-aria(${escape(s.substring(exports.SelectorType.ARIA.length + 1))})`;
568
- case exports.SelectorType.CSS:
569
- return s;
570
- case exports.SelectorType.XPath:
571
- return `::-p-xpath(${escape(s.substring(exports.SelectorType.XPath.length + 1))})`;
572
- case exports.SelectorType.Pierce:
573
- return `:scope >>> ${s.substring(exports.SelectorType.Pierce.length + 1)}`;
574
- case exports.SelectorType.Text:
575
- return `::-p-text(${escape(s.substring(exports.SelectorType.Text.length + 1))})`;
576
- }
577
- });
578
- return result.join(' >>>> ');
579
- }
580
-
581
- /**
582
- Copyright 2022 Google LLC
583
-
584
- Licensed under the Apache License, Version 2.0 (the "License");
585
- you may not use this file except in compliance with the License.
586
- You may obtain a copy of the License at
587
-
588
- https://www.apache.org/licenses/LICENSE-2.0
589
-
590
- Unless required by applicable law or agreed to in writing, software
591
- distributed under the License is distributed on an "AS IS" BASIS,
592
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
593
- See the License for the specific language governing permissions and
594
- limitations under the License.
595
- */
596
- class StringifyExtension {
597
- async beforeAllSteps(out, flow) { }
598
- async afterAllSteps(out, flow) { }
599
- async beforeEachStep(out, step, flow) { }
600
- async stringifyStep(out, step, flow) { }
601
- async afterEachStep(out, step, flow) { }
602
- }
603
-
604
- /**
605
- Copyright 2022 Google LLC
606
-
607
- Licensed under the Apache License, Version 2.0 (the "License");
608
- you may not use this file except in compliance with the License.
609
- You may obtain a copy of the License at
610
-
611
- https://www.apache.org/licenses/LICENSE-2.0
612
-
613
- Unless required by applicable law or agreed to in writing, software
614
- distributed under the License is distributed on an "AS IS" BASIS,
615
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
616
- See the License for the specific language governing permissions and
617
- limitations under the License.
618
- */
619
- /**
620
- * Stringifies a user flow to JSON with source maps.
621
- *
622
- * You probably want to strip the source map because not all
623
- * parsers support comments in JSON.
624
- */
625
- class JSONStringifyExtension extends StringifyExtension {
626
- async beforeAllSteps(out, flow) {
627
- const copy = {
628
- ...flow,
629
- steps: undefined,
630
- };
631
- // Stringify top-level attributes.
632
- const text = JSON.stringify(copy, null, out.getIndent());
633
- const lines = text.split('\n');
634
- lines.pop();
635
- lines[lines.length - 1] += ',';
636
- lines.push(out.getIndent() + `"steps": [`);
637
- out.appendLine(lines.join('\n')).startBlock().startBlock();
638
- }
639
- async afterAllSteps(out) {
640
- out
641
- .endBlock()
642
- .endBlock()
643
- .appendLine(out.getIndent() + `]`)
644
- .appendLine('}');
645
- }
646
- async stringifyStep(out, step, flow) {
647
- const stepText = JSON.stringify(step, null, out.getIndent());
648
- if (!flow) {
649
- out.appendLine(stepText);
650
- return;
651
- }
652
- const separator = flow.steps.lastIndexOf(step) === flow.steps.length - 1 ? '' : ',';
653
- out.appendLine(stepText + separator);
654
- }
655
- }
656
-
657
- /**
658
- Copyright 2022 Google LLC
659
-
660
- Licensed under the Apache License, Version 2.0 (the "License");
661
- you may not use this file except in compliance with the License.
662
- You may obtain a copy of the License at
663
-
664
- https://www.apache.org/licenses/LICENSE-2.0
665
-
666
- Unless required by applicable law or agreed to in writing, software
667
- distributed under the License is distributed on an "AS IS" BASIS,
668
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
669
- See the License for the specific language governing permissions and
670
- limitations under the License.
671
- */
672
- class InMemoryLineWriter {
673
- #indentation;
674
- #currentIndentation = 0;
675
- #lines = [];
676
- constructor(indentation) {
677
- this.#indentation = indentation;
678
- }
679
- appendLine(line) {
680
- const lines = line.split('\n').map((line) => {
681
- const indentedLine = line
682
- ? this.#indentation.repeat(this.#currentIndentation) + line.trimEnd()
683
- : '';
684
- return indentedLine;
685
- });
686
- this.#lines.push(...lines);
687
- return this;
688
- }
689
- startBlock() {
690
- this.#currentIndentation++;
691
- return this;
692
- }
693
- endBlock() {
694
- this.#currentIndentation--;
695
- if (this.#currentIndentation < 0) {
696
- throw new Error('Extra endBlock');
697
- }
698
- return this;
699
- }
700
- toString() {
701
- // Scripts should end with a final blank line.
702
- return this.#lines.join('\n') + '\n';
703
- }
704
- getIndent() {
705
- return this.#indentation;
706
- }
707
- getSize() {
708
- return this.#lines.length;
709
- }
710
- }
711
-
712
- /**
713
- Copyright 2022 Google LLC
714
-
715
- Licensed under the Apache License, Version 2.0 (the "License");
716
- you may not use this file except in compliance with the License.
717
- You may obtain a copy of the License at
718
-
719
- https://www.apache.org/licenses/LICENSE-2.0
720
-
721
- Unless required by applicable law or agreed to in writing, software
722
- distributed under the License is distributed on an "AS IS" BASIS,
723
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
724
- See the License for the specific language governing permissions and
725
- limitations under the License.
726
- */
727
- /**
728
- * Copyright (c) 2020 The Chromium Authors. All rights reserved.
729
- * Use of this source code is governed by a BSD-style license that can be
730
- * found in the LICENSE file.
731
- */
732
- function formatJSONAsJS(json, indent) {
733
- const buffer = [];
734
- format(json, buffer, 1, indent);
735
- return buffer.join('');
736
- }
737
- function format(json, buffer = [], level = 1, indent = ' ') {
738
- switch (typeof json) {
739
- case 'bigint':
740
- case 'symbol':
741
- case 'function':
742
- case 'undefined':
743
- throw new Error('Invalid JSON');
744
- case 'number':
745
- case 'boolean':
746
- buffer.push(String(json));
747
- break;
748
- case 'string':
749
- buffer.push(formatAsJSLiteral(json));
750
- break;
751
- case 'object': {
752
- if (json === null) {
753
- buffer.push('null');
754
- }
755
- else if (Array.isArray(json)) {
756
- buffer.push('[\n');
757
- for (let i = 0; i < json.length; i++) {
758
- buffer.push(indent.repeat(level));
759
- format(json[i], buffer, level + 1, indent);
760
- if (i !== json.length - 1) {
761
- buffer.push(',');
762
- }
763
- buffer.push('\n');
764
- }
765
- buffer.push(indent.repeat(level - 1) + ']');
766
- }
767
- else {
768
- buffer.push('{\n');
769
- const keys = Object.keys(json);
770
- for (let i = 0; i < keys.length; i++) {
771
- const key = keys[i];
772
- const value = json[key];
773
- if (value === undefined) {
774
- continue;
775
- }
776
- buffer.push(indent.repeat(level));
777
- buffer.push(key);
778
- buffer.push(': ');
779
- format(value, buffer, level + 1, indent);
780
- if (i !== keys.length - 1) {
781
- buffer.push(',');
782
- }
783
- buffer.push('\n');
784
- }
785
- buffer.push(indent.repeat(level - 1) + '}');
786
- }
787
- break;
788
- }
789
- default:
790
- throw new Error('Unknown object type');
791
- }
792
- return buffer;
793
- }
794
- // Taken from https://source.chromium.org/chromium/chromium/src/+/main:third_party/devtools-frontend/src/front_end/core/platform/string-utilities.ts;l=29;drc=111134437ee51d74433829bed0088f7239e18867.
795
- const toHexadecimal = (charCode, padToLength) => {
796
- return charCode.toString(16).toUpperCase().padStart(padToLength, '0');
797
- };
798
- // Remember to update the third group in the regexps patternsToEscape and
799
- // patternsToEscapePlusSingleQuote when adding new entries in this map.
800
- const escapedReplacements = new Map([
801
- ['\b', '\\b'],
802
- ['\f', '\\f'],
803
- ['\n', '\\n'],
804
- ['\r', '\\r'],
805
- ['\t', '\\t'],
806
- ['\v', '\\v'],
807
- ["'", "\\'"],
808
- ['\\', '\\\\'],
809
- ['<!--', '\\x3C!--'],
810
- ['<script', '\\x3Cscript'],
811
- ['</script', '\\x3C/script'],
812
- ]);
813
- const formatAsJSLiteral = (content) => {
814
- const patternsToEscape = /(\\|<(?:!--|\/?script))|(\p{Control})|(\p{Surrogate})/gu;
815
- const patternsToEscapePlusSingleQuote = /(\\|'|<(?:!--|\/?script))|(\p{Control})|(\p{Surrogate})/gu;
816
- const escapePattern = (match, pattern, controlChar, loneSurrogate) => {
817
- if (controlChar) {
818
- if (escapedReplacements.has(controlChar)) {
819
- // @ts-ignore https://github.com/microsoft/TypeScript/issues/13086
820
- return escapedReplacements.get(controlChar);
821
- }
822
- const twoDigitHex = toHexadecimal(controlChar.charCodeAt(0), 2);
823
- return '\\x' + twoDigitHex;
824
- }
825
- if (loneSurrogate) {
826
- const fourDigitHex = toHexadecimal(loneSurrogate.charCodeAt(0), 4);
827
- return '\\u' + fourDigitHex;
828
- }
829
- if (pattern) {
830
- return escapedReplacements.get(pattern) || '';
831
- }
832
- return match;
833
- };
834
- let escapedContent = '';
835
- let quote = '';
836
- if (!content.includes("'")) {
837
- quote = "'";
838
- escapedContent = content.replace(patternsToEscape, escapePattern);
839
- }
840
- else if (!content.includes('"')) {
841
- quote = '"';
842
- escapedContent = content.replace(patternsToEscape, escapePattern);
843
- }
844
- else if (!content.includes('`') && !content.includes('${')) {
845
- quote = '`';
846
- escapedContent = content.replace(patternsToEscape, escapePattern);
847
- }
848
- else {
849
- quote = "'";
850
- escapedContent = content.replace(patternsToEscapePlusSingleQuote, escapePattern);
851
- }
852
- return `${quote}${escapedContent}${quote}`;
853
- };
854
-
855
- /**
856
- Copyright 2022 Google LLC
857
-
858
- Licensed under the Apache License, Version 2.0 (the "License");
859
- you may not use this file except in compliance with the License.
860
- You may obtain a copy of the License at
861
-
862
- https://www.apache.org/licenses/LICENSE-2.0
863
-
864
- Unless required by applicable law or agreed to in writing, software
865
- distributed under the License is distributed on an "AS IS" BASIS,
866
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
867
- See the License for the specific language governing permissions and
868
- limitations under the License.
869
- */
870
- class PuppeteerStringifyExtension extends StringifyExtension {
871
- #shouldAppendWaitForElementHelper = false;
872
- #targetBrowser;
873
- constructor(targetBrowser = 'chrome') {
874
- super();
875
- this.#targetBrowser = targetBrowser;
876
- }
877
- async beforeAllSteps(out, flow) {
878
- out.appendLine("const puppeteer = require('puppeteer'); // v23.0.0 or later");
879
- out.appendLine('');
880
- out.appendLine('(async () => {').startBlock();
881
- if (this.#targetBrowser === 'firefox') {
882
- out.appendLine(`const browser = await puppeteer.launch({browser: 'firefox'});`);
883
- }
884
- else {
885
- out.appendLine('const browser = await puppeteer.launch();');
886
- }
887
- out.appendLine('const page = await browser.newPage();');
888
- out.appendLine(`const timeout = ${flow.timeout || defaultTimeout};`);
889
- out.appendLine('page.setDefaultTimeout(timeout);');
890
- out.appendLine('');
891
- this.#shouldAppendWaitForElementHelper = false;
892
- }
893
- async afterAllSteps(out, flow) {
894
- out.appendLine('');
895
- out.appendLine('await browser.close();');
896
- out.appendLine('');
897
- if (this.#shouldAppendWaitForElementHelper) {
898
- for (const line of waitForElementHelper.split('\n')) {
899
- out.appendLine(line);
900
- }
901
- }
902
- out.endBlock().appendLine('})().catch(err => {').startBlock();
903
- out.appendLine('console.error(err);');
904
- out.appendLine('process.exit(1);');
905
- out.endBlock().appendLine('});');
906
- }
907
- async stringifyStep(out, step, flow) {
908
- out.appendLine('{').startBlock();
909
- if (step.timeout !== undefined) {
910
- out.appendLine(`const timeout = ${step.timeout};`);
911
- }
912
- this.#appendContext(out, step);
913
- const waitForEvents = step.assertedEvents && step.type !== exports.StepType.Navigate;
914
- if (waitForEvents) {
915
- out.appendLine('const promises = [];');
916
- out.appendLine('const startWaitingForEvents = () => {').startBlock();
917
- for (const event of step.assertedEvents) {
918
- switch (event.type) {
919
- case exports.AssertedEventType.Navigation: {
920
- out.appendLine(`promises.push(${'frame' in step && step.frame ? 'frame' : 'targetPage'}.waitForNavigation());`);
921
- break;
922
- }
923
- default:
924
- throw new Error(`Event type ${event.type} is not supported`);
925
- }
926
- }
927
- out.endBlock().appendLine('}');
928
- }
929
- this.#appendStepType(out, step);
930
- if (waitForEvents) {
931
- out.appendLine('await Promise.all(promises);');
932
- }
933
- out.endBlock().appendLine('}');
934
- }
935
- #appendTarget(out, target) {
936
- if (target === 'main') {
937
- out.appendLine('const targetPage = page;');
938
- }
939
- else {
940
- out.appendLine(`const target = await browser.waitForTarget(t => t.url() === ${formatJSONAsJS(target, out.getIndent())}, { timeout });`);
941
- out.appendLine('const targetPage = await target.page();');
942
- out.appendLine('targetPage.setDefaultTimeout(timeout);');
943
- }
944
- }
945
- #appendFrame(out, path) {
946
- out.appendLine('let frame = targetPage.mainFrame();');
947
- for (const index of path) {
948
- out.appendLine(`frame = frame.childFrames()[${index}];`);
949
- }
950
- }
951
- #appendContext(out, step) {
952
- // TODO fix optional target: should it be main?
953
- this.#appendTarget(out, step.target || 'main');
954
- // TODO fix optional frame: should it be required?
955
- if (step.frame) {
956
- this.#appendFrame(out, step.frame);
957
- }
958
- }
959
- #appendLocators(out, step, action) {
960
- out.appendLine('await puppeteer.Locator.race([').startBlock();
961
- out.appendLine(step.selectors
962
- .map((s) => {
963
- return `${step.frame ? 'frame' : 'targetPage'}.locator(${formatJSONAsJS(selectorToPElementSelector(s), out.getIndent())})`;
964
- })
965
- .join(',\n'));
966
- out.endBlock().appendLine('])');
967
- out.startBlock().appendLine('.setTimeout(timeout)');
968
- if (step.assertedEvents?.length) {
969
- out.appendLine(`.on('action', () => startWaitingForEvents())`);
970
- }
971
- action();
972
- out.endBlock();
973
- }
974
- #appendClickStep(out, step) {
975
- this.#appendLocators(out, step, () => {
976
- out.appendLine('.click({');
977
- if (step.duration) {
978
- out.appendLine(` delay: ${step.duration},`);
979
- }
980
- if (step.button) {
981
- out.appendLine(` button: '${mouseButtonMap.get(step.button)}',`);
982
- }
983
- out.appendLine(' offset: {');
984
- out.appendLine(` x: ${step.offsetX},`);
985
- out.appendLine(` y: ${step.offsetY},`);
986
- out.appendLine(' },');
987
- out.appendLine('});');
988
- });
989
- }
990
- #appendDoubleClickStep(out, step) {
991
- this.#appendLocators(out, step, () => {
992
- out.appendLine('.click({');
993
- out.appendLine(` count: 2,`);
994
- if (step.duration) {
995
- out.appendLine(` delay: ${step.duration},`);
996
- }
997
- if (step.button) {
998
- out.appendLine(` button: '${mouseButtonMap.get(step.button)}',`);
999
- }
1000
- out.appendLine(' offset: {');
1001
- out.appendLine(` x: ${step.offsetX},`);
1002
- out.appendLine(` y: ${step.offsetY},`);
1003
- out.appendLine(' },');
1004
- out.appendLine('});');
1005
- });
1006
- }
1007
- #appendHoverStep(out, step) {
1008
- this.#appendLocators(out, step, () => {
1009
- out.appendLine('.hover();');
1010
- });
1011
- }
1012
- #appendChangeStep(out, step) {
1013
- this.#appendLocators(out, step, () => {
1014
- out.appendLine(`.fill(${formatJSONAsJS(step.value, out.getIndent())});`);
1015
- });
1016
- }
1017
- #appendEmulateNetworkConditionsStep(out, step) {
1018
- out.appendLine('await targetPage.emulateNetworkConditions({');
1019
- out.appendLine(` offline: ${!step.download && !step.upload},`);
1020
- out.appendLine(` downloadThroughput: ${step.download},`);
1021
- out.appendLine(` uploadThroughput: ${step.upload},`);
1022
- out.appendLine(` latency: ${step.latency},`);
1023
- out.appendLine('});');
1024
- }
1025
- #appendKeyDownStep(out, step) {
1026
- out.appendLine(`await targetPage.keyboard.down(${formatJSONAsJS(step.key, out.getIndent())});`);
1027
- }
1028
- #appendKeyUpStep(out, step) {
1029
- out.appendLine(`await targetPage.keyboard.up(${formatJSONAsJS(step.key, out.getIndent())});`);
1030
- }
1031
- #appendCloseStep(out, step) {
1032
- out.appendLine('await targetPage.close()');
1033
- }
1034
- #appendViewportStep(out, step) {
1035
- out.appendLine(`await targetPage.setViewport(${formatJSONAsJS({
1036
- width: step.width,
1037
- height: step.height,
1038
- }, out.getIndent())})`);
1039
- }
1040
- #appendScrollStep(out, step) {
1041
- if ('selectors' in step) {
1042
- this.#appendLocators(out, step, () => {
1043
- out.appendLine(`.scroll({ scrollTop: ${step.y}, scrollLeft: ${step.x}});`);
1044
- });
1045
- }
1046
- else {
1047
- out.appendLine(`await targetPage.evaluate((x, y) => { window.scroll(x, y); }, ${step.x}, ${step.y})`);
1048
- }
1049
- }
1050
- #appendStepType(out, step) {
1051
- switch (step.type) {
1052
- case exports.StepType.Click:
1053
- return this.#appendClickStep(out, step);
1054
- case exports.StepType.DoubleClick:
1055
- return this.#appendDoubleClickStep(out, step);
1056
- case exports.StepType.Hover:
1057
- return this.#appendHoverStep(out, step);
1058
- case exports.StepType.Change:
1059
- return this.#appendChangeStep(out, step);
1060
- case exports.StepType.EmulateNetworkConditions:
1061
- return this.#appendEmulateNetworkConditionsStep(out, step);
1062
- case exports.StepType.KeyDown:
1063
- return this.#appendKeyDownStep(out, step);
1064
- case exports.StepType.KeyUp:
1065
- return this.#appendKeyUpStep(out, step);
1066
- case exports.StepType.Close:
1067
- return this.#appendCloseStep(out, step);
1068
- case exports.StepType.SetViewport:
1069
- return this.#appendViewportStep(out, step);
1070
- case exports.StepType.Scroll:
1071
- return this.#appendScrollStep(out, step);
1072
- case exports.StepType.Navigate:
1073
- return this.#appendNavigationStep(out, step);
1074
- case exports.StepType.WaitForElement:
1075
- return this.#appendWaitForElementStep(out, step);
1076
- case exports.StepType.WaitForExpression:
1077
- return this.#appendWaitExpressionStep(out, step);
1078
- case exports.StepType.CustomStep:
1079
- return; // TODO: implement these
1080
- default:
1081
- return assertAllStepTypesAreHandled(step);
1082
- }
1083
- }
1084
- #appendNavigationStep(out, step) {
1085
- out.appendLine(`await targetPage.goto(${formatJSONAsJS(step.url, out.getIndent())});`);
1086
- }
1087
- #appendWaitExpressionStep(out, step) {
1088
- out.appendLine(`await ${step.frame ? 'frame' : 'targetPage'}.waitForFunction(${formatJSONAsJS(step.expression, out.getIndent())}, { timeout });`);
1089
- }
1090
- #appendWaitForElementStep(out, step) {
1091
- this.#shouldAppendWaitForElementHelper = true;
1092
- out.appendLine(`await waitForElement(${formatJSONAsJS(step, out.getIndent())}, ${step.frame ? 'frame' : 'targetPage'}, timeout);`);
1093
- }
1094
- }
1095
- const defaultTimeout = 5000;
1096
- const waitForElementHelper = `async function waitForElement(step, frame, timeout) {
1097
- const {
1098
- count = 1,
1099
- operator = '>=',
1100
- visible = true,
1101
- properties,
1102
- attributes,
1103
- } = step;
1104
- const compFn = {
1105
- '==': (a, b) => a === b,
1106
- '>=': (a, b) => a >= b,
1107
- '<=': (a, b) => a <= b,
1108
- }[operator];
1109
- await waitForFunction(async () => {
1110
- const elements = await querySelectorsAll(step.selectors, frame);
1111
- let result = compFn(elements.length, count);
1112
- const elementsHandle = await frame.evaluateHandle((...elements) => {
1113
- return elements;
1114
- }, ...elements);
1115
- await Promise.all(elements.map((element) => element.dispose()));
1116
- if (result && (properties || attributes)) {
1117
- result = await elementsHandle.evaluate(
1118
- (elements, properties, attributes) => {
1119
- for (const element of elements) {
1120
- if (attributes) {
1121
- for (const [name, value] of Object.entries(attributes)) {
1122
- if (element.getAttribute(name) !== value) {
1123
- return false;
1124
- }
1125
- }
1126
- }
1127
- if (properties) {
1128
- if (!isDeepMatch(properties, element)) {
1129
- return false;
1130
- }
1131
- }
1132
- }
1133
- return true;
1134
-
1135
- function isDeepMatch(a, b) {
1136
- if (a === b) {
1137
- return true;
1138
- }
1139
- if ((a && !b) || (!a && b)) {
1140
- return false;
1141
- }
1142
- if (!(a instanceof Object) || !(b instanceof Object)) {
1143
- return false;
1144
- }
1145
- for (const [key, value] of Object.entries(a)) {
1146
- if (!isDeepMatch(value, b[key])) {
1147
- return false;
1148
- }
1149
- }
1150
- return true;
1151
- }
1152
- },
1153
- properties,
1154
- attributes
1155
- );
1156
- }
1157
- await elementsHandle.dispose();
1158
- return result === visible;
1159
- }, timeout);
1160
- }
1161
-
1162
- async function querySelectorsAll(selectors, frame) {
1163
- for (const selector of selectors) {
1164
- const result = await querySelectorAll(selector, frame);
1165
- if (result.length) {
1166
- return result;
1167
- }
1168
- }
1169
- return [];
1170
- }
1171
-
1172
- async function querySelectorAll(selector, frame) {
1173
- if (!Array.isArray(selector)) {
1174
- selector = [selector];
1175
- }
1176
- if (!selector.length) {
1177
- throw new Error('Empty selector provided to querySelectorAll');
1178
- }
1179
- let elements = [];
1180
- for (let i = 0; i < selector.length; i++) {
1181
- const part = selector[i];
1182
- if (i === 0) {
1183
- elements = await frame.$$(part);
1184
- } else {
1185
- const tmpElements = elements;
1186
- elements = [];
1187
- for (const el of tmpElements) {
1188
- elements.push(...(await el.$$(part)));
1189
- }
1190
- }
1191
- if (elements.length === 0) {
1192
- return [];
1193
- }
1194
- if (i < selector.length - 1) {
1195
- const tmpElements = [];
1196
- for (const el of elements) {
1197
- const newEl = (await el.evaluateHandle(el => el.shadowRoot ? el.shadowRoot : el)).asElement();
1198
- if (newEl) {
1199
- tmpElements.push(newEl);
1200
- }
1201
- }
1202
- elements = tmpElements;
1203
- }
1204
- }
1205
- return elements;
1206
- }
1207
-
1208
- async function waitForFunction(fn, timeout) {
1209
- let isActive = true;
1210
- const timeoutId = setTimeout(() => {
1211
- isActive = false;
1212
- }, timeout);
1213
- while (isActive) {
1214
- const result = await fn();
1215
- if (result) {
1216
- clearTimeout(timeoutId);
1217
- return;
1218
- }
1219
- await new Promise(resolve => setTimeout(resolve, 100));
1220
- }
1221
- throw new Error('Timed out');
1222
- }`;
1223
-
1224
- /**
1225
- Copyright 2022 Google LLC
1226
-
1227
- Licensed under the Apache License, Version 2.0 (the "License");
1228
- you may not use this file except in compliance with the License.
1229
- You may obtain a copy of the License at
1230
-
1231
- https://www.apache.org/licenses/LICENSE-2.0
1232
-
1233
- Unless required by applicable law or agreed to in writing, software
1234
- distributed under the License is distributed on an "AS IS" BASIS,
1235
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1236
- See the License for the specific language governing permissions and
1237
- limitations under the License.
1238
- */
1239
- const alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
1240
- const charToIdx = alpha.split('').reduce((acc, char, idx) => {
1241
- acc.set(char, idx);
1242
- return acc;
1243
- }, new Map());
1244
- const LEAST_5_BIT_MASK = 0b011111;
1245
- const CONTINUATION_BIT_MASK = 0b100000;
1246
- const MAX_INT = 2147483647;
1247
- /**
1248
- * Encoding variable length integer into base64 (6-bit):
1249
- *
1250
- * 1 N N N N N | 0 N N N N N
1251
- *
1252
- * The first bit indicates if there is more data for the int.
1253
- */
1254
- function encodeInt(num) {
1255
- if (num < 0) {
1256
- throw new Error('Only postive integers and zero are supported');
1257
- }
1258
- if (num > MAX_INT) {
1259
- throw new Error('Only integers between 0 and ' + MAX_INT + ' are supported');
1260
- }
1261
- const result = [];
1262
- do {
1263
- let payload = num & LEAST_5_BIT_MASK;
1264
- num >>>= 5;
1265
- if (num > 0)
1266
- payload |= CONTINUATION_BIT_MASK;
1267
- result.push(alpha[payload]);
1268
- } while (num !== 0);
1269
- return result.join('');
1270
- }
1271
- function encode(nums) {
1272
- const parts = [];
1273
- for (const num of nums) {
1274
- parts.push(encodeInt(num));
1275
- }
1276
- return parts.join('');
1277
- }
1278
- function decode(str) {
1279
- const results = [];
1280
- const chrs = str.split('');
1281
- let result = 0;
1282
- let shift = 0;
1283
- for (const ch of chrs) {
1284
- const num = charToIdx.get(ch);
1285
- result |= (num & LEAST_5_BIT_MASK) << shift;
1286
- shift += 5;
1287
- const hasMore = num & CONTINUATION_BIT_MASK;
1288
- if (!hasMore) {
1289
- results.push(result);
1290
- result = 0;
1291
- shift = 0;
1292
- }
1293
- }
1294
- return results;
1295
- }
1296
-
1297
- /**
1298
- Copyright 2022 Google LLC
1299
-
1300
- Licensed under the Apache License, Version 2.0 (the "License");
1301
- you may not use this file except in compliance with the License.
1302
- You may obtain a copy of the License at
1303
-
1304
- https://www.apache.org/licenses/LICENSE-2.0
1305
-
1306
- Unless required by applicable law or agreed to in writing, software
1307
- distributed under the License is distributed on an "AS IS" BASIS,
1308
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1309
- See the License for the specific language governing permissions and
1310
- limitations under the License.
1311
- */
1312
- const SOURCE_MAP_PREFIX = '//# recorderSourceMap=';
1313
- /**
1314
- * Stringifes an entire recording. The following hooks are invoked with the `flow` parameter containing the entire flow:
1315
- * - `beforeAllSteps` (once)
1316
- * - `beforeEachStep` (per step)
1317
- * - `stringifyStep` (per step)
1318
- * - `afterEachStep` (per step)
1319
- * - `afterAllSteps` (once)
1320
- */
1321
- async function stringify(flow, opts) {
1322
- if (!opts) {
1323
- opts = {};
1324
- }
1325
- const ext = opts.extension ?? new PuppeteerStringifyExtension();
1326
- const out = opts.writer ?? new InMemoryLineWriter(opts.indentation ?? ' ');
1327
- await ext.beforeAllSteps?.(out, flow);
1328
- const sourceMap = [1]; // The first int indicates the version.
1329
- for (const step of flow.steps) {
1330
- const firstLine = out.getSize();
1331
- await ext.beforeEachStep?.(out, step, flow);
1332
- await ext.stringifyStep(out, step, flow);
1333
- await ext.afterEachStep?.(out, step, flow);
1334
- const lastLine = out.getSize();
1335
- sourceMap.push(...[firstLine, lastLine - firstLine]);
1336
- }
1337
- await ext.afterAllSteps?.(out, flow);
1338
- out.appendLine(SOURCE_MAP_PREFIX + encode(sourceMap));
1339
- return out.toString();
1340
- }
1341
- /**
1342
- * Stringifes a single step. Only the following hooks are invoked with the `flow` parameter as undefined:
1343
- * - `beforeEachStep`
1344
- * - `stringifyStep`
1345
- * - `afterEachStep`
1346
- */
1347
- async function stringifyStep(step, opts) {
1348
- if (!opts) {
1349
- opts = {};
1350
- }
1351
- let ext = opts.extension;
1352
- if (!ext) {
1353
- ext = new PuppeteerStringifyExtension();
1354
- }
1355
- if (!opts.indentation) {
1356
- opts.indentation = ' ';
1357
- }
1358
- const out = opts.writer ?? new InMemoryLineWriter(opts.indentation ?? ' ');
1359
- await ext.beforeEachStep?.(out, step);
1360
- await ext.stringifyStep(out, step);
1361
- await ext.afterEachStep?.(out, step);
1362
- return out.toString();
1363
- }
1364
- function isSourceMapLine(line) {
1365
- return line.trim().startsWith(SOURCE_MAP_PREFIX);
1366
- }
1367
- /**
1368
- * Extracts a source map from a text.
1369
- */
1370
- function parseSourceMap(text) {
1371
- const lines = text.split('\n');
1372
- for (let i = lines.length - 1; i >= 0; i--) {
1373
- const line = lines[i];
1374
- if (isSourceMapLine(line)) {
1375
- return decode(line.trim().substring(SOURCE_MAP_PREFIX.length));
1376
- }
1377
- }
1378
- return;
1379
- }
1380
- function stripSourceMap(text) {
1381
- const lines = text.split('\n');
1382
- return lines.filter((line) => !isSourceMapLine(line)).join('\n');
1383
- }
1384
-
1385
- /**
1386
- Copyright 2022 Google LLC
1387
-
1388
- Licensed under the Apache License, Version 2.0 (the "License");
1389
- you may not use this file except in compliance with the License.
1390
- You may obtain a copy of the License at
1391
-
1392
- https://www.apache.org/licenses/LICENSE-2.0
1393
-
1394
- Unless required by applicable law or agreed to in writing, software
1395
- distributed under the License is distributed on an "AS IS" BASIS,
1396
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1397
- See the License for the specific language governing permissions and
1398
- limitations under the License.
1399
- */
1400
- class RunnerExtension {
1401
- async beforeAllSteps(flow) { }
1402
- async afterAllSteps(flow) { }
1403
- async beforeEachStep(step, flow) { }
1404
- async runStep(step, flow) { }
1405
- async afterEachStep(step, flow) { }
1406
- }
1407
-
1408
- const comparators = {
1409
- '==': (a, b) => a === b,
1410
- '>=': (a, b) => a >= b,
1411
- '<=': (a, b) => a <= b,
1412
- };
1413
- function waitForTimeout(timeout) {
1414
- return new Promise((resolve) => {
1415
- setTimeout(resolve, timeout);
1416
- });
1417
- }
1418
- class PuppeteerRunnerExtension extends RunnerExtension {
1419
- browser;
1420
- page;
1421
- timeout;
1422
- constructor(browser, page, opts) {
1423
- super();
1424
- this.browser = browser;
1425
- this.page = page;
1426
- this.timeout = opts?.timeout || 5000;
1427
- }
1428
- async #ensureAutomationEmulatation(pageOrFrame) {
1429
- try {
1430
- await pageOrFrame
1431
- ._client()
1432
- .send('Emulation.setAutomationOverride', { enabled: true });
1433
- }
1434
- catch {
1435
- // ignore errors as not all versions support this command.
1436
- }
1437
- }
1438
- #getTimeoutForStep(step, flow) {
1439
- return step.timeout || flow?.timeout || this.timeout;
1440
- }
1441
- async runStep(step, flow) {
1442
- const timeout = this.#getTimeoutForStep(step, flow);
1443
- const page = this.page;
1444
- const browser = this.browser;
1445
- const targetPage = await getTargetPageForStep(browser, page, step, timeout);
1446
- let targetFrame = null;
1447
- if (!targetPage && step.target) {
1448
- targetFrame = await page.waitForFrame(step.target, { timeout });
1449
- }
1450
- const targetPageOrFrame = targetFrame || targetPage;
1451
- if (!targetPageOrFrame) {
1452
- throw new Error('Target is not found for step: ' + JSON.stringify(step));
1453
- }
1454
- await this.#ensureAutomationEmulatation(targetPageOrFrame);
1455
- const localFrame = await getFrame(targetPageOrFrame, step);
1456
- await this.runStepInFrame(step, page, targetPageOrFrame, localFrame, timeout);
1457
- }
1458
- /**
1459
- * @internal
1460
- */
1461
- async runStepInFrame(step, mainPage, targetPageOrFrame, localFrame, timeout) {
1462
- let assertedEventsPromise = null;
1463
- const startWaitingForEvents = () => {
1464
- assertedEventsPromise = waitForEvents(localFrame, step, timeout);
1465
- };
1466
- const locatorRace = this.page.locatorRace;
1467
- switch (step.type) {
1468
- case exports.StepType.DoubleClick:
1469
- await locatorRace(step.selectors.map((selector) => {
1470
- return localFrame.locator(selectorToPElementSelector(selector));
1471
- }))
1472
- .setTimeout(timeout)
1473
- .on('action', () => startWaitingForEvents())
1474
- .click({
1475
- count: 2,
1476
- button: step.button && mouseButtonMap.get(step.button),
1477
- delay: step.duration,
1478
- offset: {
1479
- x: step.offsetX,
1480
- y: step.offsetY,
1481
- },
1482
- });
1483
- break;
1484
- case exports.StepType.Click:
1485
- await locatorRace(step.selectors.map((selector) => {
1486
- return localFrame.locator(selectorToPElementSelector(selector));
1487
- }))
1488
- .setTimeout(timeout)
1489
- .on('action', () => startWaitingForEvents())
1490
- .click({
1491
- delay: step.duration,
1492
- button: step.button && mouseButtonMap.get(step.button),
1493
- offset: {
1494
- x: step.offsetX,
1495
- y: step.offsetY,
1496
- },
1497
- });
1498
- break;
1499
- case exports.StepType.Hover:
1500
- await locatorRace(step.selectors.map((selector) => {
1501
- return localFrame.locator(selectorToPElementSelector(selector));
1502
- }))
1503
- .setTimeout(timeout)
1504
- .on('action', () => startWaitingForEvents())
1505
- .hover();
1506
- break;
1507
- case exports.StepType.EmulateNetworkConditions:
1508
- {
1509
- startWaitingForEvents();
1510
- const { download, upload, latency } = step;
1511
- await mainPage.emulateNetworkConditions({
1512
- offline: !download && !upload,
1513
- download,
1514
- upload,
1515
- latency,
1516
- });
1517
- }
1518
- break;
1519
- case exports.StepType.KeyDown:
1520
- {
1521
- startWaitingForEvents();
1522
- await mainPage.keyboard.down(step.key);
1523
- await waitForTimeout(100);
1524
- }
1525
- break;
1526
- case exports.StepType.KeyUp:
1527
- {
1528
- startWaitingForEvents();
1529
- await mainPage.keyboard.up(step.key);
1530
- await waitForTimeout(100);
1531
- }
1532
- break;
1533
- case exports.StepType.Close:
1534
- {
1535
- if ('close' in targetPageOrFrame) {
1536
- startWaitingForEvents();
1537
- await targetPageOrFrame.close();
1538
- }
1539
- }
1540
- break;
1541
- case exports.StepType.Change:
1542
- await locatorRace(step.selectors.map((selector) => {
1543
- return localFrame.locator(selectorToPElementSelector(selector));
1544
- }))
1545
- .on('action', () => startWaitingForEvents())
1546
- .setTimeout(timeout)
1547
- .fill(step.value);
1548
- break;
1549
- case exports.StepType.SetViewport: {
1550
- if ('setViewport' in targetPageOrFrame) {
1551
- startWaitingForEvents();
1552
- await targetPageOrFrame.setViewport(step);
1553
- }
1554
- break;
1555
- }
1556
- case exports.StepType.Scroll: {
1557
- if ('selectors' in step) {
1558
- await locatorRace(step.selectors.map((selector) => {
1559
- return localFrame.locator(selectorToPElementSelector(selector));
1560
- }))
1561
- .on('action', () => startWaitingForEvents())
1562
- .setTimeout(timeout)
1563
- .scroll({
1564
- scrollLeft: step.x || 0,
1565
- scrollTop: step.y || 0,
1566
- });
1567
- }
1568
- else {
1569
- startWaitingForEvents();
1570
- await localFrame.evaluate((x, y) => {
1571
- /* c8 ignore start */
1572
- window.scroll(x, y);
1573
- /* c8 ignore stop */
1574
- }, step.x || 0, step.y || 0);
1575
- }
1576
- break;
1577
- }
1578
- case exports.StepType.Navigate: {
1579
- startWaitingForEvents();
1580
- await localFrame.goto(step.url);
1581
- break;
1582
- }
1583
- case exports.StepType.WaitForElement: {
1584
- try {
1585
- startWaitingForEvents();
1586
- await waitForElement(step, localFrame, timeout);
1587
- }
1588
- catch (err) {
1589
- if (err.message === 'Timed out') {
1590
- throw new Error('waitForElement timed out. The element(s) could not be found.');
1591
- }
1592
- else {
1593
- throw err;
1594
- }
1595
- }
1596
- break;
1597
- }
1598
- case exports.StepType.WaitForExpression: {
1599
- startWaitingForEvents();
1600
- await localFrame.waitForFunction(step.expression, {
1601
- timeout,
1602
- });
1603
- break;
1604
- }
1605
- case exports.StepType.CustomStep: {
1606
- // TODO implement these steps
1607
- break;
1608
- }
1609
- default:
1610
- assertAllStepTypesAreHandled(step);
1611
- }
1612
- await assertedEventsPromise;
1613
- }
1614
- }
1615
- class PuppeteerRunnerOwningBrowserExtension extends PuppeteerRunnerExtension {
1616
- async afterAllSteps() {
1617
- await this.browser.close();
1618
- }
1619
- }
1620
- async function getFrame(pageOrFrame, step) {
1621
- let frame = 'mainFrame' in pageOrFrame ? pageOrFrame.mainFrame() : pageOrFrame;
1622
- if ('frame' in step && step.frame) {
1623
- for (const index of step.frame) {
1624
- frame = frame.childFrames()[index];
1625
- }
1626
- }
1627
- return frame;
1628
- }
1629
- async function getTargetPageForStep(browser, page, step, timeout) {
1630
- if (!step.target || step.target === 'main') {
1631
- return page;
1632
- }
1633
- const target = await browser.waitForTarget((t) => t.url() === step.target, {
1634
- timeout,
1635
- });
1636
- const targetPage = await target.page();
1637
- if (!targetPage) {
1638
- return null;
1639
- }
1640
- targetPage.setDefaultTimeout(timeout);
1641
- return targetPage;
1642
- }
1643
- async function waitForEvents(pageOrFrame, step, timeout) {
1644
- const promises = [];
1645
- if (step.assertedEvents) {
1646
- for (const event of step.assertedEvents) {
1647
- switch (event.type) {
1648
- case exports.AssertedEventType.Navigation: {
1649
- promises.push(pageOrFrame.waitForNavigation({
1650
- timeout,
1651
- }));
1652
- continue;
1653
- }
1654
- default:
1655
- throw new Error(`Event type ${event.type} is not supported`);
1656
- }
1657
- }
1658
- }
1659
- await Promise.all(promises);
1660
- }
1661
- async function waitForElement(step, frame, timeout) {
1662
- const { count = 1, operator = '>=', visible = true, properties, attributes, } = step;
1663
- const compFn = comparators[operator];
1664
- await waitForFunction(async () => {
1665
- const elements = await querySelectorsAll(step.selectors, frame);
1666
- let result = compFn(elements.length, count);
1667
- const elementsHandle = await frame.evaluateHandle((...elements) => {
1668
- return elements;
1669
- }, ...elements);
1670
- await Promise.all(elements.map((element) => element.dispose()));
1671
- if (result && (properties || attributes)) {
1672
- result = await elementsHandle.evaluate((elements, properties, attributes) => {
1673
- if (attributes) {
1674
- for (const element of elements) {
1675
- for (const [name, value] of Object.entries(attributes)) {
1676
- if (element.getAttribute(name) !== value) {
1677
- return false;
1678
- }
1679
- }
1680
- }
1681
- }
1682
- if (properties) {
1683
- for (const element of elements) {
1684
- if (!isDeepMatch(properties, element)) {
1685
- return false;
1686
- }
1687
- }
1688
- }
1689
- return true;
1690
- function isDeepMatch(a, b) {
1691
- if (a === b) {
1692
- return true;
1693
- }
1694
- if ((a && !b) || (!a && b)) {
1695
- return false;
1696
- }
1697
- if (!(a instanceof Object) || !(b instanceof Object)) {
1698
- return false;
1699
- }
1700
- for (const [key, value] of Object.entries(a)) {
1701
- if (!isDeepMatch(value, b[key])) {
1702
- return false;
1703
- }
1704
- }
1705
- return true;
1706
- }
1707
- }, properties, attributes);
1708
- }
1709
- await elementsHandle.dispose();
1710
- return result === visible;
1711
- }, timeout);
1712
- }
1713
- async function querySelectorsAll(selectors, frame) {
1714
- for (const selector of selectors) {
1715
- const result = await querySelectorAll(selector, frame);
1716
- if (result.length) {
1717
- return result;
1718
- }
1719
- }
1720
- return [];
1721
- }
1722
- async function querySelectorAll(selector, frame) {
1723
- if (!Array.isArray(selector)) {
1724
- selector = [selector];
1725
- }
1726
- if (!selector.length) {
1727
- throw new Error('Empty selector provided to querySelectorAll');
1728
- }
1729
- let elementHandles = await frame.$$(selector[0]);
1730
- if (!elementHandles.length) {
1731
- return [];
1732
- }
1733
- for (const part of selector.slice(1, selector.length)) {
1734
- elementHandles = (await Promise.all(elementHandles.map(async (handle) => {
1735
- const innerHandle = await handle.evaluateHandle((el) => el.shadowRoot ? el.shadowRoot : el);
1736
- const elementHandles = await innerHandle.$$(part);
1737
- innerHandle.dispose();
1738
- handle.dispose();
1739
- return elementHandles;
1740
- }))).flat();
1741
- if (!elementHandles.length) {
1742
- return [];
1743
- }
1744
- }
1745
- return elementHandles;
1746
- }
1747
- async function waitForFunction(fn, timeout) {
1748
- let isActive = true;
1749
- const timeoutId = setTimeout(() => {
1750
- isActive = false;
1751
- }, timeout);
1752
- while (isActive) {
1753
- const result = await fn();
1754
- if (result) {
1755
- clearTimeout(timeoutId);
1756
- return;
1757
- }
1758
- await new Promise((resolve) => setTimeout(resolve, 100));
1759
- }
1760
- throw new Error('Timed out');
1761
- }
1762
-
1763
- /**
1764
- Copyright 2022 Google LLC
1765
-
1766
- Licensed under the Apache License, Version 2.0 (the "License");
1767
- you may not use this file except in compliance with the License.
1768
- You may obtain a copy of the License at
1769
-
1770
- https://www.apache.org/licenses/LICENSE-2.0
1771
-
1772
- Unless required by applicable law or agreed to in writing, software
1773
- distributed under the License is distributed on an "AS IS" BASIS,
1774
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1775
- See the License for the specific language governing permissions and
1776
- limitations under the License.
1777
- */
1778
- async function _runStepWithHooks(extension, step, flow) {
1779
- await extension.beforeEachStep?.(step, flow);
1780
- await extension.runStep(step, flow);
1781
- await extension.afterEachStep?.(step, flow);
1782
- }
1783
- class Runner {
1784
- #flow;
1785
- #extension;
1786
- #aborted = false;
1787
- /**
1788
- * @internal
1789
- */
1790
- constructor(extension) {
1791
- this.#extension = extension;
1792
- }
1793
- abort() {
1794
- this.#aborted = true;
1795
- }
1796
- set flow(flow) {
1797
- this.#flow = flow;
1798
- }
1799
- async runBeforeAllSteps(flow) {
1800
- await this.#extension.beforeAllSteps?.(flow);
1801
- }
1802
- async runAfterAllSteps(flow) {
1803
- await this.#extension.afterAllSteps?.(flow);
1804
- }
1805
- /**
1806
- * Runs the provided `step` with `beforeEachStep` and `afterEachStep` hooks.
1807
- * Parameters from the `flow` apply if the `flow` is set.
1808
- */
1809
- async runStep(step) {
1810
- await _runStepWithHooks(this.#extension, step);
1811
- }
1812
- /**
1813
- * Run all the steps in the flow
1814
- * @returns whether all the steps are run or the execution is aborted
1815
- */
1816
- async run() {
1817
- if (!this.#flow) {
1818
- throw new Error('Set the flow on the runner instance before calling `run`.');
1819
- }
1820
- const flow = this.#flow;
1821
- this.#aborted = false;
1822
- await this.#extension.beforeAllSteps?.(flow);
1823
- if (this.#aborted) {
1824
- return false;
1825
- }
1826
- for (const step of flow.steps) {
1827
- if (this.#aborted) {
1828
- await this.#extension.afterAllSteps?.(flow);
1829
- return false;
1830
- }
1831
- await _runStepWithHooks(this.#extension, step, flow);
1832
- }
1833
- await this.#extension.afterAllSteps?.(flow);
1834
- return true;
1835
- }
1836
- }
1837
- async function createRunner(flowOrExtension, maybeExtension) {
1838
- const extension = flowOrExtension instanceof RunnerExtension
1839
- ? flowOrExtension
1840
- : maybeExtension;
1841
- const flow = !(flowOrExtension instanceof RunnerExtension)
1842
- ? flowOrExtension
1843
- : undefined;
1844
- const runner = new Runner(extension ?? (await createPuppeteerRunnerOwningBrowserExtension()));
1845
- if (flow) {
1846
- runner.flow = flow;
1847
- }
1848
- return runner;
1849
- }
1850
- async function createPuppeteerRunnerOwningBrowserExtension() {
1851
- const { default: puppeteer } = await import('puppeteer');
1852
- const browser = await puppeteer.launch();
1853
- const page = await browser.newPage();
1854
- return new PuppeteerRunnerOwningBrowserExtension(browser, page);
1855
- }
1856
-
1857
- /**
1858
- Copyright 2022 Google LLC
1859
-
1860
- Licensed under the Apache License, Version 2.0 (the "License");
1861
- you may not use this file except in compliance with the License.
1862
- You may obtain a copy of the License at
1863
-
1864
- https://www.apache.org/licenses/LICENSE-2.0
1865
-
1866
- Unless required by applicable law or agreed to in writing, software
1867
- distributed under the License is distributed on an "AS IS" BASIS,
1868
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1869
- See the License for the specific language governing permissions and
1870
- limitations under the License.
1871
- */
1872
- /**
1873
- * Stringifies a user flow to a script that uses \@puppeteer/replay's own API.
1874
- */
1875
- class PuppeteerReplayStringifyExtension extends StringifyExtension {
1876
- async beforeAllSteps(out) {
1877
- out.appendLine("import url from 'url';");
1878
- out.appendLine("import { createRunner } from '@puppeteer/replay';");
1879
- out.appendLine('');
1880
- out.appendLine('export async function run(extension) {').startBlock();
1881
- out.appendLine('const runner = await createRunner(extension);');
1882
- out.appendLine('');
1883
- out.appendLine('await runner.runBeforeAllSteps();');
1884
- out.appendLine('');
1885
- }
1886
- async afterAllSteps(out) {
1887
- out.appendLine('');
1888
- out
1889
- .appendLine('await runner.runAfterAllSteps();')
1890
- .endBlock()
1891
- .appendLine('}');
1892
- out.appendLine('');
1893
- out
1894
- .appendLine('if (process && import.meta.url === url.pathToFileURL(process.argv[1]).href) {')
1895
- .startBlock()
1896
- .appendLine('run()')
1897
- .endBlock()
1898
- .appendLine('}');
1899
- }
1900
- async stringifyStep(out, step) {
1901
- out.appendLine(`await runner.runStep(${formatJSONAsJS(step, out.getIndent())});`);
1902
- }
1903
- }
1904
-
1905
- /**
1906
- Copyright 2022 Google LLC
1907
-
1908
- Licensed under the Apache License, Version 2.0 (the "License");
1909
- you may not use this file except in compliance with the License.
1910
- You may obtain a copy of the License at
1911
-
1912
- https://www.apache.org/licenses/LICENSE-2.0
1913
-
1914
- Unless required by applicable law or agreed to in writing, software
1915
- distributed under the License is distributed on an "AS IS" BASIS,
1916
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1917
- See the License for the specific language governing permissions and
1918
- limitations under the License.
1919
- */
1920
- function isNavigationStep(step) {
1921
- return Boolean(step.type === exports.StepType.Navigate ||
1922
- step.assertedEvents?.some((event) => event.type === exports.AssertedEventType.Navigation));
1923
- }
1924
- function isMobileFlow(flow) {
1925
- for (const step of flow.steps) {
1926
- if (step.type === exports.StepType.SetViewport) {
1927
- return step.isMobile;
1928
- }
1929
- }
1930
- return false;
1931
- }
1932
-
1933
- /**
1934
- Copyright 2022 Google LLC
1935
-
1936
- Licensed under the Apache License, Version 2.0 (the "License");
1937
- you may not use this file except in compliance with the License.
1938
- You may obtain a copy of the License at
1939
-
1940
- https://www.apache.org/licenses/LICENSE-2.0
1941
-
1942
- Unless required by applicable law or agreed to in writing, software
1943
- distributed under the License is distributed on an "AS IS" BASIS,
1944
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1945
- See the License for the specific language governing permissions and
1946
- limitations under the License.
1947
- */
1948
- class LighthouseStringifyExtension extends PuppeteerStringifyExtension {
1949
- #isProcessingTimespan = false;
1950
- async beforeAllSteps(out, flow) {
1951
- out.appendLine(`const fs = require('fs');`);
1952
- await super.beforeAllSteps(out, flow);
1953
- out.appendLine(`const lhApi = await import('lighthouse'); // v10.0.0 or later`);
1954
- const flags = {
1955
- screenEmulation: {
1956
- disabled: true,
1957
- },
1958
- };
1959
- out.appendLine(`const flags = ${formatJSONAsJS(flags, out.getIndent())}`);
1960
- if (isMobileFlow(flow)) {
1961
- out.appendLine(`const config = undefined;`);
1962
- }
1963
- else {
1964
- out.appendLine('const config = lhApi.desktopConfig;');
1965
- }
1966
- out.appendLine(`const lhFlow = await lhApi.startFlow(page, {name: ${formatJSONAsJS(flow.title, out.getIndent())}, config, flags});`);
1967
- }
1968
- async stringifyStep(out, step, flow) {
1969
- if (step.type === exports.StepType.SetViewport) {
1970
- await super.stringifyStep(out, step, flow);
1971
- return;
1972
- }
1973
- const isNavigation = isNavigationStep(step);
1974
- if (isNavigation) {
1975
- if (this.#isProcessingTimespan) {
1976
- out.appendLine(`await lhFlow.endTimespan();`);
1977
- this.#isProcessingTimespan = false;
1978
- }
1979
- out.appendLine(`await lhFlow.startNavigation();`);
1980
- }
1981
- else if (!this.#isProcessingTimespan) {
1982
- out.appendLine(`await lhFlow.startTimespan();`);
1983
- this.#isProcessingTimespan = true;
1984
- }
1985
- await super.stringifyStep(out, step, flow);
1986
- if (isNavigation) {
1987
- out.appendLine(`await lhFlow.endNavigation();`);
1988
- }
1989
- }
1990
- async afterAllSteps(out, flow) {
1991
- if (this.#isProcessingTimespan) {
1992
- out.appendLine(`await lhFlow.endTimespan();`);
1993
- }
1994
- out.appendLine(`const lhFlowReport = await lhFlow.generateReport();`);
1995
- out.appendLine(`fs.writeFileSync(__dirname + '/flow.report.html', lhFlowReport)`);
1996
- await super.afterAllSteps(out, flow);
1997
- }
1998
- }
1999
-
2000
- /**
2001
- Copyright 2022 Google LLC
2002
-
2003
- Licensed under the Apache License, Version 2.0 (the "License");
2004
- you may not use this file except in compliance with the License.
2005
- You may obtain a copy of the License at
2006
-
2007
- https://www.apache.org/licenses/LICENSE-2.0
2008
-
2009
- Unless required by applicable law or agreed to in writing, software
2010
- distributed under the License is distributed on an "AS IS" BASIS,
2011
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2012
- See the License for the specific language governing permissions and
2013
- limitations under the License.
2014
- */
2015
- class LighthouseRunnerExtension extends PuppeteerRunnerExtension {
2016
- #isTimespanRunning = false;
2017
- #isNavigationRunning = false;
2018
- #lhFlow;
2019
- async createFlowResult() {
2020
- if (!this.#lhFlow) {
2021
- throw new Error('Cannot get flow result before running the flow');
2022
- }
2023
- return this.#lhFlow.createFlowResult();
2024
- }
2025
- async beforeAllSteps(flow) {
2026
- await super.beforeAllSteps?.(flow);
2027
- const { startFlow, desktopConfig } = await import('lighthouse');
2028
- let config = undefined;
2029
- if (!isMobileFlow(flow)) {
2030
- config = desktopConfig;
2031
- }
2032
- this.#lhFlow = await startFlow(this.page, {
2033
- config,
2034
- flags: { screenEmulation: { disabled: true } },
2035
- name: flow.title,
2036
- });
2037
- }
2038
- async beforeEachStep(step, flow) {
2039
- await super.beforeEachStep?.(step, flow);
2040
- if (step.type === exports.StepType.SetViewport)
2041
- return;
2042
- if (isNavigationStep(step)) {
2043
- if (this.#isTimespanRunning) {
2044
- await this.#lhFlow.endTimespan();
2045
- this.#isTimespanRunning = false;
2046
- }
2047
- await this.#lhFlow.startNavigation();
2048
- this.#isNavigationRunning = true;
2049
- }
2050
- else if (!this.#isTimespanRunning) {
2051
- await this.#lhFlow.startTimespan();
2052
- this.#isTimespanRunning = true;
2053
- }
2054
- }
2055
- async afterEachStep(step, flow) {
2056
- if (this.#isNavigationRunning) {
2057
- await this.#lhFlow.endNavigation();
2058
- this.#isNavigationRunning = false;
2059
- }
2060
- await super.afterEachStep?.(step, flow);
2061
- }
2062
- async afterAllSteps(flow) {
2063
- if (this.#isTimespanRunning) {
2064
- await this.#lhFlow.endTimespan();
2065
- }
2066
- await super.afterAllSteps?.(flow);
2067
- }
2068
- }
2069
-
2070
- exports.JSONStringifyExtension = JSONStringifyExtension;
2071
- exports.LighthouseRunnerExtension = LighthouseRunnerExtension;
2072
- exports.LighthouseStringifyExtension = LighthouseStringifyExtension;
2073
- exports.PuppeteerReplayStringifyExtension = PuppeteerReplayStringifyExtension;
2074
- exports.PuppeteerRunnerExtension = PuppeteerRunnerExtension;
2075
- exports.PuppeteerRunnerOwningBrowserExtension = PuppeteerRunnerOwningBrowserExtension;
2076
- exports.PuppeteerStringifyExtension = PuppeteerStringifyExtension;
2077
- exports.Runner = Runner;
2078
- exports.RunnerExtension = RunnerExtension;
2079
- exports.Schema = Schema;
2080
- exports.StringifyExtension = StringifyExtension;
2081
- exports.assertAllStepTypesAreHandled = assertAllStepTypesAreHandled;
2082
- exports.createRunner = createRunner;
2083
- exports.formatAsJSLiteral = formatAsJSLiteral;
2084
- exports.formatJSONAsJS = formatJSONAsJS;
2085
- exports.getSelectorType = getSelectorType;
2086
- exports.maxTimeout = maxTimeout;
2087
- exports.minTimeout = minTimeout;
2088
- exports.mouseButtonMap = mouseButtonMap;
2089
- exports.parse = parse;
2090
- exports.parseSourceMap = parseSourceMap;
2091
- exports.parseStep = parseStep;
2092
- exports.pointerDeviceTypes = pointerDeviceTypes;
2093
- exports.selectorToPElementSelector = selectorToPElementSelector;
2094
- exports.stringify = stringify;
2095
- exports.stringifyStep = stringifyStep;
2096
- exports.stripSourceMap = stripSourceMap;
2097
- exports.typeableInputTypes = typeableInputTypes;
2098
- exports.validTimeout = validTimeout;
2099
- //# sourceMappingURL=main.cjs.map