Files
context-extractor/automation-js/tests/session.test.ts
T
ilia 55018a6e3e
CI / automation-js (vitest + real Chromium) (pull_request) Successful in 43s
CI / Lint + tests (pull_request) Successful in 9m52s
Add Node/TS automation twin sharing the extension core.
Expose ExtractorSession for Playwright/camoufox-js so Node automations can
import context dumps instead of shelling out to the Python package. Same
fixture as the Python tests; wired into Makefile and Gitea CI.
2026-07-15 18:17:14 -04:00

118 lines
4.3 KiB
TypeScript

import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { chromium, type Browser, type Page } from 'playwright-core';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { pathToFileURL } from 'node:url';
import { ExtractorSession } from '../src/session.js';
// Same golden fixture the Python `automation/tests/` suite uses — one file,
// two automation layers, so a markdown-formatting bug can't silently diverge
// between them.
const here = dirname(fileURLToPath(import.meta.url));
const FIXTURE_URL = pathToFileURL(
join(here, '..', '..', 'automation', 'tests', 'fixtures', 'sample.html'),
).toString();
let browser: Browser;
beforeAll(async () => {
browser = await chromium.launch({ headless: true });
});
afterAll(async () => {
await browser.close();
});
async function withPage<T>(fn: (page: Page) => Promise<T>): Promise<T> {
const p = await browser.newPage();
try {
return await fn(p);
} finally {
await p.close();
}
}
describe('ExtractorSession', () => {
it('captures console messages, page errors, and network activity', async () => {
await withPage(async (page) => {
const session = new ExtractorSession(page);
await page.goto(FIXTURE_URL, { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(150);
const store = session.getStore();
const levels = new Set(store.console.map((e) => e.level));
expect(levels.has('warn')).toBe(true);
expect(
levels.has('error') ||
store.console.some((e) => (e.msg || '').toLowerCase().includes('error')),
).toBe(true);
expect(store.errors.some((e) => (e.msg || '').includes('fixture boom'))).toBe(true);
expect(store.network.length).toBeGreaterThan(0);
});
});
it('extracts markdown from the full body and from a selector', async () => {
await withPage(async (page) => {
const session = new ExtractorSession(page);
await page.goto(FIXTURE_URL, { waitUntil: 'domcontentloaded' });
const full = await session.extractMarkdown();
expect(full.title).toBe('Context Extractor Fixture');
expect(full.markdown).toContain('Fixture Page');
expect(full.markdown).toContain('**world**');
expect(full.markdown).toContain('[docs](/docs)');
expect(full.markdown).toContain('- Alpha');
const scoped = await session.extractMarkdown('#main-content');
expect(scoped.selector).toBe('#main-content');
expect(scoped.markdown).toContain('Section');
expect(scoped.markdown).not.toContain('Skip this noise');
});
});
it('excludes hidden nodes (inline style, stylesheet class, [hidden], aria-hidden) from markdown', async () => {
await withPage(async (page) => {
const session = new ExtractorSession(page);
await page.goto(FIXTURE_URL, { waitUntil: 'domcontentloaded' });
const { markdown } = await session.extractMarkdown('#main-content');
expect(markdown).not.toContain('should-not-appear');
expect(markdown).not.toContain('secretConfig');
expect(markdown).not.toContain('lixTracking');
expect(markdown).toContain('Alpha');
expect(markdown).toContain('Beta');
});
});
it('builds an AI prompt with the expected sections', async () => {
await withPage(async (page) => {
const session = new ExtractorSession(page);
await page.goto(FIXTURE_URL, { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(150);
const prompt = await session.buildAiPrompt('#main-content');
expect(prompt.startsWith('# Page Context')).toBe(true);
expect(prompt).toContain('## Page Content');
expect(prompt).toContain('Hello **world**');
expect(/JavaScript Errors|Console Errors/.test(prompt)).toBe(true);
expect(prompt).toContain('_Extracted by Context Extractor_');
});
});
it('clears the capture store, selectively and fully', async () => {
await withPage(async (page) => {
const session = new ExtractorSession(page);
await page.goto(FIXTURE_URL, { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(100);
expect(session.getStore().console.length).toBeGreaterThan(0);
session.clear('console');
expect(session.getStore().console).toEqual([]);
session.clear();
expect(session.getStore()).toEqual({ console: [], errors: [], network: [] });
});
});
});