Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ CHANGELOG.md
dist
/docs
__fixtures__/screenshots/invalid.argos.json
packages/api-client/src/schema.ts
/packages/api-client/src/schema.ts
/examples
/.nx/workspace-data
/.agents/skills
/.agents/skills
/packages/storybook/storybook-static
82 changes: 81 additions & 1 deletion packages/playwright/src/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { describe, it, expect } from "vitest";
import { getAutomaticScreenshotName } from "./util";
import {
checkIsUsingArgosReporter,
getAutomaticScreenshotName,
getSnapshotNames,
} from "./util";
import type { TestCase, TestResult } from "@playwright/test/reporter";
import type { TestInfo } from "@playwright/test";

describe("getAutomaticScreenshotName", () => {
const createMockTest = (
Expand Down Expand Up @@ -144,3 +149,78 @@ describe("getAutomaticScreenshotName", () => {
expect(name.length).toBeLessThanOrEqual(240);
});
});

describe("getSnapshotNames", () => {
const createMockTestInfo = (
projectName: string,
repeatEachIndex = 0,
): TestInfo =>
({
project: { name: projectName },
repeatEachIndex,
}) as TestInfo;

it("prefixes the name with the project name", () => {
const names = getSnapshotNames("hero", createMockTestInfo("chromium"));
expect(names).toEqual({ name: "chromium/hero", baseName: null });
});

it("does not prefix the name when the project name is empty", () => {
// No `projects` configured in the Playwright config: the project name is
// empty. Prefixing would produce an absolute path (`/hero`).
const names = getSnapshotNames("hero", createMockTestInfo(""));
expect(names).toEqual({ name: "hero", baseName: null });
});

it("returns the bare name when there is no test info", () => {
const names = getSnapshotNames("hero", null);
expect(names).toEqual({ name: "hero", baseName: null });
});

it("handles repeated tests with an empty project name", () => {
const names = getSnapshotNames("hero", createMockTestInfo("", 2));
expect(names).toEqual({ name: "hero repeat-2", baseName: "hero" });
});
});

describe("checkIsUsingArgosReporter", () => {
const createMockTestInfo = (reporter: [string, unknown?][]): TestInfo =>
({ config: { reporter } }) as unknown as TestInfo;

it("returns false without test info", () => {
expect(checkIsUsingArgosReporter(null)).toBe(false);
});

it("detects the reporter from the import specifier", () => {
const testInfo = createMockTestInfo([
["dot"],
["@argos-ci/playwright/reporter", {}],
]);
expect(checkIsUsingArgosReporter(testInfo)).toBe(true);
});

it("detects the reporter from a Playwright-resolved absolute path", () => {
// Playwright resolves reporter ids to absolute paths pointing at the
// package's dist file, which no longer contains `/reporter`.
const testInfo = createMockTestInfo([
["list"],
["/repo/node_modules/@argos-ci/playwright/dist/reporter.mjs", {}],
]);
expect(checkIsUsingArgosReporter(testInfo)).toBe(true);
});

it("detects the reporter from a pnpm-resolved absolute path", () => {
const testInfo = createMockTestInfo([
[
"/repo/node_modules/.pnpm/@argos-ci+playwright@7.1.2/node_modules/@argos-ci/playwright/dist/reporter.mjs",
{},
],
]);
expect(checkIsUsingArgosReporter(testInfo)).toBe(true);
});

it("returns false when the reporter is not configured", () => {
const testInfo = createMockTestInfo([["dot"], ["list"]]);
expect(checkIsUsingArgosReporter(testInfo)).toBe(false);
});
});
24 changes: 20 additions & 4 deletions packages/playwright/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,21 @@ export function checkIsUsingArgosReporter(testInfo: TestInfo | null): boolean {
if (!testInfo) {
return false;
}
const reporterPath = require.resolve("@argos-ci/playwright/reporter");
// Playwright rewrites every non-builtin reporter id to an absolute resolved
// path (e.g. `…/node_modules/@argos-ci/playwright/dist/reporter.mjs`), so we
// can't match against the `@argos-ci/playwright/reporter` import specifier.
// Match the package directory instead, which is present in both the raw
// specifier and the resolved path.
let reporterPath: string | null = null;
try {
reporterPath = require.resolve("@argos-ci/playwright/reporter");
} catch {
// Ignore: the reporter entry point might not be resolvable in every setup.
}
return testInfo.config.reporter.some(
(reporter) =>
reporter[0].includes("@argos-ci/playwright/reporter") ||
reporter[0] === reporterPath,
reporter[0].includes("@argos-ci/playwright") ||
(reporterPath !== null && reporter[0] === reporterPath),
);
}

Expand Down Expand Up @@ -167,7 +177,13 @@ export function getSnapshotNames(
testInfo: TestInfo | null,
): SnapshotNames {
if (testInfo) {
const projectName = `${testInfo.project.name}/${name}`;
// The project name is empty when no `projects` are configured in the
// Playwright config. In that case we must not prefix the name, otherwise it
// becomes an absolute path (e.g. `/my-screenshot`) and `path.resolve(root,
// name)` resolves it to the filesystem root.
const projectName = testInfo.project.name
? `${testInfo.project.name}/${name}`
: name;

if (testInfo.repeatEachIndex > 0) {
return {
Expand Down
Loading