Titre de l'article
Contenu de l'article principal avec une bonne structure.
// @vitest-environment jsdom
import { describe, it, expect, afterEach } from 'vitest'
import { mount } from '@vue/test-utils'
import { axe } from 'vitest-axe'
import { assertNoA11yViolations } from '@tests/unit/accessibility/axeUtils'
import PageContainer from '../PageContainer.vue'
// Scénario d’accessibilité : conteneur de page enveloppant un contenu principal.
describe('PageContainer – accessibility (axe)', () => {
afterEach(() => {
document.body.innerHTML = ''
})
it('has no obvious axe violations with main content slot', async () => {
const wrapper = mount(PageContainer, {
slots: {
default: ' Texte de la page.Contenu principal
Ceci est le contenu principal de la page.
', }, attachTo: document.body, }) const results = await axe(wrapper.element as HTMLElement) assertNoA11yViolations(results, 'PageContainer – role="main"', { ignoreRules: ['region'], }) wrapper.unmount() }) it('has proper landmark role with role="main"', async () => { const wrapper = mount(PageContainer, { props: { role: 'main', }, slots: { default: 'Contenu principal
', }, attachTo: document.body, }) const element = wrapper.element as HTMLElement expect(element.getAttribute('role')).toBe('main') assertNoA11yViolations(await axe(element), 'PageContainer – main landmark') wrapper.unmount() }) }) describe('PageContainer – accessibility with role="region"', () => { it('has no axe violations with role="region" and aria-label', async () => { const wrapper = mount(PageContainer, { props: { role: 'region', }, attrs: { 'aria-label': 'Zone de contenu secondaire', }, slots: { default: 'Contenu de la région.
', }, attachTo: document.body, }) const results = await axe(wrapper.element as HTMLElement) assertNoA11yViolations(results, 'PageContainer – role="region" with aria-label') wrapper.unmount() }) it('has no axe violations with role="region" and aria-labelledby', async () => { const wrapper = mount(PageContainer, { props: { role: 'region', }, attrs: { 'aria-labelledby': 'region-title', }, slots: { default: 'Contenu.
', }, attachTo: document.body, }) const results = await axe(wrapper.element as HTMLElement) assertNoA11yViolations(results, 'PageContainer – role="region" with aria-labelledby') wrapper.unmount() }) }) describe('PageContainer – accessibility with role="navigation"', () => { it('has no axe violations with role="navigation"', async () => { const wrapper = mount(PageContainer, { props: { role: 'navigation', }, slots: { default: '', }, attachTo: document.body, }) const results = await axe(wrapper.element as HTMLElement) assertNoA11yViolations(results, 'PageContainer – role="navigation"', { ignoreRules: ['region'], }) wrapper.unmount() }) it('has no axe violations with role="navigation" and aria-label', async () => { const wrapper = mount(PageContainer, { props: { role: 'navigation', }, attrs: { 'aria-label': 'Navigation principale', }, slots: { default: '', }, attachTo: document.body, }) const results = await axe(wrapper.element as HTMLElement) assertNoA11yViolations(results, 'PageContainer – role="navigation" with aria-label') wrapper.unmount() }) }) describe('PageContainer – accessibility with role="contentinfo"', () => { it('has no axe violations with role="contentinfo"', async () => { const wrapper = mount(PageContainer, { props: { role: 'contentinfo', }, slots: { default: '© 2026 - Tous droits réservés
Contenu
', }, attachTo: document.body, }) const element = wrapper.element as HTMLElement expect(element.getAttribute('id')).toBe('main-content-container') const vsheet = wrapper.findComponent({ name: 'VSheet' }) expect(vsheet.attributes('id')).toBe('main-content-content') wrapper.unmount() }) it('has no axe violations with role="main" and uniqueId', async () => { const wrapper = mount(PageContainer, { props: { role: 'main', uniqueId: 'main-section', }, slots: { default: 'Section principale.
', }, attachTo: document.body, }) const element = wrapper.element as HTMLElement expect(element.getAttribute('id')).toBe('main-section-container') expect(element.getAttribute('role')).toBe('main') const results = await axe(element) assertNoA11yViolations(results, 'PageContainer – role="main" with uniqueId') wrapper.unmount() }) it('has no axe violations with role="region" and uniqueId', async () => { const wrapper = mount(PageContainer, { props: { role: 'region', uniqueId: 'sidebar', }, attrs: { 'aria-label': 'Barre latérale', }, slots: { default: 'Contenu latéral.
', }, attachTo: document.body, }) const element = wrapper.element as HTMLElement expect(element.getAttribute('id')).toBe('sidebar-container') expect(element.getAttribute('role')).toBe('region') const results = await axe(element) assertNoA11yViolations(results, 'PageContainer – role="region" with uniqueId') wrapper.unmount() }) it('has no axe violations with role="navigation" and uniqueId', async () => { const wrapper = mount(PageContainer, { props: { role: 'navigation', uniqueId: 'main-nav', }, slots: { default: '', }, attachTo: document.body, }) const element = wrapper.element as HTMLElement expect(element.getAttribute('id')).toBe('main-nav-container') expect(element.getAttribute('role')).toBe('navigation') const results = await axe(element) assertNoA11yViolations(results, 'PageContainer – role="navigation" with uniqueId') wrapper.unmount() }) it('has no axe violations with role="contentinfo" and uniqueId', async () => { const wrapper = mount(PageContainer, { props: { role: 'contentinfo', uniqueId: 'footer', }, slots: { default: 'Informations de pied de page
Corps de la page
', }, attachTo: document.body, }) // Vérifier les IDs et rôles expect((header.element as HTMLElement).getAttribute('id')).toBe('header-container') expect((header.element as HTMLElement).getAttribute('role')).toBe('banner') expect((nav.element as HTMLElement).getAttribute('id')).toBe('main-nav-container') expect((nav.element as HTMLElement).getAttribute('role')).toBe('navigation') expect((main.element as HTMLElement).getAttribute('id')).toBe('main-content-container') expect((main.element as HTMLElement).getAttribute('role')).toBe('main') // Vérifier qu'il n'y a pas de violations axe const headerResults = await axe(header.element as HTMLElement) const navResults = await axe(nav.element as HTMLElement) const mainResults = await axe(main.element as HTMLElement) assertNoA11yViolations(headerResults, 'Header landmark', { ignoreRules: ['region'] }) assertNoA11yViolations(navResults, 'Navigation landmark') assertNoA11yViolations(mainResults, 'Main landmark', { ignoreRules: ['region'] }) header.unmount() nav.unmount() main.unmount() }) it('has proper semantic structure for complete page layout', async () => { // Simulation d'une page complète avec tous les landmarks const wrapper = mount(PageContainer, { props: { role: 'main', uniqueId: 'page-main', }, slots: { default: `Contenu de l'article principal avec une bonne structure.
Contenu sans ID
', }, attachTo: document.body, }) const element = wrapper.element as HTMLElement expect(element.getAttribute('id')).toBeNull() const results = await axe(element) assertNoA11yViolations(results, 'PageContainer – without uniqueId', { ignoreRules: ['region'], }) wrapper.unmount() }) it('has no axe violations when role is not provided', async () => { const wrapper = mount(PageContainer, { slots: { default: 'Contenu sans rôle
', }, attachTo: document.body, }) const element = wrapper.element as HTMLElement expect(element.getAttribute('role')).toBeNull() const results = await axe(element) assertNoA11yViolations(results, 'PageContainer – without role', { ignoreRules: ['region'], }) wrapper.unmount() }) it('has proper color contrast with different background colors', async () => { const wrapper = mount(PageContainer, { props: { role: 'region', color: 'surface', }, attrs: { 'aria-label': 'Bloc coloré', }, slots: { default: 'Paragraphe avec contraste de couleur.
', }, attachTo: document.body, }) const results = await axe(wrapper.element as HTMLElement) assertNoA11yViolations(results, 'PageContainer – color contrast', { ignoreRules: ['region'], }) wrapper.unmount() }) it('maintains accessibility with different spacing values', async () => { const spacings = ['xs', 'sm', 'md', 'lg', 'xl'] as const for (const spacing of spacings) { const wrapper = mount(PageContainer, { props: { role: 'region', spacing, }, attrs: { 'aria-label': `Région avec spacing ${spacing}`, }, slots: { default: 'Contenu avec espacement
', }, attachTo: document.body, }) const results = await axe(wrapper.element as HTMLElement) assertNoA11yViolations(results, `PageContainer – spacing=${spacing}`) wrapper.unmount() } }) }) })