import { mount } from '@vue/test-utils'
import { describe, it, expect, vi } from 'vitest'
import { h } from 'vue'
import FooterBar from '@/components/FooterBar/FooterBar.vue'
import { locales } from '@/components/FooterBar/locales'
import { A11yComplianceEnum } from '@/components/FooterBar/A11yCompliance'
describe('FooterBar', () => {
const getComponentType = (item: { href: unknown }) => {
return item.href ? 'a' : 'RouterLink'
}
const testFunction = (complianceLabel: unknown) => {
return typeof complianceLabel === 'string' ? locales.a11yLabel(complianceLabel) : ''
}
it('renders correctly', async () => {
const wrapper = mount(FooterBar)
expect(FooterBar).toBeTruthy()
expect(wrapper.html()).toMatchSnapshot()
})
it('renders default props correctly', () => {
const wrapper = mount(FooterBar)
expect(wrapper.props().a11yCompliance).toBe('non-compliant')
expect(wrapper.props().linkItems).toBeNull()
expect(wrapper.props().sitemapRoute).toEqual({ name: 'sitemap' })
expect(wrapper.props().hideSitemapLink).toBe(false)
})
it('renders custom props correctly', () => {
const customProps = {
a11yCompliance: A11yComplianceEnum['fully-compliant'],
linkItems: [{ text: 'Custom Link', to: '/custom' }],
hideSitemapLink: true,
}
const wrapper = mount(FooterBar, { props: customProps })
expect(wrapper.props().a11yCompliance).toBe(A11yComplianceEnum['fully-compliant'])
expect(wrapper.props().linkItems).toEqual(customProps.linkItems)
expect(wrapper.props().hideSitemapLink).toBe(true)
})
it('renders footer links correctly', () => {
const wrapper = mount(FooterBar)
const links = wrapper.findAll('.vd-footer-bar-links li')
expect(links.length).toBeGreaterThan(0)
})
it('hides links based on props', () => {
const wrapper = mount(FooterBar, {
props: {
hideSitemapLink: true,
hideCguLink: true,
hideCookiesLink: true,
hideLegalNoticeLink: true,
hideA11yLink: true,
},
})
const links = wrapper.findAll('.vd-footer-bar-links li')
expect(links.length).toBe(0)
})
it('renders version if provided', () => {
const version = '1.0.0'
const wrapper = mount(FooterBar, { props: { version } })
expect(wrapper.text()).toContain(`${locales.versionLabel} ${version}`)
})
it('renders the scroll to top button and triggers scrollToTop', async () => {
// Passer un slot ou forcer une condition pour activer le mode étendu
const wrapper = mount(FooterBar, {
slots: {
default: '
Extended mode content
', // Slot pour forcer le mode étendu
},
})
// Vérifier si le bouton est bien présent dans le DOM
const button = wrapper.find('#scroll-btn')
expect(button.exists()).toBe(true)
// Simuler le clic si le bouton existe
const scrollToSpy = vi.spyOn(window, 'scrollTo')
await button.trigger('click')
expect(scrollToSpy).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' })
})
it('returns "a" when href is defined', () => {
const item = { href: 'https://example.com' }
expect(getComponentType(item)).toBe('a')
})
it('returns "RouterLink" when href is undefined', () => {
const item = { href: undefined }
expect(getComponentType(item)).toBe('RouterLink')
})
it('returns "RouterLink" when href is null', () => {
const item = { href: null }
expect(getComponentType(item)).toBe('RouterLink')
})
it('returns "RouterLink" when href is null', () => {
const item = { href: null }
expect(getComponentType(item)).toBe('RouterLink')
})
it('sets target attribute correctly based on openInNewTab', () => {
const linkItems = [
{ text: 'Link 1', href: 'https://example.com', openInNewTab: true },
{ text: 'Link 2', href: 'https://example.com', openInNewTab: false },
]
const wrapper = mount(FooterBar, {
props: { linkItems },
})
const links = wrapper.findAll('.vd-footer-bar-links a')
expect(links[0]?.attributes('target')).toBe('_blank')
expect(links[1]?.attributes('target')).toBeUndefined()
})
it('returns locales.a11yLabel when complianceLabel is a string', () => {
const complianceLabel = 'compliant'
const a11yLabelMock = vi.fn().mockReturnValue('Accessibility Label')
locales.a11yLabel = a11yLabelMock
const result = testFunction(complianceLabel)
expect(a11yLabelMock).toHaveBeenCalledWith(complianceLabel)
expect(result).toBe('Accessibility Label')
})
it('returns an empty string when complianceLabel is not a string', () => {
const complianceLabel = null
const result = testFunction(complianceLabel)
expect(result).toBe('')
})
it('have an image with a source for the desktop logo', () => {
const wrapper = mount(FooterBar, {
slots: {
default: 'Extended mode content
', // Slot pour forcer le mode étendu
},
})
const sourceElement = wrapper.find('.logo-picture source')
expect(sourceElement.exists()).toBe(true)
expect(sourceElement.attributes('srcset')).toBeTruthy()
expect(sourceElement.attributes('media')).toBe(`(min-width: 600px)`)
})
it('updates the logo dynamically when the theme changes', async () => {
const wrapper = mount(FooterBar, {
slots: {
default: () => h('div', 'Extended mode content'),
},
})
const getLogoAttributes = () => ({
desktopSrcset: wrapper.find('.logo-picture source').attributes('srcset'),
mobileSrc: wrapper.find('.logo-picture img').attributes('src'),
})
expect(getLogoAttributes()).toEqual({
desktopSrcset: expect.stringContaining('logo-desktop-white.svg'),
mobileSrc: expect.stringContaining('logo-mobile-white.svg'),
})
await wrapper.setProps({ light: true })
expect(getLogoAttributes()).toEqual({
desktopSrcset: expect.stringContaining('logo-desktop.svg'),
mobileSrc: expect.stringContaining('logo-mobile.svg'),
})
})
// Le ring de focus est géré globalement (_btns.scss) : ces tests vérifient les
// prérequis structurels (jsdom ne calcule pas le style :focus-visible).
describe('focus', () => {
// Le bouton "haut de page" (#scroll-btn) n'apparaît qu'en mode étendu (slot par défaut).
const mountExtended = (props = {}) =>
mount(FooterBar, {
props,
slots: { default: 'Contenu du footer' },
})
it('renders the back-to-top as a native