Files
topola-viewer/tests/webmcp.spec.ts
2026-05-11 18:20:19 +02:00

75 lines
2.5 KiB
TypeScript

import {expect, test} from '@playwright/test';
import {WebMcpTool} from '../src/webmcp_types';
import {setupGedcomRoute} from './helpers';
const EXPECTED_TOOL_NAMES = [
'get_selected_person',
'search_indi',
'inspect_indi',
'focus_indi',
'find_relationship_path',
'get_ancestors',
'get_descendants',
];
test.describe('WebMCP Integration', () => {
test.beforeEach(async ({page, context}) => {
await setupGedcomRoute(context);
// Add init script to expose modelContext mock BEFORE application boots.
await page.addInitScript(() => {
const registeredTools: WebMcpTool[] = [];
window.__registeredTools = registeredTools;
window.navigator.modelContext = {
registerTool: (tool: WebMcpTool) => {
registeredTools.push(tool);
},
unregisterTool: (name: string) => {
const idx = registeredTools.findIndex((t) => t.name === name);
if (idx !== -1) registeredTools.splice(idx, 1);
},
};
});
});
test('registers tools to standard modelContext', async ({page}) => {
await page.goto('/#/view?url=https://example.org/family.ged');
// Polling assertion to avoid React useEffect registration race condition.
await page.waitForFunction(
(expectedCount) => window.__registeredTools?.length === expectedCount,
EXPECTED_TOOL_NAMES.length,
);
const toolNames = await page.evaluate(() =>
window.__registeredTools
? window.__registeredTools.map((t) => t.name)
: [],
);
expect(toolNames.sort()).toEqual([...EXPECTED_TOOL_NAMES].sort());
});
test('allows running focus_indi tool', async ({page}) => {
await page.goto('/#/view?url=https://example.org/family.ged');
await page.waitForFunction(
(expectedCount) => window.__registeredTools?.length === expectedCount,
EXPECTED_TOOL_NAMES.length,
);
await expect(page.locator('#content')).toContainText('Radobod');
await expect(page.locator('#content')).not.toContainText('Chike');
// Execute the non-serializable callback inside the browser environment.
await page.evaluate(async () => {
const focusTool = window.__registeredTools
? window.__registeredTools.find((t) => t.name === 'focus_indi')
: null;
if (!focusTool) throw new Error('focus_indi tool not found');
await focusTool.execute({id: 'I21'}); // Shifts view focus to Chike.
});
// Verify that the UI updated automatically in response to the tool action.
await expect(page.locator('#content')).toContainText('Chike');
});
});