@checksum-ai/runtime 1.1.10 → 1.1.13

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.
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@checksum-ai/runtime",
3
- "version": "1.1.10",
3
+ "version": "1.1.13",
4
4
  "description": "Checksum.ai test runtime",
5
5
  "main": "index.js",
6
6
  "dependencies": {
7
- "@playwright/test": "1.41.2",
8
- "ts-node": "^10.9.1",
7
+ "@playwright/test": "1.46.0",
9
8
  "jsdom": "^22.1.0",
10
- "puppeteer-extra-plugin-stealth": "^2.11.2",
11
- "request": "^2.88.2"
9
+ "playwright-extra": "^4.3.6",
10
+ "request": "^2.88.2",
11
+ "ts-node": "^10.9.1"
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
package/repl.js CHANGED
@@ -48,7 +48,7 @@ async function start() {
48
48
  async function startWithRetry() {
49
49
  try {
50
50
  await start();
51
- } catch (e) {
51
+ } catch (e: any) {
52
52
  await awaitSleep(2000);
53
53
  await startWithRetry();
54
54
  }
package/scripts/patch.js CHANGED
@@ -1,347 +1,58 @@
1
1
  const fs = require("fs");
2
- const { join } = require("path");
2
+ const path = require("path");
3
+ const { join, resolve } = require("path");
3
4
 
4
- // Args
5
- const on = process.argv[2] !== "off";
6
-
7
- // -------- [Modifiers] -------- //
8
-
9
- // Amends the file with the given entry point text and append text
10
- // When "on" is true, the append text is added to the entry point,
11
- // otherwise the append text is completely removed from the file
12
- function amend(filePath, entryPointText, appendText) {
13
- const data = fs.readFileSync(filePath, "utf8");
14
- if (!data.includes(entryPointText)) {
15
- throw new Error("Entry point not found!", entryPointText);
16
- }
17
- // Ignore if the append text is already present
18
- if (on && data.includes(appendText)) {
19
- return;
20
- }
21
- // Add or clear according to on state
22
- const result = on
23
- ? data.replace(entryPointText, entryPointText + appendText)
24
- : data.replace(appendText, "");
25
-
26
- // Write
27
- fs.writeFileSync(filePath, result, "utf8");
5
+ function getPlaywrightPatchesDirectory() {
6
+ return join(__dirname, "playwright_patches");
28
7
  }
29
8
 
30
- // Replaces content.
31
- // When "on" is true, the new content is written to the file replacing the original content,
32
- // otherwise the original content is restored.
33
- function replaceContent(filePath, originalContent, newContent) {
34
- // Read the file content
35
- const fileContent = fs.readFileSync(filePath, "utf8");
36
-
37
- // add a marker for newContent that can be later recognized for "off" state
38
- newContent = `/* checksumai */ ${newContent}`;
39
-
40
- if (on && fileContent.includes(newContent)) {
41
- return;
42
- }
43
-
44
- // Join the lines back into a single string
45
- const updatedContent = on
46
- ? fileContent.replace(originalContent, newContent)
47
- : fileContent.replace(newContent, originalContent);
48
-
49
- // Write the modified content back to the file
50
- fs.writeFileSync(filePath, updatedContent, "utf8");
51
- }
52
-
53
- function doesFileExist(filePath) {
54
- if (!fs.existsSync(filePath)) {
55
- console.warn("File not found", filePath);
56
- return false;
57
- }
58
- return true;
59
- }
60
-
61
- // -------- [Modifications] -------- //
62
-
63
- // Remove conditions for injecting Playwright scripts
64
- function alwaysInjectScripts(projectRoot) {
65
- const file = join(
66
- projectRoot,
67
- "node_modules/playwright-core/lib/server/browserContext.js"
68
- );
69
- if (!doesFileExist(file)) {
70
- return;
71
- }
72
- const originalContent =
73
- "if ((0, _utils.debugMode)() === 'console') await this.extendInjectedScript(consoleApiSource.source);";
9
+ const availablePatchVersions = fs
10
+ .readdirSync(getPlaywrightPatchesDirectory())
11
+ .map((patchFile) => path.basename(patchFile, ".js"))
12
+ .sort();
74
13
 
75
- const newContent =
76
- "await this.extendInjectedScript(consoleApiSource.source);";
77
-
78
- replaceContent(file, originalContent, newContent);
79
- }
80
-
81
- // Add implementation for generateSelectorAndLocator and inject to Playwright console API
82
- function addGenerateSelectorAndLocator(projectRoot) {
83
- const file = join(
84
- projectRoot,
85
- "node_modules/playwright-core/lib/generated/consoleApiSource.js"
86
- );
87
- if (!doesFileExist(file)) {
88
- return;
89
- }
90
- const entryPointText1 = "this._generateLocator(element, language),\\n ";
91
- const appendText1 =
92
- "generateSelectorAndLocator: (element, language) => this._generateSelectorAndLocator(element, language),\\n asLocator,\\n ";
93
- amend(file, entryPointText1, appendText1);
94
-
95
- const entryPointText2 =
96
- 'return asLocator(language || \\"javascript\\", selector);\\n }\\n ';
97
- const appendText2 =
98
- '_generateSelectorAndLocator(element, language) {\\n if (!(element instanceof Element))\\n throw new Error(`Usage: playwright.locator(element).`);\\n const selector = this._injectedScript.generateSelector(element);\\n return {selector, locator: asLocator(language || \\"javascript\\", selector)};\\n }\\n ';
99
- amend(file, entryPointText2, appendText2);
100
- }
101
-
102
- // -------- [Runtime modifications] -------- //
103
-
104
- function expect(projectRoot) {
105
- const file = join(
106
- projectRoot,
107
- "node_modules/playwright/lib/matchers/expect.js"
108
- );
109
- if (!doesFileExist(file)) {
110
- return;
111
- }
112
- let originalContent, newContent;
113
-
114
- originalContent = `return (...args) => {
115
- const testInfo = (0, _globals.currentTestInfo)();`;
116
- newContent = `return (...args) => {
117
- let noSoft = false;
118
- if (args[args.length-1]==='no-soft'){
119
- noSoft = true;
120
- args.pop();
121
- }
122
- const testInfo = (0, _globals.currentTestInfo)();`;
123
- replaceContent(file, originalContent, newContent);
124
-
125
- originalContent = `const rawStack = (0, _utils.captureRawStack)();`;
126
- newContent = `const rawStack = (0, _utils.captureRawStack)().filter(s=>!s.includes('@checksum-ai/runtime'));`;
127
- replaceContent(file, originalContent, newContent);
128
-
129
- originalContent = `step.complete({
130
- error
131
- })`;
132
- newContent = `step.complete({
133
- error,
134
- noSoft
135
- })`;
136
- replaceContent(file, originalContent, newContent);
137
-
138
- originalContent = `if (!this._info.isSoft) throw error;`;
139
- newContent = `if (!this._info.isSoft || noSoft) throw error;`;
140
- replaceContent(file, originalContent, newContent);
141
- }
142
-
143
- function testInfo(projectRoot) {
144
- const file = join(
145
- projectRoot,
146
- "node_modules/playwright/lib/worker/testInfo.js"
147
- );
148
- if (!doesFileExist(file)) {
149
- return;
150
- }
151
- let originalContent, newContent;
152
- let entryPointText, appendText;
14
+ // console.log("patchVersions", availablePatchVersions);
153
15
 
154
- originalContent = `const rawStack = (0, _utils.captureRawStack)();`;
155
- newContent = `let rawStack = (0, _utils.captureRawStack)();`;
156
- replaceContent(file, originalContent, newContent);
157
-
158
- entryPointText = `if (!parentStep) parentStep = _utils.zones.zoneData('stepZone', rawStack) || undefined;`;
159
- appendText = `\nrawStack = rawStack.filter(s=>!s.includes('@checksum-ai/runtime'));`;
160
- amend(file, entryPointText, appendText);
161
-
162
- entryPointText = `data.location = data.location || filteredStack[0];`;
163
- appendText = `\nif (this._checksumInternal) {
164
- data.location = undefined;
165
- this._checksumInternal = false;
16
+ function findSuitablePatchVersion(version) {
17
+ let suitablePatchVersion = availablePatchVersions[0];
18
+ for (const patchVersion of availablePatchVersions) {
19
+ if (version >= patchVersion) {
20
+ suitablePatchVersion = patchVersion;
21
+ } else {
22
+ break;
166
23
  }
167
- if (this._checksumNoLocation){
168
- data.location = undefined;
169
- }`;
170
- amend(file, entryPointText, appendText);
171
-
172
- originalContent = `if (!step.error) {`;
173
- newContent = `if (!step.error && !step.preventInfectParentStepsWithError) {`;
174
- replaceContent(file, originalContent, newContent);
175
-
176
- originalContent = `_failWithError(error, isHardError) {`;
177
- newContent = `addError(error, message) {
178
- const serialized = (0, _util.serializeError)(error);
179
- serialized.message = [message, serialized.message].join('\\n\\n');
180
- serialized.stack = [message, serialized.stack].join('\\n\\n');
181
- const step = error[stepSymbol];
182
- if (step && step.boxedStack) serialized.stack = \`\${error.name}: \${error.message}\\n\${(0, _utils.stringifyStackFrames)(step.boxedStack).join('\\n')}\`;
183
- this.errors.push(serialized);
184
- }
185
- _failWithError(error, isHardError) {`;
186
- replaceContent(file, originalContent, newContent);
187
-
188
- originalContent = `if (step.isSoft && result.error) this._failWithError`;
189
- newContent = `if (!result.noSoft && step.isSoft && result.error) this._failWithError`;
190
- replaceContent(file, originalContent, newContent);
191
- }
192
-
193
- function testType(projectRoot) {
194
- const file = join(
195
- projectRoot,
196
- "node_modules/playwright/lib/common/testType.js"
197
- );
198
- if (!doesFileExist(file)) {
199
- return;
200
- }
201
-
202
- let originalContent, newContent;
203
-
204
- originalContent = `}, async () => {
205
- // Make sure that internal "step" is not leaked to the user callback.
206
- return await body();
207
- });`;
208
- newContent = `}, async (step) => {
209
- if (options.obtainStep){
210
- options.obtainStep(step);
211
- }
212
- // Make sure that internal "step" is not leaked to the user callback.
213
- return await body();
214
- });`;
215
- replaceContent(file, originalContent, newContent);
216
- }
217
-
218
- function channelOwner(projectRoot) {
219
- const file = join(
220
- projectRoot,
221
- "node_modules/playwright-core/lib/client/channelOwner.js"
222
- );
223
- if (!doesFileExist(file)) {
224
- return;
225
24
  }
226
- let originalContent, newContent;
227
- let entryPointText, appendText;
228
-
229
- entryPointText = `async _wrapApiCall(func, isInternal = false) {`;
230
- appendText = `\nif (this._checksumInternal){
231
- isInternal = true;
232
- }`;
233
- amend(file, entryPointText, appendText);
234
-
235
- originalContent = `const stack = (0, _stackTrace.captureRawStack)();`;
236
- newContent = `const stack = (0, _stackTrace.captureRawStack)().filter(s=>!s.includes('@checksum-ai/runtime'));`;
237
- replaceContent(file, originalContent, newContent);
238
-
239
- entryPointText = `let apiName = stackTrace.apiName;`;
240
- appendText = `\nif (!isInternal && this._checksumTitle){
241
- apiName = this._checksumTitle;
242
- this._checksumTitle = undefined;
243
- }`;
244
- amend(file, entryPointText, appendText);
25
+ return suitablePatchVersion;
245
26
  }
246
27
 
247
- // -------- [Run] -------- //
248
-
249
- const isRuntime = true || process.env.RUNTIME === "true";
250
28
  const projectRootFromEnv = process.env.PROJECT_ROOT;
251
-
252
29
  const projectPaths = projectRootFromEnv
253
30
  ? [projectRootFromEnv]
254
- : [
255
- ".",
256
- "../checksum-ai-libs/lib",
257
- "../backend",
258
- "../libs/lib",
259
- "../frontend",
260
- "../runtime",
261
- ].map((project) => join(process.cwd(), project));
31
+ : [".", "../", "../.."].map((project) => join(process.cwd(), project));
262
32
 
263
33
  for (const projectPath of projectPaths) {
264
34
  try {
265
- if (fs.existsSync(projectPath)) {
266
- alwaysInjectScripts(projectPath);
267
- addGenerateSelectorAndLocator(projectPath);
268
- if (isRuntime) {
269
- expect(projectPath);
270
- testInfo(projectPath);
271
- testType(projectPath);
272
- channelOwner(projectPath);
273
- }
35
+ if (fs.existsSync(join(projectPath, "node_modules", "playwright"))) {
36
+ const absolutePathToPackageJSON = resolve(
37
+ join(projectPath, "node_modules", "playwright", "package.json")
38
+ );
39
+ const packageJSON = require(absolutePathToPackageJSON);
40
+ const playwrightVersion = packageJSON.version;
41
+ const patchVersion = findSuitablePatchVersion(playwrightVersion);
42
+ // console.log(
43
+ // "Found installed version",
44
+ // playwrightVersion,
45
+ // "and will use patch for version",
46
+ // patchVersion
47
+ // );
48
+ const patchPath = resolve(
49
+ join(getPlaywrightPatchesDirectory(), `${patchVersion}.js`)
50
+ );
51
+ require(patchPath)(projectPath);
274
52
  } else {
275
53
  // console.warn("Project path not found", projectPath);
276
54
  }
277
55
  } catch (e) {
278
- // ignore
56
+ // ignore for now although we might want to notify users that patching wasn't successful
279
57
  }
280
58
  }
281
-
282
- // function alwaysInjectScriptsOld() {
283
- // const file = "node_modules/playwright-core/lib/server/browserContext.js";
284
- // const lineNumber = 108;
285
- // const originalLine =
286
- // " if ((0, _utils.debugMode)() === 'console') await this.extendInjectedScript(consoleApiSource.source);";
287
- // const newLine =
288
- // " await this.extendInjectedScript(consoleApiSource.source);";
289
- // replaceLine(file, lineNumber, originalLine, newLine);
290
- // }
291
-
292
- // // Replaces the content of the specified line in the file.
293
- // // When "on" is true, the new line is written to the file,
294
- // // otherwise the original line is restored.
295
- // function replaceLine(filePath, lineNumber, originalLine, newLine) {
296
- // // Read the file content
297
- // const fileContent = fs.readFileSync(filePath, "utf8");
298
-
299
- // // Split the content into an array of lines
300
- // const lines = fileContent.split(/\r?\n/);
301
-
302
- // // Check if the line number is within the range of the file's line count
303
- // if (lineNumber < 1 || lineNumber > lines.length) {
304
- // throw new Error("Line number out of range");
305
- // }
306
-
307
- // // Replace the content of the specified line
308
- // lines[lineNumber - 1] = on ? newLine : originalLine;
309
-
310
- // // Join the lines back into a single string
311
- // const updatedContent = lines.join("\n");
312
-
313
- // // Write the modified content back to the file
314
- // fs.writeFileSync(filePath, updatedContent, "utf8");
315
- // }
316
-
317
- // // Replaces the content of the specified line in the file.
318
- // // When "on" is true, the new line is written to the file,
319
- // // otherwise the original line is restored.
320
- // function replaceContent(filePath, originalContent, newContent) {
321
- // // Read the file content
322
- // const fileContent = fs.readFileSync(filePath, "utf8");
323
-
324
- // // add a marker for newContent that can be later recognized for "off" state
325
- // newContent = `/* checksumai */ ${newContent}`;
326
-
327
- // // Split the content into an array of lines
328
- // const lines = fileContent.split(/\r?\n/);
329
-
330
- // lines.forEach((line, index) => {
331
- // if (on) {
332
- // if (line.includes(originalContent)) {
333
- // lines[index] = line.replace(originalContent, newContent);
334
- // }
335
- // } else {
336
- // if (line.includes(newContent)) {
337
- // lines[index] = line.replace(newContent, originalContent);
338
- // }
339
- // }
340
- // });
341
-
342
- // // Join the lines back into a single string
343
- // const updatedContent = lines.join("\n");
344
-
345
- // // Write the modified content back to the file
346
- // fs.writeFileSync(filePath, updatedContent, "utf8");
347
- // }