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
node_modules
out
playwright-report
test-results

View file

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

View file

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

View file

@ -38,6 +38,7 @@ import {
declare global {
interface Window {
DEBUG_DISABLE_WALLPAPER?: boolean;
WallpaperDestroy?: () => void;
}
}
@ -388,7 +389,7 @@ const useWallpaper = (
]);
useEffect(() => {
if (sessionLoaded) {
if (sessionLoaded && !window.DEBUG_DISABLE_WALLPAPER) {
if (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,
contextMenuIsVisible,
desktopEntriesAreVisible,
disableWallpaper,
fileExplorerAddressBarHasValue,
fileExplorerEntriesAreVisible,
fileExplorerEntryHasTooltip,
@ -33,12 +34,14 @@ import {
windowsAreVisible,
} from "e2e/functions";
test.beforeEach(disableWallpaper);
test.beforeEach(async ({ page }) => page.goto("/?app=FileExplorer"));
test.beforeEach(windowsAreVisible);
test.beforeEach(fileExplorerEntriesAreVisible);
test("has address bar", async ({ page }) => {
await fileExplorerAddressBarHasValue(TEST_APP_TITLE, { page });
await clickFileExplorerAddressBar({ page });
await clickFileExplorerAddressBar({ page }, false, 2);
await fileExplorerAddressBarHasValue("/", { page });
await clickFileExplorerAddressBar({ page }, true);
@ -57,7 +60,6 @@ test("has search box", async ({ page }) => {
});
test.describe("has file(s)", () => {
test.beforeEach(fileExplorerEntriesAreVisible);
test.beforeEach(async ({ page }) =>
clickFileExplorerEntry(TEST_ROOT_FILE, { page })
);

View file

@ -8,6 +8,7 @@ import {
import {
desktopEntriesAreVisible,
desktopIsVisible,
disableWallpaper,
dragFirstDesktopEntryToWindow,
loadContainerTestApp,
windowTitlebarIsVisible,
@ -15,6 +16,8 @@ import {
windowsAreVisible,
} from "e2e/functions";
test.beforeEach(disableWallpaper);
test.describe("app container", () => {
test.beforeEach(loadContainerTestApp);
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 type { IsShown } from "e2e/constants";
import {
ACCESSIBILITY_EXCEPTION_IDS,
DESKTOP_MENU_ITEMS,
DESKTOP_SELECTOR,
NEW_FILE_LABEL,
@ -12,9 +9,6 @@ import {
SELECTION_SELECTOR,
} from "e2e/constants";
import {
backgroundIsUrl,
canvasBackgroundIsHidden,
canvasBackgroundIsVisible,
clickContextMenuEntry,
clickDesktop,
contextMenuEntryIsHidden,
@ -24,26 +18,16 @@ import {
desktopEntryIsHidden,
desktopEntryIsVisible,
desktopIsVisible,
disableWallpaper,
loadApp,
pressDesktopKeys,
taskbarEntriesAreVisible,
taskbarEntryIsVisible,
taskbarEntryIsOpen,
} from "e2e/functions";
test.beforeEach(disableWallpaper);
test.beforeEach(loadApp);
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);
// TODO: has grid (move file on grid)
@ -78,14 +62,6 @@ test.describe("has selection", () => {
// 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.beforeEach(async ({ page }) => clickDesktop({ page }, true));
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 }) => {
await clickContextMenuEntry(/^Inspect$/, { page });
await taskbarEntriesOpened(/^DevTools$/, page);
await taskbarEntryIsOpen(/^DevTools$/, page);
});
test("can view page source", async ({ 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 }) => {
await clickContextMenuEntry(/^Open Terminal here$/, { page });
await taskbarEntriesOpened(/^Terminal$/, page);
await taskbarEntryIsOpen(/^Terminal$/, page);
});
});
test.describe("has keyboard shortcuts", () => {
test("ctrl + shift + r (open run dialog)", async ({ page }) => {
await pressDesktopKeys("Control+Shift+KeyR", { page });
await taskbarEntriesOpened(/^Run$/, page);
await taskbarEntryIsOpen(/^Run$/, page);
});
test("ctrl + shift + e (open file explorer)", async ({ page }) => {
await pressDesktopKeys("Control+Shift+KeyE", { page });
await taskbarEntriesOpened(/^My PC$/, page);
await taskbarEntryIsOpen(/^My PC$/, page);
});
// TODO: Ctrl+Shift+D

View file

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

View file

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

View file

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

View file

@ -14,7 +14,7 @@ import {
FILE_EXPLORER_ENTRIES_SELECTOR,
FILE_EXPLORER_NAV_SELECTOR,
FILE_EXPLORER_SEARCH_BOX_LABEL,
POLLING_OPTIONS,
OFFSCREEN_CANVAS_NOT_SUPPORTED_BROWSERS,
RIGHT_CLICK,
SHEEP_SELECTOR,
START_BUTTON_SELECTOR,
@ -33,10 +33,20 @@ type TestProps = {
page: Page;
};
export const disableOffscreenCanvas = (): void => {
delete (window as Partial<Window & typeof globalThis>).OffscreenCanvas;
type TestPropsWithBrowser = TestProps & {
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
export const loadApp = async ({ page }: TestProps): Promise<Response | null> =>
page.goto("/");
@ -127,12 +137,16 @@ export const clickContextMenuEntry = async (
export const clickFileExplorerAddressBar = async (
{ page }: TestProps,
right = false
right = false,
clickCount = 1
): Promise<void> =>
page
.locator(FILE_EXPLORER_NAV_SELECTOR)
.getByLabel(FILE_EXPLORER_ADDRESS_BAR_LABEL)
.click(right ? RIGHT_CLICK : undefined);
.click({
button: right ? "right" : undefined,
clickCount,
});
export const clickFileExplorerEntry = async (
label: RegExp,
@ -189,25 +203,29 @@ export const backgroundIsUrl = async ({ page }: TestProps): Promise<void> =>
.match(/^url\(.*?\)$/)
)
).toBeTruthy()
).toPass(POLLING_OPTIONS);
).toPass();
export const windowIsMaximized = async ({ page }: TestProps): Promise<void> =>
expect(async () =>
expect(
await page.evaluate(
([windowSelector, taskbarSelector]) =>
window.innerWidth ===
(document.querySelector(windowSelector) as HTMLElement)
?.clientWidth &&
window.innerHeight -
((document.querySelector(taskbarSelector) as HTMLElement)
?.clientHeight || 0) ===
(document.querySelector(windowSelector) as HTMLElement)
?.clientHeight,
([windowSelector, taskbarSelector]) => {
const {
clientWidth: windowWidth = 0,
clientHeight: windowHeight = 0,
} = document.querySelector(windowSelector) || {};
const { clientHeight: taskbarHeight = 0 } =
document.querySelector(taskbarSelector) || {};
return (
windowWidth === window.innerWidth &&
windowHeight === window.innerHeight - taskbarHeight
);
},
[WINDOW_SELECTOR, TASKBAR_SELECTOR]
)
).toBeTruthy()
).toPass(POLLING_OPTIONS);
).toPass();
// expect->locator
export const canvasBackgroundIsHidden = async ({
@ -407,7 +425,7 @@ export const taskbarEntryHasIcon = async (
const entriesAreVisible = async (selector: string, page: Page): Promise<void> =>
expect(async () =>
expect(page.locator(selector).first()).toBeVisible()
).toPass(POLLING_OPTIONS);
).toPass();
export const desktopEntriesAreVisible = async ({
page,
@ -426,3 +444,25 @@ export const taskbarEntriesAreVisible = async ({
export const windowsAreVisible = async ({ page }: TestProps): Promise<void> =>
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",
use: {
baseURL,
trace: process.env.CI ? "off" : "retain-on-failure",
video: process.env.CI ? "off" : "retain-on-failure",
},
webServer: {
command: "yarn dev",