import { GovukComponentTestHelper } from '../../test-utils/GovukComponentTestHelper'
import { setupComponentTest } from '../../test-utils/setupComponentTest'
import { GovUKTextInput } from './govukTextInput'
vi.mock('nunjucks')
describe('govukTextInput', () => {
setupComponentTest()
const helper = new GovukComponentTestHelper(GovUKTextInput)
describe('Registration entry', () => {
it('should accept a scalar string and reject an array against the input schema', () => {
// Arrange & Act
const scalar = GovUKTextInput.inputSchema?.safeParse('hello')
const array = GovUKTextInput.inputSchema?.safeParse(['hello'])
// Assert
expect(scalar?.success).toBe(true)
expect(array?.success).toBe(false)
})
})
describe('Data transformation', () => {
it('sets default values correctly', async () => {
const params = await helper.getParams({ code: 'test-input' })
expect(params.id).toBe('test-input')
expect(params.name).toBe('test-input')
expect(params.type).toBe('text')
expect(params.value).toBeUndefined()
})
it('uses custom ID over code', async () => {
const params = await helper.getParams({
code: 'test-input',
id: 'custom-id',
})
expect(params.id).toBe('custom-id')
expect(params.name).toBe('test-input')
})
it('passes through value', async () => {
const params = await helper.getParams({
code: 'test-input',
value: 'Initial value',
})
expect(params.value).toBe('Initial value')
})
})
describe('Label transformation', () => {
it('converts string label to object format', async () => {
const params = await helper.getParams({
code: 'test-input',
label: 'Enter your name',
})
expect(params.label).toEqual({
text: 'Enter your name',
})
})
it('passes through object label unchanged', async () => {
const labelObj = {
text: 'Full Name',
classes: 'govuk-label--l',
isPageHeading: true,
}
const params = await helper.getParams({
code: 'test-input',
label: labelObj,
})
expect(params.label).toEqual(labelObj)
})
it('passes through label with HTML', async () => {
const labelObj = {
html: 'Name Required',
}
const params = await helper.getParams({
code: 'test-input',
label: labelObj,
})
expect(params.label).toEqual(labelObj)
})
})
describe('Hint transformation', () => {
it('converts string hint to object format', async () => {
const params = await helper.getParams({
code: 'test-input',
hint: 'Include your middle name',
})
expect(params.hint).toEqual({
text: 'Include your middle name',
})
})
it('passes through object hint unchanged', async () => {
const hintObj = {
text: 'Enter your full legal name',
classes: 'custom-hint',
}
const params = await helper.getParams({
code: 'test-input',
hint: hintObj,
})
expect(params.hint).toEqual(hintObj)
})
it('passes undefined hint when not provided', async () => {
const params = await helper.getParams({
code: 'test-input',
hint: undefined,
})
expect(params.hint).toBeUndefined()
})
})
describe('Input attributes', () => {
it('passes through all input attributes without transformation', async () => {
const params = await helper.getParams({
code: 'test-input',
inputMode: 'numeric',
pattern: '[0-9]*',
spellcheck: false,
autocomplete: 'email',
describedBy: 'email-requirements',
disabled: true,
autocapitalize: 'words',
prefix: { text: '£' },
suffix: { text: 'per month' },
inputWrapper: { classes: 'wrapper-class' },
inputType: 'email',
formGroup: {
classes: 'custom-form-group',
beforeInput: { text: 'Before text' },
afterInput: { html: 'After HTML' },
},
classes: 'govuk-input--width-10',
attributes: {
'data-testid': 'test-input',
'aria-describedby': 'help-text',
},
})
expect(params.inputmode).toBe('numeric')
expect(params.pattern).toBe('[0-9]*')
expect(params.spellcheck).toBe(false)
expect(params.autocomplete).toBe('email')
expect(params.describedBy).toBe('email-requirements')
expect(params.disabled).toBe(true)
expect(params.autocapitalize).toBe('words')
expect(params.prefix).toEqual({ text: '£' })
expect(params.suffix).toEqual({ text: 'per month' })
expect(params.inputWrapper).toEqual({ classes: 'wrapper-class' })
expect(params.type).toEqual('email')
expect(params.formGroup).toEqual({
classes: 'custom-form-group',
beforeInput: { text: 'Before text' },
afterInput: { html: 'After HTML' },
})
expect(params.classes).toBe('govuk-input--width-10')
expect(params.attributes).toEqual({
'data-testid': 'test-input',
'aria-describedby': 'help-text',
})
})
})
describe('Error message transformation', () => {
it('transforms error array to error message object', async () => {
const params = await helper.getParams({
code: 'test-input',
errors: [{ message: 'Enter a valid email address' }],
})
expect(params.errorMessage).toEqual({
text: 'Enter a valid email address',
})
})
it('uses first error when multiple provided', async () => {
const params = await helper.getParams({
code: 'test-input',
errors: [{ message: 'First error' }, { message: 'Second error' }],
})
expect(params.errorMessage).toEqual({
text: 'First error',
})
})
it('sets errorMessage to undefined when no errors', async () => {
const params = await helper.getParams({ code: 'test-input' })
expect(params.errorMessage).toBeUndefined()
})
})
describe('Template and context', () => {
it('calls nunjucks with correct template path', async () => {
const { template } = await helper.executeComponent({
code: 'test-input',
})
expect(template).toBe('govuk/components/input/template.njk')
})
it('wraps params in context object', async () => {
const { context } = (await helper.executeComponent({
code: 'test-input',
})) as { context: any }
expect(context).toHaveProperty('params')
expect(context.params).toHaveProperty('id')
expect(context.params).toHaveProperty('name')
expect(context.params).toHaveProperty('type')
})
})
describe('DOM rendering smoke test', () => {
it('renders a valid text input component', async () => {
const html = await helper.renderWithNunjucks({
code: 'email-address',
variant: 'govukTextInput',
inputType: 'email',
label: 'Email address',
hint: `We'll only use this to contact you`,
value: 'user@example.com',
autocomplete: 'email',
spellcheck: false,
errors: [{ message: 'Enter a valid email address' }],
})
expect(html).toContainText('govuk-input')
expect(html).toContainText('type="email"')
expect(html).toContainText('email-address')
expect(html).toContainText('Email address')
expect(html).toContainText(`We'll only use this to contact you`)
expect(html).toContainText('Enter a valid email address')
expect(html).toContainText('user@example.com')
expect(html).toContainText('autocomplete="email"')
expect(html).toContainText('spellcheck="false"')
})
})
})