Skip to content

Commit

Permalink
Merge pull request #4 from italoiz/feat/select
Browse files Browse the repository at this point in the history
feat: Add <Select /> component
  • Loading branch information
italoiz authored Jun 8, 2019
2 parents 7d065ac + 3f70fa0 commit e6d66ef
Show file tree
Hide file tree
Showing 13 changed files with 437 additions and 6,822 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ module.exports = {
'react/prop-types': 'off',
'jsx-a11y/label-has-for': 'off',
'import/prefer-default-export': 'off',
'import/named': 'off',
'react-hooks/rules-of-hooks': 'error',
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}]
},
Expand Down
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ This library uses [Unform](https://github.com/Rocketseat/unform) + [Material UI]
- [Basics](#basics)
- [Components](#components)
- [TextField Component](#textfield--component)
- [Select Component](#select--component)
- [Contributing](#contributing)
- [Contribution Guidelines](#contribution-guidelines)
- [Code of Conduct](#code-of-conduct)
Expand Down Expand Up @@ -80,6 +81,42 @@ function App() {
}
```

#### `<Select />` Component

The `<Select />` component, is similar to the default component `<Select />`. See the component documentation [here](https://material-ui.com/api/select/) for more information.

```jsx
import React from 'react';
import { Form } from '@rocketseat/unform';
import { Select } from 'unform-material-ui';

function App() {
function handleSubmit(data) {
/**
* {
* "tech": ['node'],
* "country": "brazil"
* }
*/
}

return (
<Form onSubmit={handleSubmit}>
<Select multiple name="tech" options={[
{ value: 'node', label: 'NodeJS' },
{ value: 'react', label: 'React' },
]} />

<Select name="country" label="Country" options={[
{ value: 'brazil', label: 'Brazil' },
]} />

<button type="submit">Send</button>
</Form>
);
}
```

## Contributing

Thanks for being interested on making this package better. We encourage everyone to help improving this project with some new features, bug fixes and performance issues. Please take a little bit of your time to read our guides, so this process can be faster and easier.
Expand Down
157 changes: 157 additions & 0 deletions __tests__/components/Select.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import React from 'react';
import '@testing-library/react/cleanup-after-each';
import 'jest-dom/extend-expect';

import { render, fireEvent, wait } from '@testing-library/react';
import { Form } from '@rocketseat/unform';
import { act } from 'react-test-renderer';
import * as Yup from 'yup';

import { Select } from '../../lib';

describe('<Select /> Component', () => {
it('should display select', () => {
const options = [
{ value: 'react', label: 'React' },
{ value: 'node', label: 'NodeJS' },
];

const { container, getByText } = render(
<Form onSubmit={jest.fn()}>
<Select name="tech" label="Tech" options={options} />
</Form>
);

expect(!!container.querySelector('input[type=hidden][name=tech]')).toBe(
true
);
expect(!!getByText('Tech')).toBe(true);
});

it('should display native select', () => {
const options = [
{ value: 'react', label: 'React' },
{ value: 'node', label: 'NodeJS' },
];

const { container, getByText } = render(
<Form onSubmit={jest.fn()}>
<Select native name="tech" label="Tech" options={options} />
</Form>
);

expect(!!container.querySelector('select[name=tech]')).toBe(true);
expect(container.querySelectorAll('select[name=tech] option').length).toBe(
3
);
expect(!!getByText('Tech')).toBe(true);
});

it('should return data when submit form', () => {
const submitMock = jest.fn();

const options = [
{ value: 'react', label: 'React' },
{ value: 'node', label: 'NodeJS' },
];

const { getByLabelText, getByTestId } = render(
<Form onSubmit={submitMock}>
<Select native name="tech" label="Tech" options={options} />
</Form>
);

fireEvent.change(getByLabelText('Tech'), {
target: {
value: 'node',
},
});

fireEvent.submit(getByTestId('form'));

expect(submitMock).toHaveBeenCalledWith(
{ tech: 'node' },
expect.any(Object)
);
});

it('should return default data when submit form', () => {
const submitMock = jest.fn();

const options = [
{ value: 'react', label: 'React' },
{ value: 'node', label: 'NodeJS' },
];

const { getByTestId } = render(
<Form onSubmit={submitMock} initialData={{ tech: 'node' }}>
<Select name="tech" label="Tech" options={options} />
</Form>
);

fireEvent.submit(getByTestId('form'));

expect(submitMock).toHaveBeenCalledWith(
{ tech: 'node' },
expect.any(Object)
);
});

it('should display error', async () => {
const schema = Yup.object().shape({
tech: Yup.string().required('tech is required'),
});

const { getByText, getByTestId } = render(
<Form onSubmit={jest.fn()} schema={schema}>
<Select
name="tech"
label="Tech"
options={[{ value: 'node', label: 'NodeJS' }]}
/>
</Form>
);

act(() => {
fireEvent.submit(getByTestId('form'));
});

await wait(() => {
expect(!!getByText('tech is required')).toBe(true);
});
});

it('should return multiple values when is multiple select', async () => {
const submitMock = jest.fn();

const options = [
{ value: 'react', label: 'React' },
{ value: 'node', label: 'NodeJS' },
{ value: 'angular', label: 'Angular' },
{ value: 'vuejs', label: 'VueJS' },
];

const { getByTestId, getByRole, baseElement } = render(
<Form onSubmit={submitMock}>
<Select multiple name="tech" label="Tech" options={options} />
</Form>
);

// click to open select options
fireEvent.click(getByRole('button'));

// select option
fireEvent.click(baseElement.querySelectorAll('li[role=option]')[0]);
fireEvent.click(baseElement.querySelectorAll('li[role=option]')[1]);

// send form.
fireEvent.submit(getByTestId('form'));

expect(submitMock).toHaveBeenCalledWith(
{
tech: expect.arrayContaining(['node', 'react']),
},
expect.any(Object)
);
});
});
19 changes: 19 additions & 0 deletions __tests__/components/TextField.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,23 @@ describe('<TextField /> Component', () => {
expect.any(Object)
);
});

it('should return default data on submit form', () => {
const submitMock = jest.fn();

const initialData = { name: 'foo bar' };

const { getByTestId } = render(
<Form onSubmit={submitMock} initialData={initialData}>
<TextField name="name" label="Name" />
</Form>
);

fireEvent.submit(getByTestId('form'));

expect(submitMock).toHaveBeenCalledWith(
{ name: 'foo bar' },
expect.any(Object)
);
});
});
68 changes: 65 additions & 3 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
import { Form } from '@rocketseat/unform';
import React from 'react';
import { hot } from 'react-hot-loader/root';
import * as Yup from 'yup';

import { TextField } from '../../lib';
import { TextField, Select } from '../../lib';
import GlobalStyles, { Section } from './styles';

// validation schema.
const schema = Yup.object().shape({
firstName: Yup.string(),
lastName: Yup.string(),
email: Yup.string().required(),
country: Yup.mixed(),
tech: Yup.mixed(),
withDefault: Yup.number().required(),
withError: Yup.string().required(),
multipleSelect: Yup.array(),
});

export default function App() {
function App() {
function handleSubmit(payload) {
console.log(payload);
}

const initialData = {
firstName: 'Diego',
withDefault: 1,
};

return (
<>
<Form onSubmit={handleSubmit} schema={schema}>
<Form onSubmit={handleSubmit} schema={schema} initialData={initialData}>
<Section>
<h1>{'<TextField /> Component'}</h1>

Expand All @@ -33,6 +44,55 @@ export default function App() {
</div>
</Section>

<Section>
<h1>{'<Select /> Component'}</h1>

<div>
<Select
name="country"
label="Country"
options={[
{ value: { id: 1, name: 'brazil' }, label: 'Brazil' },
{ value: 'canada', label: 'Canada' },
]}
/>

<Select
native
name="tech"
label="Tech (Native Select)"
options={[
{ value: 'react', label: 'React' },
{ value: 'node', label: 'NodeJS' },
]}
/>

<Select
name="withDefault"
label="Default value"
options={[{ value: 1, label: '#ID 1' }]}
/>

<Select
name="withError"
label="Error"
options={[{ value: 'foo', label: 'bar' }]}
/>

<Select
multiple
name="multipleSelect"
label="Multiple"
options={[
{ value: 'node', label: 'NodeJS' },
{ value: 'react', label: 'React' },
{ value: 'vuejs', label: 'Vue' },
{ value: 'angular', label: 'Angular' },
]}
/>
</div>
</Section>

<Section>
<div>
<button type="submit">ok!</button>
Expand All @@ -43,3 +103,5 @@ export default function App() {
</>
);
}

export default hot(App);
1 change: 1 addition & 0 deletions example/src/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const Section = styled.section`
max-width: 400px;
display: inline-grid;
grid-column-gap: 15px;
grid-template-columns: repeat(2, 1fr);
}
`;

Expand Down
Loading

0 comments on commit e6d66ef

Please sign in to comment.