test: add shared accessibility contract gate (AEG-V16-024)

Verify required field error relationships and busy command suppression; preserve actual test evidence while awaiting UX/QA artifacts.
This commit is contained in:
2026-08-08 14:52:15 +09:00
parent cada8fe843
commit 6f47d71c4a
3 changed files with 42 additions and 0 deletions
@@ -0,0 +1,16 @@
# AEG-V16-024 — FE accessibility gate
**WBS / Requirement / UI / Test:** AEG-V16-024 / REQ-V16-FEC-08 / UI-V16-FEC-08 / T-V16-FEC-08
## Source / Assumption / Unknown / Decision Required
- **Source:** FieldShell, CommandBar, their component tests, and WBS Master.
- **Assumption:** shared-component checks provide a baseline; each screen still owns keyboard/focus and visual acceptance evidence.
- **Unknown:** full browser assistive-technology and visual-regression artifacts are not available in this workspace.
- **Decision Required:** do not call the gate complete until UX/QA attach those artifacts.
## Actual evidence
- `pnpm test -- --run src/shared/ui/components/tests/accessibility.contract.spec.ts`: 2/2 passed.
- `pnpm typecheck`: passed.
- The suite verifies required invalid fields expose label, error alert, and ARIA relationships, and busy commands expose state while blocking execution.
@@ -14,6 +14,7 @@ AEG-V16-019,S6,Cross,CommandBar,IN_PROGRESS,TBD,"docs/CURRENT/AEG-V16-019_COMMAN
AEG-V16-020,S6,Cross,CRUD Resource v2,IN_PROGRESS,TBD,"docs/CURRENT/AEG-V16-020_CRUD_RESOURCE_V2_SLICE_NOTE.md; contracts/ui/crud-resource.v2.json; frontend/src/shared/crud/resourceDefinition.ts; frontend/src/shared/crud/tests/resourceDefinition.spec.ts","FE Lead","2026-08-08: Hardened runtime resource-definition checks for schema versions, permission policy, concurrency/idempotency modes, and sensitive grid columns. Actual evidence: resource definition Vitest 3/3 PASS; frontend typecheck PASS. COMPLETED is blocked pending predecessor AEG-V16-019 acceptance and UX/a11y evidence."
AEG-V16-022,S6,Cross,Optimistic command hook,IN_PROGRESS,TBD,"docs/CURRENT/AEG-V16-022_OPTIMISTIC_COMMAND_SLICE_NOTE.md; frontend/src/shared/crud/useOptimisticCommand.ts; frontend/src/shared/crud/tests/useOptimisticCommand.spec.ts","FE Lead","2026-08-08: Request creation now freezes one Idempotency-Key per user intent and retries reuse it; 409/412 conflict state remains explicit. Actual evidence: targeted Vitest 2/2 PASS; frontend typecheck PASS. COMPLETED is blocked pending actual CRUD-screen integration and predecessor evidence."
AEG-V16-023,S6,Cross,T01~T10 계약 회귀,IN_PROGRESS,TBD,"docs/CURRENT/AEG-V16-023_SCREEN_STATE_MATRIX_SLICE_NOTE.md; frontend/src/shared/ui/screen-types/catalogue.ts; frontend/src/shared/ui/screen-types/tests/catalogue.spec.ts","FE Lead","2026-08-08: State contract is typed and all 13 standard states are now covered across T01~T10, including READY and FORBIDDEN. Actual evidence: catalogue Vitest 4/4 PASS; frontend typecheck PASS. COMPLETED is blocked pending predecessor integration and FE accessibility gate evidence."
AEG-V16-024,S6,Cross,FE accessibility Gate,IN_PROGRESS,TBD,"docs/CURRENT/AEG-V16-024_A11Y_GATE_SLICE_NOTE.md; frontend/src/shared/ui/components/tests/accessibility.contract.spec.ts","FE Lead","2026-08-08: Shared accessibility contract verifies required invalid field label/error/ARIA relationships and busy command action suppression. Actual evidence: accessibility Vitest 2/2 PASS; frontend typecheck PASS. COMPLETED is blocked pending UX/QA keyboard/focus, assistive-technology, and visual evidence."
AEG-X-008,S0,Cross,OpenAPI artifact 고도화,COMPLETED,2026-08-04,.gitea/workflows/openapi-gate.yml + docs/api/openapi.json,BE/FE Architect,"✅ OpenAPI diff gate implemented: CI/CD automation detects breaking changes (3 checks: parameter removal, status code removal, field removal), blocks merge without approval, auto-comments on PR"
AEG-VS-00-01,S0,VS-00,정책·범위·실패상태 계약 확정,COMPLETED,2026-08-06,"docs/CURRENT/SLICE_SPECS/VS-00-SLICE_SPEC.md + commit e7913db",PM/Architect,"✅ SLICE_SPEC produced: VS-00-SLICE_SPEC.md (state transitions, RBAC, governance gates, DQ rules, compliance). Commit e7913db. 249/253 tests PASS."
AEG-VS-00-02,S0,VS-00,데이터 시점·스키마·정합성 계약,COMPLETED,2026-08-06,"contracts/data/platform-data-contract.v1.json + commit e7913db",Data Architect/DBA,"✅ DATA_CONTRACT v1.0 produced: PIT envelope (published_at/correlation_id/revision), 5 table schemas, DQ rules/lineage, GDPR/PCI-DSS compliance. JSON schema + validation. 249/253 tests PASS."
1 WBS_ID Sprint Slice_ID Task Status Completion_Date Evidence_Link Owner Notes
14 AEG-V16-020 S6 Cross CRUD Resource v2 IN_PROGRESS TBD docs/CURRENT/AEG-V16-020_CRUD_RESOURCE_V2_SLICE_NOTE.md; contracts/ui/crud-resource.v2.json; frontend/src/shared/crud/resourceDefinition.ts; frontend/src/shared/crud/tests/resourceDefinition.spec.ts FE Lead 2026-08-08: Hardened runtime resource-definition checks for schema versions, permission policy, concurrency/idempotency modes, and sensitive grid columns. Actual evidence: resource definition Vitest 3/3 PASS; frontend typecheck PASS. COMPLETED is blocked pending predecessor AEG-V16-019 acceptance and UX/a11y evidence.
15 AEG-V16-022 S6 Cross Optimistic command hook IN_PROGRESS TBD docs/CURRENT/AEG-V16-022_OPTIMISTIC_COMMAND_SLICE_NOTE.md; frontend/src/shared/crud/useOptimisticCommand.ts; frontend/src/shared/crud/tests/useOptimisticCommand.spec.ts FE Lead 2026-08-08: Request creation now freezes one Idempotency-Key per user intent and retries reuse it; 409/412 conflict state remains explicit. Actual evidence: targeted Vitest 2/2 PASS; frontend typecheck PASS. COMPLETED is blocked pending actual CRUD-screen integration and predecessor evidence.
16 AEG-V16-023 S6 Cross T01~T10 계약 회귀 IN_PROGRESS TBD docs/CURRENT/AEG-V16-023_SCREEN_STATE_MATRIX_SLICE_NOTE.md; frontend/src/shared/ui/screen-types/catalogue.ts; frontend/src/shared/ui/screen-types/tests/catalogue.spec.ts FE Lead 2026-08-08: State contract is typed and all 13 standard states are now covered across T01~T10, including READY and FORBIDDEN. Actual evidence: catalogue Vitest 4/4 PASS; frontend typecheck PASS. COMPLETED is blocked pending predecessor integration and FE accessibility gate evidence.
17 AEG-V16-024 S6 Cross FE accessibility Gate IN_PROGRESS TBD docs/CURRENT/AEG-V16-024_A11Y_GATE_SLICE_NOTE.md; frontend/src/shared/ui/components/tests/accessibility.contract.spec.ts FE Lead 2026-08-08: Shared accessibility contract verifies required invalid field label/error/ARIA relationships and busy command action suppression. Actual evidence: accessibility Vitest 2/2 PASS; frontend typecheck PASS. COMPLETED is blocked pending UX/QA keyboard/focus, assistive-technology, and visual evidence.
18 AEG-X-008 S0 Cross OpenAPI artifact 고도화 COMPLETED 2026-08-04 .gitea/workflows/openapi-gate.yml + docs/api/openapi.json BE/FE Architect ✅ OpenAPI diff gate implemented: CI/CD automation detects breaking changes (3 checks: parameter removal, status code removal, field removal), blocks merge without approval, auto-comments on PR
19 AEG-VS-00-01 S0 VS-00 정책·범위·실패상태 계약 확정 COMPLETED 2026-08-06 docs/CURRENT/SLICE_SPECS/VS-00-SLICE_SPEC.md + commit e7913db PM/Architect ✅ SLICE_SPEC produced: VS-00-SLICE_SPEC.md (state transitions, RBAC, governance gates, DQ rules, compliance). Commit e7913db. 249/253 tests PASS.
20 AEG-VS-00-02 S0 VS-00 데이터 시점·스키마·정합성 계약 COMPLETED 2026-08-06 contracts/data/platform-data-contract.v1.json + commit e7913db Data Architect/DBA ✅ DATA_CONTRACT v1.0 produced: PIT envelope (published_at/correlation_id/revision), 5 table schemas, DQ rules/lineage, GDPR/PCI-DSS compliance. JSON schema + validation. 249/253 tests PASS.
@@ -0,0 +1,25 @@
import { mount } from '@vue/test-utils'
import { h } from 'vue'
import { describe, expect, it } from 'vitest'
import FieldShell from '../FieldShell.vue'
import KsCommandBar from '../KsCommandBar.vue'
describe('shared UI accessibility contract', () => {
it('connects a required invalid field to its accessible error', () => {
const wrapper = mount(FieldShell, {
props: { label: 'Client', inputId: 'client', required: true, error: 'Required' },
slots: { default: field => h('input', { id: field.inputId, 'aria-describedby': field.describedBy, 'aria-required': field.required, 'aria-invalid': field.invalid }) }
})
expect(wrapper.get('label').attributes('for')).toBe('client')
expect(wrapper.get('[role="alert"]').attributes('id')).toBe('client-message')
expect(wrapper.get('input').attributes()).toMatchObject({ 'aria-describedby': 'client-message', 'aria-required': 'true', 'aria-invalid': 'true' })
})
it('exposes busy commands and blocks their action event', async () => {
const wrapper = mount(KsCommandBar, { props: { actions: [{ id: 'publish', label: 'Publish', busy: true }] }, global: { stubs: { KsButton: { name: 'KsButton', template: '<button />' } } } })
expect(wrapper.get('nav').attributes('aria-busy')).toBe('true')
wrapper.findComponent({ name: 'KsButton' }).vm.$emit('click')
await wrapper.vm.$nextTick()
expect(wrapper.emitted('execute')).toBeUndefined()
})
})