test(12.1-05): unit tests for the Phase 12.1 SPA components
- BulkActionsMenu, RowStateBadges, RecordActions, PreviewField, FormErrorBanner, PasswordField and PermissionEditorField, each mounted on its own - backstop: a row state outside the fixed set renders no badge and no class - backstop: the permission editor's emission rules per mode, the locked row and codes outside the options
This commit is contained in:
68
admin/tests/list/RowStateBadges.test.ts
Normal file
68
admin/tests/list/RowStateBadges.test.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// Row state badges (UI-SPEC S4, D-12). Fixtures are neutral; no application
|
||||
// names appear in framework tests.
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import RowStateBadges from '../../src/components/list/RowStateBadges.vue'
|
||||
|
||||
const labels = { deleted: 'Deleted', negative: 'Blocked', disabled: 'Not active' }
|
||||
const badges = (states: readonly string[], use: Record<string, string> = labels) =>
|
||||
mount(RowStateBadges, { props: { states, labels: use } })
|
||||
|
||||
describe('row state badges (UI-SPEC S4, D-12)', () => {
|
||||
it.each([
|
||||
['deleted', 'Deleted', ['border', 'border-border-strong', 'text-muted']],
|
||||
['negative', 'Blocked', ['bg-danger-soft', 'text-danger']],
|
||||
['disabled', 'Not active', ['bg-subtle', 'text-muted']],
|
||||
])('renders %s as a text badge with its own classes', (state, text, classes) => {
|
||||
const wrapper = badges([state])
|
||||
const all = wrapper.findAll('[data-row-state]')
|
||||
expect(all).toHaveLength(1)
|
||||
expect(all[0]!.attributes('data-row-state')).toBe(state)
|
||||
expect(all[0]!.text()).toBe(text)
|
||||
expect(all[0]!.classes()).toEqual(expect.arrayContaining([...classes, 'rounded-pill', 'whitespace-nowrap', 'shrink-0']))
|
||||
// The state is said in text: colour alone would fail WCAG 1.4.1.
|
||||
expect(all[0]!.classes()).not.toContain('sr-only')
|
||||
expect(all[0]!.classes()).not.toContain('line-through')
|
||||
})
|
||||
|
||||
it('renders combined states in the fixed order deleted, negative, disabled', () => {
|
||||
for (const input of [
|
||||
['disabled', 'negative', 'deleted'],
|
||||
['negative', 'deleted', 'disabled'],
|
||||
['deleted', 'negative', 'disabled'],
|
||||
]) {
|
||||
const wrapper = badges(input)
|
||||
expect(wrapper.findAll('[data-row-state]').map((badge) => badge.attributes('data-row-state'))).toEqual(['deleted', 'negative', 'disabled'])
|
||||
}
|
||||
expect(badges(['disabled', 'deleted']).findAll('[data-row-state]').map((badge) => badge.text())).toEqual(['Deleted', 'Not active'])
|
||||
})
|
||||
|
||||
it('renders a repeated state once', () => {
|
||||
const wrapper = badges(['negative', 'negative', 'negative'])
|
||||
expect(wrapper.findAll('[data-row-state]')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('renders nothing at all without states', () => {
|
||||
const wrapper = badges([])
|
||||
expect(wrapper.find('span').exists()).toBe(false)
|
||||
expect(wrapper.text()).toBe('')
|
||||
})
|
||||
|
||||
it('falls back to the state name when the schema sends no label for it', () => {
|
||||
expect(badges(['negative'], {}).find('[data-row-state]').text()).toBe('negative')
|
||||
})
|
||||
|
||||
it('backstop: a row state outside the fixed set renders no badge and no class', () => {
|
||||
const hostile = ['starred', 'bg-danger-soft', 'deleted line-through', '<b>x</b>', 'DELETED', '__proto__', 'constructor', '']
|
||||
const wrapper = badges(hostile, { ...labels, starred: 'Starred', constructor: 'Constructor' })
|
||||
expect(wrapper.find('[data-row-state]').exists()).toBe(false)
|
||||
expect(wrapper.find('span').exists()).toBe(false)
|
||||
expect(wrapper.html()).not.toMatch(/starred|bg-danger-soft|line-through|Starred|Constructor/)
|
||||
|
||||
// Next to known states the unknown ones change nothing.
|
||||
const mixed = badges(['starred', 'negative', '<b>x</b>'])
|
||||
expect(mixed.findAll('[data-row-state]').map((badge) => [badge.attributes('data-row-state'), badge.text()])).toEqual([['negative', 'Blocked']])
|
||||
expect(mixed.html()).not.toContain('starred')
|
||||
expect(mixed.find('b').exists()).toBe(false)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user