Skip to content

Commit

Permalink
Fill in missing gaps in unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jakeb-nhs committed Apr 5, 2024
1 parent edd1d4f commit 92fc5ec
Show file tree
Hide file tree
Showing 16 changed files with 782 additions and 49 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"classnames": "^2.2.6"
},
"peerDependencies": {
"nhsuk-frontend": ">=8.0.0",
"nhsuk-frontend": ">=8.0.0 <9.0.0",
"react": ">=18.2.0",
"react-dom": ">=18.2.0"
},
Expand Down
127 changes: 125 additions & 2 deletions src/components/form-elements/date-input/__tests__/DateInput.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { render } from '@testing-library/react';
import { render, fireEvent } from '@testing-library/react';
import DateInput from '../DateInput';

describe('DateInput', () => {
Expand All @@ -9,5 +9,128 @@ describe('DateInput', () => {
expect(container).toMatchSnapshot();
});

// previous tests have been removed - they're testing react, not the component. New ones to be added under NUT-4646
it.each`
autoSelectNext | inputValue | monthFocusExpected
${false} | ${'1'} | ${false}
${false} | ${'11'} | ${false}
${true} | ${'1'} | ${false}
${true} | ${'11'} | ${true}
`(
'When autoSelectNext is $autoSelectNext, the day input value is $inputValue, then month focus is expected to be $monthFocusExpected',
({ autoSelectNext, inputValue, monthFocusExpected }) => {
const { container } = render(
<DateInput id="testInput" name="testInput" autoSelectNext={autoSelectNext} />,
);

const dayInput = container.querySelector('#testInput-day')!;
const monthInput = container.querySelector('#testInput-month')!;

expect(monthInput).not.toHaveFocus();

fireEvent.change(dayInput, { target: { value: inputValue } });

if (monthFocusExpected) {
expect(monthInput).toHaveFocus();
} else {
expect(monthInput).not.toHaveFocus();
}
},
);

it.each`
autoSelectNext | inputValue | yearFocusExpected
${false} | ${'1'} | ${false}
${false} | ${'11'} | ${false}
${true} | ${'1'} | ${false}
${true} | ${'11'} | ${true}
`(
'When autoSelectNext is $autoSelectNext, the day input value is $inputValue, then year focus is expected to be $yearFocusExpected',
({ autoSelectNext, inputValue, yearFocusExpected }) => {
const { container } = render(
<DateInput id="testInput" name="testInput" autoSelectNext={autoSelectNext} />,
);

const monthInput = container.querySelector('#testInput-month')!;
const yearInput = container.querySelector('#testInput-year')!;

expect(yearInput).not.toHaveFocus();

fireEvent.change(monthInput, { target: { value: inputValue } });

if (yearFocusExpected) {
expect(yearInput).toHaveFocus();
} else {
expect(yearInput).not.toHaveFocus();
}
},
);

it('Invokes the provided onChange function prop if provided', () => {
const onChange = jest.fn();

const { container } = render(<DateInput id="testInput" name="testInput" onChange={onChange} />);

const dayInput = container.querySelector('#testInput-day')!;
const monthInput = container.querySelector('#testInput-month')!;
const yearInput = container.querySelector('#testInput-year')!;

fireEvent.change(dayInput, { target: { value: '21' } });

expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({
currentTarget: {
value: {
day: '21',
month: '',
year: '',
},
},
}),
);

fireEvent.change(monthInput, { target: { value: '03' } });

expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({
currentTarget: {
value: {
day: '21',
month: '03',
year: '',
},
},
}),
);

fireEvent.change(yearInput, { target: { value: '2024' } });

expect(onChange).toHaveBeenCalledTimes(3);
expect(onChange).toHaveBeenLastCalledWith(
expect.objectContaining({
currentTarget: {
value: {
day: '21',
month: '03',
year: '2024',
},
},
}),
);
});

