Files
GEWU/web/e2e/reader.spec.ts
2026-10-14 19:21:35 +08:00

143 lines
5.8 KiB
TypeScript

import { expect, test } from '@playwright/test';
const citation = {
source_revision_id: 'dome:pilot-report:r1',
extraction_id: 'a'.repeat(64),
assertion_path: 'claims/0',
assertion_digest: 'b'.repeat(64),
quote: 'The installation hosted 400 visitors during the season.',
locator: { schema_version: 1, kind: 'text_span', block_id: 'block-1', start: 0, end: 54 },
normalization_profile: 'unicode-nfc-lf-v1',
schema_version: 1,
};
const node = {
node_id: 'dome:season-visitors',
project_id: 'dome-performance',
title: 'Visitor count during the season',
summary: 'The installation hosted 400 visitors.',
node_type: 'finding',
lifecycle: 'active',
as_of: '2026-10-13T00:00:00Z',
tags: ['installation'],
audience: ['developer'],
use_for: ['planning'],
domain: ['interactive systems'],
claims: [{
text: 'The installation hosted 400 visitors during the season.',
evidence_type: 'reported',
assessment: {
status: 'supported',
method: 'paired source claim check',
rationale: 'The cited sentence states the count.',
assessor_id: 'agent-pilot',
},
}],
assumptions: [],
limitations: [],
};
const envelope = (data: unknown[]) => ({
api_version: 'v1',
request_id: 'browser-test-request',
resolved_scope: {
projects: ['dome-performance'],
include_shared: false,
all_projects: false,
schema_version: 1,
},
retrieval_mode: 'keyword',
budget_profile: { tokenizer: 'none', encoding: 'raw-record-v1', schema_version: 1 },
tokens_used: 150,
data,
citations: [citation],
warnings: [],
omissions: [],
canonical_revision: '1'.repeat(40),
index_revision: '1'.repeat(40),
next_cursor: null,
schema_version: 1,
});
test('restores a shared search URL and reads its exact citation', async ({ page }) => {
const searchBodies: Array<Record<string, unknown>> = [];
await page.route('**/v1/**', async (route) => {
const request = route.request();
const url = new URL(request.url());
if (url.pathname === '/v1/session' && request.method() === 'GET') {
await route.fulfill({ status: 401, json: { detail: 'No browser session' } });
} else if (url.pathname === '/v1/session') {
await route.fulfill({ json: { csrf_token: 'browser-test-csrf' } });
} else if (url.pathname === '/v1/projects') {
await route.fulfill({ json: ['dome-performance'] });
} else if (url.pathname === '/v1/search') {
searchBodies.push(request.postDataJSON() as Record<string, unknown>);
await route.fulfill({ json: envelope([{ node, retrieval_score: -1.2 }]) });
} else if (url.pathname.endsWith('/history')) {
await route.fulfill({ json: envelope([{ revision: '1'.repeat(40), node }]) });
} else if (url.pathname === '/v1/neighbors') {
await route.fulfill({ json: envelope([]) });
} else if (url.pathname === '/v1/projects/dome-performance/nodes/dome%3Aseason-visitors') {
await route.fulfill({ json: envelope([node]) });
} else {
await route.fulfill({ status: 404, json: { detail: 'Unexpected test API request.' } });
}
});
await page.goto('/?project=dome-performance&q=visitors&tag=installation&audience=developer&confidence=medium&as_of_from=2024-01-01&as_of_to=2024-12-31');
await page.getByRole('button', { name: 'Use an existing credential' }).click();
await page.getByLabel('GEWU viewer credential').fill('synthetic-viewer-token');
await page.getByRole('button', { name: 'Connect' }).click();
await expect(page.getByRole('button', { name: /Visitor count during the season/ })).toBeVisible();
await expect.poll(() => searchBodies).toHaveLength(1);
expect(searchBodies[0]).toMatchObject({
query: 'visitors',
scope: { projects: ['dome-performance'] },
tags: ['installation'],
audience: ['developer'],
confidences: ['medium'],
as_of_from: '2024-01-01',
as_of_to: '2024-12-31',
});
const result = page.getByRole('button', { name: /Visitor count during the season/ });
await result.focus();
await page.keyboard.press('Enter');
await expect(page.getByRole('heading', { name: 'Claim assessments' })).toBeVisible();
await expect(page.getByRole('region', { name: 'Evidence' }).getByText(citation.quote)).toBeVisible();
await page.setViewportSize({ width: 320, height: 800 });
const documentWidth = await page.evaluate(() => document.documentElement.scrollWidth);
expect(documentWidth).toBe(320);
});
test('query editing remains passive until the reader submits Search', async ({ page }) => {
let searchCount = 0;
await page.route('**/v1/**', async (route) => {
const pathname = new URL(route.request().url()).pathname;
if (pathname === '/v1/session' && route.request().method() === 'GET') {
await route.fulfill({ status: 401, json: { detail: 'No browser session' } });
} else if (pathname === '/v1/session') {
await route.fulfill({ json: { csrf_token: 'browser-test-csrf' } });
} else if (pathname === '/v1/projects') {
await route.fulfill({ json: ['dome-performance'] });
} else if (pathname === '/v1/search') {
searchCount += 1;
await route.fulfill({ json: envelope([{ node, retrieval_score: -1.2 }]) });
} else {
await route.fulfill({ json: envelope([]) });
}
});
await page.goto('/?project=dome-performance');
await page.getByRole('button', { name: 'Use an existing credential' }).click();
await page.getByLabel('GEWU viewer credential').fill('synthetic-viewer-token');
await page.getByRole('button', { name: 'Connect' }).click();
await page.getByRole('textbox', { name: /Search claims/ }).fill('visitors');
await expect.poll(() => searchCount).toBe(0);
await page.getByRole('textbox', { name: /Search claims/ }).press('Enter');
await expect.poll(() => searchCount).toBe(1);
await expect(page.getByRole('button', { name: /Visitor count during the season/ })).toBeVisible();
});