// @vitest-environment jsdom import { afterEach, describe, expect, it } from 'vitest'; import { PageSnapshotEngine } from '../engine'; afterEach(() => { document.body.innerHTML = ''; }); /** Capture the page and return the serialized snapshot string. */ function snapshotJson(): string { return JSON.stringify(new PageSnapshotEngine().capture().payload.snapshot); } /** * Integration: redaction runs inside the engine's capture pipeline, in * the browser, before any snapshot would leave the device. Verifies the * P2 success criteria — no secret/PII reaches the serialized snapshot. */ describe('redaction integration', () => { it('redacts a password field value (safe by default, no annotation)', () => { document.body.innerHTML = `
`; const json = snapshotJson(); expect(json).not.toContain('hunter2-secret'); expect(json).toContain('‹redacted:password›'); }); it('redacts a secret-named field', () => { document.body.innerHTML = `
`; const json = snapshotJson(); expect(json).not.toContain('raw-key-value-123'); }); it('redacts PII patterns inside static text', () => { document.body.innerHTML = `

Contact: jane.doe@example.com or call later

`; const json = snapshotJson(); expect(json).not.toContain('jane.doe@example.com'); expect(json).toContain('‹redacted:email›'); }); it('drops a data-ai-redact subtree entirely', () => { document.body.innerHTML = `

secret paragraph

public paragraph

`; const json = snapshotJson(); expect(json).not.toContain('confidential-block-value'); expect(json).not.toContain('secret paragraph'); expect(json).toContain('[redacted]'); expect(json).toContain('public paragraph'); }); it('data-ai-include overrides a heuristic block for a safe value', () => { // A field named "token" would normally be redacted; data-ai-include // forces the (known-safe, public) value through. document.body.innerHTML = `
`; const json = snapshotJson(); expect(json).toContain('PUBLIC-PROJECT-ALPHA'); }); it('reports redactions in the capture telemetry', () => { document.body.innerHTML = `
`; const { telemetry } = new PageSnapshotEngine().capture(); expect(telemetry.redactedCount).toBeGreaterThanOrEqual(2); }); it('leaves a normal page completely untouched', () => { document.body.innerHTML = `

Welcome to the dashboard

`; const { payload, telemetry } = new PageSnapshotEngine().capture(); const json = JSON.stringify(payload.snapshot); expect(json).toContain('Acme Inc'); expect(json).toContain('Welcome to the dashboard'); expect(telemetry.redactedCount).toBe(0); }); });