Skip to content
This repository was archived by the owner on Dec 23, 2024. It is now read-only.

Commit e6d9ecc

Browse files
authored
Add test reporter to prevent stale screenshots (matrix-org#12743)
* Split up slow Playwright tests To optimise parallelism Deals with: ``` Slow test file: read-receipts/redactions.spec.ts (5.4m) Slow test file: read-receipts/new-messages.spec.ts (3.9m) Slow test file: read-receipts/high-level.spec.ts (3.6m) Slow test file: read-receipts/editing-messages.spec.ts (3.1m) Slow test file: read-receipts/reactions.spec.ts (2.2m) Slow test file: crypto/crypto.spec.ts (2.4m) Slow test file: settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts (1.2m) Slow test file: composer/composer.spec.ts (1.1m) Slow test file: crypto/verification.spec.ts (1.1m) ``` Signed-off-by: Michael Telatynski <[email protected]> * Move around snapshots Signed-off-by: Michael Telatynski <[email protected]> * Add test reporter to prevent stale screenshots Signed-off-by: Michael Telatynski <[email protected]> * Iterate Signed-off-by: Michael Telatynski <[email protected]> * Fix test Signed-off-by: Michael Telatynski <[email protected]> * Iterate Signed-off-by: Michael Telatynski <[email protected]> * Remove darwin screenshots which should not have been checked in Signed-off-by: Michael Telatynski <[email protected]> * Fix absolute vs relative path mismatch Signed-off-by: Michael Telatynski <[email protected]> * Revert "Remove darwin screenshots which should not have been checked in" This reverts commit 1e18997. * Iterate Signed-off-by: Michael Telatynski <[email protected]> * Revert "Revert "Remove darwin screenshots which should not have been checked in"" This reverts commit 5144b9b. * Iterate Signed-off-by: Michael Telatynski <[email protected]> * Remove stale screenshots Signed-off-by: Michael Telatynski <[email protected]> * Revert "Remove stale screenshots" This reverts commit 9beae99. * Apply same sanitization as Playwright for file name consistency Signed-off-by: Michael Telatynski <[email protected]> * add dev dep Signed-off-by: Michael Telatynski <[email protected]> * Remove stale screenshots Signed-off-by: Michael Telatynski <[email protected]> * Discard changes to playwright/flaky-reporter.ts * Update end-to-end-tests.yaml --------- Signed-off-by: Michael Telatynski <[email protected]>
1 parent 7863de6 commit e6d9ecc

21 files changed

+131
-10
lines changed

.github/workflows/end-to-end-tests.yaml

+3-2
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,14 @@ jobs:
190190

191191
- name: Merge into HTML Report
192192
if: inputs.skip != true
193-
run: yarn playwright merge-reports --reporter=html,./playwright/flaky-reporter.ts ./all-blob-reports
193+
run: yarn playwright merge-reports --reporter=html,./playwright/flaky-reporter.ts,./playwright/stale-screenshot-reporter.ts ./all-blob-reports
194194
env:
195195
# Only pass creds to the flaky-reporter on main branch runs
196196
GITHUB_TOKEN: ${{ github.ref_name == 'develop' && secrets.ELEMENT_BOT_TOKEN || '' }}
197197

198+
# Upload the HTML report even if one of our reporters fails, this can happen when stale screenshots are detected
198199
- name: Upload HTML report
199-
if: inputs.skip != true
200+
if: always() && inputs.skip != true
200201
uses: actions/upload-artifact@v4
201202
with:
202203
name: html-report

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
"fake-indexeddb": "^6.0.0",
214214
"fetch-mock-jest": "^1.5.1",
215215
"fs-extra": "^11.0.0",
216+
"glob": "^11.0.0",
216217
"jest": "^29.6.2",
217218
"jest-canvas-mock": "^2.5.2",
218219
"jest-environment-jsdom": "^29.6.2",
@@ -223,6 +224,7 @@
223224
"matrix-web-i18n": "^3.2.1",
224225
"mocha-junit-reporter": "^2.2.0",
225226
"node-fetch": "2",
227+
"playwright-core": "^1.45.1",
226228
"postcss-scss": "^4.0.4",
227229
"prettier": "3.3.2",
228230
"raw-loader": "^4.0.2",
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
Copyright 2024 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
declare module "playwright-core/lib/utils" {
18+
// This type is not public in playwright-core utils
19+
export function sanitizeForFilePath(filePath: string): string;
20+
}

playwright/e2e/settings/general-room-settings-tab.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ test.describe("General room settings tab", () => {
3434
// Assert that "Show less" details element is rendered
3535
await expect(settings.getByText("Show less")).toBeVisible();
3636

37-
await expect(settings).toMatchScreenshot();
37+
await expect(settings).toMatchScreenshot("General-room-settings-tab-should-be-rendered-properly-1.png");
3838

3939
// Click the "Show less" details element
4040
await settings.getByText("Show less").click();

playwright/e2e/settings/preferences-user-settings-tab.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ test.describe("Preferences user settings tab", () => {
3131

3232
// Assert that the top heading is rendered
3333
await expect(tab.getByRole("heading", { name: "Preferences" })).toBeVisible();
34-
await expect(tab).toMatchScreenshot();
34+
await expect(tab).toMatchScreenshot("Preferences-user-settings-tab-should-be-rendered-properly-1.png");
3535
});
3636

3737
test("should be able to change the app language", async ({ uut, user }) => {

playwright/e2e/settings/security-user-settings-tab.spec.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ test.describe("Security user settings tab", () => {
4747
test("should be rendered properly", async ({ app, page }) => {
4848
const tab = await app.settings.openUserSettings("Security");
4949
await tab.getByRole("button", { name: "Learn more" }).click();
50-
await expect(page.locator(".mx_AnalyticsLearnMoreDialog_wrapper .mx_Dialog")).toMatchScreenshot();
50+
await expect(page.locator(".mx_AnalyticsLearnMoreDialog_wrapper .mx_Dialog")).toMatchScreenshot(
51+
"Security-user-settings-tab-with-posthog-enable-b5d89-csLearnMoreDialog-should-be-rendered-properly-1.png",
52+
);
5153
});
5254
});
5355

playwright/e2e/user-onboarding/user-onboarding-new.spec.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ test.describe("User Onboarding (new user)", () => {
3535
});
3636

3737
test("page is shown and preference exists", async ({ page, app }) => {
38-
await expect(page.locator(".mx_UserOnboardingPage")).toMatchScreenshot();
38+
await expect(page.locator(".mx_UserOnboardingPage")).toMatchScreenshot(
39+
"User-Onboarding-new-user-page-is-shown-and-preference-exists-1.png",
40+
);
3941
await app.settings.openUserSettings("Preferences");
4042
await expect(page.getByText("Show shortcut to welcome checklist above the room list")).toBeVisible();
4143
});

playwright/element-web-test.ts

+23-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ limitations under the License.
1515
*/
1616

1717
import { test as base, expect as baseExpect, Locator, Page, ExpectMatcherState, ElementHandle } from "@playwright/test";
18+
import { sanitizeForFilePath } from "playwright-core/lib/utils";
1819
import AxeBuilder from "@axe-core/playwright";
1920
import _ from "lodash";
20-
import { basename } from "node:path";
21+
import { basename, extname } from "node:path";
2122

2223
import type mailhog from "mailhog";
2324
import type { IConfigOptions } from "../src/IConfigOptions";
@@ -298,11 +299,18 @@ export const test = base.extend<{
298299
},
299300
});
300301

302+
// Based on https://github.com/microsoft/playwright/blob/2b77ed4d7aafa85a600caa0b0d101b72c8437eeb/packages/playwright/src/util.ts#L206C8-L210C2
303+
function sanitizeFilePathBeforeExtension(filePath: string): string {
304+
const ext = extname(filePath);
305+
const base = filePath.substring(0, filePath.length - ext.length);
306+
return sanitizeForFilePath(base) + ext;
307+
}
308+
301309
export const expect = baseExpect.extend({
302310
async toMatchScreenshot(
303311
this: ExpectMatcherState,
304312
receiver: Page | Locator,
305-
name?: `${string}.png`,
313+
name: `${string}.png`,
306314
options?: {
307315
mask?: Array<Locator>;
308316
omitBackground?: boolean;
@@ -311,6 +319,9 @@ export const expect = baseExpect.extend({
311319
css?: string;
312320
},
313321
) {
322+
const testInfo = test.info();
323+
if (!testInfo) throw new Error(`toMatchScreenshot() must be called during the test`);
324+
314325
const page = "page" in receiver ? receiver.page() : receiver;
315326

316327
let hideTooltipsCss: string | undefined;
@@ -354,9 +365,18 @@ export const expect = baseExpect.extend({
354365
`,
355366
})) as ElementHandle<Element>;
356367

357-
await baseExpect(receiver).toHaveScreenshot(name, options);
368+
const screenshotName = sanitizeFilePathBeforeExtension(name);
369+
await baseExpect(receiver).toHaveScreenshot(screenshotName, options);
358370

359371
await style.evaluate((tag) => tag.remove());
372+
373+
testInfo.annotations.push({
374+
// `_` prefix hides it from the HTML reporter
375+
type: "_screenshot",
376+
// include a path relative to `playwright/snapshots/`
377+
description: testInfo.snapshotPath(screenshotName).split("/playwright/snapshots/", 2)[1],
378+
});
379+
360380
return { pass: true, message: () => "", name: "toMatchScreenshot" };
361381
},
362382
});
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
Copyright 2024 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
/**
18+
* Test reporter which compares the reported screenshots vs those on disk to find stale screenshots
19+
* Only intended to run from within GitHub Actions
20+
*/
21+
22+
import path from "node:path";
23+
import { glob } from "glob";
24+
25+
import type { Reporter, TestCase } from "@playwright/test/reporter";
26+
27+
const snapshotRoot = path.join(__dirname, "snapshots");
28+
29+
class StaleScreenshotReporter implements Reporter {
30+
private screenshots = new Set<string>();
31+
private success = true;
32+
33+
public onTestEnd(test: TestCase): void {
34+
for (const annotation of test.annotations) {
35+
if (annotation.type === "_screenshot") {
36+
this.screenshots.add(annotation.description);
37+
}
38+
}
39+
}
40+
41+
private error(msg: string, file: string) {
42+
if (process.env.GITHUB_ACTIONS) {
43+
console.log(`::error file=${file}::${msg}`);
44+
}
45+
console.error(msg, file);
46+
this.success = false;
47+
}
48+
49+
public async onExit(): Promise<void> {
50+
const screenshotFiles = new Set(await glob(`**/*.png`, { cwd: snapshotRoot }));
51+
for (const screenshot of screenshotFiles) {
52+
if (screenshot.split("-").at(-1) !== "linux.png") {
53+
this.error(
54+
"Found screenshot belonging to different platform, this should not be checked in",
55+
screenshot,
56+
);
57+
}
58+
}
59+
for (const screenshot of this.screenshots) {
60+
screenshotFiles.delete(screenshot);
61+
}
62+
if (screenshotFiles.size > 0) {
63+
for (const screenshot of screenshotFiles) {
64+
this.error("Stale screenshot file", screenshot);
65+
}
66+
}
67+
68+
if (!this.success) {
69+
process.exit(1);
70+
}
71+
}
72+
}
73+
74+
export default StaleScreenshotReporter;

yarn.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -7418,7 +7418,7 @@ pkg-dir@^4.2.0:
74187418
dependencies:
74197419
find-up "^4.0.0"
74207420

7421-
7421+
[email protected], playwright-core@^1.45.1:
74227422
version "1.45.1"
74237423
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.45.1.tgz#549a2701556b58245cc75263f9fc2795c1158dc1"
74247424
integrity sha512-LF4CUUtrUu2TCpDw4mcrAIuYrEjVDfT1cHbJMfwnE2+1b8PZcFzPNgvZCvq2JfQ4aTjRCCHw5EJ2tmr2NSzdPg==

0 commit comments

Comments
 (0)