Skip to content
Draft
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
8 changes: 7 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,13 @@
}
],
"simple-import-sort/imports": "warn",
"@vitest/no-focused-tests": "error"
"@vitest/no-focused-tests": "error",
"@vitest/expect-expect": [
"error",
{
"assertFunctionNames": ["expect", "compareScreenshots"]
}
]
},
"settings": {
"react": {
Expand Down
49 changes: 49 additions & 0 deletions test/compare-screenshots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { expect } from "vitest";

import { ScreenshotWithOffset } from "@cloudscape-design/browser-test-tools/page-objects";
import useBrowser from "@cloudscape-design/browser-test-tools/use-browser";

import ScenarioPageObject from "./scenario-page-object";

// Default window size to ensure 4-columns layout is used.
const windowSize = { width: 1600, height: 800 };

export interface ScreenshotTestConfiguration {
width?: number;
height?: number;
skipBrowsers?: Array<string>;
retries?: number;
}

interface PermutationScreenshot extends ScreenshotWithOffset {
id: string;
}

export type TestCallback = (
page: ScenarioPageObject,
) => Promise<ScreenshotWithOffset | PermutationScreenshot[] | undefined>;

export default function compareScreenshots(...args: [ScreenshotTestConfiguration, TestCallback] | [TestCallback]) {
let testFn: TestCallback;
let configuration: ScreenshotTestConfiguration;
if (args.length === 1) {
configuration = {};
testFn = args[0];
} else {
configuration = args[0];
testFn = args[1];
}

return useBrowser({ ...windowSize, ...configuration }, async (browser) => {
const page = new ScenarioPageObject(browser);
const result = await testFn(page);

if (result && "image" in result) {
const imageBuffer = result.image;

expect(imageBuffer).toMatchImageSnapshot();

Check failure on line 46 in test/compare-screenshots.ts

View workflow job for this annotation

GitHub Actions / Run Tests

test/visual/avatar.test.ts > Avatar > permutations

Error: New snapshot was not written. The update flag must be explicitly passed to write a new snapshot. + This is likely because this test is run in a continuous integration (CI) environment in which snapshots are not written by default. ❯ test/compare-screenshots.ts:46:27 ❯ node_modules/@cloudscape-design/browser-test-tools/use-browser.js:36:13

Check failure on line 46 in test/compare-screenshots.ts

View workflow job for this annotation

GitHub Actions / Run Tests

test/visual/avatar.test.ts > Avatar > custom style

Error: New snapshot was not written. The update flag must be explicitly passed to write a new snapshot. + This is likely because this test is run in a continuous integration (CI) environment in which snapshots are not written by default. ❯ test/compare-screenshots.ts:46:27 ❯ node_modules/@cloudscape-design/browser-test-tools/use-browser.js:36:13
}
})();
}
45 changes: 45 additions & 0 deletions test/scenario-page-object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { ScreenshotPageObject, ScreenshotWithOffset } from "@cloudscape-design/browser-test-tools/page-objects";

const screenshotAreaSelector = ".screenshot-area";

export default class ScenarioPageObject extends ScreenshotPageObject {
private baseUrl?: URL;

constructor(
browser: ConstructorParameters<typeof ScreenshotPageObject>[0],
public readonly forceScrollAndMerge: boolean = false,
) {
super(browser);
}

captureScreenshotArea(): Promise<ScreenshotWithOffset> {
return this.captureBySelector(screenshotAreaSelector);
}

async openScenario(scenarioName: string, queryParams?: Record<string, string>) {
await this.openIntegrationTestPage(scenarioName, queryParams);
}

async openIntegrationTestPage(pageName: string, queryParams: Record<string, string> = {}) {
if (pageName.includes("?")) {
throw new Error(
`Scenario name "${pageName}" may not contain query parameters. To pass extra params use the second argument.`,
);
}
const params = new URLSearchParams(queryParams);
params.append("motionDisabled", "true");
params.append("screenshotMode", "true");
const pagePath = `/#/${pageName}?${params.toString()}`;
await this.browser.url(pagePath);
await this.waitForVisible("main");
await this.waitForJsTimers(100);
}

async openPage(pagePath: string) {
const pageUrl = new URL(pagePath, this.baseUrl).toString();
await this.browser.url(pageUrl);
}
}
27 changes: 0 additions & 27 deletions test/utils.ts

This file was deleted.

21 changes: 21 additions & 0 deletions test/visual/avatar.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { describe, test } from "vitest";

import compareScreenshots from "../compare-screenshots";

describe("Avatar", () => {
test("custom style", () =>
compareScreenshots(async (page) => {
await page.openScenario("avatar/custom-style");
return page.captureScreenshotArea();
}));

test("permutations", () =>
compareScreenshots(async (page) => {
await page.openScenario("avatar/permutations");
// The page does not actually use our permutations component,
// therefore we capture the entire screenshot area at once.
return page.captureScreenshotArea();
}));
});
15 changes: 7 additions & 8 deletions test/visual/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import path from "path";
import { expect, test } from "vitest";
import { test } from "vitest";

import { ScreenshotPageObject } from "@cloudscape-design/browser-test-tools/page-objects";

import { setupTest } from "../utils";
import compareScreenshots from "../compare-screenshots";
import ScenarioPageObject from "../scenario-page-object";

const pagesMap = import.meta.glob("../../pages/**/*.page.tsx", { as: "raw" });
const pages = Object.keys(pagesMap)
.map((page) => page.replace(/\.page\.tsx$/, ""))
.map((page) => "/#/" + path.relative("../../pages/", page));

test.each(pages)("matches snapshot for %s", (route) =>
setupTest(route, ScreenshotPageObject, async (page) => {
compareScreenshots(async (page: ScenarioPageObject) => {
await page.openScenario(route);
const hasScreenshotArea = await page.isExisting(".screenshot-area");

if (hasScreenshotArea) {
const pngString = await page.fullPageScreenshot();
expect(pngString).toMatchImageSnapshot();
return page.captureScreenshotArea();
}
})(),
}),
);
Loading