test(web): pin the assembled snapshot lane's locale through the browser
The assembled Web snapshot lane selected its locale with a `dsh.locale` localStorage key. That key stopped selecting anything once the locale preference moved to the Host settings document, so the image-display scenario's Chinese expectations met the English default and failed. Pin the navigator languages the boot env already documents, and state the image-display expectations in the lane's English copy — the fixture session title stays Chinese because it is fixture data, not product copy.
This commit is contained in:
@@ -70,7 +70,12 @@ let unmount: (() => void) | undefined
|
|||||||
export function installAssembledBootEnv(): void {
|
export function installAssembledBootEnv(): void {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
localStorage.clear()
|
localStorage.clear()
|
||||||
localStorage.setItem('dsh.locale', 'en')
|
// The locale service derives its provisional locale from the browser and
|
||||||
|
// takes an explicit choice only from Host settings, which this lane's
|
||||||
|
// fixture transport does not serve; pinning the navigator is what selects
|
||||||
|
// English here.
|
||||||
|
Object.defineProperty(navigator, 'languages', { value: ['en-US'], configurable: true })
|
||||||
|
Object.defineProperty(navigator, 'language', { value: 'en-US', configurable: true })
|
||||||
document.title = 'DeepSeek Harness'
|
document.title = 'DeepSeek Harness'
|
||||||
vi.stubGlobal('ResizeObserver', ResizeObserverStub)
|
vi.stubGlobal('ResizeObserver', ResizeObserverStub)
|
||||||
vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) =>
|
vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) =>
|
||||||
@@ -88,6 +93,11 @@ export function installAssembledBootEnv(): void {
|
|||||||
document.head.querySelectorAll('style[data-plugin]').forEach((style) => { style.remove() })
|
document.head.querySelectorAll('style[data-plugin]').forEach((style) => { style.remove() })
|
||||||
document.title = ''
|
document.title = ''
|
||||||
history.replaceState(null, '', '/')
|
history.replaceState(null, '', '/')
|
||||||
|
// Deleting the own properties uncovers jsdom's own accessors again
|
||||||
|
// (Navigator declares both readonly, hence the erased receiver).
|
||||||
|
const ownNavigator = navigator as unknown as Record<string, unknown>
|
||||||
|
delete ownNavigator.languages
|
||||||
|
delete ownNavigator.language
|
||||||
vi.unstubAllGlobals()
|
vi.unstubAllGlobals()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ installAssembledBootEnv()
|
|||||||
|
|
||||||
/** Open the fixture history session (the alpha log carrying the turn-72 image pair) and wait for its gallery. */
|
/** Open the fixture history session (the alpha log carrying the turn-72 image pair) and wait for its gallery. */
|
||||||
async function openFixtureSession(): Promise<void> {
|
async function openFixtureSession(): Promise<void> {
|
||||||
const tree = await screen.findByRole('tree', { name: '会话' }, { timeout: 10_000 })
|
const tree = await screen.findByRole('tree', { name: 'Sessions' }, { timeout: 10_000 })
|
||||||
const group = (await within(tree).findAllByText('fixture'))
|
const group = (await within(tree).findAllByText('fixture'))
|
||||||
.map(el => el.closest<HTMLElement>('[role="treeitem"]'))
|
.map(el => el.closest<HTMLElement>('[role="treeitem"]'))
|
||||||
.find(el => el?.getAttribute('aria-expanded') !== null)
|
.find(el => el?.getAttribute('aria-expanded') !== null)
|
||||||
@@ -33,7 +33,6 @@ async function openFixtureSession(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('renders the history image pair through the authorized attachment route and opens the lightbox', async () => {
|
it('renders the history image pair through the authorized attachment route and opens the lightbox', async () => {
|
||||||
localStorage.setItem('dsh.locale', 'zh')
|
|
||||||
mountAssembledApp()
|
mountAssembledApp()
|
||||||
await openFixtureSession()
|
await openFixtureSession()
|
||||||
|
|
||||||
@@ -73,24 +72,23 @@ it('renders the history image pair through the authorized attachment route and o
|
|||||||
fireEvent.doubleClick(frame)
|
fireEvent.doubleClick(frame)
|
||||||
const lightbox = await screen.findByRole('dialog')
|
const lightbox = await screen.findByRole('dialog')
|
||||||
expect(within(lightbox).getByRole('img').getAttribute('src')?.split(':')[0]).toBe('blob')
|
expect(within(lightbox).getByRole('img').getAttribute('src')?.split(':')[0]).toBe('blob')
|
||||||
fireEvent.click(within(lightbox).getByRole('button', { name: /关闭/ }))
|
fireEvent.click(within(lightbox).getByRole('button', { name: /Close/ }))
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.queryByRole('dialog')).toBeNull()
|
expect(screen.queryByRole('dialog')).toBeNull()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('accepts pasted images into the composer rail in order and removes them', async () => {
|
it('accepts pasted images into the composer rail in order and removes them', async () => {
|
||||||
localStorage.setItem('dsh.locale', 'zh')
|
|
||||||
mountAssembledApp()
|
mountAssembledApp()
|
||||||
|
|
||||||
const tree = await screen.findByRole('tree', { name: '会话' }, { timeout: 10_000 })
|
const tree = await screen.findByRole('tree', { name: 'Sessions' }, { timeout: 10_000 })
|
||||||
const start = tree.querySelector<HTMLButtonElement>('button[aria-label="在“fixture”中新建会话"]')
|
const start = tree.querySelector<HTMLButtonElement>('button[aria-label="New session in fixture"]')
|
||||||
if (start === null) throw new Error('fixture Workspace new-session action missing')
|
if (start === null) throw new Error('fixture Workspace new-session action missing')
|
||||||
fireEvent.click(start)
|
fireEvent.click(start)
|
||||||
|
|
||||||
// Image-only send arming is pinned at package level (input-bar.spec.tsx);
|
// Image-only send arming is pinned at package level (input-bar.spec.tsx);
|
||||||
// this assembled lane pins the intake chain over the built graph.
|
// this assembled lane pins the intake chain over the built graph.
|
||||||
const textarea = await screen.findByPlaceholderText('描述你想要构建的内容', {}, { timeout: 10_000 })
|
const textarea = await screen.findByPlaceholderText('Describe what you want to build', {}, { timeout: 10_000 })
|
||||||
const image = new File([new Uint8Array([137, 80, 78, 71])], 'pasted.png', { type: 'image/png' })
|
const image = new File([new Uint8Array([137, 80, 78, 71])], 'pasted.png', { type: 'image/png' })
|
||||||
fireEvent.paste(textarea, {
|
fireEvent.paste(textarea, {
|
||||||
clipboardData: {
|
clipboardData: {
|
||||||
@@ -102,7 +100,7 @@ it('accepts pasted images into the composer rail in order and removes them', asy
|
|||||||
// The rail is an accessible group holding the draft thumbnail (queried via
|
// The rail is an accessible group holding the draft thumbnail (queried via
|
||||||
// DOM: jsdom's a11y-visibility computation hides the composer subtree).
|
// DOM: jsdom's a11y-visibility computation hides the composer subtree).
|
||||||
const rail = await waitFor(() => {
|
const rail = await waitFor(() => {
|
||||||
const el = document.querySelector('[role="group"][aria-label="待发送图片"]')
|
const el = document.querySelector('[role="group"][aria-label="Pending images"]')
|
||||||
if (el === null) throw new Error('attachment rail missing')
|
if (el === null) throw new Error('attachment rail missing')
|
||||||
return el
|
return el
|
||||||
}, { timeout: 5_000 })
|
}, { timeout: 5_000 })
|
||||||
@@ -129,10 +127,10 @@ it('accepts pasted images into the composer rail in order and removes them', asy
|
|||||||
.toEqual(['pasted.png', 'second.png'])
|
.toEqual(['pasted.png', 'second.png'])
|
||||||
})
|
})
|
||||||
|
|
||||||
const remove = [...rail.querySelectorAll('button[aria-label^="移除图片"]')]
|
const remove = [...rail.querySelectorAll('button[aria-label^="Remove image"]')]
|
||||||
if (remove.length !== 2) throw new Error('remove buttons missing')
|
if (remove.length !== 2) throw new Error('remove buttons missing')
|
||||||
for (const button of remove) fireEvent.click(button)
|
for (const button of remove) fireEvent.click(button)
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(document.querySelector('[role="group"][aria-label="待发送图片"]')).toBeNull()
|
expect(document.querySelector('[role="group"][aria-label="Pending images"]')).toBeNull()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user