diff --git a/scripts/check-text-newlines-browser.mjs b/scripts/check-text-newlines-browser.mjs index dc6b6f2..b0aeb5e 100644 --- a/scripts/check-text-newlines-browser.mjs +++ b/scripts/check-text-newlines-browser.mjs @@ -28,12 +28,16 @@ try { server = await createServer({ root, configFile: false, server: { host: '127.0.0.1', port: 0, strictPort: true }, - resolve: { alias: [ - { find: /^(?:.*\/)?primitive-adapter\.ts$/, replacement: resolve(root, 'src/client/standalone/primitive-adapter.tsx') }, - { find: /^react$/, replacement: resolve(root, 'node_modules/react/index.js') }, - { find: /^react\/jsx-runtime$/, replacement: resolve(root, 'node_modules/react/jsx-runtime.js') }, - { find: /^react-dom\/client$/, replacement: resolve(root, 'node_modules/react-dom/client.js') }, - ] }, + resolve: { + dedupe: ['react', 'react-dom'], + alias: [ + { find: /^(?:.*\/)?primitive-adapter\.ts$/, replacement: resolve(root, 'src/client/standalone/primitive-adapter.tsx') }, + ], + }, + optimizeDeps: { + include: ['react', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom', 'react-dom/client'], + force: true, + }, }) await server.listen() const address = server.httpServer.address() @@ -49,8 +53,21 @@ try { await writeFile(join(out, 'page.html'), stdout) await writeFile(join(out, 'browser.log'), stderr) const raw = /
([^<]*)<\/pre>/.exec(stdout)?.[1]
- if (raw === undefined || raw === 'pending') throw new Error('Browser fixture did not finish; inspect page.html and browser.log')
- const results = JSON.parse(raw.replaceAll('"', '"').replaceAll(''', "'").replaceAll('<', '<').replaceAll('>', '>').replaceAll('&', '&'))
+ const browserErrors = /([\s\S]*?)<\/pre>/.exec(stdout)?.[1]
+ /** 解码 Chromium dump-dom 输出的 HTML 文本。 */
+ const decodeBrowserText = value => value
+ .replaceAll('"', '"')
+ .replaceAll(''', "'")
+ .replaceAll('<', '<')
+ .replaceAll('>', '>')
+ .replaceAll('&', '&')
+ const errorSummary = browserErrors === undefined ? '' : decodeBrowserText(browserErrors).trim().slice(0, 2000)
+ if (raw === undefined || raw === 'pending') {
+ const detail = errorSummary === '' ? 'inspect page.html and browser.log' : `Browser errors:\n${errorSummary}`
+ throw new Error(`Browser fixture did not finish; ${detail}`)
+ }
+ if (errorSummary !== '') throw new Error(`Browser reported client errors:\n${errorSummary}`)
+ const results = JSON.parse(decodeBrowserText(raw))
await writeFile(join(out, 'results.json'), JSON.stringify(results, null, 2) + '\n')
if (results.length !== 118) throw new Error(`Expected 118 initial/repeated-control layout checks, got ${results.length}`)
const failed = results.filter(result => !result.pass)
diff --git a/tests/browser/text-newlines.html b/tests/browser/text-newlines.html
index d6327fc..43962d6 100644
--- a/tests/browser/text-newlines.html
+++ b/tests/browser/text-newlines.html
@@ -1 +1,21 @@
-Issues 249 and 280 browser regressions Browser layout regressions
pending
+Issues 249 and 280 browser regressions Browser layout regressions
pending
diff --git a/tests/browser/text-newlines.tsx b/tests/browser/text-newlines.tsx
index 06b98e2..6c683dc 100644
--- a/tests/browser/text-newlines.tsx
+++ b/tests/browser/text-newlines.tsx
@@ -1,5 +1,6 @@
/** Synthetic real-renderer regression for #249. No host or model service. */
import { createRoot } from 'react-dom/client'
+import { flushSync } from 'react-dom'
import { GenuiBlock } from '../../src/client/GenuiBlock.tsx'
import css from '../../src/client/GenuiBlock.module.css'
import { STANDALONE_THEME_CSS } from '../../src/client/artifact/standalone-theme.ts'
@@ -86,16 +87,24 @@ cases.push({
selector: '', expected: '', whiteSpace: '', detailWhitespace: true,
})
-createRoot(document.getElementById('root')!).render(
-
- {cases.map((item, index) => (
-
- {item.name}
-
-
- ))}
- ,
-)
+const root = createRoot(document.getElementById('root')!)
+flushSync(() => {
+ root.render(
+
+ {cases.map((item, index) => (
+
+ {item.name}
+
+
+ ))}
+ ,
+ )
+})
+
+const mountedFixtures = document.querySelectorAll('#fixtures > .case').length
+if (mountedFixtures !== cases.length) {
+ throw new Error(`React fixture mount incomplete: expected ${cases.length}, got ${mountedFixtures}`)
+}
/** Character ranges measure actual painted line boxes, including rich text. */
function measure(phase: string) {