Consolidate redundant end-to-end tests #61
No files matched your search
@@ -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
@@ -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
@@ -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 ({
|
||||
|
||||
@@ -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
|
||||
}) => {
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in new issue
Block a user