import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import SkipLink from '../SkipLink.vue'
import { locales } from '../locales'
// Create a mock router
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: { template: '
Home
' } },
{ path: '/about', component: { template: 'About
' } },
],
})
describe('SkipLink', () => {
beforeEach(() => {
vi.restoreAllMocks()
})
it('renders correctly', async () => {
const wrapper = mount(SkipLink, {
global: {
plugins: [router],
},
})
expect(wrapper.html()).toMatchSnapshot()
})
it('accepte des props personnalisées', () => {
const customLabel = 'Accéder au contenu'
const customTarget = '#content'
const wrapper = mount(SkipLink, {
props: {
label: customLabel,
target: customTarget,
},
})
const link = wrapper.find('a.sy-skip-link')
expect(link.text()).toBe(customLabel)
expect(link.attributes('href')).toBe(customTarget)
})
it('utilise les valeurs par défaut', () => {
const wrapper = mount(SkipLink)
const link = wrapper.find('a.sy-skip-link')
expect(link.text()).toBe(locales.label)
expect(link.attributes('href')).toBe('#main')
})
it('contient les attributs d\'accessibilité corrects', () => {
const wrapper = mount(SkipLink)
expect(wrapper.find('nav').attributes('aria-label')).toBe('Liens d\'évitement')
expect(wrapper.find('a.sy-skip-link').exists()).toBe(true)
})
it('ne déplace pas le focus si la navigation échoue', async () => {
// Mock du router avec un hook afterEach qui simule un échec
const mockRouter = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
afterEach: (callback: any) => {
// Simuler un appel avec fail=true
callback(
{ path: '/new-path' },
{ path: '/' },
true, // fail=true
)
},
}
// Espionner querySelector et focus
const linkElement = document.createElement('a')
const focusSpy = vi.spyOn(linkElement, 'focus')
vi.spyOn(document, 'querySelector').mockImplementation(() => linkElement)
// Mock de getCurrentInstance pour injecter notre router
// eslint-disable-next-line @typescript-eslint/no-require-imports
vi.spyOn(require('vue'), 'getCurrentInstance').mockReturnValue({
appContext: {
app: {
config: {
globalProperties: {
$router: mockRouter,
},
},
},
},
})
mount(SkipLink)
await new Promise(resolve => setTimeout(resolve, 0))
expect(focusSpy).not.toHaveBeenCalled()
})
it('ne déplace pas le focus si le chemin reste identique', async () => {
// Mock du router avec un hook afterEach où to.path = from.path
const mockRouter = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic type
afterEach: (callback: any) => {
// Simuler un appel avec les mêmes chemins
callback(
{ path: '/same-path' },
{ path: '/same-path' },
false,
)
},
}
// Espionner querySelector et focus
const linkElement = document.createElement('a')
const focusSpy = vi.spyOn(linkElement, 'focus')
vi.spyOn(document, 'querySelector').mockImplementation(() => linkElement)
// Mock de getCurrentInstance
/* eslint-disable */
vi.spyOn(require('vue'), 'getCurrentInstance').mockReturnValue({
appContext: {
app: {
config: {
globalProperties: {
$router: mockRouter,
},
},
},
},
})
mount(SkipLink)
await new Promise(resolve => setTimeout(resolve, 0))
expect(focusSpy).not.toHaveBeenCalled()
})
})