@pxdiff/playwright 0.0.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/dist/fixture.d.ts +12 -0
- package/dist/fixture.d.ts.map +1 -0
- package/dist/fixture.js +41 -0
- package/dist/fixture.js.map +1 -0
- package/dist/git.d.ts +4 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +61 -0
- package/dist/git.js.map +1 -0
- package/dist/git.test.d.ts +2 -0
- package/dist/git.test.d.ts.map +1 -0
- package/dist/git.test.js +119 -0
- package/dist/git.test.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/matchers.d.ts +11 -0
- package/dist/matchers.d.ts.map +1 -0
- package/dist/matchers.js +110 -0
- package/dist/matchers.js.map +1 -0
- package/dist/matchers.test.d.ts +2 -0
- package/dist/matchers.test.d.ts.map +1 -0
- package/dist/matchers.test.js +185 -0
- package/dist/matchers.test.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Page } from "@playwright/test";
|
|
2
|
+
import type { PxdiffContext, PxdiffFixtureOptions } from "./types.js";
|
|
3
|
+
/** Module-level WeakMap for passing context from fixture to matcher. */
|
|
4
|
+
export declare const contextMap: WeakMap<Page, PxdiffContext>;
|
|
5
|
+
export declare function createPxdiffFixture(options?: PxdiffFixtureOptions): {
|
|
6
|
+
_pxdiff: readonly [({ page }: {
|
|
7
|
+
page: Page;
|
|
8
|
+
}, use: (value: undefined) => Promise<void>) => Promise<void>, {
|
|
9
|
+
readonly auto: true;
|
|
10
|
+
}];
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=fixture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7C,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAItE,wEAAwE;AACxE,eAAO,MAAM,UAAU,8BAAqC,CAAC;AAE7D,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,oBAAoB;kCAG9C;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,OAAO,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC;;;EAuC3E"}
|
package/dist/fixture.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { PxdiffClient } from "@pxdiff/sdk";
|
|
2
|
+
import { detectBaselineRef, detectBranch, detectCommit } from "./git.js";
|
|
3
|
+
const DEFAULT_API_URL = "https://api.pxdiff.com";
|
|
4
|
+
/** Module-level WeakMap for passing context from fixture to matcher. */
|
|
5
|
+
export const contextMap = new WeakMap();
|
|
6
|
+
export function createPxdiffFixture(options) {
|
|
7
|
+
return {
|
|
8
|
+
_pxdiff: [
|
|
9
|
+
async ({ page }, use) => {
|
|
10
|
+
const apiKey = process.env.PXDIFF_API_KEY;
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
throw new Error("PXDIFF_API_KEY environment variable is required. " +
|
|
13
|
+
"Get your API key from https://app.pxdiff.com.");
|
|
14
|
+
}
|
|
15
|
+
const apiUrl = options?.apiUrl ?? process.env.PXDIFF_API_URL ?? DEFAULT_API_URL;
|
|
16
|
+
const suite = options?.suite ?? "playwright";
|
|
17
|
+
const blocking = options?.blocking ?? true;
|
|
18
|
+
const autoBaseline = options?.autoBaseline ?? true;
|
|
19
|
+
const branch = await detectBranch(options?.git?.branch ?? process.env.PXDIFF_BRANCH);
|
|
20
|
+
const commit = await detectCommit(options?.git?.commit ?? process.env.PXDIFF_COMMIT);
|
|
21
|
+
const baselineRef = detectBaselineRef() ?? branch;
|
|
22
|
+
// Verify the client can be created (validates apiKey format etc.)
|
|
23
|
+
new PxdiffClient({ apiKey, apiUrl });
|
|
24
|
+
contextMap.set(page, {
|
|
25
|
+
apiKey,
|
|
26
|
+
apiUrl,
|
|
27
|
+
suite,
|
|
28
|
+
blocking,
|
|
29
|
+
autoBaseline,
|
|
30
|
+
branch,
|
|
31
|
+
commit,
|
|
32
|
+
baselineRef,
|
|
33
|
+
});
|
|
34
|
+
await use(undefined);
|
|
35
|
+
contextMap.delete(page);
|
|
36
|
+
},
|
|
37
|
+
{ auto: true },
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=fixture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixture.js","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGzE,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD,wEAAwE;AACxE,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,OAAO,EAAuB,CAAC;AAE7D,MAAM,UAAU,mBAAmB,CAAC,OAA8B;IACjE,OAAO;QACN,OAAO,EAAE;YACR,KAAK,EAAE,EAAE,IAAI,EAAkB,EAAE,GAAwC,EAAE,EAAE;gBAC5E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;gBAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;oBACb,MAAM,IAAI,KAAK,CACd,mDAAmD;wBAClD,+CAA+C,CAChD,CAAC;gBACH,CAAC;gBAED,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,eAAe,CAAC;gBAChF,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,YAAY,CAAC;gBAC7C,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,IAAI,CAAC;gBAC3C,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,IAAI,CAAC;gBAEnD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBACrF,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBACrF,MAAM,WAAW,GAAG,iBAAiB,EAAE,IAAI,MAAM,CAAC;gBAElD,kEAAkE;gBAClE,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;gBAErC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE;oBACpB,MAAM;oBACN,MAAM;oBACN,KAAK;oBACL,QAAQ;oBACR,YAAY;oBACZ,MAAM;oBACN,MAAM;oBACN,WAAW;iBACX,CAAC,CAAC;gBAEH,MAAM,GAAG,CAAC,SAAS,CAAC,CAAC;gBAErB,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACzB,CAAC;YACD,EAAE,IAAI,EAAE,IAAI,EAAE;SACL;KACV,CAAC;AACH,CAAC"}
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAKA,wBAAsB,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBrE;AAED,wBAAsB,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBrE;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAUjD"}
|
package/dist/git.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
export async function detectBranch(override) {
|
|
5
|
+
if (override)
|
|
6
|
+
return override;
|
|
7
|
+
// GitHub Actions: PR head branch
|
|
8
|
+
const ghHead = process.env.GITHUB_HEAD_REF;
|
|
9
|
+
if (ghHead)
|
|
10
|
+
return ghHead;
|
|
11
|
+
// GitHub Actions: push branch (strip refs/heads/ prefix)
|
|
12
|
+
const ghRef = process.env.GITHUB_REF;
|
|
13
|
+
if (ghRef) {
|
|
14
|
+
const prefix = "refs/heads/";
|
|
15
|
+
return ghRef.startsWith(prefix) ? ghRef.slice(prefix.length) : ghRef;
|
|
16
|
+
}
|
|
17
|
+
// GitLab CI
|
|
18
|
+
const glRef = process.env.CI_COMMIT_REF_NAME;
|
|
19
|
+
if (glRef)
|
|
20
|
+
return glRef;
|
|
21
|
+
// Local git
|
|
22
|
+
try {
|
|
23
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
24
|
+
return stdout.trim();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new Error("Failed to detect git branch. Set PXDIFF_BRANCH or run in a git repository.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function detectCommit(override) {
|
|
31
|
+
if (override)
|
|
32
|
+
return override;
|
|
33
|
+
// GitHub Actions
|
|
34
|
+
const ghSha = process.env.GITHUB_SHA;
|
|
35
|
+
if (ghSha)
|
|
36
|
+
return ghSha;
|
|
37
|
+
// GitLab CI
|
|
38
|
+
const glSha = process.env.CI_COMMIT_SHA;
|
|
39
|
+
if (glSha)
|
|
40
|
+
return glSha;
|
|
41
|
+
// Local git
|
|
42
|
+
try {
|
|
43
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "HEAD"]);
|
|
44
|
+
return stdout.trim();
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
throw new Error("Failed to detect git commit. Set PXDIFF_COMMIT or run in a git repository.");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function detectBaselineRef() {
|
|
51
|
+
// GitHub Actions: PR base branch
|
|
52
|
+
const ghBase = process.env.GITHUB_BASE_REF;
|
|
53
|
+
if (ghBase)
|
|
54
|
+
return ghBase;
|
|
55
|
+
// Explicit override
|
|
56
|
+
const pxdiffRef = process.env.PXDIFF_BASELINE_REF;
|
|
57
|
+
if (pxdiffRef)
|
|
58
|
+
return pxdiffRef;
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAiB;IACnD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,iCAAiC;IACjC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC3C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,yDAAyD;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACrC,IAAI,KAAK,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,aAAa,CAAC;QAC7B,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACtE,CAAC;IAED,YAAY;IACZ,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC7C,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,YAAY;IACZ,IAAI,CAAC;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;QACrF,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAC/F,CAAC;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAiB;IACnD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,iBAAiB;IACjB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACrC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,YAAY;IACZ,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IACxC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,YAAY;IACZ,IAAI,CAAC;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;QACrE,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAC/F,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iBAAiB;IAChC,iCAAiC;IACjC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC3C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,oBAAoB;IACpB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IAClD,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAEhC,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.test.d.ts","sourceRoot":"","sources":["../src/git.test.ts"],"names":[],"mappings":""}
|
package/dist/git.test.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
// Mock child_process before importing the module
|
|
3
|
+
vi.mock("node:child_process", () => ({
|
|
4
|
+
execFile: vi.fn(),
|
|
5
|
+
}));
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
7
|
+
import { detectBaselineRef, detectBranch, detectCommit } from "./git.js";
|
|
8
|
+
function mockExecFile(stdout) {
|
|
9
|
+
vi.mocked(execFile).mockImplementation((_cmd, _args, cb) => {
|
|
10
|
+
cb(null, { stdout });
|
|
11
|
+
return undefined;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function mockExecFileError() {
|
|
15
|
+
vi.mocked(execFile).mockImplementation((_cmd, _args, cb) => {
|
|
16
|
+
cb(new Error("git not found"));
|
|
17
|
+
return undefined;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
describe("detectBranch", () => {
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
vi.unstubAllEnvs();
|
|
23
|
+
});
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
vi.restoreAllMocks();
|
|
26
|
+
});
|
|
27
|
+
it("returns override when provided", async () => {
|
|
28
|
+
expect(await detectBranch("my-branch")).toBe("my-branch");
|
|
29
|
+
});
|
|
30
|
+
it("reads GITHUB_HEAD_REF for PR branches", async () => {
|
|
31
|
+
vi.stubEnv("GITHUB_HEAD_REF", "feat/new-feature");
|
|
32
|
+
expect(await detectBranch()).toBe("feat/new-feature");
|
|
33
|
+
});
|
|
34
|
+
it("reads GITHUB_REF and strips refs/heads/ prefix", async () => {
|
|
35
|
+
vi.stubEnv("GITHUB_HEAD_REF", "");
|
|
36
|
+
vi.stubEnv("GITHUB_REF", "refs/heads/main");
|
|
37
|
+
expect(await detectBranch()).toBe("main");
|
|
38
|
+
});
|
|
39
|
+
it("returns GITHUB_REF as-is when not a heads ref", async () => {
|
|
40
|
+
vi.stubEnv("GITHUB_HEAD_REF", "");
|
|
41
|
+
vi.stubEnv("GITHUB_REF", "refs/tags/v1.0.0");
|
|
42
|
+
expect(await detectBranch()).toBe("refs/tags/v1.0.0");
|
|
43
|
+
});
|
|
44
|
+
it("reads CI_COMMIT_REF_NAME for GitLab CI", async () => {
|
|
45
|
+
vi.stubEnv("GITHUB_HEAD_REF", "");
|
|
46
|
+
vi.stubEnv("GITHUB_REF", "");
|
|
47
|
+
vi.stubEnv("CI_COMMIT_REF_NAME", "develop");
|
|
48
|
+
expect(await detectBranch()).toBe("develop");
|
|
49
|
+
});
|
|
50
|
+
it("falls back to git rev-parse", async () => {
|
|
51
|
+
vi.stubEnv("GITHUB_HEAD_REF", "");
|
|
52
|
+
vi.stubEnv("GITHUB_REF", "");
|
|
53
|
+
vi.stubEnv("CI_COMMIT_REF_NAME", "");
|
|
54
|
+
mockExecFile("feature-branch\n");
|
|
55
|
+
expect(await detectBranch()).toBe("feature-branch");
|
|
56
|
+
});
|
|
57
|
+
it("throws when git command fails and no env vars set", async () => {
|
|
58
|
+
vi.stubEnv("GITHUB_HEAD_REF", "");
|
|
59
|
+
vi.stubEnv("GITHUB_REF", "");
|
|
60
|
+
vi.stubEnv("CI_COMMIT_REF_NAME", "");
|
|
61
|
+
mockExecFileError();
|
|
62
|
+
await expect(detectBranch()).rejects.toThrow("Failed to detect git branch");
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe("detectCommit", () => {
|
|
66
|
+
beforeEach(() => {
|
|
67
|
+
vi.unstubAllEnvs();
|
|
68
|
+
});
|
|
69
|
+
afterEach(() => {
|
|
70
|
+
vi.restoreAllMocks();
|
|
71
|
+
});
|
|
72
|
+
it("returns override when provided", async () => {
|
|
73
|
+
expect(await detectCommit("abc123")).toBe("abc123");
|
|
74
|
+
});
|
|
75
|
+
it("reads GITHUB_SHA", async () => {
|
|
76
|
+
vi.stubEnv("GITHUB_SHA", "deadbeef1234567890abcdef");
|
|
77
|
+
expect(await detectCommit()).toBe("deadbeef1234567890abcdef");
|
|
78
|
+
});
|
|
79
|
+
it("reads CI_COMMIT_SHA for GitLab CI", async () => {
|
|
80
|
+
vi.stubEnv("GITHUB_SHA", "");
|
|
81
|
+
vi.stubEnv("CI_COMMIT_SHA", "gitlab-sha-123");
|
|
82
|
+
expect(await detectCommit()).toBe("gitlab-sha-123");
|
|
83
|
+
});
|
|
84
|
+
it("falls back to git rev-parse", async () => {
|
|
85
|
+
vi.stubEnv("GITHUB_SHA", "");
|
|
86
|
+
vi.stubEnv("CI_COMMIT_SHA", "");
|
|
87
|
+
mockExecFile("abcdef1234567890\n");
|
|
88
|
+
expect(await detectCommit()).toBe("abcdef1234567890");
|
|
89
|
+
});
|
|
90
|
+
it("throws when git command fails and no env vars set", async () => {
|
|
91
|
+
vi.stubEnv("GITHUB_SHA", "");
|
|
92
|
+
vi.stubEnv("CI_COMMIT_SHA", "");
|
|
93
|
+
mockExecFileError();
|
|
94
|
+
await expect(detectCommit()).rejects.toThrow("Failed to detect git commit");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe("detectBaselineRef", () => {
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
vi.unstubAllEnvs();
|
|
100
|
+
});
|
|
101
|
+
afterEach(() => {
|
|
102
|
+
vi.restoreAllMocks();
|
|
103
|
+
});
|
|
104
|
+
it("reads GITHUB_BASE_REF for PR base branch", () => {
|
|
105
|
+
vi.stubEnv("GITHUB_BASE_REF", "main");
|
|
106
|
+
expect(detectBaselineRef()).toBe("main");
|
|
107
|
+
});
|
|
108
|
+
it("reads PXDIFF_BASELINE_REF when set", () => {
|
|
109
|
+
vi.stubEnv("GITHUB_BASE_REF", "");
|
|
110
|
+
vi.stubEnv("PXDIFF_BASELINE_REF", "develop");
|
|
111
|
+
expect(detectBaselineRef()).toBe("develop");
|
|
112
|
+
});
|
|
113
|
+
it("returns null when no env vars set", () => {
|
|
114
|
+
vi.stubEnv("GITHUB_BASE_REF", "");
|
|
115
|
+
vi.stubEnv("PXDIFF_BASELINE_REF", "");
|
|
116
|
+
expect(detectBaselineRef()).toBeNull();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=git.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.test.js","sourceRoot":"","sources":["../src/git.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createPxdiffFixture } from "./fixture.js";
|
|
2
|
+
export { pxdiffMatchers } from "./matchers.js";
|
|
3
|
+
export type { MatchScreenshotOptions, PxdiffFixtureOptions, PxdiffResult, } from "./types.js";
|
|
4
|
+
declare module "@playwright/test" {
|
|
5
|
+
interface Matchers<R, T> {
|
|
6
|
+
toMatchScreenshot(name: string, options?: import("./types.js").MatchScreenshotOptions): Promise<R>;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACX,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,GACZ,MAAM,YAAY,CAAC;AAGpB,OAAO,QAAQ,kBAAkB,CAAC;IACjC,UAAU,QAAQ,CAAC,CAAC,EAAE,CAAC;QACtB,iBAAiB,CAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,YAAY,EAAE,sBAAsB,GACnD,OAAO,CAAC,CAAC,CAAC,CAAC;KACd;CACD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Locator, Page } from "@playwright/test";
|
|
2
|
+
import type { MatchScreenshotOptions } from "./types.js";
|
|
3
|
+
export declare const pxdiffMatchers: {
|
|
4
|
+
toMatchScreenshot(this: {
|
|
5
|
+
isNot: boolean;
|
|
6
|
+
}, received: Page | Locator, name: string, options?: MatchScreenshotOptions): Promise<{
|
|
7
|
+
pass: boolean;
|
|
8
|
+
message: () => string;
|
|
9
|
+
}>;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=matchers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,YAAY,CAAC;AAyBvE,eAAO,MAAM,cAAc;4BAEnB;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,YACd,IAAI,GAAG,OAAO,QAClB,MAAM,YACF,sBAAsB;;;;CA2GjC,CAAC"}
|
package/dist/matchers.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { PxdiffClient } from "@pxdiff/sdk";
|
|
2
|
+
import { contextMap } from "./fixture.js";
|
|
3
|
+
function isPage(value) {
|
|
4
|
+
return (typeof value === "object" &&
|
|
5
|
+
value !== null &&
|
|
6
|
+
"screenshot" in value &&
|
|
7
|
+
"viewportSize" in value &&
|
|
8
|
+
!("page" in value));
|
|
9
|
+
}
|
|
10
|
+
function getPage(received) {
|
|
11
|
+
if (isPage(received))
|
|
12
|
+
return received;
|
|
13
|
+
if (typeof received === "object" &&
|
|
14
|
+
received !== null &&
|
|
15
|
+
"page" in received &&
|
|
16
|
+
typeof received.page === "function") {
|
|
17
|
+
return received.page();
|
|
18
|
+
}
|
|
19
|
+
throw new Error(`toMatchScreenshot() expects a Page or Locator. Got: ${typeof received}`);
|
|
20
|
+
}
|
|
21
|
+
export const pxdiffMatchers = {
|
|
22
|
+
async toMatchScreenshot(received, name, options) {
|
|
23
|
+
const page = getPage(received);
|
|
24
|
+
const ctx = contextMap.get(page);
|
|
25
|
+
if (!ctx) {
|
|
26
|
+
return {
|
|
27
|
+
pass: false,
|
|
28
|
+
message: () => "pxdiff context not found. Make sure you called createPxdiffFixture() " +
|
|
29
|
+
"and extended your test with the fixtures.",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Set viewport if requested
|
|
33
|
+
if (options?.viewport) {
|
|
34
|
+
await page.setViewportSize(options.viewport);
|
|
35
|
+
}
|
|
36
|
+
// Take screenshot
|
|
37
|
+
const screenshotTarget = isPage(received) ? page : received;
|
|
38
|
+
const png = await screenshotTarget.screenshot({
|
|
39
|
+
fullPage: options?.fullPage,
|
|
40
|
+
mask: options?.mask,
|
|
41
|
+
animations: options?.animations,
|
|
42
|
+
timeout: options?.timeout,
|
|
43
|
+
});
|
|
44
|
+
// Get viewport dimensions
|
|
45
|
+
const viewportSize = page.viewportSize();
|
|
46
|
+
const viewport = viewportSize
|
|
47
|
+
? { width: viewportSize.width, height: viewportSize.height }
|
|
48
|
+
: undefined;
|
|
49
|
+
// Upload and diff
|
|
50
|
+
const client = new PxdiffClient({ apiKey: ctx.apiKey, apiUrl: ctx.apiUrl });
|
|
51
|
+
const result = await client.uploadSnapshotWithDiff({
|
|
52
|
+
name,
|
|
53
|
+
png,
|
|
54
|
+
suite: ctx.suite,
|
|
55
|
+
branch: ctx.branch,
|
|
56
|
+
commit: ctx.commit,
|
|
57
|
+
baselineRef: ctx.baselineRef ?? ctx.branch,
|
|
58
|
+
viewport,
|
|
59
|
+
autoBaseline: ctx.autoBaseline,
|
|
60
|
+
});
|
|
61
|
+
const pxdiffResult = {
|
|
62
|
+
status: result.status,
|
|
63
|
+
diffPercentage: result.diffPercentage,
|
|
64
|
+
diffUrl: result.diffS3Key,
|
|
65
|
+
snapshotName: name,
|
|
66
|
+
viewport: viewport ?? null,
|
|
67
|
+
};
|
|
68
|
+
// Attach result as test annotation
|
|
69
|
+
const testInfo = page?.context?.()
|
|
70
|
+
?._testInfo;
|
|
71
|
+
if (testInfo &&
|
|
72
|
+
typeof testInfo === "object" &&
|
|
73
|
+
"annotations" in testInfo &&
|
|
74
|
+
Array.isArray(testInfo.annotations)) {
|
|
75
|
+
testInfo.annotations.push({
|
|
76
|
+
type: "pxdiff",
|
|
77
|
+
description: JSON.stringify(pxdiffResult),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// Determine pass/fail
|
|
81
|
+
const blocking = options?.blocking ?? ctx.blocking;
|
|
82
|
+
if (result.status === "unchanged" || result.status === "new") {
|
|
83
|
+
return {
|
|
84
|
+
pass: true,
|
|
85
|
+
message: () => `Screenshot "${name}" is ${result.status}.`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// Status is "changed"
|
|
89
|
+
if (options?.maxDiffPixelRatio !== undefined &&
|
|
90
|
+
result.diffPercentage !== null &&
|
|
91
|
+
result.diffPercentage / 100 <= options.maxDiffPixelRatio) {
|
|
92
|
+
return {
|
|
93
|
+
pass: true,
|
|
94
|
+
message: () => `Screenshot "${name}" changed by ${result.diffPercentage}% ` +
|
|
95
|
+
`(within maxDiffPixelRatio of ${options.maxDiffPixelRatio}).`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (!blocking) {
|
|
99
|
+
return {
|
|
100
|
+
pass: true,
|
|
101
|
+
message: () => `Screenshot "${name}" changed by ${result.diffPercentage ?? "unknown"}% (non-blocking).`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
pass: false,
|
|
106
|
+
message: () => `Screenshot "${name}" has visual differences.\n Diff: ${result.diffPercentage ?? "unknown"}%\n Diff ID: ${result.diffId}\n${result.diffS3Key ? ` Diff image: ${result.diffS3Key}\n` : ""} Review and approve the changes in the pxdiff dashboard.`,
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=matchers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.js","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.test.d.ts","sourceRoot":"","sources":["../src/matchers.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { contextMap } from "./fixture.js";
|
|
3
|
+
import { pxdiffMatchers } from "./matchers.js";
|
|
4
|
+
// Mock PxdiffClient
|
|
5
|
+
vi.mock("@pxdiff/sdk", () => ({
|
|
6
|
+
PxdiffClient: vi.fn().mockImplementation(() => ({
|
|
7
|
+
uploadSnapshotWithDiff: vi.fn(),
|
|
8
|
+
})),
|
|
9
|
+
}));
|
|
10
|
+
import { PxdiffClient } from "@pxdiff/sdk";
|
|
11
|
+
function createMockPage(viewportSize = { width: 1280, height: 720 }) {
|
|
12
|
+
const page = {
|
|
13
|
+
screenshot: vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3])),
|
|
14
|
+
viewportSize: vi.fn().mockReturnValue(viewportSize),
|
|
15
|
+
setViewportSize: vi.fn().mockResolvedValue(undefined),
|
|
16
|
+
context: vi.fn().mockReturnValue({ _testInfo: null }),
|
|
17
|
+
};
|
|
18
|
+
return page;
|
|
19
|
+
}
|
|
20
|
+
function createMockLocator(page) {
|
|
21
|
+
const locator = {
|
|
22
|
+
screenshot: vi.fn().mockResolvedValue(new Uint8Array([4, 5, 6])),
|
|
23
|
+
page: vi.fn().mockReturnValue(page),
|
|
24
|
+
};
|
|
25
|
+
return locator;
|
|
26
|
+
}
|
|
27
|
+
const defaultContext = {
|
|
28
|
+
apiKey: "pxd_test123",
|
|
29
|
+
apiUrl: "https://api.test.pxdiff.com",
|
|
30
|
+
suite: "e2e",
|
|
31
|
+
blocking: true,
|
|
32
|
+
autoBaseline: true,
|
|
33
|
+
branch: "feat/test",
|
|
34
|
+
commit: "abc123",
|
|
35
|
+
baselineRef: "main",
|
|
36
|
+
};
|
|
37
|
+
function mockUploadResult(result) {
|
|
38
|
+
const fullResult = {
|
|
39
|
+
name: "test-screenshot",
|
|
40
|
+
suite: "e2e",
|
|
41
|
+
status: "unchanged",
|
|
42
|
+
diffPercentage: null,
|
|
43
|
+
diffId: "diff-1",
|
|
44
|
+
captureId: "cap-1",
|
|
45
|
+
currentS3Key: null,
|
|
46
|
+
baselineS3Key: null,
|
|
47
|
+
diffS3Key: null,
|
|
48
|
+
...result,
|
|
49
|
+
};
|
|
50
|
+
vi.mocked(PxdiffClient).mockImplementation(() => ({
|
|
51
|
+
uploadSnapshotWithDiff: vi.fn().mockResolvedValue(fullResult),
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
describe("pxdiffMatchers.toMatchScreenshot", () => {
|
|
55
|
+
let page;
|
|
56
|
+
const matcherContext = { isNot: false };
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
page = createMockPage();
|
|
59
|
+
contextMap.set(page, { ...defaultContext });
|
|
60
|
+
});
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
contextMap.delete(page);
|
|
63
|
+
vi.restoreAllMocks();
|
|
64
|
+
});
|
|
65
|
+
it("passes for unchanged snapshots", async () => {
|
|
66
|
+
mockUploadResult({ status: "unchanged" });
|
|
67
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "homepage");
|
|
68
|
+
expect(result.pass).toBe(true);
|
|
69
|
+
expect(result.message()).toContain("unchanged");
|
|
70
|
+
});
|
|
71
|
+
it("passes for new snapshots", async () => {
|
|
72
|
+
mockUploadResult({ status: "new" });
|
|
73
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "new-page");
|
|
74
|
+
expect(result.pass).toBe(true);
|
|
75
|
+
expect(result.message()).toContain("new");
|
|
76
|
+
});
|
|
77
|
+
it("fails for changed snapshots in blocking mode", async () => {
|
|
78
|
+
mockUploadResult({
|
|
79
|
+
status: "changed",
|
|
80
|
+
diffPercentage: 5.2,
|
|
81
|
+
diffId: "diff-abc",
|
|
82
|
+
diffS3Key: "diffs/diff-abc/hash.png",
|
|
83
|
+
});
|
|
84
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "login");
|
|
85
|
+
expect(result.pass).toBe(false);
|
|
86
|
+
expect(result.message()).toContain("visual differences");
|
|
87
|
+
expect(result.message()).toContain("5.2%");
|
|
88
|
+
expect(result.message()).toContain("diff-abc");
|
|
89
|
+
});
|
|
90
|
+
it("passes for changed snapshots in non-blocking mode (fixture-level)", async () => {
|
|
91
|
+
contextMap.set(page, { ...defaultContext, blocking: false });
|
|
92
|
+
mockUploadResult({ status: "changed", diffPercentage: 3.1 });
|
|
93
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "dashboard");
|
|
94
|
+
expect(result.pass).toBe(true);
|
|
95
|
+
expect(result.message()).toContain("non-blocking");
|
|
96
|
+
});
|
|
97
|
+
it("passes for changed snapshots in non-blocking mode (option-level)", async () => {
|
|
98
|
+
mockUploadResult({ status: "changed", diffPercentage: 2.0 });
|
|
99
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "dashboard", {
|
|
100
|
+
blocking: false,
|
|
101
|
+
});
|
|
102
|
+
expect(result.pass).toBe(true);
|
|
103
|
+
expect(result.message()).toContain("non-blocking");
|
|
104
|
+
});
|
|
105
|
+
it("passes when diffPercentage is within maxDiffPixelRatio", async () => {
|
|
106
|
+
mockUploadResult({ status: "changed", diffPercentage: 0.5 });
|
|
107
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "subtle-change", { maxDiffPixelRatio: 0.01 });
|
|
108
|
+
expect(result.pass).toBe(true);
|
|
109
|
+
expect(result.message()).toContain("maxDiffPixelRatio");
|
|
110
|
+
});
|
|
111
|
+
it("fails when diffPercentage exceeds maxDiffPixelRatio", async () => {
|
|
112
|
+
mockUploadResult({ status: "changed", diffPercentage: 5.0 });
|
|
113
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "big-change", {
|
|
114
|
+
maxDiffPixelRatio: 0.01,
|
|
115
|
+
});
|
|
116
|
+
expect(result.pass).toBe(false);
|
|
117
|
+
expect(result.message()).toContain("visual differences");
|
|
118
|
+
});
|
|
119
|
+
it("works with a Locator instead of Page", async () => {
|
|
120
|
+
const locator = createMockLocator(page);
|
|
121
|
+
mockUploadResult({ status: "unchanged" });
|
|
122
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, locator, "button");
|
|
123
|
+
expect(result.pass).toBe(true);
|
|
124
|
+
// Should call screenshot on the locator, not the page
|
|
125
|
+
expect(locator.screenshot.mock.calls).toHaveLength(1);
|
|
126
|
+
});
|
|
127
|
+
it("returns error when context is missing", async () => {
|
|
128
|
+
contextMap.delete(page);
|
|
129
|
+
const result = await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "no-context");
|
|
130
|
+
expect(result.pass).toBe(false);
|
|
131
|
+
expect(result.message()).toContain("pxdiff context not found");
|
|
132
|
+
});
|
|
133
|
+
it("sets viewport before taking screenshot", async () => {
|
|
134
|
+
mockUploadResult({ status: "unchanged" });
|
|
135
|
+
const viewport = { width: 375, height: 812 };
|
|
136
|
+
await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "mobile", {
|
|
137
|
+
viewport,
|
|
138
|
+
});
|
|
139
|
+
expect(page.setViewportSize.mock
|
|
140
|
+
.calls[0]).toEqual([viewport]);
|
|
141
|
+
});
|
|
142
|
+
it("passes screenshot options through", async () => {
|
|
143
|
+
mockUploadResult({ status: "unchanged" });
|
|
144
|
+
await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "full-page", {
|
|
145
|
+
fullPage: true,
|
|
146
|
+
animations: "disabled",
|
|
147
|
+
timeout: 5000,
|
|
148
|
+
});
|
|
149
|
+
const screenshotCall = page.screenshot.mock.calls[0]?.[0];
|
|
150
|
+
expect(screenshotCall?.fullPage).toBe(true);
|
|
151
|
+
expect(screenshotCall?.animations).toBe("disabled");
|
|
152
|
+
expect(screenshotCall?.timeout).toBe(5000);
|
|
153
|
+
});
|
|
154
|
+
it("sends correct metadata to uploadSnapshotWithDiff", async () => {
|
|
155
|
+
const uploadMock = vi.fn().mockResolvedValue({
|
|
156
|
+
name: "test",
|
|
157
|
+
suite: "e2e",
|
|
158
|
+
status: "unchanged",
|
|
159
|
+
diffPercentage: null,
|
|
160
|
+
diffId: "diff-1",
|
|
161
|
+
captureId: "cap-1",
|
|
162
|
+
currentS3Key: null,
|
|
163
|
+
baselineS3Key: null,
|
|
164
|
+
diffS3Key: null,
|
|
165
|
+
});
|
|
166
|
+
vi.mocked(PxdiffClient).mockImplementation(() => ({
|
|
167
|
+
uploadSnapshotWithDiff: uploadMock,
|
|
168
|
+
}));
|
|
169
|
+
await pxdiffMatchers.toMatchScreenshot.call(matcherContext, page, "test");
|
|
170
|
+
expect(uploadMock).toHaveBeenCalledWith({
|
|
171
|
+
name: "test",
|
|
172
|
+
png: expect.any(Uint8Array),
|
|
173
|
+
suite: "e2e",
|
|
174
|
+
branch: "feat/test",
|
|
175
|
+
commit: "abc123",
|
|
176
|
+
baselineRef: "main",
|
|
177
|
+
viewport: { width: 1280, height: 720 },
|
|
178
|
+
autoBaseline: true,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
it("throws for non-page/non-locator values", async () => {
|
|
182
|
+
await expect(pxdiffMatchers.toMatchScreenshot.call(matcherContext, "not-a-page", "test")).rejects.toThrow("toMatchScreenshot() expects a Page or Locator");
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=matchers.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.test.js","sourceRoot":"","sources":["../src/matchers.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,oBAAoB;AACpB,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7B,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC;QAC/C,sBAAsB,EAAE,EAAE,CAAC,EAAE,EAAE;KAC/B,CAAC,CAAC;CACH,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,SAAS,cAAc,CAAC,YAAY,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IAClE,MAAM,IAAI,GAAG;QACZ,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChE,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,YAAY,CAAC;QACnD,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;QACrD,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACrD,CAAC;IACF,OAAO,IAAkD,CAAC;AAC3D,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAqC;IAC/D,MAAM,OAAO,GAAG;QACf,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC;KACnC,CAAC;IACF,OAAO,OAAwD,CAAC;AACjE,CAAC;AAED,MAAM,cAAc,GAAkB;IACrC,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,6BAA6B;IACrC,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,IAAI;IACd,YAAY,EAAE,IAAI;IAClB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,MAAM;CACnB,CAAC;AAEF,SAAS,gBAAgB,CAAC,MAAmC;IAC5D,MAAM,UAAU,GAAuB;QACtC,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,WAAW;QACnB,cAAc,EAAE,IAAI;QACpB,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,OAAO;QAClB,YAAY,EAAE,IAAI;QAClB,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,IAAI;QACf,GAAG,MAAM;KACT,CAAC;IACF,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,kBAAkB,CACzC,GAAG,EAAE,CACJ,CAAC;QACA,sBAAsB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC;KAC7D,CAAiD,CACnD,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IACjD,IAAI,IAAqC,CAAC;IAC1C,MAAM,cAAc,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAExC,UAAU,CAAC,GAAG,EAAE;QACf,IAAI,GAAG,cAAc,EAAE,CAAC;QACxB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,cAAc,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACd,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,EAAE,CAAC,eAAe,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC/C,gBAAgB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QAE1C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QAE7F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACzC,gBAAgB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAEpC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QAE7F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC7D,gBAAgB,CAAC;YAChB,MAAM,EAAE,SAAS;YACjB,cAAc,EAAE,GAAG;YACnB,MAAM,EAAE,UAAU;YAClB,SAAS,EAAE,yBAAyB;SACpC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAE1F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QAClF,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,gBAAgB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QAE9F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QACjF,gBAAgB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE;YAC7F,QAAQ,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACvE,gBAAgB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CACzD,cAAc,EACd,IAAI,EACJ,eAAe,EACf,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAC3B,CAAC;QAEF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACpE,gBAAgB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,YAAY,EAAE;YAC9F,iBAAiB,EAAE,IAAI;SACvB,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACxC,gBAAgB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QAE1C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAE9F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,sDAAsD;QACtD,MAAM,CACJ,OAAqE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAC5F,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACtD,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAExB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;QAE/F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACvD,gBAAgB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QAE7C,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3E,QAAQ;SACR,CAAC,CAAC;QAEH,MAAM,CACJ,IAAuE,CAAC,eAAe,CAAC,IAAI;aAC3F,KAAK,CAAC,CAAC,CAAC,CACV,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QAClD,gBAAgB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QAE1C,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE;YAC9E,QAAQ,EAAE,IAAI;YACd,UAAU,EAAE,UAAU;YACtB,OAAO,EAAE,IAAI;SACb,CAAC,CAAC;QAEH,MAAM,cAAc,GACnB,IACA,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpD,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YAC5C,IAAI,EAAE,MAAM;YACZ,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,WAAW;YACnB,cAAc,EAAE,IAAI;YACpB,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,OAAO;YAClB,YAAY,EAAE,IAAI;YAClB,aAAa,EAAE,IAAI;YACnB,SAAS,EAAE,IAAI;SACf,CAAC,CAAC;QACH,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,kBAAkB,CACzC,GAAG,EAAE,CACJ,CAAC;YACA,sBAAsB,EAAE,UAAU;SAClC,CAAiD,CACnD,CAAC;QAEF,MAAM,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAE1E,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC;YACvC,IAAI,EAAE,MAAM;YACZ,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;YAC3B,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,WAAW;YACnB,MAAM,EAAE,QAAQ;YAChB,WAAW,EAAE,MAAM;YACnB,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;YACtC,YAAY,EAAE,IAAI;SAClB,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,MAAM,CACX,cAAc,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,YAAqB,EAAE,MAAM,CAAC,CACpF,CAAC,OAAO,CAAC,OAAO,CAAC,+CAA+C,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface PxdiffFixtureOptions {
|
|
2
|
+
/** Suite name for grouping snapshots. Defaults to test file name. */
|
|
3
|
+
suite?: string;
|
|
4
|
+
/** If true, changed snapshots fail the test. Defaults to true. */
|
|
5
|
+
blocking?: boolean;
|
|
6
|
+
/** API URL override. Defaults to PXDIFF_API_URL env or https://api.pxdiff.com. */
|
|
7
|
+
apiUrl?: string;
|
|
8
|
+
/** Git metadata overrides. Auto-detected when not provided. */
|
|
9
|
+
git?: {
|
|
10
|
+
branch?: string;
|
|
11
|
+
commit?: string;
|
|
12
|
+
};
|
|
13
|
+
/** Auto-promote snapshots to baseline when no baseline exists. Defaults to true. */
|
|
14
|
+
autoBaseline?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface MatchScreenshotOptions {
|
|
17
|
+
/** Override blocking mode for this snapshot. */
|
|
18
|
+
blocking?: boolean;
|
|
19
|
+
/** Custom diff threshold (0-1). */
|
|
20
|
+
threshold?: number;
|
|
21
|
+
/** Viewport size to set before taking the screenshot. */
|
|
22
|
+
viewport?: {
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
};
|
|
26
|
+
/** Take full-page screenshot. Defaults to false. */
|
|
27
|
+
fullPage?: boolean;
|
|
28
|
+
/** Locators to mask before taking the screenshot. */
|
|
29
|
+
mask?: unknown[];
|
|
30
|
+
/** Maximum acceptable diff ratio (0-1). If diff is below this, the assertion passes. */
|
|
31
|
+
maxDiffPixelRatio?: number;
|
|
32
|
+
/** Animation handling: 'disabled' freezes animations. */
|
|
33
|
+
animations?: "disabled" | "allow";
|
|
34
|
+
/** Screenshot timeout in ms. */
|
|
35
|
+
timeout?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface PxdiffResult {
|
|
38
|
+
status: "new" | "changed" | "unchanged";
|
|
39
|
+
diffPercentage: number | null;
|
|
40
|
+
diffUrl: string | null;
|
|
41
|
+
snapshotName: string;
|
|
42
|
+
viewport: {
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
} | null;
|
|
46
|
+
}
|
|
47
|
+
export interface PxdiffContext {
|
|
48
|
+
apiKey: string;
|
|
49
|
+
apiUrl: string;
|
|
50
|
+
suite: string;
|
|
51
|
+
blocking: boolean;
|
|
52
|
+
autoBaseline: boolean;
|
|
53
|
+
branch: string;
|
|
54
|
+
commit: string;
|
|
55
|
+
baselineRef: string | null;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACpC,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,GAAG,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,oFAAoF;IACpF,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACtC,gDAAgD;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qDAAqD;IACrD,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,wFAAwF;IACxF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yDAAyD;IACzD,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAClC,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,WAAW,CAAC;IACxC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pxdiff/playwright",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"import": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@pxdiff/sdk": "0.0.1"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@playwright/test": ">=1.40"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@playwright/test": "^1.50.0",
|
|
22
|
+
"typescript": "^5.7.3",
|
|
23
|
+
"vitest": "^3.0.5"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc --build",
|
|
27
|
+
"typecheck": "tsc --build --noEmit",
|
|
28
|
+
"test": "vitest run"
|
|
29
|
+
}
|
|
30
|
+
}
|