A test file under packages/client now says which face it covers:
`*.client.spec.{ts,tsx}` and its `*.client.{ts,tsx}` helpers belong to the
Client aggregate, `*.host.spec.ts` to the host aggregate. The carrier's four
node-half specs take the Host suffix.
The two suffixes are mutually exclusive, so each aggregate excludes the
other's and both keep one broad test glob: `exclude` wins over `include`, and
`packages/client/**` no longer has to be excluded wholesale from the host
program with per-file `files` entries carved back out of it. A Host-face spec
that reaches only Host source therefore needs no cross-face project
reference, which the split-project rule rejects.
vitest still discovers every file through `**/*.spec.{ts,tsx}`.
48 lines
1.7 KiB
TypeScript
48 lines
1.7 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { cleanup, render } from '@testing-library/react'
|
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
import { OnboardingSurface } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
|
|
let appRoot: HTMLDivElement
|
|
|
|
beforeEach(() => {
|
|
appRoot = document.createElement('div')
|
|
appRoot.id = 'root'
|
|
document.body.appendChild(appRoot)
|
|
})
|
|
|
|
afterEach(() => {
|
|
cleanup()
|
|
appRoot.remove()
|
|
})
|
|
|
|
describe('OnboardingSurface', () => {
|
|
it('portals the overlay chrome to document.body around its content', () => {
|
|
const view = render(<OnboardingSurface><p>step content</p></OnboardingSurface>)
|
|
// Portaled: the overlay is a body child, not inside the render container.
|
|
expect(view.container.querySelector('[class*="onboardingOverlay"]')).toBeNull()
|
|
const overlay = document.body.querySelector('[class*="onboardingOverlay"]')
|
|
expect(overlay).not.toBeNull()
|
|
// The onboarding e2e pins the mask by class substring; the stage carries
|
|
// the content.
|
|
expect(overlay!.querySelector('[class*="onboardingMask"]')).not.toBeNull()
|
|
const stage = overlay!.querySelector('[class*="onboardingStage"]')
|
|
expect(stage).not.toBeNull()
|
|
expect(stage!.textContent).toBe('step content')
|
|
})
|
|
|
|
it('holds #root inert for exactly its own lifetime', () => {
|
|
const view = render(<OnboardingSurface>x</OnboardingSurface>)
|
|
expect(appRoot.inert).toBe(true)
|
|
view.unmount()
|
|
expect(appRoot.inert).toBe(false)
|
|
})
|
|
|
|
it('renders without an #root element (compositions that mount elsewhere)', () => {
|
|
appRoot.remove()
|
|
const view = render(<OnboardingSurface>x</OnboardingSurface>)
|
|
expect(document.body.querySelector('[class*="onboardingStage"]')!.textContent).toBe('x')
|
|
view.unmount()
|
|
})
|
|
})
|