Files
pchelpmaster/tests/e2e/smoke.e2e.ts
T
kamaskandClaude Opus 5.5 82e097f876 test(e2e): add playwright e2e stand with test pocketbase and axe checks
- playwright.config.ts: test PocketBase (port 8190) and ng serve (port 4300)
  as webServers, SIGTERM shutdown so the stand removes its temp dir
- fixtures: user via open registration, api SDK client, signedInPage with pb_auth cookie
- expectNoA11yViolations runs all axe rules (WCAG and best-practice)
- render home route on the server; main and h1 placeholder in app shell
- config tests for playwright.config.ts in test:lint; docs updated

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:12:04 +03:00

130 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Смоук стенда e2e: приложение и тестовый PocketBase подняты, прокси /pb работает, axe и фикстуры работают.
import { expectNoA11yViolations } from './a11y';
import { expect, test } from './fixtures';
test.describe('главная', () => {
test('главная отвечает статусом 200', async ({ page }) => {
const response = await page.goto('/');
expect(response?.status()).toBe(200);
});
test.describe('HTML от сервера', () => {
// Без JS браузер показывает ровно ту разметку, что отдал SSR.
test.use({ javaScriptEnabled: false });
test('в HTML от сервера есть main и h1', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('main')).toBeVisible();
await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
});
});
test('на отрисованной главной есть main и h1', async ({ page }) => {
await page.goto('/');
await expect(page.getByRole('main')).toBeVisible();
await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
});
test('на главной нет нарушений доступности', async ({ page }) => {
await page.goto('/');
await expectNoA11yViolations(page);
});
});
test.describe('прокси /pb', () => {
test('/pb/api/health с origin приложения отдаёт health PocketBase', async ({ request }) => {
const response = await request.get('/pb/api/health');
expect(response.status()).toBe(200);
// Без прокси ng serve ответил бы на неизвестный путь index.html со статусом 200.
expect(await response.json()).toMatchObject({ code: 200 });
});
});
test.describe('хелпер expectNoA11yViolations', () => {
test('падает на нарушении WCAG и называет правило', async ({ page }) => {
await page.setContent(
'<!doctype html><html lang="ru"><head><title>Тест</title></head>' +
'<body><main><h1>Тест</h1><img src="data:,"></main></body></html>',
);
await expect(expectNoA11yViolations(page)).rejects.toThrow(/image-alt/);
});
test('падает и на правилах best-practice', async ({ page }) => {
// Нет main и h1: это правила best-practice, а не WCAG.
await page.setContent(
'<!doctype html><html lang="ru"><head><title>Тест</title></head>' +
'<body><p>Текст</p></body></html>',
);
await expect(expectNoA11yViolations(page)).rejects.toThrow(/landmark-one-main/);
});
test('не падает на чистой странице', async ({ page }) => {
await page.setContent(
'<!doctype html><html lang="ru"><head><title>Тест</title></head>' +
'<body><main><h1>Тест</h1><p>Текст</p></main></body></html>',
);
await expect(expectNoA11yViolations(page)).resolves.toBeUndefined();
});
});
test.describe('фикстуры', () => {
test('api действует от имени user', async ({ api, user }) => {
expect(api.authStore.record?.id).toBe(user.id);
await expect(api.collection('users').getOne(user.id)).resolves.toMatchObject({
email: user.email,
});
});
test('signedInPage: cookie pb_auth с Path=/, SameSite=Lax, без HttpOnly', async ({
signedInPage,
}) => {
const cookies = await signedInPage.context().cookies();
expect(cookies.find((c) => c.name === 'pb_auth')).toMatchObject({
path: '/',
sameSite: 'Lax',
httpOnly: false,
});
});
test('signedInPage: токен из cookie принимает auth-refresh через /pb', async ({
signedInPage,
user,
}) => {
await signedInPage.goto('/');
// Выполняется в браузере: cookie читается из document.cookie, как её прочитает SDK.
const result = await signedInPage.evaluate(async () => {
const raw = document.cookie
.split('; ')
.find((c) => c.startsWith('pb_auth='))
?.slice('pb_auth='.length);
const { token } = JSON.parse(decodeURIComponent(raw ?? '{}')) as { token?: string };
const response = await fetch('/pb/api/collections/users/auth-refresh', {
method: 'POST',
headers: { Authorization: token ?? '' },
});
const body = (await response.json()) as { record?: { id?: string } };
return { status: response.status, recordId: body.record?.id };
});
expect(result).toEqual({ status: 200, recordId: user.id });
});
test('обычная page остаётся гостевой рядом с signedInPage', async ({ page, signedInPage }) => {
const signedInCookies = await signedInPage.context().cookies();
const guestCookies = await page.context().cookies();
expect(signedInCookies.map((c) => c.name)).toContain('pb_auth');
expect(guestCookies.map((c) => c.name)).not.toContain('pb_auth');
});
});