fix(B01): preserve question routing and nested disclosure state
This commit is contained in:
1 parent
21ca0e0fc3
commit
51531dcae8
15 files changed
+341
-55
No files matched your search
@@ -44,3 +44,32 @@ const expandedGrouped=renderToStaticMarkup(<CompletedFold parts={message.parts!}
|
||||
assert.deepEqual([...expandedGrouped.matchAll(/data-index="(\d+)"/g)].map(m=>Number(m[1])),[0,1,2,3,4,5])
|
||||
assert.deepEqual([...expandedGrouped.matchAll(/data-local-group="(\d+)"/g)].map(m=>Number(m[1])),[1,4],
|
||||
'opening completion must preserve independently controlled local summaries')
|
||||
|
||||
// A01: exercise the real native name through MessageBubble, not just its projection.
|
||||
const nativeQuestion = {...question, status: 'done' as const, tools: question.tools!.map(tool => ({...tool, output: 'RAW SDK ANSWER'}))}
|
||||
for (const name of ['AskUserQuestion', 'askuserquestion', 'ask_user_question', 'AskFollowupQuestion', 'ask-followup-question']) {
|
||||
const fixture = {...nativeQuestion, tools: nativeQuestion.tools.map(tool => ({...tool, name}))}
|
||||
const before = JSON.stringify(fixture)
|
||||
const markup = renderToStaticMarkup(<MessageBubble message={fixture}/>)
|
||||
assert.match(markup, /ask-user-question--completed/, `${name} routes to dedicated question card`)
|
||||
assert.doesNotMatch(markup, /RAW SDK ANSWER/, `${name} suppresses raw SDK answer`)
|
||||
assert.equal(JSON.stringify(fixture), before, 'rendering does not rewrite recorded names or metadata')
|
||||
}
|
||||
const ordinary = renderToStaticMarkup(<MessageBubble message={{...nativeQuestion, interactions: [], tools: [{...nativeQuestion.tools[0], name: 'CustomQuestionReporter', metadata: undefined}]}}/>)
|
||||
assert.doesNotMatch(ordinary, /ask-user-question--completed/)
|
||||
assert.match(ordinary, /RAW SDK ANSWER/, 'ordinary tools retain their raw output')
|
||||
console.log('A01 native MessageBubble identity aliases, immutable inputs and ordinary raw output passed')
|
||||
const importedNative = {...nativeQuestion, interactions: [], tools: nativeQuestion.tools.map(tool => ({...tool,
|
||||
args: {questions: [{id: 'q1', question: 'Imported native question'}]}, output: 'q1 -> imported answer', metadata: {importedHistory: true}
|
||||
}))}
|
||||
const importedMarkup = renderToStaticMarkup(<MessageBubble message={importedNative}/>)
|
||||
assert.match(importedMarkup, /ask-user-question--completed/)
|
||||
assert.equal(importedNative.tools[0].name, 'AskUserQuestion', 'historical display adaptation does not rewrite stored name')
|
||||
const duplicateMarkup = renderToStaticMarkup(<MessageBubble message={{...nativeQuestion, interactions: [...nativeQuestion.interactions!, ...nativeQuestion.interactions!]}}/>)
|
||||
assert.equal((duplicateMarkup.match(/ask-user-question--completed/g) || []).length, 1, 'linked answers have one dedicated card')
|
||||
const legacyNative = {...nativeQuestion, parts: undefined, tools: nativeQuestion.tools.map(tool => ({...tool, metadata: {questionAnswer: {questions: [{id: 'legacy', question: 'Unknown-position question', answers: ['legacy answer']}]}}})), interactions: []}
|
||||
const legacyNativeMarkup = renderToStaticMarkup(<MessageBubble message={legacyNative}/>)
|
||||
assert.match(legacyNativeMarkup, /历史问答(原始位置不可用)/)
|
||||
assert.equal((legacyNativeMarkup.match(/Unknown-position question/g) || []).length, 1)
|
||||
assert.doesNotMatch(legacyNativeMarkup, /RAW SDK ANSWER/)
|
||||
console.log('A01 imported native card, linked dedup and unknown-position compatibility passed')
|
||||
@@ -0,0 +1,68 @@
|
||||
/** Real nested React DOM components; deliberately no Electron, SDK, network, or layout claim. */
|
||||
import assert from 'node:assert/strict'
|
||||
import { createRequire } from 'node:module'
|
||||
const { JSDOM } = createRequire(process.cwd() + '/package.json')(process.env.YCODE_TEST_DOM_MODULE || 'jsdom')
|
||||
const dom = new JSDOM('<html><body><main id="root"></main></body></html>', { pretendToBeVisual: true, url: 'http://localhost/' })
|
||||
for (const key of ['window', 'document', 'Node', 'Element', 'HTMLElement', 'MouseEvent', 'KeyboardEvent', 'Event']) Object.defineProperty(globalThis, key, { value: dom.window[key], configurable: true })
|
||||
Object.defineProperty(globalThis, 'navigator', { value: dom.window.navigator, configurable: true })
|
||||
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true })
|
||||
const { act } = require('react') as typeof import('react')
|
||||
const { createRoot } = require('react-dom/client') as typeof import('react-dom/client')
|
||||
const { CompletedFold } = require('../src/renderer/src/workbuddy/conversation/CompletedFold') as typeof import('../src/renderer/src/workbuddy/conversation/CompletedFold')
|
||||
const { ToolGroup } = require('../src/renderer/src/workbuddy/conversation/ToolCall') as typeof import('../src/renderer/src/workbuddy/conversation/ToolCall')
|
||||
const { ToolCallRenderer } = require('../src/renderer/src/workbuddy/conversation/ToolCallRenderer') as typeof import('../src/renderer/src/workbuddy/conversation/ToolCallRenderer')
|
||||
const { ThinkingBlock, TaskBlock, PlanCreateBlock } = require('../src/renderer/src/workbuddy/conversation/SpecializedBlocks') as typeof import('../src/renderer/src/workbuddy/conversation/SpecializedBlocks')
|
||||
const root = createRoot(document.getElementById('root')!)
|
||||
const tool = (id: string) => ({ id, name: id === 'q' ? 'AskUserQuestion' : 'UnknownOrdinaryTool', status: 'executed' as const, args: { value: id }, result: 'RAW TOOL RESULT', metaData: id === 'q' ? { questionAnswer: { questions: [{ question: 'Choose?', answers: ['Yes'] }] } } : undefined })
|
||||
const initialParts = [{ type: 'reasoning', id: 'r', text: 'Thought' }, { type: 'tool', toolId: 't' }, { type: 'tool', toolId: 'q' }, { type: 'text', text: 'Answer' }, { type: 'reasoning', id: 'r2', text: 'Later thought' }, { type: 'tool', toolId: 't2' }, { type: 'tool', toolId: 'task' }, { type: 'tool', toolId: 'plan' }]
|
||||
function Fixture({ parts = initialParts, id = 'message-one', finished = true }: { parts?: typeof initialParts; id?: string; finished?: boolean }) {
|
||||
return <CompletedFold foldId={id} parts={parts} turnFinished={finished} classifyToolCall={part => part.toolId === 'q' ? { role: 'inline-question' } : undefined}
|
||||
renderGroup={(group, children) => <ToolGroup variant="summary" className={`group-${group.units[0].part.id || group.units[0].part.toolId}`} stats={{ toolCallCount: group.toolCallCount, messageCount: group.units.length, errorCount: 0 }}>{children}</ToolGroup>}
|
||||
renderUnit={part => part.type === 'tool' && part.toolId === 'task' ? <TaskBlock status="executed" data={{ finalResult: 'Task result', toolInfo: [] }} /> : part.type === 'tool' && part.toolId === 'plan' ? <PlanCreateBlock status="success" data={{ id: 'plan', name: 'Plan', todolist: [] }} /> : part.type === 'reasoning' ? <ThinkingBlock text={String(part.text)} isFinished /> : part.type === 'tool' ? <ToolCallRenderer tool={tool(String(part.toolId))} /> : <p>{String(part.text)}</p>} />
|
||||
}
|
||||
const get = (selector: string) => { const el = document.querySelector(selector); assert.ok(el, selector); return el }
|
||||
const expanded = (selector: string) => get(selector).getAttribute('aria-expanded')
|
||||
const outer = '.cr-collapse--completed > .cr-collapse__header'
|
||||
const question = '.ask-user-question__header .cr-tool-head__main'
|
||||
const ordinary = '[data-tool-call-id="t"] .cr-tool-head__main'
|
||||
const thinking = '.group-r .cr-reasoning > .cr-collapse__header'
|
||||
const group = '.group-r > .cr-collapse__header'
|
||||
const second = '.group-r2 > .cr-collapse__header'
|
||||
async function click(selector: string) { await act(async () => get(selector).dispatchEvent(new MouseEvent('click', { bubbles: true }))) }
|
||||
async function keyboard(selector: string, key: string) { await act(async () => get(selector).dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true, cancelable: true }))) }
|
||||
async function main() {
|
||||
await act(async () => root.render(<Fixture />))
|
||||
assert.equal(expanded(outer), 'false')
|
||||
await keyboard(outer, 'Enter')
|
||||
for (const selector of [group, thinking, ordinary, question]) { assert.equal(expanded(selector), 'false'); await click(selector); assert.equal(expanded(selector), 'true') }
|
||||
assert.equal(expanded(second), 'false', 'local summaries are independent')
|
||||
for (const selector of ['.cb-task-result-item-title', '.cb-plan-header-left']) { assert.equal(expanded(selector), 'true'); await click(selector); assert.equal(expanded(selector), 'false') }
|
||||
await keyboard(outer, ' ')
|
||||
const content = document.getElementById(get(outer).getAttribute('aria-controls')!)!
|
||||
assert.equal(content.getAttribute('aria-hidden'), 'true')
|
||||
assert.ok(content.hasAttribute('inert'), 'outer hidden descendants cannot receive focus')
|
||||
await keyboard(outer, 'Enter')
|
||||
for (const selector of [group, thinking, ordinary, question]) assert.equal(expanded(selector), 'true', `${selector} survives outer remount`)
|
||||
assert.equal(expanded(second), 'false')
|
||||
for (const selector of ['.cb-task-result-item-title', '.cb-plan-header-left']) assert.equal(expanded(selector), 'false', 'specialized tool choice retained')
|
||||
await click(ordinary)
|
||||
await act(async () => root.render(<Fixture parts={[...initialParts, { type: 'tool', toolId: 't3' }]} />))
|
||||
await click(outer); await click(outer)
|
||||
assert.equal(expanded(ordinary), 'false', 'explicit collapsed choice persists after later event')
|
||||
for (const selector of [group, thinking, question]) assert.equal(expanded(selector), 'true', `${selector} retained after later event`)
|
||||
assert.equal(expanded(second), 'false')
|
||||
assert.equal(document.querySelectorAll('.ask-user-question--completed').length, 1, 'no duplicated hidden content trees')
|
||||
await act(async () => root.render(<Fixture id="message-two" />))
|
||||
assert.equal(expanded(outer), 'false', 'message identity resets outer state')
|
||||
await click(outer)
|
||||
for (const selector of [group, thinking, ordinary, question]) assert.equal(expanded(selector), 'false', 'message identity isolates nested state')
|
||||
await act(async () => root.render(<Fixture id="live-message" finished={false} />))
|
||||
for (const selector of [group, thinking, ordinary, question]) await click(selector)
|
||||
await act(async () => root.render(<Fixture id="live-message" finished />))
|
||||
assert.equal(expanded(outer), 'false', 'completion starts folded after live events')
|
||||
await click(outer)
|
||||
for (const selector of [group, thinking, ordinary, question]) assert.equal(expanded(selector), 'true', `${selector} survives live-to-completed reparenting`)
|
||||
await act(async () => root.unmount()); dom.window.close()
|
||||
console.log('completed-fold-nested: real question/tool/thinking/local-summary remount, event, keyboard and identity contracts passed')
|
||||
}
|
||||
main().then(() => process.exit(0)).catch(error => { console.error(error); dom.window.close(); process.exit(1) })
|
||||
@@ -0,0 +1,61 @@
|
||||
/** B01 A04: structural/CSS and DOM contracts, not browser geometry or pixel acceptance. */
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import React, { act } from 'react'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import type { AskUserQuestionTool } from '../src/renderer/src/workbuddy/conversation/AskUserQuestion'
|
||||
import { AskUserQuestion } from '../src/renderer/src/workbuddy/conversation/AskUserQuestion'
|
||||
|
||||
const tool: AskUserQuestionTool = { name: 'AskUserQuestion', status: 'success', metadata: { questionAnswer: {
|
||||
questions: [{ id: 'q', question: 'Which runtime?', answers: ['Node.js'] }]
|
||||
} } }
|
||||
const markup = renderToStaticMarkup(<AskUserQuestion tool={tool} contentSettled={false} />)
|
||||
assert.match(markup, /cr-tool-head/)
|
||||
assert.match(markup, /cr-tool-exp__content ask-user-question__content/)
|
||||
assert.doesNotMatch(markup, /ask-user-question__(?:icon|arrow|title)/)
|
||||
const css = readFileSync('src/renderer/src/workbuddy/conversation/conversation.css', 'utf8')
|
||||
const recovered = readFileSync('src/renderer/src/workbuddy/conversation/tool-result-source.css', 'utf8')
|
||||
assert.match(css, /\.ask-user-question--completed \{ background: transparent; border: 0; border-radius: 0; padding: 2px 0; \}/)
|
||||
assert.match(css, /\.ask-user-question--completed \.ask-user-question__content \{ border: 0; \}/)
|
||||
// Contract is sourced from the checked-in REA-recovered ToolExpandable, not the old local 360px card.
|
||||
const contentRule = [...recovered.matchAll(/(?:^|})\.cr-tool-exp__content\{([^}]+)\}/g)].map(match => match[1]).join(';')
|
||||
for (const declaration of ['background:var(--cr-bg-primary-default,#2a2c31)', 'border-radius:16px', 'max-height:300px', 'padding:12px 16px', 'overflow:auto']) assert.ok(contentRule.includes(declaration), declaration)
|
||||
for (const kind of ['question', 'answer']) assert.match(css, new RegExp(`\\.question-answer-transcript__${kind} \\{[^}]*font-size: var\\(--yc-font-size-5\\); font-weight: 400; line-height: 1\\.75;`))
|
||||
console.log('question-answer-shell: structural and recovered CSS contracts passed')
|
||||
|
||||
async function main() {
|
||||
if (!process.env.YCODE_TEST_DOM_MODULE) {
|
||||
console.log('question-answer-shell: DOM checks NOT RUN (set YCODE_TEST_DOM_MODULE to an available jsdom module)')
|
||||
return
|
||||
}
|
||||
const { JSDOM } = createRequire(process.cwd() + '/package.json')(process.env.YCODE_TEST_DOM_MODULE || 'jsdom')
|
||||
const dom = new JSDOM('<html><body><main id="root"></main></body></html>', { pretendToBeVisual: true })
|
||||
for (const key of ['window', 'document', 'Node', 'Element', 'HTMLElement', 'MouseEvent', 'KeyboardEvent']) Object.defineProperty(globalThis, key, { value: dom.window[key], configurable: true })
|
||||
Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true })
|
||||
const root = createRoot(document.querySelector('#root')!)
|
||||
await act(async () => root.render(<AskUserQuestion tool={tool} contentSettled />))
|
||||
const header = document.querySelector<HTMLElement>('.ask-user-question__header [role="button"]')!
|
||||
const content = document.getElementById(header.getAttribute('aria-controls')!)!
|
||||
assert.ok(header)
|
||||
assert.equal(header.tabIndex, 0)
|
||||
assert.equal(header.getAttribute('aria-expanded'), 'false')
|
||||
assert.equal(content.getAttribute('aria-hidden'), 'true')
|
||||
assert.ok(content.hasAttribute('inert'))
|
||||
assert.equal(content.contains(header), false, 'title and toggle must be outside gray content')
|
||||
assert.equal(content.querySelectorAll('.question-answer-transcript__item').length, 1)
|
||||
for (const key of ['Enter', ' ']) {
|
||||
await act(async () => { header.dispatchEvent(new dom.window.KeyboardEvent('keydown', { key, bubbles: true, cancelable: true })) })
|
||||
assert.equal(header.getAttribute('aria-expanded'), key === 'Enter' ? 'true' : 'false')
|
||||
assert.equal(content.hasAttribute('inert'), key !== 'Enter')
|
||||
}
|
||||
await act(async () => header.click())
|
||||
assert.equal(header.getAttribute('aria-expanded'), 'true')
|
||||
assert.equal(content.getAttribute('aria-hidden'), 'false')
|
||||
assert.match(content.textContent!, /Which runtime\?Node.js/)
|
||||
await act(async () => root.unmount())
|
||||
dom.window.close()
|
||||
console.log('question-answer-shell: DOM hierarchy, controls linkage, click, Enter, Space and inert contracts passed')
|
||||
}
|
||||
main().then(() => process.exit(0)).catch(error => { console.error(error); process.exit(1) })
|
||||
@@ -0,0 +1,64 @@
|
||||
/** A01 real component DOM regression. Offline only; does not verify browser geometry or SDK execution. */
|
||||
import assert from 'node:assert/strict'
|
||||
import { createRequire } from 'node:module'
|
||||
import type { ChatMessage } from '../src/shared/types'
|
||||
const { JSDOM } = createRequire(process.cwd() + '/package.json')(process.env.YCODE_TEST_DOM_MODULE || 'jsdom')
|
||||
const dom = new JSDOM('<!doctype html><html><body><main id="root"></main></body></html>', {pretendToBeVisual:true,url:'http://localhost/'})
|
||||
for (const key of ['window','document','Node','Element','HTMLElement','MouseEvent','KeyboardEvent','Event']) Object.defineProperty(globalThis,key,{value:dom.window[key],configurable:true})
|
||||
Object.defineProperty(globalThis,'navigator',{value:dom.window.navigator,configurable:true})
|
||||
Object.assign(globalThis,{IS_REACT_ACT_ENVIRONMENT:true})
|
||||
const React = require('react') as typeof import('react')
|
||||
const {act} = React
|
||||
const {createRoot} = require('react-dom/client') as typeof import('react-dom/client')
|
||||
const MessageBubble = require('../src/renderer/src/components/MessageBubble').default as typeof import('../src/renderer/src/components/MessageBubble').default
|
||||
const root = createRoot(document.getElementById('root')!)
|
||||
const click = (el: Element) => el.dispatchEvent(new MouseEvent('click',{bubbles:true}))
|
||||
const answer = {questions:[{id:'q1',question:'Choose a unique option',answers:['Unique answer']}]}
|
||||
const base: ChatMessage = {id:'native-question',role:'assistant',createdAt:1,content:'Final prose',status:'done',parts:[{type:'tool',toolId:'q'},{type:'text',text:'Final prose'}],tools:[{id:'q',name:'AskUserQuestion',args:{questions:[{id:'q1',question:'Choose a unique option'}]},argsRaw:'{}',status:'ok',output:'RAW SDK ANSWER'}],interactions:[{id:'i',runId:'r',kind:'question',toolCallId:'q',title:'Question',questions:[],status:'answered',answer}]}
|
||||
let checks=0
|
||||
const check=(condition:unknown,label:string)=>{assert.ok(condition,label);checks++}
|
||||
async function main(){
|
||||
for (const name of ['AskUserQuestion','askuserquestion','ask_user_question']) {
|
||||
const fixture={...base,tools:base.tools!.map(tool=>({...tool,name})),interactions:[...base.interactions!,...base.interactions!]}
|
||||
const before=JSON.stringify(fixture)
|
||||
await act(async()=>root.render(<MessageBubble key={name} message={fixture}/>))
|
||||
check(!document.body.textContent!.includes('RAW SDK ANSWER'),`${name}: no raw answer`)
|
||||
await act(async()=>click(document.querySelector('.cr-collapse--completed > .cr-collapse__header')!))
|
||||
check(document.querySelectorAll('.ask-user-question--completed').length===1,`${name}: linked duplicate interactions produce one question card`)
|
||||
await act(async()=>click(document.querySelector('.ask-user-question__header .cr-tool-head__main')!))
|
||||
check(document.querySelector('.ask-user-question__header .cr-tool-head__main')?.getAttribute('aria-expanded')==='true',`${name}: answered card actually expanded`)
|
||||
check(document.querySelectorAll('.question-answer-transcript__question').length===1,`${name}: expanded answer occurs exactly once`)
|
||||
check(document.body.textContent!.includes('Choose a unique option') && document.body.textContent!.includes('Unique answer'),`${name}: question and answer visible`)
|
||||
check(JSON.stringify(fixture)===before,`${name}: recorded source unchanged`)
|
||||
}
|
||||
// Native SDK identity throughout pending → answered → completed → outer toggle.
|
||||
const pending: ChatMessage={...base,status:'streaming',parts:[{type:'tool',toolId:'q'}],interactions:[],tools:base.tools!.map(tool=>({...tool,status:'running',output:undefined}))}
|
||||
await act(async()=>root.render(<MessageBubble key="lifecycle" message={pending}/>))
|
||||
check(!!document.querySelector('.ask-user-question--pending'),'native pending question uses specialized renderer')
|
||||
await act(async()=>root.render(<MessageBubble key="lifecycle" message={{...base,status:'streaming'}}/>))
|
||||
check(!!document.querySelector('.ask-user-question--completed'),'native answered question uses transcript while turn runs')
|
||||
await act(async()=>root.render(<MessageBubble key="lifecycle" message={base}/>))
|
||||
const outer=()=>document.querySelector('.cr-collapse--completed > .cr-collapse__header')!
|
||||
await act(async()=>click(outer()))
|
||||
const header=()=>document.querySelector('.ask-user-question__header .cr-tool-head__main')!
|
||||
if(header().getAttribute('aria-expanded')!=='true') await act(async()=>click(header()))
|
||||
await act(async()=>click(outer()));await act(async()=>click(outer()))
|
||||
check(header().getAttribute('aria-expanded')==='true','native answered choice survives completed outer collapse/reopen')
|
||||
check(!document.body.textContent!.includes('RAW SDK ANSWER'),'native lifecycle never leaks raw SDK answer')
|
||||
const imported={...base,interactions:[],tools:base.tools!.map(tool=>({...tool,output:'q1 -> Unique answer',metadata:{importedHistory:true}}))}
|
||||
await act(async()=>root.render(<MessageBubble key="imported" message={imported}/>))
|
||||
await act(async()=>click(document.querySelector('.cr-collapse--completed > .cr-collapse__header')!))
|
||||
await act(async()=>click(document.querySelector('.ask-user-question__header .cr-tool-head__main')!))
|
||||
check(document.body.textContent!.includes('Unique answer'),'historical native name and answer-text adaptation preserved')
|
||||
check(imported.tools[0].name==='AskUserQuestion','historical stored name unchanged')
|
||||
for (const interactions of [base.interactions, []]) {
|
||||
const legacy={...base,parts:undefined,interactions,tools:base.tools!.map(tool=>({...tool,metadata:{questionAnswer:answer}}))}
|
||||
await act(async()=>root.render(<MessageBubble key={`legacy-${interactions?.length}`} message={legacy}/>))
|
||||
check(document.querySelector('.question-history-unpositioned')?.getAttribute('aria-label')==='历史问答(原始位置不可用)','missing recorded position remains explicitly unknown')
|
||||
check(document.querySelectorAll('.question-answer-transcript__question').length===1,'unknown-position metadata and interaction do not duplicate')
|
||||
check(!document.body.textContent!.includes('RAW SDK ANSWER'),'unknown-position raw duplicate suppressed')
|
||||
}
|
||||
await act(async()=>root.unmount());dom.window.close()
|
||||
console.log(`question-identity: ${checks} A01 DOM checks passed (not Electron/pixel/SDK acceptance)`)
|
||||
}
|
||||
main().then(() => process.exit(0)).catch(error=>{console.error(error);process.exit(1)})
|
||||
@@ -3,7 +3,7 @@ import { build } from 'esbuild'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
const tests = [
|
||||
'model-selection-alignment-regression.ts', 'model-settings-alignment-regression.ts', 'session-factory-alignment-regression.ts',
|
||||
'session-composer-alignment-regression.tsx', 'alignment-conversation-regression.tsx',
|
||||
'session-composer-alignment-regression.tsx', 'alignment-conversation-regression.tsx', 'question-answer-shell-regression.tsx',
|
||||
'runtime-authorization-regression.ts', 'permission-intercept-regression.tsx'
|
||||
]
|
||||
for (const file of tests) {
|
||||
@@ -24,7 +24,7 @@ for (const file of ['scripts/build-runtime-regressions.mjs', '.tmp/claude-approv
|
||||
|
||||
// Optional DOM tests use separately installed jsdom, not Electron/CLI or an upstream model.
|
||||
if (process.env.YCODE_TEST_DOM_MODULE) {
|
||||
for (const file of ['task-popconfirm-regression', 'question-interaction-regression', 'permission-intercept-dom-regression']) {
|
||||
for (const file of ['task-popconfirm-regression', 'question-interaction-regression', 'question-identity-regression', 'completed-fold-nested-regression', 'permission-intercept-dom-regression']) {
|
||||
const outfile = `.tmp/alignment-tests/${file}.cjs`
|
||||
await build({ entryPoints: [`scripts/${file}.tsx`], outfile, bundle: true, platform: 'node', format: 'cjs', jsx: 'automatic', loader: { '.css': 'empty' }, logLevel: 'warning' })
|
||||
const result = spawnSync(process.execPath, [outfile], { stdio: 'inherit', timeout: 120000 })
|
||||
|
||||
Reference in new issue
Block a user