Consolidate redundant end-to-end tests #61

Merged
eleith merged 1 commits from consolidate-e2e-tests into main 2026-10-27 20:21:30 +00:00
5 changed files with 66 additions and 138 deletions

No files matched your search

+1 -8
View File
@@ -1,18 +1,11 @@
import { expect, test } from '@playwright/test';
test('serves the configured directory from the production build', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveTitle('Directory');
await expect(page.getByRole('heading', { name: 'Directory' })).toBeVisible();
await expect(page.getByText("A small directory for your family's homelab.")).toBeVisible();
await expect(page.getByText('No bookmarks yet.')).toBeVisible();
});
test.describe('without JavaScript', () => {
test.use({ javaScriptEnabled: false });
test('renders useful initial HTML and serves the bundled icon', async ({ page, request }) => {
await page.goto('/');
await expect(page).toHaveTitle('Directory');
await expect(page.getByRole('heading', { name: 'Directory' })).toBeVisible();
await expect(page.getByText("A small directory for your family's homelab.")).toBeVisible();
await expect(page.getByText('No bookmarks yet.')).toBeVisible();
+20 -24
View File
@@ -61,7 +61,6 @@ async function fixtures() {
await writeFile(join(publicDir, 'café family.svg'), svg);
await writeFile(join(publicDir, 'book.png'), png);
await writeFile(join(publicDir, 'private-brand.svg'), svg);
await writeFile(join(publicDir, 'invalid.png'), '<html>not an image</html>');
return { directory, publicDir };
} catch (error) {
await rm(directory, { recursive: true, force: true });
@@ -287,30 +286,27 @@ test('valid reloads keep the alias but change bytes; invalid and auth-changing c
}
});
for (const source of ['/public/missing.svg', '/public/invalid.png']) {
test(`configured unavailable source ${source} returns 404 without bundled fallback`, async ({
browser
}) => {
const fixture = await fixtures();
const server = await startServer({
configuration: configuration(source),
publicDir: fixture.publicDir
});
const context = await browser.newContext({ javaScriptEnabled: false });
try {
await server.ready();
await expectNotFound(server);
const page = await context.newPage();
await page.goto(`${server.url}/signin`);
await expect(page.locator('head link[rel="icon"]')).toHaveCount(1);
await expect(page.locator('head link[rel="icon"]')).toHaveAttribute('href', '/favicon');
expectNoPrivateData(await page.content(), [source]);
} finally {
await context.close();
await stop(server, fixture.directory);
}
test('a missing configured favicon returns 404 without bundled fallback', async ({ browser }) => {
const source = '/public/missing.svg';
const fixture = await fixtures();
const server = await startServer({
configuration: configuration(source),
publicDir: fixture.publicDir
});
}
const context = await browser.newContext({ javaScriptEnabled: false });
try {
await server.ready();
await expectNotFound(server);
const page = await context.newPage();
await page.goto(`${server.url}/signin`);
await expect(page.locator('head link[rel="icon"]')).toHaveCount(1);
await expect(page.locator('head link[rel="icon"]')).toHaveAttribute('href', '/favicon');
expectNoPrivateData(await page.content(), [source]);
} finally {
await context.close();
await stop(server, fixture.directory);
}
});
test('no-auth mode remains open without changing alias selection', async () => {
const fixture = await fixtures();
+45 -44
View File
@@ -85,7 +85,6 @@ test.beforeEach(async () => {
await writeFile(join(publicDir, 'PRIVATE_SELECTED_LOGO.svg'), logo);
await writeFile(join(publicDir, 'PRIVATE_OTHER_IMAGE.svg'), favicon);
await writeFile(join(publicDir, 'PRIVATE_TAB_ICON.svg'), favicon);
await writeFile(join(publicDir, 'invalid.svg'), 'not an image');
});
test.afterEach(async () => {
@@ -342,50 +341,52 @@ test('only selected logo bytes are public, with independent favicon and no arbit
}
});
for (const source of [null, '/public/missing.svg', '/public/invalid.svg']) {
for (const javaScriptEnabled of [false, true]) {
test(`${source ?? 'bundled default'} logo with JavaScript ${javaScriptEnabled}`, async ({
browser
}) => {
const app = await startServer({
configuration: brandedConfiguration(credentialsAuth, source),
publicDir
});
const context = await browser.newContext({
javaScriptEnabled,
viewport: { width: 360, height: 800 }
});
try {
await app.ready();
const page = await context.newPage();
let logoRequests = 0;
page.on('request', (request) => {
if (new URL(request.url()).pathname === '/logo') logoRequests++;
});
await page.goto(`${app.url}/signin`);
const image = page.locator('header img');
if (source !== null && !javaScriptEnabled) {
await expect(image).toHaveAttribute('src', '/logo');
await expect(image).toHaveJSProperty('complete', true);
await expect(image).toHaveJSProperty('naturalWidth', 0);
} else await expectDecoded(image, '/favicon.png');
expect(logoRequests).toBe(source === null ? 0 : 1);
await expect(page.getByRole('heading')).toHaveText(`Sign in to ${siteTitle}`);
await expect(page.getByRole('button', { name: 'Sign in', exact: true })).toBeEnabled();
await expect(page.locator('head link[rel="icon"]')).toHaveJSProperty(
'href',
`${app.url}/favicon`
);
expect(Buffer.from(await (await app.fetch('/favicon.png')).arrayBuffer())).toEqual(
await readFile(new URL('../static/favicon.png', import.meta.url))
);
expect((await app.fetch('/logo')).status).toBe(404);
} finally {
await context.close();
expect(await app.stop()).toEqual({ code: 0, signal: null });
}
for (const { source, javaScriptEnabled } of [
{ source: null, javaScriptEnabled: false },
{ source: '/public/missing.svg', javaScriptEnabled: false },
{ source: '/public/missing.svg', javaScriptEnabled: true }
]) {
test(`${source ?? 'bundled default'} logo with JavaScript ${javaScriptEnabled}`, async ({
browser
}) => {
const app = await startServer({
configuration: brandedConfiguration(credentialsAuth, source),
publicDir
});
}
const context = await browser.newContext({
javaScriptEnabled,
viewport: { width: 360, height: 800 }
});
try {
await app.ready();
const page = await context.newPage();
let logoRequests = 0;
page.on('request', (request) => {
if (new URL(request.url()).pathname === '/logo') logoRequests++;
});
await page.goto(`${app.url}/signin`);
const image = page.locator('header img');
if (source !== null && !javaScriptEnabled) {
await expect(image).toHaveAttribute('src', '/logo');
await expect(image).toHaveJSProperty('complete', true);
await expect(image).toHaveJSProperty('naturalWidth', 0);
} else await expectDecoded(image, '/favicon.png');
expect(logoRequests).toBe(source === null ? 0 : 1);
await expect(page.getByRole('heading')).toHaveText(`Sign in to ${siteTitle}`);
await expect(page.getByRole('button', { name: 'Sign in', exact: true })).toBeEnabled();
await expect(page.locator('head link[rel="icon"]')).toHaveJSProperty(
'href',
`${app.url}/favicon`
);
expect(Buffer.from(await (await app.fetch('/favicon.png')).arrayBuffer())).toEqual(
await readFile(new URL('../static/favicon.png', import.meta.url))
);
expect((await app.fetch('/logo')).status).toBe(404);
} finally {
await context.close();
expect(await app.stop()).toEqual({ code: 0, signal: null });
}
});
}
test('sign-in catches a logo failure before hydration and stops after a failed fallback', async ({
-61
View File
@@ -138,67 +138,6 @@ for (const javaScriptEnabled of [true, false]) {
}
}
test('a configured image that fails before hydration falls back once in the same SSR image', async ({
page
}) => {
await writeFile(join(publicDir, 'private-brand-a.svg'), 'not an image');
const app = await boot(sourceA);
const scripts = Promise.withResolvers<void>();
let heldScripts = 0;
await page.route('**/_app/immutable/**', async (route) => {
if (route.request().resourceType() === 'script') {
heldScripts++;
await scripts.promise;
}
await route.continue();
});
try {
await page.goto(app.url, { waitUntil: 'commit' });
const image = page.locator('header img');
await expect(image).toHaveAttribute('src', sourceA);
await expectBroken(image);
await expect.poll(() => heldScripts).toBeGreaterThan(0);
const ssrImage = await image.elementHandle();
scripts.resolve();
await expectDecoded(image, '/favicon.png');
expect(await image.evaluate((node, previous) => node === previous, ssrImage)).toBe(true);
await ssrImage?.dispose();
} finally {
scripts.resolve();
await page.unrouteAll({ behavior: 'wait' });
}
});
for (const source of [sourceA, undefined]) {
test(`${source ? 'failed primary and fallback' : 'failed default'} stop after one bundled image request`, async ({
page
}) => {
await writeFile(join(publicDir, 'private-brand-a.svg'), 'not an image');
const app = await boot(source);
let requests = 0;
await page.route('**/favicon.png', async (route) => {
requests++;
await route.abort();
});
const failed = page.waitForEvent(
'requestfailed',
(request) => new URL(request.url()).pathname === '/favicon.png'
);
await page.goto(app.url);
await failed;
const image = page.locator('header img');
await expect(image).toHaveAttribute('src', '/favicon.png');
await expectBroken(image);
await page.evaluate(
() =>
new Promise<void>((resolve) =>
requestAnimationFrame(() => requestAnimationFrame(() => resolve()))
)
);
expect(requests).toBe(1);
});
}
test('without JavaScript a broken configured header leaves title and native navigation usable', async ({
browser
}) => {
-1
View File
@@ -40,7 +40,6 @@ export function createAuthentication(config: DirectoryAuth & { origin: string })
secret,
trustHost: true,
basePath: '/auth',
// An empty value prevents Auth.js from enabling an environment-inferred redirect proxy.
redirectProxyUrl: '',
session: { strategy: 'jwt', maxAge: WEEK_SECONDS },
providers: buildProviders(config),