chore: establish YCode replication baseline and TODO
This commit is contained in:
commit
6dc59f89ba
1118 files changed
+196002
No files matched your search
@@ -0,0 +1,124 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { isValidElement, type ReactElement, type ReactNode } from 'react'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { CopyButton, RecoveredCodeBlock, type RecoveredCodeBlockProps } from '../src/renderer/src/workbuddy/components/CodeBlock'
|
||||
|
||||
function hasClassToken(markup: string, token: string): boolean {
|
||||
return [...markup.matchAll(/class="([^"]*)"/g)]
|
||||
.some((match) => match[1].split(/\s+/).includes(token))
|
||||
}
|
||||
|
||||
function assertHasClass(markup: string, token: string): void {
|
||||
assert.ok(hasClassToken(markup, token), `expected class token ${token}`)
|
||||
}
|
||||
|
||||
function elementHasClass(element: ReactElement, token: string): boolean {
|
||||
const className = (element.props as { className?: string }).className ?? ''
|
||||
return className.split(/\s+/).includes(token)
|
||||
}
|
||||
|
||||
function findElement(node: ReactNode, predicate: (element: ReactElement) => boolean): ReactElement | null {
|
||||
if (!isValidElement(node)) return null
|
||||
if (predicate(node)) return node
|
||||
const children = (node.props as { children?: ReactNode }).children
|
||||
for (const child of Array.isArray(children) ? children : [children]) {
|
||||
const match = findElement(child, predicate)
|
||||
if (match) return match
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function testFileMetadataAndRenderedChildren(): void {
|
||||
const rawCode = 'const answer = 42\n'
|
||||
const renderedChild = (
|
||||
<code className="language-typescript">
|
||||
<span className="token keyword">const</span> answer = <span className="token number">42</span>
|
||||
</code>
|
||||
)
|
||||
const opened: Array<[string, number, number]> = []
|
||||
const props: RecoveredCodeBlockProps = {
|
||||
code: rawCode,
|
||||
language: 'typescript',
|
||||
fileMeta: {
|
||||
startLine: 12,
|
||||
endLine: 18,
|
||||
filePath: 'src/example.ts',
|
||||
fileName: 'example.ts',
|
||||
metaLanguage: 'typescript'
|
||||
},
|
||||
children: renderedChild,
|
||||
isRendering: false,
|
||||
onOpenFile: (path, start, end) => opened.push([path, start, end])
|
||||
}
|
||||
|
||||
const tree = RecoveredCodeBlock(props)
|
||||
const html = renderToStaticMarkup(tree)
|
||||
assertHasClass(html, 'cr-code-like-box')
|
||||
assertHasClass(html, 'cr-code-like-box__header')
|
||||
assertHasClass(html, 'cr-code-like-box__content')
|
||||
assertHasClass(html, 'cr-code-block__file-title')
|
||||
assertHasClass(html, 'cr-code-block__file-title--clickable')
|
||||
assertHasClass(html, 'cr-code-block__file-name')
|
||||
assertHasClass(html, 'cr-code-block__line-range')
|
||||
assert.match(html, /title="12:18:src\/example\.ts"/)
|
||||
assert.match(html, /example\.ts/)
|
||||
assert.match(html, /L12-L18/)
|
||||
assertHasClass(html, 'cr-code-block__pre')
|
||||
assert.match(html, /<pre\b[^>]*><code class="language-typescript">/)
|
||||
assertHasClass(html, 'token')
|
||||
assert.match(html, /class="token keyword"/)
|
||||
assert.doesNotMatch(html, /const answer = 42/)
|
||||
|
||||
const copy = findElement(tree, (element) => element.type === CopyButton)
|
||||
assert.ok(copy, 'code block should render the shared copy button')
|
||||
const copyProps = copy.props as { text: string; label?: string }
|
||||
assert.equal(copyProps.text, rawCode, 'copy should receive raw source text, not rendered children')
|
||||
assert.equal(copyProps.label, '复制')
|
||||
|
||||
const fileButton = findElement(tree, (element) =>
|
||||
element.type === 'button' &&
|
||||
elementHasClass(element, 'cr-code-block__file-title--clickable')
|
||||
)
|
||||
assert.ok(fileButton)
|
||||
;(fileButton.props as { onClick(): void }).onClick()
|
||||
assert.deepEqual(opened, [['src/example.ts', 12, 18]])
|
||||
}
|
||||
|
||||
function testLanguageFallbackAndNonClickableFile(): void {
|
||||
const fallbackHtml = renderToStaticMarkup(
|
||||
<RecoveredCodeBlock code="plain source" language="" />
|
||||
)
|
||||
assertHasClass(fallbackHtml, 'cr-code-block__language')
|
||||
assert.match(fallbackHtml, />plaintext<\/span>/)
|
||||
assertHasClass(fallbackHtml, 'cr-code-block__pre')
|
||||
assert.match(fallbackHtml, /<pre\b[^>]*>plain source<\/pre>/)
|
||||
|
||||
const metadata: NonNullable<RecoveredCodeBlockProps['fileMeta']> = {
|
||||
startLine: 3,
|
||||
endLine: 4,
|
||||
filePath: 'README.md',
|
||||
fileName: 'README.md'
|
||||
}
|
||||
const tree = RecoveredCodeBlock({ code: 'source', language: 'markdown', fileMeta: metadata })
|
||||
const html = renderToStaticMarkup(tree)
|
||||
assertHasClass(html, 'cr-code-block__file-title')
|
||||
assert.match(html, /title="3:4:README\.md"/)
|
||||
assert.equal(hasClassToken(html, 'cr-code-block__file-title--clickable'), false)
|
||||
assert.equal(findElement(tree, (element) => element.type === 'button' &&
|
||||
elementHasClass(element, 'cr-code-block__file-title')), null,
|
||||
'file metadata without an open callback should not be a fake clickable button')
|
||||
}
|
||||
|
||||
function testCopyButtonMarkup(): void {
|
||||
const html = renderToStaticMarkup(<CopyButton text="tool output" label="复制工具输出" className="tool-copy" />)
|
||||
assertHasClass(html, 'cr-code-block__copy-tooltip')
|
||||
assertHasClass(html, 'cr-code-block__copy-button')
|
||||
assertHasClass(html, 'tool-copy')
|
||||
assert.match(html, /aria-label="复制工具输出"/)
|
||||
assert.match(html, /title="复制工具输出"/)
|
||||
}
|
||||
|
||||
testFileMetadataAndRenderedChildren()
|
||||
testLanguageFallbackAndNonClickableFile()
|
||||
testCopyButtonMarkup()
|
||||
console.log('code-block-regression: all checks passed')
|
||||
Reference in new issue
Block a user