// @vitest-environment jsdom /** * What a face is called, everywhere one appears. * * These are the names an app's own tests compute — `getByRole('button', { name })` * runs the same algorithm — and every one of them was wrong until 2026-09-08: * a face read as its initials, and a face beside a name read the name twice. * The initials are a drawing of a name, not text. */ import { afterEach, describe, expect, it } from 'vitest' import { cleanup, render, screen } from '@testing-library/react' import { Avatar } from './Avatar' import { AvatarGroup } from './AvatarGroup' import { MenuItem, MenuPanel } from './Menu' import { Person } from './Person' import { PersonTrigger } from './PersonTrigger' afterEach(cleanup) /** * `getByRole`'s `name` matches the *accessible* name exactly, computed by the * same algorithm a browser uses — so a query that finds nothing is the failure * being asserted, and the message names what it looked for. This is also how * both apps query their own controls, which is what makes it the right test. */ describe('a face beside a name says nothing of its own', () => { it('a button holding a Person is called the person, once', () => { render( , ) // "AD Ana Duarte" before: the initials were read as text. expect(screen.getByRole('button', { name: 'Ana Duarte' })).toBeTruthy() }) it('and once when there is a picture rather than initials', () => { render( , ) // "Ana Duarte Ana Duarte" before: the alt text and the name were both read. expect(screen.getByRole('button', { name: 'Ana Duarte' })).toBeTruthy() }) it('a menu row led by a face is called by its label', () => { render( } onClick={() => {}} /> , ) expect(screen.getByRole('button', { name: 'Ana Duarte' })).toBeTruthy() }) it('a bare face is not in the accessibility tree at all', () => { const { container } = render() expect(container.firstElementChild?.getAttribute('aria-hidden')).toBe('true') }) }) describe('a face that stands on its own says whose it is', () => { it('the compact PersonTrigger is called the person', () => { render() // "AD" before — the initials, and the only name the control had. expect(screen.getByRole('button', { name: 'Ana Duarte' })).toBeTruthy() }) it('a caller may name the destination instead', () => { render() expect(screen.getByRole('button', { name: 'Account menu' })).toBeTruthy() }) it('an unnamed person falls back to what the caller calls them', () => { render() expect(screen.getByRole('button', { name: 'Anonymous' })).toBeTruthy() }) it('the row shape is called the person, without the initials in front', () => { render() expect(screen.getByRole('button', { name: 'Ana Duarte' })).toBeTruthy() }) it('a stack of faces names each of them', () => { render() // "AD" and "BC" before. expect(screen.getAllByRole('img').map((el) => el.getAttribute('aria-label'))).toEqual(['Ana Duarte', 'Ben Carter']) }) }) describe('the compact trigger keeps a focus ring', () => { /** `focus:outline-none` took the browser's ring away and put nothing back, * so the account trigger had no visible focus at all. */ it('does not remove its own outline', () => { render() expect(screen.getByRole('button').className).not.toContain('outline-none') }) })