@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/.gitignore +1 -0
- package/checksumlib.js +3 -3
- package/cli.js +49 -171
- package/index.d.ts +21 -4
- package/index.js +248 -259
- package/package.json +1 -1
- package/scripts/patch.js +219 -44
- package/test-run-monitor.js +37 -3
package/package.json
CHANGED
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
|
|
31
|
-
// When "on" is true, the new
|
|
32
|
-
// otherwise the original
|
|
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
|
-
|
|
66
|
-
|
|
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 =
|
|
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
|
+
// }
|