Initial
This commit is contained in:
commit
b43955e0d9
162 changed files with 15425 additions and 0 deletions
63
tests/e2e/export.spec.ts
Normal file
63
tests/e2e/export.spec.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import { test, expect, type Page } from '@playwright/test';
|
||||
|
||||
async function login(page: Page) {
|
||||
await page.goto('/login/');
|
||||
await page.fill('#lg-username', 'demo');
|
||||
await page.fill('#lg-password', 'demo');
|
||||
await page.click('button[type=submit]');
|
||||
await expect(page.getByTestId('nav-menu')).toBeVisible();
|
||||
}
|
||||
|
||||
test('a computed scenario exports as GPX, KML and CSV', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.getByTestId('run-btn').click();
|
||||
await expect(page.getByTestId('flight-time')).toBeVisible({ timeout: 15000 });
|
||||
|
||||
for (const fmt of ['gpx', 'kml', 'csv'] as const) {
|
||||
const download = page.waitForEvent('download');
|
||||
await page.getByTestId(`export-${fmt}`).click();
|
||||
const file = await download;
|
||||
expect(file.suggestedFilename()).toMatch(new RegExp(`\\.${fmt}$`));
|
||||
}
|
||||
});
|
||||
|
||||
test('a shared link opens read-only without a session and can be revoked', async ({
|
||||
page,
|
||||
context
|
||||
}) => {
|
||||
await login(page);
|
||||
await page.getByTestId('run-btn').click();
|
||||
await expect(page.getByTestId('flight-time')).toBeVisible({ timeout: 15000 });
|
||||
|
||||
// Mint a share link from the history row.
|
||||
await page.goto('/user/predictions/');
|
||||
await context.grantPermissions(['clipboard-read', 'clipboard-write']);
|
||||
await page.getByTestId('history-share').first().click();
|
||||
await expect(page.locator('.toast')).toBeVisible();
|
||||
const url = await page.evaluate(() => navigator.clipboard.readText());
|
||||
expect(url).toMatch(/\/p\/[0-9a-f-]{36}\//);
|
||||
|
||||
// The link resolves for a visitor with no session at all.
|
||||
const anon = await context.browser()!.newContext();
|
||||
const anonPage = await anon.newPage();
|
||||
await anonPage.goto(url);
|
||||
await expect(anonPage.getByTestId('shared-summary')).toBeVisible({ timeout: 15000 });
|
||||
// It is read-only: no run controls, but the data is still exportable.
|
||||
await expect(anonPage.getByTestId('run-btn')).toHaveCount(0);
|
||||
await expect(anonPage.getByTestId('shared-export-gpx')).toBeVisible();
|
||||
|
||||
// Revoking breaks the link. The share endpoint is keyed by the prediction id
|
||||
// (the token only grants read access), so take the id from the shared page.
|
||||
const predictionId = await anonPage.evaluate(async (u: string) => {
|
||||
const token = u.split('/p/')[1].replace(/\/$/, '');
|
||||
const res = await fetch(`/api/predictions/shared/${token}/`);
|
||||
return (await res.json()).id as string;
|
||||
}, url);
|
||||
|
||||
const revoke = await page.request.delete(`/api/predictions/${predictionId}/share/`);
|
||||
expect(revoke.ok()).toBe(true);
|
||||
|
||||
await anonPage.reload();
|
||||
await expect(anonPage.getByTestId('shared-error')).toBeVisible();
|
||||
await anon.close();
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue