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
@@ -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) })
|
||||
Reference in new issue
Block a user