import { MojComponentTestHelper } from '../../test-utils/MojComponentTestHelper'
import { setupComponentTest } from '../../test-utils/setupComponentTest'
import { MOJProgressBar } from './mojProgressBar'
vi.mock('nunjucks')
describe('mojProgressBar', () => {
setupComponentTest()
const helper = new MojComponentTestHelper(MOJProgressBar)
describe('Item data transformation', () => {
it('should transform item with string label to object format', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Step 1' }],
})
// Assert
expect(params.items?.[0].label).toEqual({ text: 'Step 1' })
})
it('should pass through item with object label unchanged', async () => {
// Arrange
const label = {
text: 'Step 1',
classes: 'custom-label-class',
}
// Act
const params = await helper.getParams({
items: [{ label }],
})
// Assert
expect(params.items?.[0].label).toEqual(label)
})
it('should pass through item label with HTML content', async () => {
// Arrange
const label = {
html: 'Important Step',
}
// Act
const params = await helper.getParams({
items: [{ label }],
})
// Assert
expect(params.items?.[0].label).toEqual(label)
})
it('should transform multiple items correctly', async () => {
// Arrange
const items = [
{ label: 'Personal details' },
{ label: { text: 'Contact information', classes: 'custom' } },
{ label: { html: 'Review' } },
]
// Act
const params = await helper.getParams({ items })
// Assert
expect(params.items).toHaveLength(3)
expect(params.items?.[0].label).toEqual({ text: 'Personal details' })
expect(params.items?.[1].label).toEqual({ text: 'Contact information', classes: 'custom' })
expect(params.items?.[2].label).toEqual({ html: 'Review' })
})
it('should omit items when visibleWhen evaluates to false', async () => {
// Arrange
const items = [
{ label: 'Personal details' },
{ label: 'Internal check', visibleWhen: false },
{ label: 'Review', visibleWhen: true },
]
// Act
const params = await helper.getParams({ items })
// Assert
expect(params.items.map((item: { label: { text: string } }) => item.label.text)).toEqual([
'Personal details',
'Review',
])
})
})
describe('Item states', () => {
it('should pass through active state as true', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Current step', active: true }],
})
// Assert
expect(params.items?.[0].active).toBe(true)
})
it('should pass through active state as false', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Inactive step', active: false }],
})
// Assert
expect(params.items?.[0].active).toBe(false)
})
it('should leave active undefined when not provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Step' }],
})
// Assert
expect(params.items?.[0].active).toBeUndefined()
})
it('should pass through complete state as true', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Completed step', complete: true }],
})
// Assert
expect(params.items?.[0].complete).toBe(true)
})
it('should pass through complete state as false', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Incomplete step', complete: false }],
})
// Assert
expect(params.items?.[0].complete).toBe(false)
})
it('should leave complete undefined when not provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Step' }],
})
// Assert
expect(params.items?.[0].complete).toBeUndefined()
})
it('should handle item with both active and complete states', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [
{ label: 'Done', complete: true, active: false },
{ label: 'Current', complete: false, active: true },
],
})
// Assert
expect(params.items?.[0].complete).toBe(true)
expect(params.items?.[0].active).toBe(false)
expect(params.items?.[1].complete).toBe(false)
expect(params.items?.[1].active).toBe(true)
})
it('should handle pending state (neither active nor complete)', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Future step' }],
})
// Assert
expect(params.items?.[0].active).toBeUndefined()
expect(params.items?.[0].complete).toBeUndefined()
})
})
describe('Item identifiers', () => {
it('should pass through item id when provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ id: 'step-personal-details', label: 'Personal details' }],
})
// Assert
expect(params.items?.[0].id).toBe('step-personal-details')
})
it('should leave item id undefined when not provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Step' }],
})
// Assert
expect(params.items?.[0].id).toBeUndefined()
})
it('should pass through multiple item ids', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ id: 'step-1', label: 'First' }, { id: 'step-2', label: 'Second' }, { label: 'Third' }],
})
// Assert
expect(params.items?.[0].id).toBe('step-1')
expect(params.items?.[1].id).toBe('step-2')
expect(params.items?.[2].id).toBeUndefined()
})
})
describe('Progress bar options', () => {
it('should pass through id when provided', async () => {
// Arrange & Act
const params = await helper.getParams({
id: 'application-progress',
items: [{ label: 'Step' }],
})
// Assert
expect(params.id).toBe('application-progress')
})
it('should leave id undefined when not provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Step' }],
})
// Assert
expect(params.id).toBeUndefined()
})
it('should pass through label for accessibility', async () => {
// Arrange & Act
const params = await helper.getParams({
label: 'Application progress',
items: [{ label: 'Step' }],
})
// Assert
expect(params.label).toBe('Application progress')
})
it('should leave label undefined when not provided', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Step' }],
})
// Assert
expect(params.label).toBeUndefined()
})
})
describe('Item optional attributes', () => {
it('should pass through item classes', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [
{
label: 'Step',
classes: 'custom-item-class',
},
],
})
// Assert
expect(params.items?.[0].classes).toBe('custom-item-class')
})
it('should pass through item attributes', async () => {
// Arrange
const attributes = {
'data-testid': 'progress-item-1',
'data-tracking': 'step-viewed',
}
// Act
const params = await helper.getParams({
items: [
{
label: 'Step',
attributes,
},
],
})
// Assert
expect(params.items?.[0].attributes).toEqual(attributes)
})
})
describe('Container optional attributes', () => {
it('should pass through classes', async () => {
// Arrange & Act
const params = await helper.getParams({
items: [{ label: 'Step' }],
classes: 'custom-progress-bar-class',
})
// Assert
expect(params.classes).toBe('custom-progress-bar-class')
})
it('should pass through attributes', async () => {
// Arrange
const attributes = {
'data-testid': 'progress-bar',
'data-module': 'progress-tracker',
}
// Act
const params = await helper.getParams({
items: [{ label: 'Step' }],
attributes,
})
// Assert
expect(params.attributes).toEqual(attributes)
})
})
describe('Template and context', () => {
it('should call nunjucks with correct template path', async () => {
// Arrange & Act
const { template } = await helper.executeComponent({
items: [{ label: 'Step' }],
})
// Assert
expect(template).toBe('moj/components/progress-bar/template.njk')
})
it('should wrap params in context object', async () => {
// Arrange & Act
const { context } = await helper.executeComponent({
items: [{ label: 'Step' }],
})
// Assert
expect(context).toHaveProperty('params')
expect((context as { params: Record }).params).toHaveProperty('items')
})
it('should include all params in context', async () => {
// Arrange & Act
const { context } = await helper.executeComponent({
id: 'application-progress',
label: 'Application progress',
items: [
{
id: 'step-1',
label: 'Personal details',
complete: true,
classes: 'item-custom',
attributes: { 'data-step': '1' },
},
{
id: 'step-2',
label: { text: 'Contact information', classes: 'label-custom' },
active: true,
},
{
label: 'Review and submit',
},
],
classes: 'custom-progress-class',
attributes: { 'data-test': 'value' },
})
// Assert
const params = (context as { params: Record }).params
expect(params).toHaveProperty('id', 'application-progress')
expect(params).toHaveProperty('label', 'Application progress')
expect(params).toHaveProperty('items')
expect(params.items).toHaveLength(3)
expect(params).toHaveProperty('classes', 'custom-progress-class')
expect(params).toHaveProperty('attributes')
})
it('should transform all item labels in context', async () => {
// Arrange & Act
const { context } = await helper.executeComponent({
items: [
{ label: 'String label' },
{ label: { text: 'Object label' } },
{ label: { html: 'HTML label' } },
],
})
// Assert
const params = (context as { params: Record }).params
expect(params.items[0].label).toEqual({ text: 'String label' })
expect(params.items[1].label).toEqual({ text: 'Object label' })
expect(params.items[2].label).toEqual({ html: 'HTML label' })
})
})
})