Files
deepseek-harness/packages/client/ui-primitives/tests/switch.client.spec.tsx
T
Yichen Jiang 452b2a816a refactor(client): share the capsule tag, switch, and idle state dot
Client feature plugins never import one another's components, so
ui-primitives is their only channel for sharing one. Nothing told an
author to look there first, and the package offered nothing to look
at: its README named six source files against forty-plus exports.

Add Tag (read-only capsule badge, eight tones) and Switch (36x20
toggle with a required accessible name), extend StateDotState with
idle for a tracked subject with no activity, and move ui-agent-preset,
ui-settings-plugins, and ui-settings-plugin-inventory onto them.

The plugin inventory's conditional tag referenced
--dsw-alias-state-warning-primary, which does not exist, so both
themes had been painting its hardcoded #b45309 fallback.

State the reuse rule as the first step of the new-component checklist,
and give the README a component catalog so the rule has something to
check. The rule is guidance, not a gate: a package may still write its
own control, and the Agent Note records the five that stay local.
2026-09-05 14:32:59 +08:00

55 lines
2.4 KiB
TypeScript

// @vitest-environment jsdom
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { Switch } from '@deepseek-ai/dsh-client-ui-primitives'
afterEach(cleanup)
describe('Switch', () => {
it('exposes its state and its caller-owned name to assistive technology', () => {
render(<Switch checked label="Subagent model selection" onChange={() => {}} />)
const control = screen.getByRole('switch', { name: 'Subagent model selection' })
expect(control.getAttribute('aria-checked')).toBe('true')
})
it('reports the state the click asks for, not the state it has', () => {
const onChange = vi.fn()
const { rerender } = render(<Switch checked={false} label="Toggle" onChange={onChange} />)
fireEvent.click(screen.getByRole('switch'))
expect(onChange).toHaveBeenCalledWith(true)
onChange.mockClear()
rerender(<Switch checked label="Toggle" onChange={onChange} />)
fireEvent.click(screen.getByRole('switch'))
expect(onChange).toHaveBeenCalledWith(false)
})
it('stays silent while disabled', () => {
const onChange = vi.fn()
render(<Switch checked={false} disabled label="Toggle" onChange={onChange} />)
const control = screen.getByRole('switch')
expect((control as HTMLButtonElement).disabled).toBe(true)
fireEvent.click(control)
expect(onChange).not.toHaveBeenCalled()
})
it('carries a lock reason as the hover title when the owner names one', () => {
render(<Switch checked={false} disabled label="Toggle" title="Managed by policy" onChange={() => {}} />)
expect(screen.getByRole('switch').getAttribute('title')).toBe('Managed by policy')
})
it('never submits a surrounding form', () => {
const onSubmit = vi.fn((event: { preventDefault: () => void }) => { event.preventDefault() })
render(<form onSubmit={onSubmit}><Switch checked={false} label="Toggle" onChange={() => {}} /></form>)
fireEvent.click(screen.getByRole('switch'))
expect(onSubmit).not.toHaveBeenCalled()
})
it('keeps a caller class alongside its own so a render site can place it', () => {
render(<Switch checked={false} className="placed" label="Toggle" onChange={() => {}} />)
const control = screen.getByRole('switch')
expect(control.classList.contains('placed')).toBe(true)
expect(control.classList.length).toBeGreaterThan(1)
})
})