87 lines
3.3 KiB
TypeScript
87 lines
3.3 KiB
TypeScript
import { expect, test, type Page } from '@playwright/test';
|
|
|
|
const PASSWORD = 'Sup3rSecure!123';
|
|
|
|
test.describe.configure({ mode: 'serial' });
|
|
|
|
function uniqueEmail(prefix: string) {
|
|
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}@example.com`;
|
|
}
|
|
|
|
async function gotoAuthPage(page: Page, path: string) {
|
|
await page.goto(path, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForLoadState('networkidle');
|
|
}
|
|
|
|
async function signUp(page: Page, email: string) {
|
|
await gotoAuthPage(page, '/auth/signup');
|
|
await page.locator('input[autocomplete="name"]').fill('Playwright Watchlist User');
|
|
await page.locator('input[autocomplete="email"]').fill(email);
|
|
await page.locator('input[autocomplete="new-password"]').first().fill(PASSWORD);
|
|
await page.locator('input[autocomplete="new-password"]').nth(1).fill(PASSWORD);
|
|
await page.getByRole('button', { name: 'Create account' }).click();
|
|
}
|
|
|
|
async function expectStableDashboard(page: Page) {
|
|
await expect(page.getByRole('heading', { name: 'Command Center' })).toBeVisible({ timeout: 30_000 });
|
|
await expect(page).toHaveURL(/\/$/, { timeout: 30_000 });
|
|
}
|
|
|
|
async function countSyncTasks(page: Page, ticker: string) {
|
|
return await page.evaluate(async (requestedTicker) => {
|
|
const response = await fetch('/api/tasks?limit=20', {
|
|
credentials: 'include',
|
|
cache: 'no-store'
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Unable to load tasks: ${response.status}`);
|
|
}
|
|
|
|
const payload = await response.json() as {
|
|
tasks?: Array<{
|
|
task_type?: string;
|
|
payload?: {
|
|
ticker?: string;
|
|
};
|
|
}>;
|
|
};
|
|
|
|
return (payload.tasks ?? []).filter((task) => (
|
|
task.task_type === 'sync_filings'
|
|
&& task.payload?.ticker === requestedTicker
|
|
)).length;
|
|
}, ticker);
|
|
}
|
|
|
|
test('coverage save stays metadata-only until sync filings is clicked', async ({ page }) => {
|
|
await signUp(page, uniqueEmail('playwright-watchlist-sync'));
|
|
await expectStableDashboard(page);
|
|
|
|
await page.goto('/watchlist', { waitUntil: 'domcontentloaded' });
|
|
await expect(page.getByRole('heading', { name: 'Coverage', exact: true })).toBeVisible({ timeout: 30_000 });
|
|
|
|
await page.getByLabel('Coverage ticker').fill('NVDA');
|
|
await page.getByLabel('Coverage company name').fill('NVIDIA Corporation');
|
|
await page.getByLabel('Coverage sector').fill('Technology');
|
|
await page.getByLabel('Coverage category').fill('core');
|
|
await page.getByLabel('Coverage tags').fill('semis, ai');
|
|
await page.getByRole('button', { name: 'Save coverage' }).click();
|
|
|
|
const coverageRow = page.locator('tr').filter({ hasText: 'NVDA' });
|
|
await expect(coverageRow).toContainText('NVIDIA Corporation');
|
|
|
|
const notice = page.getByTestId('watchlist-post-create-notice');
|
|
await expect(notice).toContainText('NVDA added to coverage. Filing sync has not started yet.');
|
|
await expect(notice.getByRole('button', { name: 'Sync filings' })).toBeVisible();
|
|
await expect(coverageRow.getByRole('button', { name: 'Sync filings' })).toBeVisible();
|
|
|
|
await page.waitForTimeout(1_000);
|
|
expect(await countSyncTasks(page, 'NVDA')).toBe(0);
|
|
|
|
await notice.getByRole('button', { name: 'Sync filings' }).click();
|
|
|
|
await expect(notice).toContainText('NVDA added to coverage. Filing sync is queued.');
|
|
await expect.poll(async () => await countSyncTasks(page, 'NVDA')).toBe(1);
|
|
});
|