Skip to content

Commit a1466f0

Browse files
authored
chore: Refactors visual tests setup (#393)
1 parent 6cae59e commit a1466f0

File tree

7 files changed

+235
-158
lines changed

7 files changed

+235
-158
lines changed

package-lock.json

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/visual-test-setup.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const snapshotDir = join(__dirname, "./..", process.env.VISUAL_REGRESSION_SNAPSH
88

99
const toMatchImageSnapshot = configureToMatchImageSnapshot({
1010
customSnapshotsDir: snapshotDir,
11+
customSnapshotIdentifier: ({ currentTestName }) => currentTestName.replace("/#/", "").replace(/[\s]/g, "-"),
1112
});
1213

1314
expect.extend({ toMatchImageSnapshot });

test/visual/drag-states.test.ts

Lines changed: 91 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -1,193 +1,137 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
import { expect, test } from "vitest";
43

5-
import { ScreenshotPageObject } from "@cloudscape-design/browser-test-tools/page-objects";
4+
import { expect, test } from "vitest";
65

76
import createWrapper from "../../lib/components/test-utils/selectors";
8-
import { makeQueryUrl, setupTest } from "../utils";
7+
import { makeQueryUrl } from "../utils";
8+
import { setupScreenshotTest } from "./utils";
99

1010
const boardWrapper = createWrapper().findBoard();
1111
const itemsPaletteWrapper = createWrapper().findItemsPalette();
1212
const boardItemHandle = (id: string) => boardWrapper.findItemById(id).findDragHandle().toSelector();
1313
const boardItemResizeHandle = (id: string) => boardWrapper.findItemById(id).findResizeHandle().toSelector();
1414

15-
class DndPageObject extends ScreenshotPageObject {
16-
async focus(selector: string) {
17-
await this.browser.execute((target) => {
18-
(document.querySelector(target) as HTMLButtonElement)!.focus();
19-
}, selector);
20-
}
21-
22-
async getElementCenter(selector: string) {
23-
const targetRect = await this.getBoundingBox(selector);
24-
const x = Math.round(targetRect.left + targetRect.width / 2);
25-
const y = Math.round(targetRect.top + targetRect.height / 2);
26-
return { x, y };
27-
}
28-
29-
async mouseDown(selector: string) {
30-
const center = await this.getElementCenter(selector);
31-
await (await this.browser.$(selector)).moveTo();
32-
await this.browser.performActions([
33-
{
34-
type: "pointer",
35-
id: "event",
36-
parameters: { pointerType: "mouse" },
37-
actions: [
38-
{ type: "pointerMove", duration: 0, origin: "pointer", ...center },
39-
{ type: "pointerDown", button: 0 },
40-
{ type: "pause", duration: 10 },
41-
],
42-
},
43-
]);
44-
}
45-
46-
async mouseMove(xOffset: number, yOffset: number) {
47-
await this.browser.performActions([
48-
{
49-
type: "pointer",
50-
id: "event",
51-
parameters: { pointerType: "mouse" },
52-
actions: [
53-
{ type: "pointerMove", duration: 100, origin: "pointer", x: xOffset, y: yOffset },
54-
{ type: "pause", duration: 10 },
55-
],
56-
},
57-
]);
58-
}
59-
60-
async mouseUp() {
61-
await this.browser.performActions([
62-
{
63-
type: "pointer",
64-
id: "event",
65-
parameters: { pointerType: "mouse" },
66-
actions: [
67-
{ type: "pointerUp", button: 0 },
68-
{ type: "pause", duration: 10 },
69-
],
70-
},
71-
]);
72-
}
73-
74-
async fullPageScreenshot() {
75-
// Necessary for animations to complete.
76-
await this.pause(100);
77-
return super.fullPageScreenshot();
78-
}
79-
}
80-
8115
test(
82-
"renders correctly styled focus ring around the drag handle",
83-
setupTest("/index.html#/dnd/engine-a2h-test", DndPageObject, async (page) => {
16+
"drag-states/renders correctly styled focus ring around the drag handle",
17+
setupScreenshotTest("/index.html#/dnd/engine-a2h-test", async (page) => {
8418
await page.focus(boardItemHandle("A"));
8519
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
8620
}),
8721
);
8822

8923
test(
90-
"renders correctly styled focus ring around the resize handle",
91-
setupTest("/index.html#/dnd/engine-a2h-test", DndPageObject, async (page) => {
24+
"drag-states/renders correctly styled focus ring around the resize handle",
25+
setupScreenshotTest("/index.html#/dnd/engine-a2h-test", async (page) => {
9226
await page.focus(boardItemResizeHandle("A"));
9327
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
9428
}),
9529
);
9630

9731
test(
98-
"active item overlays other items",
99-
setupTest("/index.html#/dnd/engine-a2h-test", DndPageObject, async (page) => {
32+
"drag-states/active item overlays other items",
33+
setupScreenshotTest("/index.html#/dnd/engine-a2h-test", async (page) => {
10034
await page.focus(boardItemHandle("A"));
10135
await page.keys(["Enter"]);
10236
await page.keys(["ArrowDown"]);
10337
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
10438
}),
10539
);
10640

107-
test(
108-
"resizes 4x2 item down to 2x1 one step at a time",
109-
setupTest(
110-
makeQueryUrl(
111-
[
112-
["A", "A", "B", "C"],
113-
["A", "A", "B", "C"],
114-
["A", "A", "D", "E"],
115-
["A", "A", "D", "E"],
116-
["F", "G", " ", " "],
117-
["F", "G", " ", " "],
118-
],
119-
[],
120-
),
121-
DndPageObject,
122-
async (page) => {
123-
await page.focus(boardItemResizeHandle("A"));
124-
await page.keys(["Enter"]);
125-
await page.keys(["ArrowLeft"]);
126-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
41+
for (let i = 1; i <= 3; i++) {
42+
test(
43+
`drag-states/resizes 4x2 item down to 2x1 one step at a time ${i}`,
44+
setupScreenshotTest(
45+
makeQueryUrl(
46+
[
47+
["A", "A", "B", "C"],
48+
["A", "A", "B", "C"],
49+
["A", "A", "D", "E"],
50+
["A", "A", "D", "E"],
51+
["F", "G", " ", " "],
52+
["F", "G", " ", " "],
53+
],
54+
[],
55+
),
12756

128-
await page.keys(["ArrowUp"]);
129-
await page.keys(["ArrowUp"]);
130-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
57+
async (page) => {
58+
await page.focus(boardItemResizeHandle("A"));
59+
await page.keys(["Enter"]);
60+
await page.keys(["ArrowLeft"]);
61+
i === 1 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
13162

132-
await page.keys(["Enter"]);
133-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
134-
},
135-
),
136-
);
63+
await page.keys(["ArrowUp"]);
64+
await page.keys(["ArrowUp"]);
65+
i === 2 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
13766

138-
test(
139-
"palette item size remains the same after drag start",
140-
setupTest("/index.html#/dnd/engine-a2h-test", DndPageObject, async (page) => {
141-
await page.mouseDown(itemsPaletteWrapper.findItemById("L").findDragHandle().toSelector());
142-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
67+
await page.keys(["Enter"]);
68+
i === 3 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
69+
},
70+
),
71+
);
72+
}
14373

144-
await page.mouseUp();
145-
await page.windowScrollTo({ top: 600 });
74+
for (let i = 1; i <= 2; i++) {
75+
test(
76+
`drag-states/palette item size remains the same after drag start ${i}`,
77+
setupScreenshotTest("/index.html#/dnd/engine-a2h-test", async (page) => {
78+
await page.mouseDown(itemsPaletteWrapper.findItemById("L").findDragHandle().toSelector());
79+
i === 1 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
14680

147-
await page.mouseDown(itemsPaletteWrapper.findItemById("Q").findDragHandle().toSelector());
148-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
149-
}),
150-
);
81+
await page.mouseUp();
82+
await page.windowScrollTo({ top: 600 });
15183

152-
test(
153-
"palette item size adjusts to board item size when moved over board",
154-
setupTest("/index.html#/dnd/engine-a2h-test", DndPageObject, async (page) => {
155-
await page.mouseDown(itemsPaletteWrapper.findItemById("K").findDragHandle().toSelector());
156-
await page.mouseMove(-200, 0);
157-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
84+
await page.mouseDown(itemsPaletteWrapper.findItemById("Q").findDragHandle().toSelector());
85+
i === 2 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
86+
}),
87+
);
88+
}
15889

159-
await page.mouseMove(200, 0);
160-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
161-
}),
162-
);
90+
for (let i = 1; i <= 2; i++) {
91+
test(
92+
`drag-states/palette item size adjusts to board item size when moved over board ${i}`,
93+
setupScreenshotTest("/index.html#/dnd/engine-a2h-test", async (page) => {
94+
await page.mouseDown(itemsPaletteWrapper.findItemById("K").findDragHandle().toSelector());
95+
await page.mouseMove(-200, 0);
96+
i === 1 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
97+
98+
await page.mouseMove(200, 0);
99+
i === 2 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
100+
}),
101+
);
102+
}
163103

164-
test(
165-
"palette item with min colspan=2 can be inserted into 1-column layout",
166-
setupTest("/index.html#/dnd/engine-a2p-test", DndPageObject, async (page) => {
167-
await page.setWindowSize({ width: 800, height: 800 });
104+
for (let i = 1; i <= 2; i++) {
105+
test(
106+
`drag-states/palette item with min colspan=2 can be inserted into 1-column layout ${i}`,
107+
setupScreenshotTest("/index.html#/dnd/engine-a2p-test", async (page) => {
108+
await page.setWindowSize({ width: 800, height: 800 });
168109

169-
await page.focus(itemsPaletteWrapper.findItemById("R").findDragHandle().toSelector());
170-
await page.keys(["Enter"]);
110+
await page.focus(itemsPaletteWrapper.findItemById("R").findDragHandle().toSelector());
111+
await page.keys(["Enter"]);
171112

172-
await page.keys(["ArrowLeft"]);
173-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
113+
await page.keys(["ArrowLeft"]);
114+
i === 1 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
174115

175-
await page.keys(["Enter"]);
176-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
177-
}),
178-
);
116+
await page.keys(["Enter"]);
117+
i === 2 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
118+
}),
119+
);
120+
}
179121

180-
test(
181-
"split-panel prevents collisions when inserting an item from the palette at the bottom",
182-
setupTest("/index.html#/with-app-layout/integ", DndPageObject, async (page) => {
183-
await page.setWindowSize({ width: 600, height: 800 });
122+
for (let i = 1; i <= 2; i++) {
123+
test(
124+
`drag-states/split-panel prevents collisions when inserting an item from the palette at the bottom ${i}`,
125+
setupScreenshotTest("/index.html#/with-app-layout/integ", async (page) => {
126+
await page.setWindowSize({ width: 600, height: 800 });
184127

185-
await page.click(`[data-testid="add-widget"]`);
128+
await page.click(`[data-testid="add-widget"]`);
186129

187-
await page.mouseDown(itemsPaletteWrapper.findItemById("counter").findDragHandle().toSelector());
188-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
130+
await page.mouseDown(itemsPaletteWrapper.findItemById("counter").findDragHandle().toSelector());
131+
i === 1 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
189132

190-
await page.mouseMove(0, -400);
191-
expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
192-
}),
193-
);
133+
await page.mouseMove(0, -400);
134+
i === 2 && expect(await page.fullPageScreenshot()).toMatchImageSnapshot();
135+
}),
136+
);
137+
}

test/visual/index.test.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,47 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3+
34
import path from "path";
45
import { expect, test } from "vitest";
56

6-
import { ScreenshotPageObject } from "@cloudscape-design/browser-test-tools/page-objects";
7+
import { setupScreenshotTest } from "./utils";
8+
9+
interface Scenario {
10+
desc: string;
11+
url: string;
12+
}
713

8-
import { setupTest } from "../utils";
14+
function pageUrl(page: string, params?: Record<string, string>) {
15+
const urlParams = new URLSearchParams({ screenshotMode: "true", ...params });
16+
return `/#${page}?${urlParams.toString()}`;
17+
}
918

19+
const ignoredPages = new Set([
20+
"/conditional/conditional",
21+
"/dnd/engine-a2p-test-async",
22+
"/dnd/engine-query-test",
23+
"/micro-frontend/integration",
24+
"/widget-container/keyboard",
25+
]);
1026
const pagesMap = import.meta.glob("../../pages/**/*.page.tsx", { query: "?raw" });
11-
const pages = Object.keys(pagesMap)
27+
const allStaticPages = Object.keys(pagesMap)
1228
.map((page) => page.replace(/\.page\.tsx$/, ""))
13-
.map((page) => "/#/" + path.relative("../../pages/", page));
29+
.map((page) => "/" + path.relative("../../pages/", page))
30+
.filter((page) => !ignoredPages.has(page));
31+
32+
const rtlStaticPages = ["/dnd/engine-a2h-test", "/with-app-layout/integ"];
1433

15-
test.each(pages)("matches snapshot for %s", (route) =>
16-
setupTest(route, ScreenshotPageObject, async (page) => {
17-
const hasScreenshotArea = await page.isExisting(".screenshot-area");
34+
const scenarios: Scenario[] = [
35+
...allStaticPages.map((page) => ({ desc: `${page}-static-ltr`, url: pageUrl(page) })),
36+
...rtlStaticPages.map((page) => ({ desc: `${page}-static-rtl`, url: pageUrl(page, { direction: "rtl" }) })),
37+
];
1838

19-
if (hasScreenshotArea) {
39+
for (const { desc, url } of scenarios) {
40+
test(
41+
`${desc}`,
42+
setupScreenshotTest(url, async (page) => {
2043
const pngString = await page.fullPageScreenshot();
2144
expect(pngString).toMatchImageSnapshot();
22-
}
23-
})(),
24-
);
45+
}),
46+
);
47+
}

0 commit comments

Comments
 (0)