import { GovukComponentTestHelper } from '../../test-utils/GovukComponentTestHelper' import { setupComponentTest } from '../../test-utils/setupComponentTest' import { GovUKPasswordInput } from './govukPasswordInput' vi.mock('nunjucks') describe('govukPasswordInput', () => { setupComponentTest() const helper = new GovukComponentTestHelper(GovUKPasswordInput) describe('Data transformation', () => { it('sets default values correctly', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field' }) // Assert expect(params.id).toBe('password-field') expect(params.name).toBe('password-field') expect(params.value).toBeUndefined() }) it('uses custom ID over code', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', id: 'custom-password-id', }) // Assert expect(params.id).toBe('custom-password-id') expect(params.name).toBe('password-field') }) it('passes through value', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', value: 'initial-password-value', }) // Assert expect(params.value).toBe('initial-password-value') }) }) describe('Label transformation', () => { it('converts string label to object format', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', label: 'Password', }) // Assert expect(params.label).toEqual({ text: 'Password', }) }) it('passes through object label unchanged', async () => { // Arrange const labelObj = { text: 'Create a password', classes: 'govuk-label--l', isPageHeading: true, } // Act const params = await helper.getParams({ code: 'password-field', label: labelObj, }) // Assert expect(params.label).toEqual(labelObj) }) it('passes through label with HTML', async () => { // Arrange const labelObj = { html: 'Password Required', } // Act const params = await helper.getParams({ code: 'password-field', label: labelObj, }) // Assert expect(params.label).toEqual(labelObj) }) }) describe('Hint transformation', () => { it('converts string hint to object format', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', hint: 'Your password must be at least 8 characters', }) // Assert expect(params.hint).toEqual({ text: 'Your password must be at least 8 characters', }) }) it('passes through object hint unchanged', async () => { // Arrange const hintObj = { text: 'Include numbers and special characters', classes: 'custom-hint', } // Act const params = await helper.getParams({ code: 'password-field', hint: hintObj, }) // Assert expect(params.hint).toEqual(hintObj) }) it('passes undefined hint when not provided', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', hint: undefined, }) // Assert expect(params.hint).toBeUndefined() }) }) describe('Password-specific options', () => { it('passes through showPasswordText', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', showPasswordText: 'Show password', }) // Assert expect(params.showPasswordText).toBe('Show password') }) it('passes through hidePasswordText', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', hidePasswordText: 'Hide password', }) // Assert expect(params.hidePasswordText).toBe('Hide password') }) it('passes through showPasswordAriaLabelText', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', showPasswordAriaLabelText: 'Show your password', }) // Assert expect(params.showPasswordAriaLabelText).toBe('Show your password') }) it('passes through hidePasswordAriaLabelText', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', hidePasswordAriaLabelText: 'Hide your password', }) // Assert expect(params.hidePasswordAriaLabelText).toBe('Hide your password') }) it('passes through passwordShownAnnouncementText', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', passwordShownAnnouncementText: 'Password shown', }) // Assert expect(params.passwordShownAnnouncementText).toBe('Password shown') }) it('passes through passwordHiddenAnnouncementText', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', passwordHiddenAnnouncementText: 'Password hidden', }) // Assert expect(params.passwordHiddenAnnouncementText).toBe('Password hidden') }) it('passes through button customization options', async () => { // Arrange const buttonObj = { classes: 'custom-button-class', } // Act const params = await helper.getParams({ code: 'password-field', button: buttonObj, }) // Assert expect(params.button).toEqual(buttonObj) }) it('passes through all password options together', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', showPasswordText: 'Show', hidePasswordText: 'Hide', showPasswordAriaLabelText: 'Show your password', hidePasswordAriaLabelText: 'Hide your password', passwordShownAnnouncementText: 'Your password is visible', passwordHiddenAnnouncementText: 'Your password is hidden', button: { classes: 'custom-toggle-button' }, }) // Assert expect(params.showPasswordText).toBe('Show') expect(params.hidePasswordText).toBe('Hide') expect(params.showPasswordAriaLabelText).toBe('Show your password') expect(params.hidePasswordAriaLabelText).toBe('Hide your password') expect(params.passwordShownAnnouncementText).toBe('Your password is visible') expect(params.passwordHiddenAnnouncementText).toBe('Your password is hidden') expect(params.button).toEqual({ classes: 'custom-toggle-button' }) }) }) describe('Input attributes', () => { it('passes through all input attributes without transformation', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', disabled: true, autocomplete: 'current-password', describedBy: 'password-requirements', formGroup: { classes: 'custom-form-group', beforeInput: { text: 'Before text' }, afterInput: { html: 'After HTML' }, }, classes: 'govuk-input--width-20', attributes: { 'data-testid': 'password-input', 'aria-describedby': 'help-text', }, }) // Assert expect(params.disabled).toBe(true) expect(params.autocomplete).toBe('current-password') expect(params.describedBy).toBe('password-requirements') expect(params.formGroup).toEqual({ classes: 'custom-form-group', beforeInput: { text: 'Before text' }, afterInput: { html: 'After HTML' }, }) expect(params.classes).toBe('govuk-input--width-20') expect(params.attributes).toEqual({ 'data-testid': 'password-input', 'aria-describedby': 'help-text', }) }) }) describe('Error message transformation', () => { it('transforms error array to error message object', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', errors: [{ message: 'Enter your password' }], }) // Assert expect(params.errorMessage).toEqual({ text: 'Enter your password', }) }) it('uses first error when multiple provided', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field', errors: [{ message: 'First error' }, { message: 'Second error' }], }) // Assert expect(params.errorMessage).toEqual({ text: 'First error', }) }) it('sets errorMessage to undefined when no errors', async () => { // Arrange // Act const params = await helper.getParams({ code: 'password-field' }) // Assert expect(params.errorMessage).toBeUndefined() }) }) describe('Template and context', () => { it('calls nunjucks with correct template path', async () => { // Arrange // Act const { template } = await helper.executeComponent({ code: 'password-field', }) // Assert expect(template).toBe('govuk/components/password-input/template.njk') }) it('wraps params in context object', async () => { // Arrange // Act const { context } = (await helper.executeComponent({ code: 'password-field', })) as { context: any } // Assert expect(context).toHaveProperty('params') expect(context.params).toHaveProperty('id') expect(context.params).toHaveProperty('name') }) }) describe('DOM rendering smoke test', () => { it('renders a valid password input component', async () => { // Arrange // Act const html = await helper.renderWithNunjucks({ code: 'user-password', variant: 'govukPasswordInput', label: 'Password', hint: 'Your password must be at least 8 characters', value: 'test-password-value', autocomplete: 'current-password', errors: [{ message: 'Enter your password' }], showPasswordText: 'Show', hidePasswordText: 'Hide', }) // Assert expect(html).toContainText('govuk-password-input') expect(html).toContainText('user-password') expect(html).toContainText('Password') expect(html).toContainText('Your password must be at least 8 characters') expect(html).toContainText('Enter your password') expect(html).toContainText('test-password-value') expect(html).toContainText('autocomplete="current-password"') expect(html).toContainText('Show') }) }) })