import { axe } from 'vitest-axe'; import type { RenderResult } from '@testing-library/react'; import { act, cleanup, render, screen } from '@testing-library/react'; import * as PasswordToggleField from './password-toggle-field'; import { afterEach, describe, it, beforeEach, expect } from 'vitest'; import { userEvent, type UserEvent } from '@testing-library/user-event'; describe('given a default PasswordToggleField', () => { let rendered: RenderResult; let user: UserEvent; afterEach(cleanup); beforeEach(() => { user = userEvent.setup(); rendered = render( <> , ); }); afterEach(cleanup); it('should have no accessibility violations', async () => { expect(await axe(rendered.container)).toHaveNoViolations(); }); it('should initially be hidden', () => { const toggle = screen.getByRole('button', { name: 'Show' }); expect(toggle.textContent).toBe('Show'); }); it('toggles the children when clicked', async () => { const toggle = screen.getByRole('button', { name: 'Show' }); await act(async () => await user.click(toggle)); expect(toggle.textContent).toBe('Hide'); }); it('should initially render input as `type=password`', async () => { const input = screen.getByLabelText('Password'); expect(input.type).toBe('password'); }); it('should initially render input as `type=text` when toggled', async () => { const input = screen.getByLabelText('Password'); const toggle = screen.getByRole('button', { name: 'Show' }); await act(async () => await user.click(toggle)); expect(input.type).toBe('text'); }); it('should re-focus the input after toggling', async () => { const input = screen.getByLabelText('Password'); const toggle = screen.getByRole('button', { name: 'Show' }); await act(async () => await user.click(toggle)); expect(document.activeElement).toBe(input); }); it("should restore the input's selection after toggling", async () => { const input = screen.getByLabelText('Password'); const toggle = screen.getByRole('button', { name: 'Show' }); await act(async () => await user.click(input)); await act(async () => await user.type(input, 'p')); await act(async () => await user.click(toggle)); // selection should be at the end of the input value expect(input.selectionStart).toBe(1); expect(input.selectionEnd).toBe(1); await act(async () => await user.type(input, 'assword')); input.selectionStart = 0; input.selectionEnd = 4; await act(async () => await user.click(toggle)); expect(input.selectionStart).toBe(0); expect(input.selectionEnd).toBe(4); }); }); describe('given a PasswordToggleField with an Icon', () => { let rendered: RenderResult; let user: UserEvent; afterEach(cleanup); beforeEach(() => { user = userEvent.setup(); rendered = render( <> } hidden={} /> , ); }); afterEach(cleanup); it('should have no accessibility violations', async () => { expect(await axe(rendered.container)).toHaveNoViolations(); }); it('should initially be hidden', () => { const icon = screen.getByTestId('closed'); expect(icon).toBeVisible(); expect(screen.queryByTestId('open')).not.toBeInTheDocument(); }); it('toggles the icon when clicked', async () => { const toggle = screen.getByRole('button', { name: 'Show password' }); await act(async () => await user.click(toggle)); expect(screen.getByTestId('open')).toBeVisible(); expect(screen.queryByTestId('closed')).not.toBeInTheDocument(); }); it('should initially render input as `type=password`', async () => { const input = screen.getByLabelText('Password'); expect(input.type).toBe('password'); }); it('should initially render input as `type=text` when toggled', async () => { const input = screen.getByLabelText('Password'); const toggle = screen.getByRole('button', { name: 'Show password' }); await act(async () => await user.click(toggle)); expect(input.type).toBe('text'); }); it('should retain its value when toggled', async () => { const input = screen.getByLabelText('Password'); const toggle = screen.getByRole('button', { name: 'Show password' }); await act(async () => await user.type(input, 'pass123')); await act(async () => await user.click(toggle)); expect(input).toHaveValue('pass123'); }); }); describe('given a PasswordToggleField in a form', () => { let user: UserEvent; afterEach(cleanup); beforeEach(() => { user = userEvent.setup(); render(
e.preventDefault()}>
, ); }); afterEach(cleanup); it('should reset visibility to hidden after submission', async () => { const toggle = screen.getByRole('button', { name: 'Show' }); const input = screen.getByLabelText('Password'); await act(() => user.click(toggle)); expect(input.type).toBe('text'); const submitButton = screen.getByText('Submit'); await act(() => user.click(submitButton)); expect(input.type).toBe('password'); }); }); function EyeClosedIcon(props: React.SVGProps) { return ( ); } function EyeOpenIcon(props: React.SVGProps) { return ( ); }