Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions __tests__/unit/a11y-nomes-acessiveis.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { describe, it, expect } from 'vitest'
import { readFileSync } from 'node:fs'
import { join } from 'node:path'

// ─── Botões só de ícone sem nome acessível (#106) ──────────────────────────
//
// Não há infra de render de componente no projeto (sem jsdom/testing-library).
// O gate possível é sobre o texto-fonte, padrão já usado em row-actions.test.ts
// (#54) e a11y-estado-selecao.test.ts (#107).
//
// A asserção precisa ancorar no <Button> que envolve o ícone, não no arquivo
// inteiro — senão um aria-label em qualquer outro botão do mesmo arquivo
// deixaria o teste verde com o gatilho ainda sem nome.

function findClosestButtonWithIcon(source: string, iconTag: string): string | undefined {
// Ancora no <Button> MAIS PRÓXIMO do ícone: a lookahead negativa impede o
// match de atravessar outro "<Button" antes de alcançar o ícone-alvo — sem
// isso um regex guloso/lazy simples pegaria o botão de criar ("+ Categoria",
// "+ Novo grupo", "+ Nova conta"), que abre antes do de editar no mesmo
// arquivo e também usa onClick={() => setOpen(true)}.
//
// Para no início da tag do ícone (não em "</Button>"): estender até o fechamento
// incluiria os atributos do próprio ícone no trecho, e um aria-label colocado
// ali por engano (o erro que esta issue existe para barrar) passaria a asserção
// de linha isolada sempre que o prettier quebrasse os atributos do ícone.
const pattern = new RegExp(`<Button\\b(?:(?!<Button\\b)[\\s\\S])*?<${iconTag}\\b`)
return source.match(pattern)?.[0]
}

describe('Lápis de editar — cadastro (#127)', () => {
const cases = [
{
name: 'CategoryDialog — editar categoria',
path: 'components/categorias/CategoryDialog.tsx',
},
{
name: 'GroupDialog — editar grupo',
path: 'components/categorias/GroupDialog.tsx',
},
{
name: 'AccountDialog — editar conta',
path: 'components/contas/AccountDialog.tsx',
},
]

for (const { name, path } of cases) {
describe(name, () => {
const source = readFileSync(join(process.cwd(), path), 'utf-8')
const trigger = findClosestButtonWithIcon(source, 'Pencil')

it('encontra o bloco do botão de editar (o mais próximo do ícone Pencil)', () => {
expect(trigger).toBeDefined()
})

it('expõe aria-label no <Button> do gatilho, não no ícone', () => {
expect(trigger).toMatch(/^\s*aria-label="[^"]+"\s*$/m)
})
})
}
})
1 change: 1 addition & 0 deletions components/categorias/CategoryDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export function CategoryDialog(props: Props) {
variant="ghost"
className="h-7 w-7 text-text-tertiary hover:text-text-primary"
onClick={() => setOpen(true)}
aria-label="Editar categoria"
>
<Pencil className="h-3.5 w-3.5" />
</Button>
Expand Down
1 change: 1 addition & 0 deletions components/categorias/GroupDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export function GroupDialog(props: Props) {
variant="ghost"
className="h-7 w-7 text-text-tertiary hover:text-text-primary"
onClick={() => setOpen(true)}
aria-label="Editar grupo"
>
<Pencil className="h-3.5 w-3.5" />
</Button>
Expand Down
1 change: 1 addition & 0 deletions components/contas/AccountDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ export function AccountDialog(props: Props) {
variant="ghost"
className="h-7 w-7 text-text-tertiary hover:text-text-primary"
onClick={() => setOpen(true)}
aria-label="Editar conta"
>
<Pencil className="h-3.5 w-3.5" />
</Button>
Expand Down
Loading