142 lines
5.8 KiB
TypeScript
142 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();
|
||
|
|
});
|