it('Renders the specified children instead of date fields if provided', () => {
const { container } = render(
<DateInput id="testInput" name="testInput">
<div id="testDiv"></div>
</DateInput>,
);

expect(container.querySelector('#testInput-day')).toBeNull();
expect(container.querySelector('#testInput-month')).toBeNull();
expect(container.querySelector('#testInput-year')).toBeNull();

expect(container.querySelector('#testDiv')).not.toBeNull();
});
});
21 changes: 20 additions & 1 deletion src/components/form-elements/select/__tests__/Select.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,26 @@ describe('Select', () => {
return <Select onClick={handleClick} selectRef={ref} />;
};

// further tests need to be added as part of NUT-4646
it('Matches the snapshot', () => {
const { container } = render(
<Select id="test-select">
<Select.Option value="1">Option 1</Select.Option>
<Select.Option value="2">Option 2</Select.Option>
</Select>,
);

expect(container).toMatchSnapshot();
});

it.each([true, false])('Adds the appropriate class if error is specified as %s', (error) => {
const { container } = render(<Select id="test-select" error={error} />);

if (error) {
expect(container.querySelector('#test-select')).toHaveClass('nhsuk-select--error');
} else {
expect(container.querySelector('#test-select')).not.toHaveClass('nhsuk-select--error');
}
});

it('should handle DOM events where ref Exists', () => {
const useRefSpy = jest
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Select Matches the snapshot 1`] = `
<div>
<div
class="nhsuk-form-group"
>
<select
class="nhsuk-select"
id="test-select"
name="test-select"
>
<option
value="1"
>
Option 1
</option>
<option
value="2"
>
Option 2
</option>
</select>
</div>
</div>
`;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import TextInput from '../TextInput';
import { InputWidth } from '@util/types/NHSUKTypes';

describe('TextInput', () => {
afterEach(() => {
Expand All @@ -17,8 +18,6 @@ describe('TextInput', () => {
return <TextInput type="button" onClick={handleClick} inputRef={ref} />;
};

// further tests need to be added as part of NUT-4646

it('should handle click where ref Exists', () => {
const useRefSpy = jest
.spyOn(React, 'useRef')
Expand All @@ -32,4 +31,77 @@ describe('TextInput', () => {
expect(useRefSpy).toBeCalledWith(null);
expect(mock).toBeCalledTimes(1);
});

it.each<InputWidth | undefined>([undefined, '5', '10'])(
'Sets the provided input width if specified with %s',
(width) => {
const { container } = render(<TextInput width={width} />);

const input = container.querySelector('.nhsuk-input');

if (width) {
expect(input).toHaveClass(`nhsuk-input--width-${width}`);
} else {
expect(input?.className.indexOf('nhsuk-input--width')).toBe(-1);
}
},
);

it.each<string | boolean | undefined>([undefined, true, false, 'error'])(
'Sets the error class if specified with %s',
(error) => {
const { container } = render(<TextInput error={error} />);

const input = container.querySelector('.nhsuk-input');

if (error) {
expect(input).toHaveClass('nhsuk-input--error');
} else {
expect(input).not.toHaveClass('nhsuk-input--error');
}
},
);

it('Sets the provided input width if specified', () => {
const { container } = render(<TextInput width="5" />);

expect(container.querySelector('.nhsuk-input')).toHaveClass('nhsuk-input--width-5');
});

it.each`
prefix | suffix
${'£'} | ${'per item'}
${'£'} | ${undefined}
${undefined} | ${'per item'}
${undefined} | ${undefined}
`(
'Renders expected prefix and suffix when provided $prefix and $suffix',
({ prefix, suffix }) => {
const { container } = render(<TextInput prefix={prefix} suffix={suffix} />);

const prefixElement = container.querySelector('.nhsuk-input__wrapper > .nhsuk-input__prefix');
const suffixElement = container.querySelector('.nhsuk-input__wrapper > .nhsuk-input__suffix');

if (prefix) {
expect(prefixElement).not.toBeNull();
expect(prefixElement?.textContent).toBe(prefix);
} else {
expect(prefixElement).toBeNull();
}

if (suffix) {
expect(suffixElement).not.toBeNull();
expect(suffixElement?.textContent).toBe(suffix);
} else {
expect(suffixElement).toBeNull();
}

if (!prefix && !suffix) {
expect(container.querySelector('.nhsuk-input__wrapper')).toBeNull();
expect(container.querySelector('.nhsuk-input')).not.toBeNull();
} else {
expect(container.querySelector('.nhsuk-input__wrapper > .nhsuk-input')).not.toBeNull();
}
},
);
});
2 changes: 1 addition & 1 deletion src/components/navigation/breadcrumb/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const Back: Back = ({

interface Breadcrumb extends React.FC<HTMLProps<HTMLDivElement>> {
Item: Item;
Back: Item;
Back: Back;
}

type SplitChildren = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { ElementType } from 'react';
import { render } from '@testing-library/react';
import Breadcrumb from '../';

Expand Down Expand Up @@ -55,4 +55,53 @@ describe('Breadcrumb', () => {

expect(container.querySelector('#otherElement')?.textContent).toEqual('Test Element');
});

it.each<string | undefined>([undefined, 'Test label'])(
'Renders as expected when aria label is specified as %s',
(ariaLabel) => {
const { container } = render(<Breadcrumb aria-label={ariaLabel}></Breadcrumb>);

const breadcrumbElement = container.querySelector('.nhsuk-breadcrumb');

expect(breadcrumbElement?.getAttribute('aria-label')).toBe(ariaLabel ?? 'Breadcrumb');
},
);

describe('The BreadcrumbBack component', () => {
it.each<string | undefined>([undefined, 'Accessible prefix'])(
'Renders as expected with visually hidden text when accessiblePrefix is specified as %s',
(accessiblePrefix) => {
const { container } = render(
<Breadcrumb>
<Breadcrumb.Back href="/back" accessiblePrefix={accessiblePrefix}>
Breadcrumb 2
</Breadcrumb.Back>
</Breadcrumb>,
);

const hiddenSpan = container.querySelector(
'.nhsuk-breadcrumb__backlink > .nhsuk-u-visually-hidden',
);

expect(hiddenSpan?.textContent).toBe(accessiblePrefix ?? 'Back to &nbsp;');
},
);

it.each<ElementType | undefined>([undefined, 'button'])(
'Renders with asElement when specified as %s',
(asElement) => {
const { container } = render(
<Breadcrumb>
<Breadcrumb.Back href="/back" asElement={asElement}>
Breadcrumb 2
</Breadcrumb.Back>
</Breadcrumb>,
);

const component = container.querySelector('.nhsuk-breadcrumb__backlink');

expect(component?.nodeName).toBe(asElement?.toString()?.toUpperCase() ?? 'A');
},
);
});
});
Loading

0 comments on commit 92fc5ec

Please sign in to comment.