SPB Git

Repository Public

setup-offline.spec.ts 3.3 KB 64 lines typescript

1import { expect, test } from '@playwright/test';2import { apiLogin, resetMock, totp, watch } from './helpers';34test.afterAll(async ({ browser }) => {5  const page = await browser.newPage();6  await resetMock(page, true);7  await page.close();8});910test('first-run setup: token + account, mandatory TOTP enrolment with a locally rendered QR', async ({ page }) => {11  const w = watch(page);12  await resetMock(page, false);13  await page.goto('/');14  await expect(page).toHaveURL(/\/setup\//);15  await page.getByTestId('setup-token').fill('mock-setup-token-0000');16  await page.getByTestId('setup-username').fill('owner');17  await page.getByTestId('setup-password').fill('short');18  await expect(page.getByTestId('setup-submit')).toBeDisabled(); // < 12 characters19  await page.getByTestId('setup-password').fill('a-long-passphrase-42');20  await page.getByTestId('setup-confirm').fill('a-long-passphrase-42');21  await page.getByTestId('setup-submit').click();2223  // the account is not usable yet: the app shell refuses to load before a second factor exists24  await expect(page.getByTestId('second-factor-enroll')).toBeVisible();25  expect((await (await page.request.get('/api/v1/auth/status')).json()).authenticated).toBe(false);26  await page.getByTestId('totp-start').click();27  await expect(page.locator('canvas[role="img"]')).toBeVisible();28  expect(await page.locator('canvas[role="img"]').evaluate((c: HTMLCanvasElement) => c.width)).toBeGreaterThan(100);29  const secret = (await page.getByTestId('totp-secret').getAttribute('data-secret'))!;30  await page.getByTestId('totp-enroll-code').fill(totp(secret));31  await page.getByRole('button', { name: 'Verify and enable' }).click();32  await expect(page).toHaveURL(/\/terminal\//);33  await expect(page.getByTestId('no-session')).toBeVisible();34  expect(await page.evaluate(() => JSON.stringify({ ...localStorage }) + JSON.stringify({ ...sessionStorage }))).not.toMatch(/csrf|token|secret|passphrase/i);35  w.expectClean();36});3738test('offline: the cached shell loads and says the remote session keeps running; /api is never cached', async ({ page, context }) => {39  await resetMock(page, true);40  await apiLogin(page);41  await page.goto('/terminal/');42  await expect(page.getByTestId('no-session')).toBeVisible();43  // wait for the service worker to control the page and finish caching the shell44  await page.evaluate(async () => { await navigator.serviceWorker.ready; });45  await page.reload();46  await expect(page.getByTestId('no-session')).toBeVisible();47  await expect.poll(() => page.evaluate(() => !!navigator.serviceWorker.controller)).toBe(true);48  const cached = await page.evaluate(async () => {49    const out: string[] = [];50    for (const name of await caches.keys()) for (const req of await (await caches.open(name)).keys()) out.push(new URL(req.url).pathname);51    return out;52  });53  expect(cached.some((p) => p.startsWith('/_next/static/'))).toBe(true);54  expect(cached).toContain('/terminal/');55  expect(cached.filter((p) => p.startsWith('/api'))).toEqual([]);5657  await context.setOffline(true);58  await page.reload();59  await expect(page.getByTestId('offline-state')).toHaveText('Offline — the remote session keeps running on the server');60  await context.setOffline(false);61  await page.getByRole('button', { name: 'Retry' }).click();62  await expect(page.getByTestId('no-session')).toBeVisible();63});64
Files main
Menu

Theme