chore: establish YCode replication baseline and TODO

This commit is contained in:
xiaohan.yuan committed 2026-10-17 02:43:49 +08:00
commit 6dc59f89ba
1118 files changed
+196002

No files matched your search

+91
View File
@@ -0,0 +1,91 @@
// 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) })