Add component tests for EndRunModal, GameGrid, RulesConfiguration, Layout
33 tests covering rendering, user interactions (userEvent clicks), prop callbacks, filter state, and conditional description text. Adds a matchMedia stub to the vitest setup file so components importing useTheme don't throw in jsdom. Also adds actionlint and zizmor pre-commit hooks for GitHub Actions linting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
84
frontend/src/components/RulesConfiguration.test.tsx
Normal file
84
frontend/src/components/RulesConfiguration.test.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { RulesConfiguration } from './RulesConfiguration'
|
||||
import { DEFAULT_RULES } from '../types/rules'
|
||||
import type { NuzlockeRules } from '../types/rules'
|
||||
|
||||
function setup(overrides: Partial<React.ComponentProps<typeof RulesConfiguration>> = {}) {
|
||||
const props = {
|
||||
rules: { ...DEFAULT_RULES },
|
||||
onChange: vi.fn(),
|
||||
...overrides,
|
||||
}
|
||||
render(<RulesConfiguration {...props} />)
|
||||
return props
|
||||
}
|
||||
|
||||
describe('RulesConfiguration', () => {
|
||||
it('renders all rule section headings', () => {
|
||||
setup()
|
||||
expect(screen.getByText('Core Rules')).toBeInTheDocument()
|
||||
expect(screen.getByText('Playstyle')).toBeInTheDocument()
|
||||
expect(screen.getByText('Run Variant')).toBeInTheDocument()
|
||||
expect(screen.getByText('Type Restriction')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the enabled/total count', () => {
|
||||
setup()
|
||||
expect(screen.getByText(/\d+ of \d+ rules enabled/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the Reset to Default button', () => {
|
||||
setup()
|
||||
expect(screen.getByRole('button', { name: /reset to default/i })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('calls onChange with updated rules when a rule is toggled off', async () => {
|
||||
const { onChange } = setup()
|
||||
// RuleToggle renders a role="switch" with no accessible name; navigate
|
||||
// to it via the sibling label text.
|
||||
const label = screen.getByText('Duplicates Clause')
|
||||
// Structure: span → .flex.items-center.gap-2 → .flex-1.pr-4 → row div → switch button
|
||||
const switchEl = label
|
||||
.closest('div[class]')
|
||||
?.parentElement?.parentElement?.querySelector('[role="switch"]') as HTMLElement
|
||||
await userEvent.click(switchEl)
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ duplicatesClause: false }))
|
||||
})
|
||||
|
||||
it('calls onChange with DEFAULT_RULES when Reset to Default is clicked', async () => {
|
||||
const { onChange } = setup({ rules: { ...DEFAULT_RULES, duplicatesClause: false } })
|
||||
await userEvent.click(screen.getByRole('button', { name: /reset to default/i }))
|
||||
expect(onChange).toHaveBeenCalledWith(DEFAULT_RULES)
|
||||
})
|
||||
|
||||
it('calls onReset when Reset to Default is clicked', async () => {
|
||||
const onReset = vi.fn()
|
||||
setup({ onReset })
|
||||
await userEvent.click(screen.getByRole('button', { name: /reset to default/i }))
|
||||
expect(onReset).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('toggles a type on when a type button is clicked', async () => {
|
||||
const { onChange } = setup()
|
||||
await userEvent.click(screen.getByRole('button', { name: /fire/i }))
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ allowedTypes: ['fire'] }))
|
||||
})
|
||||
|
||||
it('shows Clear selection button when types are selected', () => {
|
||||
setup({ rules: { ...DEFAULT_RULES, allowedTypes: ['fire'] } })
|
||||
expect(screen.getByRole('button', { name: /clear selection/i })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('clears selected types when Clear selection is clicked', async () => {
|
||||
const { onChange } = setup({ rules: { ...DEFAULT_RULES, allowedTypes: ['fire', 'water'] } })
|
||||
await userEvent.click(screen.getByRole('button', { name: /clear selection/i }))
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ allowedTypes: [] }))
|
||||
})
|
||||
|
||||
it('hides rules in the hiddenRules set', () => {
|
||||
const hiddenRules = new Set<keyof NuzlockeRules>(['duplicatesClause'])
|
||||
setup({ hiddenRules })
|
||||
expect(screen.queryByText('Duplicates Clause')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user