@smoothdeploy/playwright 1.60.1 → 1.61.0
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/lib/agents/generateAgents.js +48 -0
- package/lib/cli/testActions.js +2 -0
- package/lib/common/index.js +168 -135
- package/lib/common/index.js.txt +8 -8
- package/lib/index.js +18 -13
- package/lib/loader/loaderProcessEntry.js +1 -1
- package/lib/matchers/expect.js +18 -16
- package/lib/matchers/expect.js.txt +3 -3
- package/lib/mcp/test/testContext.js +5 -1
- package/lib/program.js +9 -3
- package/lib/runner/index.js +138 -88
- package/lib/runner/index.js.txt +8 -8
- package/lib/transform/esmLoader.js +149 -42
- package/lib/transform/esmLoader.js.txt +7 -5
- package/lib/util.js +12 -15
- package/lib/worker/workerProcessEntry.js +46 -1429
- package/lib/worker/workerProcessEntry.js.txt +4 -8
- package/package.json +2 -2
- package/types/test.d.ts +67 -17
package/lib/index.js
CHANGED
|
@@ -402,16 +402,6 @@ const playwrightFixtures = {
|
|
|
402
402
|
}
|
|
403
403
|
} : {};
|
|
404
404
|
const context = await browser.newContext({ ...videoOptions, ...options });
|
|
405
|
-
if (process.env.PW_CLOCK === "frozen") {
|
|
406
|
-
await context._wrapApiCall(async () => {
|
|
407
|
-
await context.clock.install({ time: 0 });
|
|
408
|
-
await context.clock.pauseAt(1e3);
|
|
409
|
-
}, { internal: true });
|
|
410
|
-
} else if (process.env.PW_CLOCK === "realtime") {
|
|
411
|
-
await context._wrapApiCall(async () => {
|
|
412
|
-
await context.clock.install({ time: 0 });
|
|
413
|
-
}, { internal: true });
|
|
414
|
-
}
|
|
415
405
|
let closed = false;
|
|
416
406
|
const close = async () => {
|
|
417
407
|
if (closed)
|
|
@@ -419,8 +409,7 @@ const playwrightFixtures = {
|
|
|
419
409
|
closed = true;
|
|
420
410
|
const closeReason = testInfo.status === "timedOut" ? "Test timeout of " + testInfo.timeout + "ms exceeded." : "Test ended.";
|
|
421
411
|
await context.close({ reason: closeReason });
|
|
422
|
-
const
|
|
423
|
-
const preserveVideo = captureVideo && (videoMode === "on" || testFailed && videoMode === "retain-on-failure" || videoMode === "on-first-retry" && testInfo.retry === 1);
|
|
412
|
+
const preserveVideo = captureVideo && shouldPreserveVideo(videoMode, testInfo);
|
|
424
413
|
if (preserveVideo) {
|
|
425
414
|
const { pagesWithVideo: pagesForVideo } = contexts.get(context);
|
|
426
415
|
const videos = pagesForVideo.map((p) => p.video()).filter((video2) => !!video2);
|
|
@@ -490,7 +479,23 @@ function normalizeVideoMode(video) {
|
|
|
490
479
|
return videoMode;
|
|
491
480
|
}
|
|
492
481
|
function shouldCaptureVideo(videoMode, testInfo) {
|
|
493
|
-
return videoMode === "on" || videoMode === "retain-on-failure" || videoMode === "on-first-retry" && testInfo.retry === 1;
|
|
482
|
+
return videoMode === "on" || videoMode === "retain-on-failure" || videoMode === "retain-on-failure-and-retries" || videoMode === "on-first-retry" && testInfo.retry === 1 || videoMode === "on-all-retries" && testInfo.retry > 0 || videoMode === "retain-on-first-failure" && testInfo.retry === 0;
|
|
483
|
+
}
|
|
484
|
+
function shouldPreserveVideo(videoMode, testInfo) {
|
|
485
|
+
const testFailed = testInfo.status !== testInfo.expectedStatus;
|
|
486
|
+
switch (videoMode) {
|
|
487
|
+
case "on":
|
|
488
|
+
case "on-first-retry":
|
|
489
|
+
case "on-all-retries":
|
|
490
|
+
return true;
|
|
491
|
+
case "retain-on-failure":
|
|
492
|
+
case "retain-on-first-failure":
|
|
493
|
+
return testFailed;
|
|
494
|
+
case "retain-on-failure-and-retries":
|
|
495
|
+
return testFailed || testInfo.retry > 0;
|
|
496
|
+
default:
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
494
499
|
}
|
|
495
500
|
function normalizeScreenshotMode(screenshot) {
|
|
496
501
|
if (!screenshot)
|
|
@@ -24,7 +24,7 @@ var LoaderMain = class extends import_common.ProcessRunner {
|
|
|
24
24
|
return { fileSuite: fileSuite._deepSerialize(), testErrors };
|
|
25
25
|
}
|
|
26
26
|
async getCompilationCacheFromLoader() {
|
|
27
|
-
await import_common.
|
|
27
|
+
await import_common.transform.incorporateCompilationCache();
|
|
28
28
|
return import_common.cc.serializeCompilationCache();
|
|
29
29
|
}
|
|
30
30
|
};
|
package/lib/matchers/expect.js
CHANGED
|
@@ -11976,8 +11976,7 @@ var NonConfigProperties = [
|
|
|
11976
11976
|
"fullPage",
|
|
11977
11977
|
"mask",
|
|
11978
11978
|
"maskColor",
|
|
11979
|
-
"omitBackground"
|
|
11980
|
-
"timeout"
|
|
11979
|
+
"omitBackground"
|
|
11981
11980
|
];
|
|
11982
11981
|
var SnapshotHelper = class {
|
|
11983
11982
|
constructor(state, testInfo, matcherName, locator, anonymousSnapshotExtension, configOptions, nameOrOptions, optOptions) {
|
|
@@ -12596,6 +12595,7 @@ var import_fs2 = __toESM(require("fs"));
|
|
|
12596
12595
|
var import_path2 = __toESM(require("path"));
|
|
12597
12596
|
var { escapeTemplateString, isString: isString3 } = require("playwright-core/lib/coreBundle").iso;
|
|
12598
12597
|
var { existsAsync } = require("playwright-core/lib/coreBundle").utils;
|
|
12598
|
+
var kImpossibleAriaMatch = `- none "Generating new baseline"`;
|
|
12599
12599
|
async function toMatchAriaSnapshot(receiver, expectedParam, options = {}) {
|
|
12600
12600
|
const matcherName = "toMatchAriaSnapshot";
|
|
12601
12601
|
expectTypes(receiver, ["Page", "Locator"], matcherName);
|
|
@@ -12620,14 +12620,14 @@ async function toMatchAriaSnapshot(receiver, expectedParam, options = {}) {
|
|
|
12620
12620
|
expected = await import_fs2.default.promises.readFile(expectedPath, "utf8").catch(() => "");
|
|
12621
12621
|
timeout = expectedParam?.timeout ?? this.timeout;
|
|
12622
12622
|
}
|
|
12623
|
-
const
|
|
12624
|
-
if (
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12629
|
-
|
|
12630
|
-
|
|
12623
|
+
const isMissingBaseline = updateSnapshots === "missing" && !expected;
|
|
12624
|
+
if (isMissingBaseline && this.isNot) {
|
|
12625
|
+
const message2 = `Matchers using ".not" can't generate new baselines`;
|
|
12626
|
+
return { pass: this.isNot, message: () => message2, name: "toMatchAriaSnapshot" };
|
|
12627
|
+
}
|
|
12628
|
+
const generateBaseline = !this.isNot && (updateSnapshots === "all" || isMissingBaseline);
|
|
12629
|
+
if (generateBaseline) {
|
|
12630
|
+
expected = kImpossibleAriaMatch;
|
|
12631
12631
|
}
|
|
12632
12632
|
expected = unshift(expected);
|
|
12633
12633
|
const globalChildren = expectConfig().toMatchAriaSnapshot?.children;
|
|
@@ -12668,12 +12668,12 @@ async function toMatchAriaSnapshot(receiver, expectedParam, options = {}) {
|
|
|
12668
12668
|
if (errorMessage)
|
|
12669
12669
|
return { pass: this.isNot, message, name: "toMatchAriaSnapshot", expected };
|
|
12670
12670
|
if (!this.isNot) {
|
|
12671
|
-
if (
|
|
12671
|
+
if (generateBaseline || updateSnapshots === "changed" && pass === this.isNot) {
|
|
12672
12672
|
if (expectedPath) {
|
|
12673
12673
|
await import_fs2.default.promises.mkdir(import_path2.default.dirname(expectedPath), { recursive: true });
|
|
12674
12674
|
await import_fs2.default.promises.writeFile(expectedPath, typedReceived.regex, "utf8");
|
|
12675
12675
|
const relativePath = import_path2.default.relative(process.cwd(), expectedPath);
|
|
12676
|
-
if (
|
|
12676
|
+
if (isMissingBaseline) {
|
|
12677
12677
|
const message3 = `A snapshot doesn't exist at ${relativePath}, writing actual.`;
|
|
12678
12678
|
return { pass: true, message: () => "", name: "toMatchAriaSnapshot", softError: new Error(message3), shouldNotRetryTest: true };
|
|
12679
12679
|
}
|
|
@@ -12684,7 +12684,7 @@ async function toMatchAriaSnapshot(receiver, expectedParam, options = {}) {
|
|
|
12684
12684
|
const suggestedRebaseline = `\`
|
|
12685
12685
|
${escapeTemplateString(indent2(typedReceived.regex, "{indent} "))}
|
|
12686
12686
|
{indent}\``;
|
|
12687
|
-
if (
|
|
12687
|
+
if (isMissingBaseline) {
|
|
12688
12688
|
const message2 = "A snapshot is not provided, generating new baseline.";
|
|
12689
12689
|
return { pass: true, message: () => "", name: "toMatchAriaSnapshot", suggestedRebaseline, softError: new Error(message2), shouldNotRetryTest: true };
|
|
12690
12690
|
}
|
|
@@ -12818,9 +12818,11 @@ function createExpect(info) {
|
|
|
12818
12818
|
newInfo.isSoft = configuration.soft;
|
|
12819
12819
|
return createExpect(newInfo);
|
|
12820
12820
|
};
|
|
12821
|
-
|
|
12822
|
-
|
|
12823
|
-
|
|
12821
|
+
Object.defineProperty(expectFn, "soft", {
|
|
12822
|
+
configurable: true,
|
|
12823
|
+
enumerable: true,
|
|
12824
|
+
get: () => info.isSoft ? expectFn : createExpect({ ...info, isSoft: true })
|
|
12825
|
+
});
|
|
12824
12826
|
expectFn.poll = (actual, messageOrOptions) => {
|
|
12825
12827
|
const poll = isString4(messageOrOptions) ? {} : messageOrOptions || {};
|
|
12826
12828
|
return createMatchers(actual, { ...info, poll: { timeout: poll.timeout, intervals: poll.intervals } }, messageOrOptions);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# packages/playwright/lib/matchers/expect.js
|
|
2
|
-
# total: 513.
|
|
2
|
+
# total: 513.8 KB
|
|
3
3
|
|
|
4
4
|
## Inlined (64)
|
|
5
5
|
7.9 KB node_modules/@babel/code-frame/lib/index.js
|
|
@@ -56,14 +56,14 @@
|
|
|
56
56
|
7.6 KB node_modules/stack-utils/index.js
|
|
57
57
|
0.4 KB node_modules/stack-utils/node_modules/escape-string-regexp/index.js
|
|
58
58
|
6.8 KB node_modules/to-regex-range/index.js
|
|
59
|
-
10.
|
|
59
|
+
10.4 KB packages/playwright/src/matchers/expect.ts
|
|
60
60
|
45.2 KB packages/playwright/src/matchers/expectLibrary.ts
|
|
61
61
|
3.3 KB packages/playwright/src/matchers/matcherHint.ts
|
|
62
62
|
16.0 KB packages/playwright/src/matchers/matchers.ts
|
|
63
63
|
1.3 KB packages/playwright/src/matchers/toBeTruthy.ts
|
|
64
64
|
2.1 KB packages/playwright/src/matchers/toEqual.ts
|
|
65
65
|
2.4 KB packages/playwright/src/matchers/toHaveURL.ts
|
|
66
|
-
5.
|
|
66
|
+
5.7 KB packages/playwright/src/matchers/toMatchAriaSnapshot.ts
|
|
67
67
|
15.1 KB packages/playwright/src/matchers/toMatchSnapshot.ts
|
|
68
68
|
3.0 KB packages/playwright/src/matchers/toMatchText.ts
|
|
69
69
|
|
|
@@ -89,6 +89,7 @@ class TestContext {
|
|
|
89
89
|
async _enqueue(fn) {
|
|
90
90
|
const next = this._testOpQueue.then(fn);
|
|
91
91
|
this._testOpQueue = next.then(() => {
|
|
92
|
+
}, () => {
|
|
92
93
|
});
|
|
93
94
|
return await next;
|
|
94
95
|
}
|
|
@@ -199,7 +200,8 @@ class TestContext {
|
|
|
199
200
|
releaseStdio();
|
|
200
201
|
}
|
|
201
202
|
};
|
|
202
|
-
const
|
|
203
|
+
const abort = signal ? signalToPromise(signal) : void 0;
|
|
204
|
+
const abortPromise = abort ? abort.promise.then(() => "interrupted") : new Promise(() => {
|
|
203
205
|
});
|
|
204
206
|
try {
|
|
205
207
|
const reporter = new MCPListReporter({ configDir, screen, includeTestId: true });
|
|
@@ -225,6 +227,8 @@ class TestContext {
|
|
|
225
227
|
testRunnerAndScreen.output.push(String(e));
|
|
226
228
|
await cleanup();
|
|
227
229
|
return { output: testRunnerAndScreen.output.join("\n"), status };
|
|
230
|
+
} finally {
|
|
231
|
+
abort?.dispose();
|
|
228
232
|
}
|
|
229
233
|
await cleanup();
|
|
230
234
|
return { output: testRunnerAndScreen.output.join("\n"), status };
|
package/lib/program.js
CHANGED
|
@@ -46,8 +46,11 @@ function addTestCommand(program2) {
|
|
|
46
46
|
return command;
|
|
47
47
|
});
|
|
48
48
|
command.action(async (args, opts) => {
|
|
49
|
+
const dashDashIndex = process.argv.indexOf("--");
|
|
50
|
+
const postDashCount = dashDashIndex >= 0 ? process.argv.length - 1 - dashDashIndex : 0;
|
|
51
|
+
const testFilters = args.slice(0, args.length - postDashCount);
|
|
49
52
|
try {
|
|
50
|
-
await (0, import_testActions.runTests)(
|
|
53
|
+
await (0, import_testActions.runTests)(testFilters, opts);
|
|
51
54
|
} catch (e) {
|
|
52
55
|
console.error(e);
|
|
53
56
|
gracefullyProcessExitDoNotHang(1);
|
|
@@ -144,7 +147,7 @@ function addInitAgentsCommand(program2) {
|
|
|
144
147
|
const command = program2.command("init-agents");
|
|
145
148
|
command.description("Initialize repository agents");
|
|
146
149
|
const option = command.createOption("--loop <loop>", "Agentic loop provider");
|
|
147
|
-
option.choices(["claude", "copilot", "opencode", "vscode", "vscode-legacy"]);
|
|
150
|
+
option.choices(["claude", "codex", "copilot", "opencode", "vscode", "vscode-legacy"]);
|
|
148
151
|
command.addOption(option);
|
|
149
152
|
command.option("-c, --config <file>", `Configuration file to find a project to use for seed test`);
|
|
150
153
|
command.option("--project <project>", "Project to use for seed test");
|
|
@@ -157,6 +160,8 @@ function addInitAgentsCommand(program2) {
|
|
|
157
160
|
await import_generateAgents.VSCodeGenerator.init(loadedConfig, opts.project);
|
|
158
161
|
} else if (opts.loop === "claude") {
|
|
159
162
|
await import_generateAgents.ClaudeGenerator.init(loadedConfig, opts.project, opts.prompts);
|
|
163
|
+
} else if (opts.loop === "codex") {
|
|
164
|
+
await import_generateAgents.CodexGenerator.init(loadedConfig, opts.project, opts.prompts);
|
|
160
165
|
} else {
|
|
161
166
|
await import_generateAgents.CopilotGenerator.init(loadedConfig, opts.project, opts.prompts);
|
|
162
167
|
return;
|
|
@@ -174,10 +179,11 @@ const testOptions = [
|
|
|
174
179
|
["--fully-parallel", { description: `Run all tests in parallel (default: false)` }],
|
|
175
180
|
["--global-timeout <timeout>", { description: `Maximum time this test suite can run in milliseconds (default: unlimited)` }],
|
|
176
181
|
["-g, --grep <grep>", { description: `Only run tests matching this regular expression (default: ".*")` }],
|
|
177
|
-
["--grep-invert <grep>", { description: `Only run tests that do not match this regular expression` }],
|
|
182
|
+
["-G, --grep-invert <grep>", { description: `Only run tests that do not match this regular expression` }],
|
|
178
183
|
["--headed", { description: `Run tests in headed browsers (default: headless)` }],
|
|
179
184
|
["--ignore-snapshots", { description: `Ignore screenshot and snapshot expectations` }],
|
|
180
185
|
["--last-failed", { description: `Only re-run the failures` }],
|
|
186
|
+
["--last-failed-file <file>", { description: `Override the default path for the last-run JSON file used with --last-failed (default: <outputDir>/.last-run.json). Same as PLAYWRIGHT_LAST_RUN_OUTPUT_FILE environment variable.` }],
|
|
181
187
|
["--list", { description: `Collect all the tests and report them, but do not run` }],
|
|
182
188
|
["--max-failures <N>", { description: `Stop after the first N failures` }],
|
|
183
189
|
["--no-deps", { description: `Do not run project dependencies` }],
|