// Native YCode-only fixture check against the saved REA same-state homepage layout. const fs = require('node:fs') const path = require('node:path') const assert = require('node:assert/strict') const { app, BrowserWindow } = require('electron') app.disableHardwareAcceleration() const root = path.resolve(__dirname, '..') const output = path.join(root, '.tmp', 'home-style-parity-20261016') assert.ok(output.startsWith(path.join(root, '.tmp') + path.sep)) fs.mkdirSync(output, { recursive: true }) app.setPath('userData', path.join(output, 'user-data')) const evidence = JSON.parse(fs.readFileSync(path.join(root, '.tmp/rea-home-static-20261016/layout.json'), 'utf8')) const sourceNodes = evidence.layout.documents[0].nodes const source = index => sourceNodes.find(node => node.node_index === index) const selectors = ['.wb-home-header__title', '.quick-actions__item', '.wb-scene-tabs', '.wb-home-composer__input-slot', '.wb-composer__surface', '.cr-input-container'] const properties = ['font-family', 'font-size', 'font-weight', 'line-height', 'color', 'border-top-color', 'box-shadow', 'padding-top', 'gap'] app.whenReady().then(async () => { await require('esbuild').build({ entryPoints: [path.join(root, '.tmp/source-home-fixture.tsx')], bundle: true, outfile: path.join(output, 'fixture.js'), platform: 'browser', format: 'iife', jsx: 'automatic', loader: { '.png': 'file', '.woff2': 'file' }, logLevel: 'warning' }) // Same fixed viewport/main-content coordinates as the previous fixture. fs.writeFileSync(path.join(output, 'index.html'), fs.readFileSync(path.join(root, '.tmp/home-native-ui/index.html'))) const win = new BrowserWindow({ width: 1336, height: 901, useContentSize: true, frame: false, show: false, webPreferences: { contextIsolation: true, nodeIntegration: false, backgroundThrottling: false, offscreen: true } }) const errors = [] win.webContents.on('console-message', (_event, level, message) => { if (level === 3) errors.push(message) }) await win.loadFile(path.join(output, 'index.html')) await new Promise(resolve => setTimeout(resolve, 1350)) const measure = () => win.webContents.executeJavaScript(`(${function (selectors, properties) { return selectors.flatMap(selector => Array.from(document.querySelectorAll(selector), (el, index) => { const r = el.getBoundingClientRect(), s = getComputedStyle(el) return { selector, index, text: el.textContent, bounds: [r.x, r.y, r.width, r.height], focused: el.matches(':focus-within'), styles: Object.fromEntries(properties.map(key => [key, s.getPropertyValue(key)])) } })) }.toString()})(${JSON.stringify(selectors)},${JSON.stringify(properties)})`) const unfocused = await measure() win.webContents.debugger.attach('1.3') // Own app only: real native pointer events put the textarea in the source focus state. for (const type of ['mousePressed', 'mouseReleased']) await win.webContents.debugger.sendCommand('Input.dispatchMouseEvent', { type, x: 500, y: 395, button: 'left', clickCount: 1 }) await win.webContents.capturePage() await new Promise(resolve => setTimeout(resolve, 250)) const focused = await measure() fs.writeFileSync(path.join(output, 'focused.png'), (await win.webContents.capturePage()).toPNG()) const find = (selector, index = 0) => focused.find(node => node.selector === selector && node.index === index) const title = find('.wb-home-header__title'), ppt = find('.quick-actions__item', 3) const container = find('.cr-input-container'), outer = find('.wb-composer__surface') const checks = { titleSize: title.bounds.slice(2), titleColor: title.styles.color, pptWidth: ppt.bounds[2], chipsFont: ppt.styles['font-family'], chipsLineHeight: ppt.styles['line-height'], focused: container.focused, focusedShadow: container.styles['box-shadow'], focusedBorder: container.styles['border-top-color'], outerShadow: outer.styles['box-shadow'], xDeltaDueToUnchangedFixtureSidebar: title.bounds[0] - source(791).bounds[0], errors, } fs.writeFileSync(path.join(output, 'report.json'), JSON.stringify({ evidenceId: evidence.evidenceId, capturedAt: new Date().toISOString(), checks, unfocused, focused, scope: 'Fresh YCode fixture bundle; source work scene and real pointer focus; sidebar width and data remain fixture-owned.', }, null, 2)) assert.deepEqual(checks.titleSize, source(791).bounds.slice(2)) assert.equal(checks.titleColor, source(791).styles.color) assert.equal(checks.pptWidth, source(833).bounds[2]) assert.equal(checks.chipsFont, source(833).styles['font-family']) assert.equal(checks.chipsLineHeight, source(833).styles['line-height']) for (let index = 0; index < 7; index += 1) { const chip = find('.quick-actions__item', index), original = source(827 + index * 2) assert.deepEqual(chip.bounds.slice(1), original.bounds.slice(1)) assert.equal(chip.bounds[0] - original.bounds[0], -2.125) for (const property of ['font-family', 'font-size', 'font-weight', 'line-height']) { assert.equal(chip.styles[property], original.styles[property]) } } const beforeFocus = unfocused.find(node => node.selector === '.cr-input-container') assert.equal(beforeFocus.focused, false) assert.notEqual(beforeFocus.styles['box-shadow'], checks.focusedShadow) assert.equal(checks.focused, true) assert.equal(checks.focusedShadow, source(848).styles['box-shadow']) assert.equal(checks.focusedBorder, source(848).styles['border-top-color']) assert.equal(checks.outerShadow, source(845).styles['box-shadow']) assert.equal(checks.xDeltaDueToUnchangedFixtureSidebar, -2.125) for (const [selector, index] of [['.wb-scene-tabs', 795], ['.wb-home-composer__input-slot', 841], ['.cr-input-container', 848]]) { const node = find(selector), original = source(index) assert.deepEqual(node.bounds.slice(1), original.bounds.slice(1)) } assert.deepEqual(errors, []) win.webContents.debugger.detach() win.destroy() console.log(JSON.stringify({ status: 'PASS', output, checks })) app.quit() }).catch(error => { console.error(error); app.exit(1) })