// @vitest-environment jsdom
/**
* What `Banner.mdx` claims about the dismiss added at stage 3 (D21).
*
* The point of the first test is the one that is easy to lose: a banner
* without `onDismiss` must render exactly what it always did. Every banner in
* both apps is that one, and a prop that quietly changed their DOM would be a
* change nobody asked for.
*/
import { afterEach, describe, expect, it, vi } from 'vitest'
import { cleanup, render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Banner } from './Banner'
afterEach(cleanup)
describe('Banner', () => {
it('is one element with the text in it when there is no dismiss', () => {
const { container } = render(Two people are editing this.)
const root = container.firstElementChild!
expect(root.children).toHaveLength(0)
expect(root.textContent).toBe('Two people are editing this.')
expect(screen.queryByRole('button')).toBeNull()
})
it('offers a dismiss when asked, and reports it', async () => {
const onDismiss = vi.fn()
const user = userEvent.setup()
render(
The relay is not answering.
,
)
await user.click(screen.getByRole('button', { name: 'Dismiss' }))
expect(onDismiss).toHaveBeenCalledTimes(1)
})
it('lets the caller name the dismiss', () => {
render(
{}} dismissLabel="Hide this notice">
Saved.
,
)
expect(screen.getByRole('button', { name: 'Hide this notice' })).toBeTruthy()
})
it('announces an error and stays polite otherwise', () => {
const { rerender, container } = render(Could not save.)
expect(container.firstElementChild!.getAttribute('role')).toBe('alert')
rerender(Could not save.)
expect(container.firstElementChild!.getAttribute('role')).toBe('status')
// and the same either side of the dismiss
rerender(
{}}>
Could not save.
,
)
expect(container.firstElementChild!.getAttribute('role')).toBe('alert')
})
it('puts an icon before the line and one small muted action after it, on one line (Katerina, 2026-09-18)', async () => {
const onClick = vi.fn()
const { container } = render(
} action={{ label: 'Join', onClick }}>
You are not in Alpha yet
,
)
const row = container.firstElementChild!
expect(row.getAttribute('role')).toBe('status')
expect(row.firstElementChild!.querySelector('[data-testid="icon"]')).not.toBeNull()
const line = screen.getByText(/You are not in/)
expect(line.className).toContain('truncate')
const button = screen.getByRole('button', { name: 'Join' })
expect(line.nextElementSibling).toBe(button)
await userEvent.click(button)
expect(onClick).toHaveBeenCalledOnce()
// No dismiss unless asked for.
expect(screen.queryByRole('button', { name: 'Dismiss' })).toBeNull()
})
it('an icon alone still keeps the line on one line, and a dismiss alone still wraps', () => {
const { rerender } = render(
}>
One line
,
)
expect(screen.getByText('One line').className).toContain('truncate')
rerender(
{}}>
One line
,
)
expect(screen.getByText('One line').className).not.toContain('truncate')
})
})