@checksum-ai/runtime 1.0.92 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checksum-ai/runtime",
3
- "version": "1.0.92",
3
+ "version": "1.1.1",
4
4
  "description": "Checksum.ai test runtime",
5
5
  "main": "index.js",
6
6
  "dependencies": {
package/scripts/patch.js CHANGED
@@ -27,34 +27,9 @@ function amend(filePath, entryPointText, appendText) {
27
27
  fs.writeFileSync(filePath, result, "utf8");
28
28
  }
29
29
 
30
- // Replaces the content of the specified line in the file.
31
- // When "on" is true, the new line is written to the file,
32
- // otherwise the original line is restored.
33
- function replaceLine(filePath, lineNumber, originalLine, newLine) {
34
- // Read the file content
35
- const fileContent = fs.readFileSync(filePath, "utf8");
36
-
37
- // Split the content into an array of lines
38
- const lines = fileContent.split(/\r?\n/);
39
-
40
- // Check if the line number is within the range of the file's line count
41
- if (lineNumber < 1 || lineNumber > lines.length) {
42
- throw new Error("Line number out of range");
43
- }
44
-
45
- // Replace the content of the specified line
46
- lines[lineNumber - 1] = on ? newLine : originalLine;
47
-
48
- // Join the lines back into a single string
49
- const updatedContent = lines.join("\n");
50
-
51
- // Write the modified content back to the file
52
- fs.writeFileSync(filePath, updatedContent, "utf8");
53
- }
54
-
55
- // Replaces the content of the specified line in the file.
56
- // When "on" is true, the new line is written to the file,
57
- // otherwise the original line is restored.
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.
58
33
  function replaceContent(filePath, originalContent, newContent) {
59
34
  // Read the file content
60
35
  const fileContent = fs.readFileSync(filePath, "utf8");
@@ -62,23 +37,14 @@ function replaceContent(filePath, originalContent, newContent) {
62
37
  // add a marker for newContent that can be later recognized for "off" state
63
38
  newContent = `/* checksumai */ ${newContent}`;
64
39
 
65
- // Split the content into an array of lines
66
- const lines = fileContent.split(/\r?\n/);
67
-
68
- lines.forEach((line, index) => {
69
- if (on) {
70
- if (line.includes(originalContent)) {
71
- lines[index] = line.replace(originalContent, newContent);
72
- }
73
- } else {
74
- if (line.includes(newContent)) {
75
- lines[index] = line.replace(newContent, originalContent);
76
- }
77
- }
78
- });
40
+ if (on && fileContent.includes(newContent)) {
41
+ return;
42
+ }
79
43
 
80
44
  // Join the lines back into a single string
81
- const updatedContent = lines.join("\n");
45
+ const updatedContent = on
46
+ ? fileContent.replace(originalContent, newContent)
47
+ : fileContent.replace(newContent, originalContent);
82
48
 
83
49
  // Write the modified content back to the file
84
50
  fs.writeFileSync(filePath, updatedContent, "utf8");
@@ -133,12 +99,158 @@ function addGenerateSelectorAndLocator(projectRoot) {
133
99
  amend(file, entryPointText2, appendText2);
134
100
  }
135
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;
153
+
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;
166
+ }
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
+ }
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);
245
+ }
246
+
136
247
  // -------- [Run] -------- //
137
248
 
249
+ const isRuntime = true || process.env.RUNTIME === "true";
138
250
  const projectRootFromEnv = process.env.PROJECT_ROOT;
139
251
  const projectPaths = projectRootFromEnv
140
252
  ? [projectRootFromEnv]
141
- : ["backend", "lib", "frontend"].map((project) =>
253
+ : ["backend", "lib", "frontend", "runtime"].map((project) =>
142
254
  join(__dirname, "..", project)
143
255
  );
144
256
 
@@ -147,6 +259,12 @@ for (const projectPath of projectPaths) {
147
259
  if (fs.existsSync(projectPath)) {
148
260
  alwaysInjectScripts(projectPath);
149
261
  addGenerateSelectorAndLocator(projectPath);
262
+ if (isRuntime) {
263
+ expect(projectPath);
264
+ testInfo(projectPath);
265
+ testType(projectPath);
266
+ channelOwner(projectPath);
267
+ }
150
268
  }
151
269
  } catch (e) {
152
270
  console.warn("Unable to patch playwright", projectPath, e);
@@ -162,3 +280,60 @@ for (const projectPath of projectPaths) {
162
280
  // " await this.extendInjectedScript(consoleApiSource.source);";
163
281
  // replaceLine(file, lineNumber, originalLine, newLine);
164
282
  // }
283
+
284
+ // // Replaces the content of the specified line in the file.
285
+ // // When "on" is true, the new line is written to the file,
286
+ // // otherwise the original line is restored.
287
+ // function replaceLine(filePath, lineNumber, originalLine, newLine) {
288
+ // // Read the file content
289
+ // const fileContent = fs.readFileSync(filePath, "utf8");
290
+
291
+ // // Split the content into an array of lines
292
+ // const lines = fileContent.split(/\r?\n/);
293
+
294
+ // // Check if the line number is within the range of the file's line count
295
+ // if (lineNumber < 1 || lineNumber > lines.length) {
296
+ // throw new Error("Line number out of range");
297
+ // }
298
+
299
+ // // Replace the content of the specified line
300
+ // lines[lineNumber - 1] = on ? newLine : originalLine;
301
+
302
+ // // Join the lines back into a single string
303
+ // const updatedContent = lines.join("\n");
304
+
305
+ // // Write the modified content back to the file
306
+ // fs.writeFileSync(filePath, updatedContent, "utf8");
307
+ // }
308
+
309
+ // // Replaces the content of the specified line in the file.
310
+ // // When "on" is true, the new line is written to the file,
311
+ // // otherwise the original line is restored.
312
+ // function replaceContent(filePath, originalContent, newContent) {
313
+ // // Read the file content
314
+ // const fileContent = fs.readFileSync(filePath, "utf8");
315
+
316
+ // // add a marker for newContent that can be later recognized for "off" state
317
+ // newContent = `/* checksumai */ ${newContent}`;
318
+
319
+ // // Split the content into an array of lines
320
+ // const lines = fileContent.split(/\r?\n/);
321
+
322
+ // lines.forEach((line, index) => {
323
+ // if (on) {
324
+ // if (line.includes(originalContent)) {
325
+ // lines[index] = line.replace(originalContent, newContent);
326
+ // }
327
+ // } else {
328
+ // if (line.includes(newContent)) {
329
+ // lines[index] = line.replace(newContent, originalContent);
330
+ // }
331
+ // }
332
+ // });
333
+
334
+ // // Join the lines back into a single string
335
+ // const updatedContent = lines.join("\n");
336
+
337
+ // // Write the modified content back to the file
338
+ // fs.writeFileSync(filePath, updatedContent, "utf8");
339
+ // }