Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(select): Change tests to react-testing-library and improve coverage #412

Merged
merged 9 commits into from
Feb 7, 2020
52 changes: 52 additions & 0 deletions cypress/integration/Select.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import * as h from '../helpers';

const getSelect = () => {
return cy.get(`select`);
};

const selectedValue = 'mail';

describe('Select', () => {
before(() => {
h.stories.visit();
});
['Plain', 'Alert', 'Error'].forEach(story => {
context(`given the '${story}' story is rendered`, () => {
beforeEach(() => {
h.stories.load('Components|Inputs/Select/React/Top Label', story);
});

it('should pass accessibility checks', () => {
cy.checkA11y();
});

context(`when '${selectedValue}' is selected`, () => {
beforeEach(() => {
getSelect().select(selectedValue);
});

it('should be focused', () => {
getSelect().should('be.focused');
});

it(`should have a value of '${selectedValue}'`, () => {
getSelect().should('have.value', selectedValue);
});
});
});
});

context(`given the 'Disabled' story is rendered`, () => {
beforeEach(() => {
h.stories.load('Components|Inputs/Select/React/Top Label', 'Disabled');
});

it('should pass accessibility checks', () => {
cy.checkA11y();
});

it('should be disabled', () => {
getSelect().should('be.disabled');
});
});
});
48 changes: 47 additions & 1 deletion modules/form-field/react/stories/stories_Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import * as React from 'react';
import {storiesOf} from '@storybook/react';
import withReadme from 'storybook-readme/with-readme';
import {controlComponent} from '../../../../utils/storybook';
import {StaticStates} from '@workday/canvas-kit-labs-react-core';
import {controlComponent, ComponentStatesTable, permutateProps} from '../../../../utils/storybook';

import FormField from '..';
import README from '../../../select/react/README.md';
Expand Down Expand Up @@ -208,3 +209,48 @@ storiesOf('Components|Inputs/Select/React/Left Label', module)
)}
</FormField>
));

storiesOf('Components|Inputs/Select/React/Visual Testing', module)
.addParameters({component: Select})
.addDecorator(withReadme(README))
.add('States', () => (
<StaticStates>
<ComponentStatesTable
rowProps={[
{label: 'Default', props: {}},
{label: 'Alert', props: {error: Select.ErrorType.Alert}},
{label: 'Error', props: {error: Select.ErrorType.Error}},
]}
columnProps={permutateProps(
{
className: [
{label: 'Default', value: ''},
{label: 'Hover', value: 'hover'},
{label: 'Focus', value: 'focus'},
{label: 'Focus Hover', value: 'focus hover'},
{label: 'Active', value: 'active'},
{label: 'Active Hover', value: 'active hover'},
],
disabled: [{label: '', value: false}, {label: 'Disabled', value: true}],
},
props => {
if (props.disabled && !['', 'hover'].includes(props.className)) {
return false;
}
return true;
}
)}
>
{props => (
<Select
{...props}
style={{minWidth: 60, width: 100}}
onChange={() => {}} // eslint-disable-line no-empty-function
>
<SelectOption value="email" label="E-mail" />
<SelectOption value="phone" label="Phone" />
</Select>
)}
</ComponentStatesTable>
</StaticStates>
));
96 changes: 74 additions & 22 deletions modules/select/react/spec/Select.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,90 @@
import * as React from 'react';
import {mount} from 'enzyme';
import {render, fireEvent} from '@testing-library/react';
import SelectOption from '../lib/SelectOption';
import Select from '../lib/Select';

describe('Select', () => {
const cb = jest.fn();

const role = 'listbox';

afterEach(() => {
cb.mockReset();
});

test('renders two select options as expected', () => {
const component = mount(
<Select name="contact">
<SelectOption value="email" label="E-mail" />
<SelectOption value="phone" label="Phone" />
</Select>
);
describe('when rendered with an id', () => {
it('should render a select with id', () => {
const id = 'mySelect';
const {getByRole} = render(
<Select id={id} onChange={cb}>
<SelectOption value="email" label="E-mail" />
<SelectOption value="phone" label="Phone" />
</Select>
);
expect(getByRole(role)).toHaveAttribute('id', id);
});
});

describe('when rendered with disabled attribute', () => {
it('should render a disabled select', () => {
const {getByRole} = render(
<Select disabled={true} onChange={cb}>
<SelectOption value="email" label="E-mail" />
<SelectOption value="phone" label="Phone" />
</Select>
);
expect(getByRole(role)).toHaveProperty('disabled', true);
});
});

describe('when rendered with a value', () => {
it('it should render a select whose selected option matches value', () => {
const selectedValue = 'phone';
const {getByDisplayValue} = render(
<Select onChange={cb} value={selectedValue}>
<SelectOption value="email" label="E-mail" />
<SelectOption value={selectedValue} label={selectedValue} />
</Select>
);
expect(getByDisplayValue(selectedValue)).toBeDefined();
});
});

const options = component.find('option');
describe('when rendered with extra, arbitrary props', () => {
it('should spread extra props onto the select', () => {
const attr = 'test';
const {getByRole} = render(
<Select data-propspread={attr} onChange={cb}>
<SelectOption value="email" label="E-mail" />
<SelectOption value="phone" label="Phone" />
</Select>
);
expect(getByRole(role)).toHaveAttribute('data-propspread', attr);
});
});

expect(options.length).toEqual(2);
describe('when rendered with two select options as children', () => {
it('should render two options', () => {
const {getAllByRole} = render(
<Select onChange={cb}>
<SelectOption value="email" label="E-mail" />
<SelectOption value="phone" label="Phone" />
</Select>
);
expect(getAllByRole('option')).toHaveLength(2);
});
});

test('Select should spread extra props', () => {
const component = mount(
<Select name="contact" data-propspread="test">
<SelectOption value="email" label="E-mail" />
<SelectOption value="phone" label="Phone" />
</Select>
);
const select = component
.find('select') // TODO: Standardize on prop spread location (see #150)
.getDOMNode();
expect(select.getAttribute('data-propspread')).toBe('test');
component.unmount();
describe('when changed', () => {
it('should call a callback function', () => {
const {getByRole} = render(
<Select onChange={cb}>
<SelectOption value="email" label="E-mail" />
<SelectOption value="phone" label="Phone" />
</Select>
);
fireEvent.change(getByRole(role));
expect(cb).toHaveBeenCalledTimes(1);
});
});
});