74 lines
2.4 KiB
TypeScript
74 lines
2.4 KiB
TypeScript
import {
|
|
test as base,
|
|
expect,
|
|
type Page,
|
|
type BrowserContext,
|
|
} from '@playwright/test';
|
|
|
|
/**
|
|
* Shared fixtures and helpers.
|
|
*
|
|
* Works against either the mock plugin (VITE_USE_MOCK_API=true) or the real
|
|
* Django backend (stratoflights). Mock accepts any credentials; Django
|
|
* expects demo/demo and enforces CSRF.
|
|
*
|
|
* The `TEST_USERNAME` / `TEST_PASSWORD` envs let CI override the default.
|
|
*
|
|
* Critical detail: login/logout must go through `page.context().request` so
|
|
* cookies are shared between API calls and the page. Using the plain
|
|
* `request` fixture gives you a separate cookie jar.
|
|
*/
|
|
|
|
const USERNAME = process.env.TEST_USERNAME ?? 'demo';
|
|
const PASSWORD = process.env.TEST_PASSWORD ?? 'demo';
|
|
|
|
export async function login(context: BrowserContext): Promise<void> {
|
|
const request = context.request;
|
|
await request.get('/api/csrf/');
|
|
const state = await context.storageState();
|
|
const csrf = state.cookies.find((c) => c.name === 'csrftoken')?.value ?? '';
|
|
const res = await request.post('/api/login/', {
|
|
data: { username: USERNAME, password: PASSWORD },
|
|
headers: { 'X-CSRFToken': csrf, 'Content-Type': 'application/json' },
|
|
});
|
|
if (!res.ok()) {
|
|
throw new Error(
|
|
`Login failed: ${res.status()} ${await res.text()}. Is stratoflights running on :8000 with a user "${USERNAME}" / "${PASSWORD}"?`,
|
|
);
|
|
}
|
|
}
|
|
|
|
export async function logout(context: BrowserContext): Promise<void> {
|
|
const state = await context.storageState();
|
|
const csrf = state.cookies.find((c) => c.name === 'csrftoken')?.value ?? '';
|
|
await context.request.post('/api/logout/', {
|
|
headers: { 'X-CSRFToken': csrf, 'Content-Type': 'application/json' },
|
|
});
|
|
// Clear cookies so the page navigator is fully anonymous next goto.
|
|
await context.clearCookies();
|
|
}
|
|
|
|
export const test = base.extend({
|
|
page: async ({ page }, use) => {
|
|
const hardErrors: string[] = [];
|
|
page.on('pageerror', (e) => hardErrors.push(`[pageerror] ${e.message}`));
|
|
page.on('console', (msg) => {
|
|
if (msg.type() === 'error') {
|
|
// eslint-disable-next-line no-console
|
|
console.log(' [page console.error]', msg.text());
|
|
}
|
|
});
|
|
await use(page);
|
|
if (hardErrors.length > 0) throw new Error('Page errors:\n' + hardErrors.join('\n'));
|
|
},
|
|
});
|
|
|
|
export { expect };
|
|
|
|
export async function openPredict(page: Page) {
|
|
await page.goto('/predict');
|
|
await page
|
|
.locator('.map-container canvas')
|
|
.first()
|
|
.waitFor({ state: 'attached', timeout: 15_000 });
|
|
}
|