Test improvements

This commit is contained in:
Dustin Brett 2023-07-21 10:48:34 -07:00
parent 257cac3412
commit 0a21e753f9
15 changed files with 160 additions and 86 deletions

View File

@ -5,3 +5,5 @@
.vscode .vscode
node_modules node_modules
out out
playwright-report
test-results

View File

@ -2,6 +2,8 @@
.next .next
node_modules node_modules
out out
playwright-report
public public
scripts scripts
test-results
*.config.js *.config.js

View File

@ -2,4 +2,6 @@
.next .next
node_modules node_modules
out out
playwright-report
public public
test-results

View File

@ -38,6 +38,7 @@ import {
declare global { declare global {
interface Window { interface Window {
DEBUG_DISABLE_WALLPAPER?: boolean;
WallpaperDestroy?: () => void; WallpaperDestroy?: () => void;
} }
} }
@ -388,7 +389,7 @@ const useWallpaper = (
]); ]);
useEffect(() => { useEffect(() => {
if (sessionLoaded) { if (sessionLoaded && !window.DEBUG_DISABLE_WALLPAPER) {
if (wallpaperTimerRef.current) { if (wallpaperTimerRef.current) {
window.clearTimeout(wallpaperTimerRef.current); window.clearTimeout(wallpaperTimerRef.current);
} }

31
e2e/Accessibility.spec.ts Normal file
View File

@ -0,0 +1,31 @@
import AxeBuilder from "@axe-core/playwright";
import { expect, test } from "@playwright/test";
import { ACCESSIBILITY_EXCEPTION_IDS } from "e2e/constants";
import {
canvasBackgroundIsVisible,
clockCanvasOrTextIsVisible,
clockIsVisible,
desktopEntriesAreVisible,
desktopIsVisible,
loadApp,
startButtonIsVisible,
taskbarIsVisible,
} from "e2e/functions";
test.beforeEach(loadApp);
test.beforeEach(desktopIsVisible);
test.beforeEach(desktopEntriesAreVisible);
test.beforeEach(taskbarIsVisible);
test.beforeEach(startButtonIsVisible);
test.beforeEach(clockIsVisible);
test.beforeEach(clockCanvasOrTextIsVisible);
test.beforeEach(canvasBackgroundIsVisible);
test("pass accessibility scan", async ({ page }) =>
expect(
(
await new AxeBuilder({ page })
.disableRules(ACCESSIBILITY_EXCEPTION_IDS)
.analyze()
).violations
).toEqual([]));

View File

@ -21,6 +21,7 @@ import {
contextMenuEntryIsVisible, contextMenuEntryIsVisible,
contextMenuIsVisible, contextMenuIsVisible,
desktopEntriesAreVisible, desktopEntriesAreVisible,
disableWallpaper,
fileExplorerAddressBarHasValue, fileExplorerAddressBarHasValue,
fileExplorerEntriesAreVisible, fileExplorerEntriesAreVisible,
fileExplorerEntryHasTooltip, fileExplorerEntryHasTooltip,
@ -33,12 +34,14 @@ import {
windowsAreVisible, windowsAreVisible,
} from "e2e/functions"; } from "e2e/functions";
test.beforeEach(disableWallpaper);
test.beforeEach(async ({ page }) => page.goto("/?app=FileExplorer")); test.beforeEach(async ({ page }) => page.goto("/?app=FileExplorer"));
test.beforeEach(windowsAreVisible); test.beforeEach(windowsAreVisible);
test.beforeEach(fileExplorerEntriesAreVisible);
test("has address bar", async ({ page }) => { test("has address bar", async ({ page }) => {
await fileExplorerAddressBarHasValue(TEST_APP_TITLE, { page }); await fileExplorerAddressBarHasValue(TEST_APP_TITLE, { page });
await clickFileExplorerAddressBar({ page }); await clickFileExplorerAddressBar({ page }, false, 2);
await fileExplorerAddressBarHasValue("/", { page }); await fileExplorerAddressBarHasValue("/", { page });
await clickFileExplorerAddressBar({ page }, true); await clickFileExplorerAddressBar({ page }, true);
@ -57,7 +60,6 @@ test("has search box", async ({ page }) => {
}); });
test.describe("has file(s)", () => { test.describe("has file(s)", () => {
test.beforeEach(fileExplorerEntriesAreVisible);
test.beforeEach(async ({ page }) => test.beforeEach(async ({ page }) =>
clickFileExplorerEntry(TEST_ROOT_FILE, { page }) clickFileExplorerEntry(TEST_ROOT_FILE, { page })
); );

View File

@ -8,6 +8,7 @@ import {
import { import {
desktopEntriesAreVisible, desktopEntriesAreVisible,
desktopIsVisible, desktopIsVisible,
disableWallpaper,
dragFirstDesktopEntryToWindow, dragFirstDesktopEntryToWindow,
loadContainerTestApp, loadContainerTestApp,
windowTitlebarIsVisible, windowTitlebarIsVisible,
@ -15,6 +16,8 @@ import {
windowsAreVisible, windowsAreVisible,
} from "e2e/functions"; } from "e2e/functions";
test.beforeEach(disableWallpaper);
test.describe("app container", () => { test.describe("app container", () => {
test.beforeEach(loadContainerTestApp); test.beforeEach(loadContainerTestApp);
test.beforeEach(windowsAreVisible); test.beforeEach(windowsAreVisible);

View File

@ -1,9 +1,6 @@
import AxeBuilder from "@axe-core/playwright";
import type { Page } from "@playwright/test";
import { expect, test } from "@playwright/test"; import { expect, test } from "@playwright/test";
import type { IsShown } from "e2e/constants"; import type { IsShown } from "e2e/constants";
import { import {
ACCESSIBILITY_EXCEPTION_IDS,
DESKTOP_MENU_ITEMS, DESKTOP_MENU_ITEMS,
DESKTOP_SELECTOR, DESKTOP_SELECTOR,
NEW_FILE_LABEL, NEW_FILE_LABEL,
@ -12,9 +9,6 @@ import {
SELECTION_SELECTOR, SELECTION_SELECTOR,
} from "e2e/constants"; } from "e2e/constants";
import { import {
backgroundIsUrl,
canvasBackgroundIsHidden,
canvasBackgroundIsVisible,
clickContextMenuEntry, clickContextMenuEntry,
clickDesktop, clickDesktop,
contextMenuEntryIsHidden, contextMenuEntryIsHidden,
@ -24,26 +18,16 @@ import {
desktopEntryIsHidden, desktopEntryIsHidden,
desktopEntryIsVisible, desktopEntryIsVisible,
desktopIsVisible, desktopIsVisible,
disableWallpaper,
loadApp, loadApp,
pressDesktopKeys, pressDesktopKeys,
taskbarEntriesAreVisible, taskbarEntryIsOpen,
taskbarEntryIsVisible,
} from "e2e/functions"; } from "e2e/functions";
test.beforeEach(disableWallpaper);
test.beforeEach(loadApp); test.beforeEach(loadApp);
test.beforeEach(desktopIsVisible); test.beforeEach(desktopIsVisible);
test("pass accessibility scan", async ({ page }) =>
expect(
(
await new AxeBuilder({ page })
.disableRules(ACCESSIBILITY_EXCEPTION_IDS)
.analyze()
).violations
).toEqual([]));
test("has background", canvasBackgroundIsVisible);
test("has file entry", desktopEntriesAreVisible); test("has file entry", desktopEntriesAreVisible);
// TODO: has grid (move file on grid) // TODO: has grid (move file on grid)
@ -78,14 +62,6 @@ test.describe("has selection", () => {
// TODO: file entry (single/multi) // TODO: file entry (single/multi)
}); });
const taskbarEntriesOpened = async (
label: RegExp,
page: Page
): Promise<void> => {
await taskbarEntriesAreVisible({ page });
await taskbarEntryIsVisible(label, { page });
};
test.describe("has context menu", () => { test.describe("has context menu", () => {
test.beforeEach(async ({ page }) => clickDesktop({ page }, true)); test.beforeEach(async ({ page }) => clickDesktop({ page }, true));
test.beforeEach(contextMenuIsVisible); test.beforeEach(contextMenuIsVisible);
@ -157,47 +133,31 @@ test.describe("has context menu", () => {
}); });
}); });
test("can change background", async ({ page }) => {
await canvasBackgroundIsVisible({ page });
await clickContextMenuEntry(/^Background$/, { page });
await clickContextMenuEntry(/^Picture Slideshow$/, { page });
await canvasBackgroundIsHidden({ page });
await backgroundIsUrl({ page });
await page.reload();
await desktopIsVisible({ page });
await canvasBackgroundIsHidden({ page });
await backgroundIsUrl({ page });
});
test("can inspect", async ({ page }) => { test("can inspect", async ({ page }) => {
await clickContextMenuEntry(/^Inspect$/, { page }); await clickContextMenuEntry(/^Inspect$/, { page });
await taskbarEntriesOpened(/^DevTools$/, page); await taskbarEntryIsOpen(/^DevTools$/, page);
}); });
test("can view page source", async ({ page }) => { test("can view page source", async ({ page }) => {
await clickContextMenuEntry(/^View page source$/, { page }); await clickContextMenuEntry(/^View page source$/, { page });
await taskbarEntriesOpened(/^index.html - Monaco Editor$/, page); await taskbarEntryIsOpen(/^index.html - Monaco Editor$/, page);
}); });
test("can open terminal", async ({ page }) => { test("can open terminal", async ({ page }) => {
await clickContextMenuEntry(/^Open Terminal here$/, { page }); await clickContextMenuEntry(/^Open Terminal here$/, { page });
await taskbarEntriesOpened(/^Terminal$/, page); await taskbarEntryIsOpen(/^Terminal$/, page);
}); });
}); });
test.describe("has keyboard shortcuts", () => { test.describe("has keyboard shortcuts", () => {
test("ctrl + shift + r (open run dialog)", async ({ page }) => { test("ctrl + shift + r (open run dialog)", async ({ page }) => {
await pressDesktopKeys("Control+Shift+KeyR", { page }); await pressDesktopKeys("Control+Shift+KeyR", { page });
await taskbarEntriesOpened(/^Run$/, page); await taskbarEntryIsOpen(/^Run$/, page);
}); });
test("ctrl + shift + e (open file explorer)", async ({ page }) => { test("ctrl + shift + e (open file explorer)", async ({ page }) => {
await pressDesktopKeys("Control+Shift+KeyE", { page }); await pressDesktopKeys("Control+Shift+KeyE", { page });
await taskbarEntriesOpened(/^My PC$/, page); await taskbarEntryIsOpen(/^My PC$/, page);
}); });
// TODO: Ctrl+Shift+D // TODO: Ctrl+Shift+D

View File

@ -2,6 +2,7 @@ import { test } from "@playwright/test";
import { import {
clickDesktop, clickDesktop,
clickStartButton, clickStartButton,
disableWallpaper,
loadApp, loadApp,
startMenuEntryIsVisible, startMenuEntryIsVisible,
startMenuIsHidden, startMenuIsHidden,
@ -9,6 +10,7 @@ import {
startMenuSidebarEntryIsVisible, startMenuSidebarEntryIsVisible,
} from "e2e/functions"; } from "e2e/functions";
test.beforeEach(disableWallpaper);
test.beforeEach(loadApp); test.beforeEach(loadApp);
test.beforeEach(clickStartButton); test.beforeEach(clickStartButton);
test.beforeEach(startMenuIsVisible); test.beforeEach(startMenuIsVisible);

View File

@ -1,19 +1,15 @@
import { test } from "@playwright/test"; import { test } from "@playwright/test";
import { import { TEST_APP_ICON, TEST_APP_TITLE } from "e2e/constants";
OFFSCREEN_CANVAS_NOT_SUPPORTED_BROWSERS,
TEST_APP_ICON,
TEST_APP_TITLE,
} from "e2e/constants";
import { import {
calendarIsVisible, calendarIsVisible,
clickClock, clickClock,
clickStartButton, clickStartButton,
clockCanvasIsHidden, clockCanvasIsHidden,
clockCanvasIsVisible, clockCanvasOrTextIsVisible,
clockIsVisible, clockIsVisible,
clockTextIsHidden,
clockTextIsVisible, clockTextIsVisible,
disableOffscreenCanvas, disableOffscreenCanvas,
disableWallpaper,
loadApp, loadApp,
loadTestApp, loadTestApp,
sheepIsVisible, sheepIsVisible,
@ -25,6 +21,8 @@ import {
taskbarIsVisible, taskbarIsVisible,
} from "e2e/functions"; } from "e2e/functions";
test.beforeEach(disableWallpaper);
test.describe("elements", () => { test.describe("elements", () => {
test.beforeEach(loadApp); test.beforeEach(loadApp);
test.beforeEach(taskbarIsVisible); test.beforeEach(taskbarIsVisible);
@ -46,18 +44,10 @@ test.describe("elements", () => {
test.describe("has clock", () => { test.describe("has clock", () => {
test.beforeEach(clockIsVisible); test.beforeEach(clockIsVisible);
test("via canvas", async ({ browserName, page }) => { test("via canvas", clockCanvasOrTextIsVisible);
if (OFFSCREEN_CANVAS_NOT_SUPPORTED_BROWSERS.has(browserName)) {
await clockTextIsVisible({ page });
await clockCanvasIsHidden({ page });
} else {
await clockTextIsHidden({ page });
await clockCanvasIsVisible({ page });
}
});
test("via text", async ({ page }) => { test("via text", async ({ page }) => {
await page.addInitScript(disableOffscreenCanvas); await disableOffscreenCanvas({ page });
await page.reload(); await page.reload();
await clockTextIsVisible({ page }); await clockTextIsVisible({ page });

View File

@ -0,0 +1,35 @@
import { test } from "@playwright/test";
import {
backgroundIsUrl,
canvasBackgroundIsHidden,
canvasBackgroundIsVisible,
clickContextMenuEntry,
clickDesktop,
contextMenuIsVisible,
desktopIsVisible,
loadApp,
} from "e2e/functions";
test.beforeEach(loadApp);
test.beforeEach(desktopIsVisible);
test("has background", canvasBackgroundIsVisible);
test("can change background", async ({ page }) => {
await clickDesktop({ page }, true);
await contextMenuIsVisible({ page });
await canvasBackgroundIsVisible({ page });
await clickContextMenuEntry(/^Background$/, { page });
await clickContextMenuEntry(/^Picture Slideshow$/, { page });
await canvasBackgroundIsHidden({ page });
await backgroundIsUrl({ page });
await page.reload();
await desktopIsVisible({ page });
await canvasBackgroundIsHidden({ page });
await backgroundIsUrl({ page });
});

View File

@ -8,6 +8,7 @@ import {
clickCloseWindow, clickCloseWindow,
clickMaximizeWindow, clickMaximizeWindow,
clickMinimizeWindow, clickMinimizeWindow,
disableWallpaper,
doubleClickWindowTitlebar, doubleClickWindowTitlebar,
doubleClickWindowTitlebarIcon, doubleClickWindowTitlebarIcon,
dragWindowToDesktop, dragWindowToDesktop,
@ -21,9 +22,11 @@ import {
windowsAreVisible, windowsAreVisible,
} from "e2e/functions"; } from "e2e/functions";
test.beforeEach(disableWallpaper);
test.beforeEach(loadTestApp); test.beforeEach(loadTestApp);
// TODO: Check if window animation is indeed happening, and wait for it // TODO: Check if window animation is indeed happening, and wait for it
// Q: Click titlebar to make sure it's focused and also for auto wait? Do in FE also.
test.beforeEach(windowsAreVisible); test.beforeEach(windowsAreVisible);
test.beforeEach(windowTitlebarIsVisible); test.beforeEach(windowTitlebarIsVisible);

View File

@ -9,7 +9,6 @@ type LocatorWaitForProps = Parameters<Locator["waitFor"]>[0];
export const EXACT = { exact: true }; export const EXACT = { exact: true };
export const FORCE = { force: true }; export const FORCE = { force: true };
export const POLLING_OPTIONS = { timeout: 20000 };
export const RIGHT_CLICK = { button: "right" } as LocatorClickProps; export const RIGHT_CLICK = { button: "right" } as LocatorClickProps;
export const VISIBLE = { state: "visible" } as LocatorWaitForProps; export const VISIBLE = { state: "visible" } as LocatorWaitForProps;

View File

@ -14,7 +14,7 @@ import {
FILE_EXPLORER_ENTRIES_SELECTOR, FILE_EXPLORER_ENTRIES_SELECTOR,
FILE_EXPLORER_NAV_SELECTOR, FILE_EXPLORER_NAV_SELECTOR,
FILE_EXPLORER_SEARCH_BOX_LABEL, FILE_EXPLORER_SEARCH_BOX_LABEL,
POLLING_OPTIONS, OFFSCREEN_CANVAS_NOT_SUPPORTED_BROWSERS,
RIGHT_CLICK, RIGHT_CLICK,
SHEEP_SELECTOR, SHEEP_SELECTOR,
START_BUTTON_SELECTOR, START_BUTTON_SELECTOR,
@ -33,10 +33,20 @@ type TestProps = {
page: Page; page: Page;
}; };
export const disableOffscreenCanvas = (): void => { type TestPropsWithBrowser = TestProps & {
delete (window as Partial<Window & typeof globalThis>).OffscreenCanvas; browserName: string;
}; };
export const disableOffscreenCanvas = ({ page }: TestProps): Promise<void> =>
page.addInitScript(() => {
delete (window as Partial<Window & typeof globalThis>).OffscreenCanvas;
});
export const disableWallpaper = ({ page }: TestProps): Promise<void> =>
page.addInitScript(() => {
window.DEBUG_DISABLE_WALLPAPER = true;
});
// action // action
export const loadApp = async ({ page }: TestProps): Promise<Response | null> => export const loadApp = async ({ page }: TestProps): Promise<Response | null> =>
page.goto("/"); page.goto("/");
@ -127,12 +137,16 @@ export const clickContextMenuEntry = async (
export const clickFileExplorerAddressBar = async ( export const clickFileExplorerAddressBar = async (
{ page }: TestProps, { page }: TestProps,
right = false right = false,
clickCount = 1
): Promise<void> => ): Promise<void> =>
page page
.locator(FILE_EXPLORER_NAV_SELECTOR) .locator(FILE_EXPLORER_NAV_SELECTOR)
.getByLabel(FILE_EXPLORER_ADDRESS_BAR_LABEL) .getByLabel(FILE_EXPLORER_ADDRESS_BAR_LABEL)
.click(right ? RIGHT_CLICK : undefined); .click({
button: right ? "right" : undefined,
clickCount,
});
export const clickFileExplorerEntry = async ( export const clickFileExplorerEntry = async (
label: RegExp, label: RegExp,
@ -189,25 +203,29 @@ export const backgroundIsUrl = async ({ page }: TestProps): Promise<void> =>
.match(/^url\(.*?\)$/) .match(/^url\(.*?\)$/)
) )
).toBeTruthy() ).toBeTruthy()
).toPass(POLLING_OPTIONS); ).toPass();
export const windowIsMaximized = async ({ page }: TestProps): Promise<void> => export const windowIsMaximized = async ({ page }: TestProps): Promise<void> =>
expect(async () => expect(async () =>
expect( expect(
await page.evaluate( await page.evaluate(
([windowSelector, taskbarSelector]) => ([windowSelector, taskbarSelector]) => {
window.innerWidth === const {
(document.querySelector(windowSelector) as HTMLElement) clientWidth: windowWidth = 0,
?.clientWidth && clientHeight: windowHeight = 0,
window.innerHeight - } = document.querySelector(windowSelector) || {};
((document.querySelector(taskbarSelector) as HTMLElement) const { clientHeight: taskbarHeight = 0 } =
?.clientHeight || 0) === document.querySelector(taskbarSelector) || {};
(document.querySelector(windowSelector) as HTMLElement)
?.clientHeight, return (
windowWidth === window.innerWidth &&
windowHeight === window.innerHeight - taskbarHeight
);
},
[WINDOW_SELECTOR, TASKBAR_SELECTOR] [WINDOW_SELECTOR, TASKBAR_SELECTOR]
) )
).toBeTruthy() ).toBeTruthy()
).toPass(POLLING_OPTIONS); ).toPass();
// expect->locator // expect->locator
export const canvasBackgroundIsHidden = async ({ export const canvasBackgroundIsHidden = async ({
@ -407,7 +425,7 @@ export const taskbarEntryHasIcon = async (
const entriesAreVisible = async (selector: string, page: Page): Promise<void> => const entriesAreVisible = async (selector: string, page: Page): Promise<void> =>
expect(async () => expect(async () =>
expect(page.locator(selector).first()).toBeVisible() expect(page.locator(selector).first()).toBeVisible()
).toPass(POLLING_OPTIONS); ).toPass();
export const desktopEntriesAreVisible = async ({ export const desktopEntriesAreVisible = async ({
page, page,
@ -426,3 +444,25 @@ export const taskbarEntriesAreVisible = async ({
export const windowsAreVisible = async ({ page }: TestProps): Promise<void> => export const windowsAreVisible = async ({ page }: TestProps): Promise<void> =>
entriesAreVisible(WINDOW_SELECTOR, page); entriesAreVisible(WINDOW_SELECTOR, page);
// meta function
export const clockCanvasOrTextIsVisible = async ({
browserName,
page,
}: TestPropsWithBrowser): Promise<void> => {
if (OFFSCREEN_CANVAS_NOT_SUPPORTED_BROWSERS.has(browserName)) {
await clockTextIsVisible({ page });
await clockCanvasIsHidden({ page });
} else {
await clockTextIsHidden({ page });
await clockCanvasIsVisible({ page });
}
};
export const taskbarEntryIsOpen = async (
label: RegExp,
page: Page
): Promise<void> => {
await taskbarEntriesAreVisible({ page });
await taskbarEntryIsVisible(label, { page });
};

View File

@ -26,6 +26,8 @@ const config: PlaywrightTestConfig = {
testDir: "e2e", testDir: "e2e",
use: { use: {
baseURL, baseURL,
trace: process.env.CI ? "off" : "retain-on-failure",
video: process.env.CI ? "off" : "retain-on-failure",
}, },
webServer: { webServer: {
command: "yarn dev", command: "yarn dev",