Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
narthur committed Aug 24, 2022
1 parent 5187c54 commit 99d2734
Show file tree
Hide file tree
Showing 21 changed files with 214 additions and 150 deletions.
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/public
/src/serviceWorker.js
.eslintrc.js
.eslintrc.js
/dist
3 changes: 3 additions & 0 deletions __mocks__/@mui/x-date-pickers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ function makePicker({
parseValue: (value: string) => Date;
}) {
return function MockPicker(p: any) {
// if (!(p.value instanceof Date)) {
// throw new Error('p.value should be instance of Date object');
// }
const [value, setValue] = React.useState(formatValue(p.value));
return p.renderInput({
label: p.label,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"prettier": "2.4.1",
"rollup-plugin-visualizer": "^5.8.0",
"tslint-config-prettier": "^1.18.0",
"type-fest": "^2.19.0",
"typescript": "^4.7.4",
"vite": "2.7.0",
"vitest": "^0.21.1",
Expand Down
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

104 changes: 58 additions & 46 deletions src/App.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ vi.mock('./components/molecules/LoadingIndicator');
vi.mock('react-ga');
vi.mock('react-list');
vi.mock('./lib/getQueryClient');
vi.mock('@mui/x-date-pickers');

const mockUseSession = useSession as Mock;

Expand All @@ -48,7 +49,6 @@ function renderPage() {

describe('App', () => {
beforeEach(() => {
vi.resetAllMocks();
loadNowDate(new Date('10/29/2020'));
vi.spyOn(browser, 'scrollIntoView').mockImplementation(() => undefined);
window.localStorage.clear();
Expand Down Expand Up @@ -215,7 +215,9 @@ describe('App', () => {

userEvent.type(getDueInput(), '{backspace}0');

userEvent.click(screen.getByText('Add'));
expect(getDueInput()).toHaveValue('01/08/2020');

userEvent.click(await screen.findByText('Add'));

await screen.findByText('Due date must be in the future');

Expand Down Expand Up @@ -312,9 +314,7 @@ describe('App', () => {
userEvent.click(screen.getByLabelText('Menu'));
userEvent.click(screen.getByText('Copy'));

expect(await screen.findByLabelText('Due Date *')).toHaveValue(
'02/08/2020'
);
expect(await screen.findByLabelText(/Due Date/)).toHaveValue('02/08/2020');
});

it('closes menu when clicking copy', async () => {
Expand Down Expand Up @@ -362,9 +362,9 @@ describe('App', () => {
it('includes recurring options', async () => {
renderPage();

await openForm();
openForm();

userEvent.type(getTaskInput(), 'recurring_task');
userEvent.type(await screen.findByLabelText('Task *'), 'recurring_task');

userEvent.click(screen.getByLabelText('Enable recurrence'));
userEvent.type(screen.getByLabelText('Interval in days'), '7');
Expand All @@ -375,48 +375,58 @@ describe('App', () => {
expect(screen.getByText('recurring_task')).toBeInTheDocument();
});

expect(addTask).toBeCalledWith(
expect.any(String),
expect.any(String),
expect.any(Number),
expect.objectContaining({ days: 7 })
);
await waitFor(() => {
expect(addTask).toBeCalledWith(
expect.any(String),
expect.any(String),
expect.any(Number),
expect.objectContaining({ days: 7 })
);
});
});

it('Does not include recurrence options if recurrence is not enabled', async () => {
renderPage();

await openForm();
openForm();

userEvent.type(getTaskInput(), 'non_recurring_task');
userEvent.type(
await screen.findByLabelText('Task *'),
'non_recurring_task'
);
userEvent.click(screen.getByText('Add'));

await waitFor(() => {
expect(screen.getByText('non_recurring_task')).toBeInTheDocument();
});

expect(addTask).toBeCalledWith(
expect.any(String),
expect.any(String),
expect.any(Number),
undefined
);
await waitFor(() => {
expect(addTask).toBeCalledWith(
expect.any(String),
expect.any(String),
expect.any(Number),
undefined
);
});
});

it('does not show interval field if recurrence not enabled', async () => {
it('does not show interval field if recurrence not enabled', () => {
renderPage();

await openForm();
openForm();

expect(screen.queryByLabelText('Interval in days')).not.toBeInTheDocument();
});

it('does not post recurring options if recurrence not enabled', async () => {
renderPage();

await openForm();
openForm();

userEvent.type(getTaskInput(), 'non_recurring_task');
userEvent.type(
await screen.findByLabelText('Task *'),
'non_recurring_task'
);

userEvent.click(screen.getByLabelText('Enable recurrence'));
userEvent.type(screen.getByLabelText('Interval in days'), '7');
Expand All @@ -427,36 +437,38 @@ describe('App', () => {
expect(screen.getByText('non_recurring_task')).toBeInTheDocument();
});

expect(addTask).toBeCalledWith(
expect.any(String),
expect.any(String),
expect.any(Number),
undefined
);
await waitFor(() => {
expect(addTask).toBeCalledWith(
expect.any(String),
expect.any(String),
expect.any(Number),
undefined
);
});
});

it('it remembers recurring options when toggling recurrence', async () => {
renderPage();

await openForm();
openForm();

userEvent.type(getTaskInput(), 'recurring_task');
userEvent.type(await screen.findByLabelText('Task *'), 'recurring_task');

userEvent.click(screen.getByLabelText('Enable recurrence'));
userEvent.type(screen.getByLabelText('Interval in days'), '7');
userEvent.click(screen.getByLabelText('Enable recurrence'));
userEvent.click(screen.getByLabelText('Enable recurrence'));
userEvent.click(await screen.findByLabelText('Enable recurrence'));
userEvent.type(await screen.findByLabelText('Interval in days'), '7');
userEvent.click(await screen.findByLabelText('Enable recurrence'));
userEvent.click(await screen.findByLabelText('Enable recurrence'));

userEvent.click(await screen.findByText('Add'));
await screen.findByText('recurring_task');

userEvent.click(screen.getByText('Add'));
await waitFor(() => {
expect(screen.getByText('recurring_task')).toBeInTheDocument();
expect(addTask).toBeCalledWith(
expect.any(String),
expect.any(String),
expect.any(Number),
expect.objectContaining({ days: 7 })
);
});

expect(addTask).toBeCalledWith(
expect.any(String),
expect.any(String),
expect.any(Number),
expect.objectContaining({ days: 7 })
);
});
});
12 changes: 11 additions & 1 deletion src/components/molecules/Task.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Task from './Task';
import React from 'react';
import {
expectNever,
loadNowDate,
renderWithQueryProvider,
resolveWithDelay,
withMutedReactQueryLogger,
Expand Down Expand Up @@ -236,7 +237,14 @@ describe('Task component', () => {
userEvent.type(screen.getByLabelText('Stakes *'), '{backspace}1');
userEvent.click(screen.getByText('Save'));

await expectNever(() => expect(editTask).toBeCalled());
// This test may not be effective, since if the submission was made,
// the expectation may have happened previous to the request. We can't
// wait for an error message because the minimum is enforced on the
// stakes field, preventing the request from being made in the first
// place. This test used to use `expectNever`, but it's better to
// avoid using that since it requires a `waitFor` to timeout before
// passing, slowing down the test significantly.
expect(editTask).not.toBeCalled();
});

it('enforces maximum due', async () => {
Expand Down Expand Up @@ -266,6 +274,8 @@ describe('Task component', () => {
});

it('closes edit dialog on save', async () => {
loadNowDate('2/1/2020, 11:59 PM');

renderTask();

await openEditDialog();
Expand Down
46 changes: 25 additions & 21 deletions src/components/organisms/DueForm.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import renderCompo
import { render, RenderResult, screen } from '@testing-library/react';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import React from 'react';
import TaskForm, { TaskFormProps } from './TaskForm';
import userEvent from '@testing-library/user-event';
import { vi } from 'vitest';

vi.mock('@mui/x-date-pickers');

const renderComponent = (props: Partial<TaskFormProps> = {}) => {
const p: TaskFormProps = {
Expand All @@ -13,69 +21,65 @@ const renderComponent = (props: Partial<TaskFormProps> = {}) => {
...props,
};

const result: RenderResult = render(
const view: RenderResult = render(
<LocalizationProvider dateAdapter={AdapterDateFns}>
<TaskForm {...p} />
</LocalizationProvider>
);

return {
...result,
taskInput: result.getByLabelText('Task *') as HTMLInputElement,
dueDateInput: result.getByLabelText('Due Date *') as HTMLInputElement,
dueTimeInput: result.getByLabelText('Due Time *') as HTMLInputElement,
centsInput: result.getByLabelText('Stakes *') as HTMLInputElement,
...view,
taskInput: screen.getByLabelText('Task *'),
dueDateInput: screen.getByLabelText('Due Date *'),
dueTimeInput: screen.getByLabelText('Due Time *'),
centsInput: screen.getByLabelText('Stakes *'),
};
};

describe('due form', () => {
it('calls onChange when due modified', async () => {
const onChange = jest.fn();
it('calls onChange when due modified', () => {
const onChange = vi.fn();

const { dueTimeInput } = renderComponent({ onChange });

await userEvent.type(dueTimeInput, '{backspace}{backspace}am');
userEvent.type(dueTimeInput, '{backspace}{backspace}am');

expect(onChange).toBeCalled();
});

it('preserves time when editing date', async () => {
const onChange = jest.fn();
it('preserves time when editing date', () => {
const onChange = vi.fn();

const { dueDateInput } = renderComponent({
due: '1/1/2021, 11:59 PM',
cents: 500,
onChange,
});

await userEvent.type(dueDateInput, '{backspace}2{enter}');
userEvent.type(dueDateInput, '{backspace}2{enter}');

expect(onChange).toBeCalledWith(
expect.objectContaining({
task: '',
due: '1/1/2022, 11:59 PM',
cents: 500,
})
);
});

it('preserves date when editing time', async () => {
const onChange = jest.fn();
it('preserves date when editing time', () => {
const onChange = vi.fn();

const { dueTimeInput } = renderComponent({
due: '1/1/2020, 11:59 PM',
cents: 500,
onChange,
});

await userEvent.type(dueTimeInput, '{backspace}M{enter}');
userEvent.type(dueTimeInput, '{backspace}M{enter}');

expect(onChange).toBeCalledWith(
expect.objectContaining({
task: '',
due: '1/1/2020, 11:59 PM',
cents: 500,
})
);
});
})
});
Loading

1 comment on commit 99d2734

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.