import { GovukComponentTestHelper } from '../../test-utils/GovukComponentTestHelper'
import { setupComponentTest } from '../../test-utils/setupComponentTest'
import { GovUKBreadcrumbs } from './govukBreadcrumbs'
vi.mock('nunjucks')
describe('GOV.UK Breadcrumbs Component', () => {
setupComponentTest()
const helper = new GovukComponentTestHelper(GovUKBreadcrumbs)
describe('Item data transformation', () => {
it('sets single item correctly', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home' }],
})
// Assert
expect(params.items).toHaveLength(1)
expect(params.items[0]).toEqual({ text: 'Home' })
})
it('sets multiple items correctly', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [
{ text: 'Home', href: '/' },
{ text: 'Passports, travel and living abroad', href: '/browse/abroad' },
{ text: 'Travel abroad' },
],
})
// Assert
expect(params.items).toHaveLength(3)
expect(params.items[0]).toEqual({ text: 'Home', href: '/' })
expect(params.items[1]).toEqual({ text: 'Passports, travel and living abroad', href: '/browse/abroad' })
expect(params.items[2]).toEqual({ text: 'Travel abroad' })
})
it('sets item with href', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home', href: '/' }],
})
// Assert
expect(params.items[0]).toEqual({ text: 'Home', href: '/' })
})
it('sets item without href for current page', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home', href: '/' }, { text: 'Current Page' }],
})
// Assert
expect(params.items[1]).toEqual({ text: 'Current Page' })
expect(params.items[1].href).toBeUndefined()
})
})
describe('Item content', () => {
it('sets text content correctly', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Plain text breadcrumb' }],
})
// Assert
expect(params.items[0].text).toBe('Plain text breadcrumb')
expect(params.items[0].html).toBeUndefined()
})
it('uses html content when provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ html: 'Home' }],
})
// Assert
expect(params.items[0].html).toBe('Home')
})
it('uses html over text when both provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'This is ignored', html: 'This is used' }],
})
// Assert
expect(params.items[0].html).toBe('This is used')
expect(params.items[0].text).toBe('This is ignored')
})
it('sets item attributes correctly', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [
{
text: 'Home',
href: '/',
attributes: {
'data-tracking': 'breadcrumb-home',
},
},
],
})
// Assert
expect(params.items[0].attributes).toEqual({
'data-tracking': 'breadcrumb-home',
})
})
it('handles multiple items with different content types', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home', href: '/' }, { html: 'Documents', href: '/documents' }, { text: 'Current' }],
})
// Assert
expect(params.items[0]).toEqual({ text: 'Home', href: '/' })
expect(params.items[1]).toEqual({ html: 'Documents', href: '/documents' })
expect(params.items[2]).toEqual({ text: 'Current' })
})
})
describe('Breadcrumbs options', () => {
it('sets collapseOnMobile when true', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home', href: '/' }, { text: 'Section', href: '/section' }, { text: 'Page' }],
collapseOnMobile: true,
})
// Assert
expect(params.collapseOnMobile).toBe(true)
})
it('does not set collapseOnMobile when false', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home', href: '/' }, { text: 'Page' }],
collapseOnMobile: false,
})
// Assert
expect(params.collapseOnMobile).toBe(false)
})
it('does not set collapseOnMobile when not provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home', href: '/' }, { text: 'Page' }],
})
// Assert
expect(params.collapseOnMobile).toBeUndefined()
})
it('sets labelText for accessibility', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home', href: '/' }],
labelText: 'Custom breadcrumb navigation',
})
// Assert
expect(params.labelText).toBe('Custom breadcrumb navigation')
})
it('does not set labelText when not provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home', href: '/' }],
})
// Assert
expect(params.labelText).toBeUndefined()
})
})
describe('Optional attributes', () => {
it('passes through classes', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home' }],
classes: 'app-breadcrumbs--custom',
})
// Assert
expect(params.classes).toBe('app-breadcrumbs--custom')
})
it('passes through attributes', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home' }],
attributes: {
'data-module': 'custom-breadcrumbs',
'data-track': 'breadcrumb-navigation',
},
})
// Assert
expect(params.attributes).toEqual({
'data-module': 'custom-breadcrumbs',
'data-track': 'breadcrumb-navigation',
})
})
it('handles all options together', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [
{ text: 'Home', href: '/' },
{ html: 'Section', href: '/section' },
{ text: 'Current Page' },
],
collapseOnMobile: true,
labelText: 'Site navigation',
classes: 'app-breadcrumbs--large',
attributes: {
'data-module': 'app-breadcrumbs',
},
})
// Assert
expect(params.items).toHaveLength(3)
expect(params.collapseOnMobile).toBe(true)
expect(params.labelText).toBe('Site navigation')
expect(params.classes).toBe('app-breadcrumbs--large')
expect(params.attributes).toEqual({
'data-module': 'app-breadcrumbs',
})
})
})
describe('Template and context', () => {
it('calls nunjucks with correct template path', async () => {
// Arrange & Act
const { template } = await helper.executeComponent({
items: [{ text: 'Home', href: '/' }],
})
// Assert
expect(template).toBe('govuk/components/breadcrumbs/template.njk')
})
it('wraps params in correct context structure', async () => {
// Arrange & Act
const { context } = (await helper.executeComponent({
items: [{ text: 'Home', href: '/' }, { text: 'Current' }],
labelText: 'Navigation',
})) as { context: { params: any } }
// Assert
expect(context).toHaveProperty('params')
expect(context.params.items).toHaveLength(2)
expect(context.params.labelText).toBe('Navigation')
})
})
describe('DOM rendering smoke test', () => {
it('renders breadcrumbs with multiple items', async () => {
// Arrange & Act
const html = await helper.renderWithNunjucks({
items: [
{ text: 'Home', href: '/' },
{ text: 'Passports, travel and living abroad', href: '/browse/abroad' },
{ text: 'Travel abroad' },
],
})
// Assert
expect(html).toContain('govuk-breadcrumbs')
expect(html).toContain('Home')
expect(html).toContain('Passports, travel and living abroad')
expect(html).toContain('Travel abroad')
expect(html).toContain('/')
expect(html).toContain('/browse/abroad')
})
it('renders breadcrumbs with collapseOnMobile', async () => {
// Arrange & Act
const html = await helper.renderWithNunjucks({
items: [
{ text: 'Home', href: '/' },
{ text: 'Section', href: '/section' },
{ text: 'Subsection', href: '/subsection' },
{ text: 'Current' },
],
collapseOnMobile: true,
})
// Assert
expect(html).toContain('govuk-breadcrumbs')
expect(html).toContain('govuk-breadcrumbs--collapse-on-mobile')
})
it('renders breadcrumbs with custom label text', async () => {
// Arrange & Act
const html = await helper.renderWithNunjucks({
items: [{ text: 'Home', href: '/' }, { text: 'Current' }],
labelText: 'Site navigation breadcrumb',
})
// Assert
expect(html).toContain('govuk-breadcrumbs')
expect(html).toContain('Site navigation breadcrumb')
})
it('renders breadcrumbs with HTML content', async () => {
// Arrange & Act
const html = await helper.renderWithNunjucks({
items: [{ html: 'Home', href: '/' }, { text: 'Current Page' }],
})
// Assert
expect(html).toContain('govuk-breadcrumbs')
expect(html).toContain('Home')
expect(html).toContain('Current Page')
})
it('renders breadcrumbs with custom classes', async () => {
// Arrange & Act
const html = await helper.renderWithNunjucks({
items: [{ text: 'Home', href: '/' }],
classes: 'app-breadcrumbs--custom',
})
// Assert
expect(html).toContain('govuk-breadcrumbs')
expect(html).toContain('app-breadcrumbs--custom')
})
})
describe('Conditional item visibility', () => {
it('omits items where visibleWhen evaluates to false', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [
{ text: 'Home', href: '/' },
{ text: 'Admin', href: '/admin', visibleWhen: false },
{ text: 'Account' },
],
})
// Assert
expect(params.items).toHaveLength(2)
expect(params.items[0]).toEqual({ text: 'Home', href: '/' })
expect(params.items[1]).toEqual({ text: 'Account' })
})
it('keeps items where visibleWhen is undefined', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ text: 'Home' }],
})
// Assert
expect(params.items).toHaveLength(1)
})
})
})