69 lines
4.7 KiB
JavaScript
69 lines
4.7 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import fs from 'node:fs/promises'
|
|
import path from 'node:path'
|
|
import { tmpdir } from 'node:os'
|
|
import { pathToFileURL } from 'node:url'
|
|
|
|
const runtime = path.resolve('.tmp/rea-css-runtime')
|
|
const moduleAt = relative => import(pathToFileURL(path.join(runtime, 'dist', relative)).href)
|
|
const { inspectElectronPageInputSchema, electronPageInspectionSchema } = await moduleAt('domain/javascript/electronObservation.js')
|
|
const { inspectCdpElectronPage } = await moduleAt('browser/CdpElectronInspection.js')
|
|
const { createElectronEvidence } = await moduleAt('application/javascript/ElectronEvidence.js')
|
|
const fixture = await fs.mkdtemp(path.join(tmpdir(), 'rea-css-contract-'))
|
|
try {
|
|
const html = path.join(fixture, 'index.html'), css = path.join(fixture, 'app.css')
|
|
await fs.writeFile(html, '<!doctype html><title>REA fixture</title>')
|
|
await fs.writeFile(css, '.fixture { color: blue; }')
|
|
const pageUrl = pathToFileURL(html).href, cssUrl = pathToFileURL(css).href
|
|
const frame = { id: 'frame-main', url: pageUrl }
|
|
const input = inspectElectronPageInputSchema.parse({ cdp_endpoint: 'http://127.0.0.1:9223', target_id: 'test', observation_ms: 0, include_style_sources: true })
|
|
assert.equal(input.include_style_sources, true)
|
|
assert.equal(input.include_script_sources, false)
|
|
assert.equal(inspectElectronPageInputSchema.safeParse({ ...input, visual_probe: { include_fonts: true } }).success, false, 'a probe cannot be silently ignored without include_visuals')
|
|
assert.equal(inspectElectronPageInputSchema.parse({ cdp_endpoint: 'http://127.0.0.1:9223', target_id: 'test' }).include_style_sources, false)
|
|
assert.equal(inspectElectronPageInputSchema.safeParse({ ...input, cdp_endpoint: 'https://example.com' }).success, false)
|
|
let listener
|
|
const calls = []
|
|
const connection = {
|
|
onEvent(callback) { listener = callback; return () => { listener = undefined } },
|
|
async send(method, _params, sessionId) {
|
|
calls.push(method)
|
|
if (method === 'Page.getFrameTree') return { frameTree: { frame } }
|
|
if (method === 'Page.getResourceTree') return { frameTree: { frame, resources: [{ url: cssUrl, type: 'Stylesheet', mimeType: 'text/css' }] } }
|
|
if (method === 'DOMSnapshot.captureSnapshot') return { strings: [], documents: [] }
|
|
if (method === 'Target.getTargets') return { targetInfos: [] }
|
|
if (method === 'CSS.enable') {
|
|
listener({ sessionId, method: 'CSS.styleSheetAdded', params: { header: { styleSheetId: 'css-1', frameId: frame.id, sourceURL: cssUrl, origin: 'regular', isInline: false } } })
|
|
listener({ sessionId: 'another-session', method: 'CSS.styleSheetAdded', params: { header: { styleSheetId: 'foreign-session', frameId: frame.id, sourceURL: cssUrl, origin: 'regular' } } })
|
|
}
|
|
if (method === 'CSS.getStyleSheetText') return { text: '.fixture { color: blue; }' }
|
|
return {}
|
|
}
|
|
}
|
|
const context = {
|
|
connection, sessionId: 'session-main', input,
|
|
target: { id: 'test', type: 'page', title: 'REA fixture', attached: null },
|
|
discovery: { version: { product: 'Fixture/1', protocol_version: '1.3', revision: 'fixture', user_agent: 'fixture', js_version: 'fixture' } }
|
|
}
|
|
const result = electronPageInspectionSchema.parse(await inspectCdpElectronPage(context))
|
|
assert.equal(result.styles.total, 1, 'foreign session events cannot be attributed to this target')
|
|
assert.equal(result.styles.items[0].source.artifact.text, '.fixture { color: blue; }')
|
|
assert.equal(result.styles.items[0].file_path, await fs.realpath(css))
|
|
assert.equal(result.styles.source_failures, 0)
|
|
assert.equal(result.styles.truncated, false)
|
|
assert.ok(calls.indexOf('DOM.enable') < calls.indexOf('CSS.enable'))
|
|
assert.equal(listener, undefined, 'capture listener is removed')
|
|
const evidence = createElectronEvidence('inspect_electron_page', input, result, { id: 'rea-cdp-electron', name: 'REA Electron file-page CDP observation provider', version: '1+css-local.1' })
|
|
assert.equal(evidence.parameters.include_style_sources, true)
|
|
assert.equal(evidence.normalized_result.styles.items.length, 1)
|
|
assert.match(evidence.evidence_id, /^ev_[a-f0-9]{64}$/)
|
|
calls.length = 0
|
|
const optedOut = electronPageInspectionSchema.parse(await inspectCdpElectronPage({ ...context, input: { ...input, include_style_sources: false } }))
|
|
assert.equal(optedOut.styles.items.length, 0)
|
|
assert.equal(calls.some(method => method.startsWith('CSS.') || method === 'DOM.enable'), false)
|
|
assert.equal(calls.some(method => method === 'Runtime.evaluate'), false)
|
|
console.log('REA CSS runtime contracts passed: opt-in, session attribution, schema retention, Evidence, and existing opt-out behavior')
|
|
} finally {
|
|
await fs.rm(fixture, { recursive: true, force: true })
|
|
}
|