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

+102
View File
@@ -0,0 +1,102 @@
// Exercise the actual YCode WebContentsView host against a loopback-only HTTP server.
if (!process.versions.electron) {
const path = require('node:path')
require('esbuild').buildSync({ entryPoints: ['src/main/browser-host.ts'], platform: 'node', format: 'cjs', bundle: true,
external: ['electron'], outfile: '.tmp/browser-host-test-module.cjs', logLevel: 'silent' })
require('esbuild').buildSync({ entryPoints: ['src/shared/browser-host.ts'], platform: 'node', format: 'cjs', bundle: true,
outfile: '.tmp/browser-host-contract.cjs', logLevel: 'silent' })
const env = { ...process.env }
delete env.ELECTRON_RUN_AS_NODE
const result = require('node:child_process').spawnSync(require('electron'), [__filename], { env, windowsHide: true, stdio: 'inherit', timeout: 60000 })
process.exitCode = result.status ?? 1
} else {
const { app, BrowserWindow, WebContentsView } = require('electron')
const assert = require('node:assert/strict')
const path = require('node:path')
const http = require('node:http')
app.setPath('userData', path.resolve('.tmp/browser-host-regression-data'))
app.disableHardwareAcceleration()
const server = http.createServer((req, res) => {
const page = req.url === '/b' ? 'B' : 'A'
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
res.end(`<html><head><title>Local ${page}</title></head><body>Local ${page}<a href="/b">Next</a></body></html>`)
})
let owner, other
async function waitFor(check, label) {
for (let attempt = 0; attempt < 200; attempt++) { if (await check()) return; await new Promise(resolve => setTimeout(resolve, 25)) }
throw Error('Browser condition timed out: ' + label)
}
app.whenReady().then(async () => {
const host = require(path.resolve('.tmp/browser-host-test-module.cjs'))
const contract = require(path.resolve('.tmp/browser-host-contract.cjs'))
assert.equal(contract.normalizeBrowserAddressInput('127.0.0.1:1234/a'), 'http://127.0.0.1:1234/a')
assert.equal(contract.normalizeBrowserAddressInput('example.com'), 'https://example.com/')
assert.equal(contract.normalizeBrowserAddressInput('hello world'), 'https://www.sogou.com/web?query=hello%20world')
assert.throws(() => contract.normalizeBrowserHostUrl('https://user:secret@example.com'), /仅支持/)
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve))
const base = `http://127.0.0.1:${server.address().port}`
owner = new BrowserWindow({ width: 800, height: 600, show: false, webPreferences: { sandbox: true, nodeIntegration: false, contextIsolation: true } })
other = new BrowserWindow({ width: 800, height: 600, show: false })
const first = host.createBrowser(owner, 'task-a')
const second = host.createBrowser(owner, 'task-b')
const result = await host.navigateBrowser(owner, first.id, base + '/a', 'task-a')
assert.equal(result.title, 'Local A')
assert.equal(result.error, undefined)
assert.throws(() => host.getBrowserState(owner, first.id, 'task-b'), /不属于/)
assert.throws(() => host.getBrowserState(other, first.id, 'task-a'), /不属于/)
assert.throws(() => host.getBrowserState(owner, first.id), /不属于/)
await assert.rejects(() => host.navigateBrowser(owner, first.id, 'file:///C:/Windows/win.ini', 'task-a'), /仅支持/)
await assert.rejects(() => host.navigateBrowser(owner, first.id, 'javascript:alert(1)', 'task-a'), /仅支持/)
assert.equal(host.getBrowserState(owner, first.id, 'task-a').url, base + '/a')
const views = owner.contentView.children.filter(view => view instanceof WebContentsView)
assert.equal(views.length, 2)
const primary = views.find(view => view.webContents.getURL() === base + '/a')
const secondary = views.find(view => view !== primary)
const secondaryContents = secondary.webContents
const prefs = primary.webContents.getLastWebPreferences()
assert.equal(prefs.sandbox, true); assert.equal(prefs.nodeIntegration, false); assert.equal(prefs.contextIsolation, true)
assert.ok(!prefs.preload)
assert.equal(await primary.webContents.executeJavaScript('typeof require'), 'undefined')
assert.equal(await primary.webContents.executeJavaScript('typeof process'), 'undefined')
assert.equal(await primary.webContents.executeJavaScript('Notification.requestPermission()'), 'denied')
await primary.webContents.session.cookies.set({ url: base, name: 'isolation', value: 'private-to-first' })
assert.equal((await secondary.webContents.session.cookies.get({ url: base, name: 'isolation' })).length, 0)
host.setBrowserBounds(owner, first.id, { x: -20, y: 50, width: 2000, height: 2000 }, 'task-a')
const [width, height] = owner.getContentSize()
assert.deepEqual(primary.getBounds(), { x: 0, y: 50, width, height: height - 50 })
assert.equal(host.getBrowserState(owner, first.id, 'task-a').visible, true)
assert.throws(() => host.setBrowserBounds(owner, first.id, { x: .5, y: 0, width: 10, height: 10 }, 'task-a'), /整数/)
host.hideBrowser(owner, first.id, 'task-a')
assert.equal(host.getBrowserState(owner, first.id, 'task-a').visible, false)
await host.navigateBrowser(owner, first.id, base + '/b', 'task-a')
assert.equal(host.getBrowserState(owner, first.id, 'task-a').canGoBack, true)
host.backBrowser(owner, first.id, 'task-a')
await waitFor(() => host.getBrowserState(owner, first.id, 'task-a').title === 'Local A' && !host.getBrowserState(owner, first.id, 'task-a').loading, 'back to A')
assert.equal(host.getBrowserState(owner, first.id, 'task-a').canGoForward, true)
host.forwardBrowser(owner, first.id, 'task-a')
await waitFor(() => host.getBrowserState(owner, first.id, 'task-a').title === 'Local B' && !host.getBrowserState(owner, first.id, 'task-a').loading, 'forward to B')
host.reloadBrowser(owner, first.id, 'task-a')
await waitFor(() => !host.getBrowserState(owner, first.id, 'task-a').loading, 'reload')
await primary.webContents.executeJavaScript(`window.open(${JSON.stringify(base + '/a')}, '_blank'); undefined`)
await waitFor(() => host.getBrowserState(owner, first.id, 'task-a').title === 'Local A', 'popup stays in owned browser')
assert.equal(BrowserWindow.getAllWindows().length, 2)
host.closeBrowser(owner, first.id, 'task-a')
assert.throws(() => host.getBrowserState(owner, first.id, 'task-a'), /不存在/)
const draft = host.createBrowser(owner)
assert.throws(() => host.rebindBrowser(other, draft.id, undefined, 'created-session'), /不属于/)
const rebound = host.rebindBrowser(owner, draft.id, undefined, 'created-session')
assert.equal(rebound.sessionId, 'created-session')
assert.equal(rebound.id, draft.id)
assert.throws(() => host.getBrowserState(owner, draft.id), /不属于/)
assert.equal(host.getBrowserState(owner, draft.id, 'created-session').sessionId, 'created-session')
host.closeBrowser(owner, draft.id, 'created-session')
owner.destroy()
await waitFor(() => secondaryContents.isDestroyed(), 'owner closes child browser')
assert.throws(() => host.getBrowserState(owner, second.id, 'task-b'), /不存在/)
console.log('Actual Electron browser host: loopback navigation/back/forward/reload, sandbox, cookie/window/session isolation, bounds, popup routing and lifecycle passed')
}).catch(error => { console.error(error); process.exitCode = 1 }).finally(() => {
if (owner && !owner.isDestroyed()) owner.destroy()
if (other && !other.isDestroyed()) other.destroy()
server.close(() => app.exit(process.exitCode || 0))
})
}