Skip to content

Commit

Permalink
feat: NewTimeLineModal tests added
Browse files Browse the repository at this point in the history
  • Loading branch information
mythter committed Aug 9, 2024
1 parent 84348d1 commit 15e3436
Show file tree
Hide file tree
Showing 2 changed files with 310 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
import {
cleanup, fireEvent, render, screen, waitFor,
} from '@testing-library/react';
import user from '@testing-library/user-event';

import TimelineItem, { DateViewPattern, HistoricalContextUpdate } from '@/models/timeline/chronology.model';

import '@testing-library/jest-dom';

import NewTimelineModal from './NewTimelineModal.component';

const mockTimeLine: TimelineItem = {
id: 1,
title: 'mockTitle',
description: 'mockDescription',
date: '2020-02-20T00:00:00.000Z',
dateViewPattern: DateViewPattern.DateMonthYear,
historicalContexts: [],
};

// needed to render component without errors
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: (query: any) => ({
matches: false,
media: query,
onchange: null,
addListener: () => {},
removeListener: () => {},
addEventListener: () => {},
removeEventListener: () => {},
dispatchEvent: () => {},
}),
});

jest.mock('@/app/common/components/Editor/QEditor.component', () => ({
__esModule: true,
default: jest.fn((props) => {
const { value, onChange, maxChars } = props;
const valueToSet = value ?? '';
const handleOnChange = (newValue: string) => {
onChange(newValue.slice(0, 3000));
};
return (
<div>
<input
type="text"
value={valueToSet}
onChange={(e) => handleOnChange(e.target.value)}
maxLength={maxChars}
/>
</div>
);
}),
}));

const addTimelineMock = jest.fn();
jest.mock('@stores/root-store', () => ({
__esModule: true,
default: jest.fn(() => ({
timelineItemStore: {
getTimelineItemArray: [],
addTimeline: addTimelineMock,
timelineItemMap: new Map<number, TimelineItem>(),
},
historicalContextStore: {
historicalContextArray: [
{ id: 1, title: 'context 1' },
{ id: 2, title: 'context 2' },
],
fetchHistoricalContextAll: jest.fn(),
},
})),
}));

const open = true;
const setOpen = () => {};
const onChangeMock = jest.fn();

describe('NewTimelineModal test', () => {
afterEach(() => {
jest.clearAllMocks();
cleanup();
});

it('should be rendered', async () => {
render(
<NewTimelineModal
open={open}
setIsModalOpen={setOpen}
onChange={onChangeMock}
/>,
);

const inputTitle = screen.getByTestId('input-title');
const selectDate = screen.getByTestId('select-date');
const datePicker = screen.getByTestId('date-picker');
const selectContext = screen.getByTestId('select-context');
const textareaDescription = screen.getByTestId('textarea-description');
const buttonSave = screen.getByTestId('button-save');

await waitFor(() => {
expect(inputTitle).toBeInTheDocument();
expect(selectDate).toBeInTheDocument();
expect(datePicker).toBeInTheDocument();
expect(selectContext).toBeInTheDocument();
expect(textareaDescription).toBeInTheDocument();
expect(buttonSave).toBeInTheDocument();
});
});

it('should create timeline with required fields only', async () => {
render(
<NewTimelineModal
open={open}
setIsModalOpen={setOpen}
onChange={onChangeMock}
/>,
);

// Arrange
const inputTitle = screen.getByTestId('input-title');
const datePicker = screen.getByTestId('date-picker');
const textareaDescription = screen.getByTestId('textarea-description');
const buttonSave = screen.getByTestId('button-save');

const createTimelineWithRequiredOnly: TimelineItem = {
id: -1,
title: 'title',
description: 'description',
date: '2024-08-08T00:00:00.000Z',
dateViewPattern: DateViewPattern.DateMonthYear,
historicalContexts: [],
};

// Act
await waitFor(() => {
user.type(inputTitle, createTimelineWithRequiredOnly.title);
fireEvent.mouseDown(datePicker);
fireEvent.change(datePicker, { target: { value: '2024, 8 August' } });
fireEvent.click(document.querySelectorAll('.ant-picker-cell-selected')[0]);
user.type(textareaDescription, createTimelineWithRequiredOnly.description!);
user.click(buttonSave);
});

// Assert
await waitFor(() => {
expect(onChangeMock).toHaveBeenCalled();
expect(addTimelineMock).toHaveBeenCalled();
expect(addTimelineMock).toHaveBeenCalledWith(createTimelineWithRequiredOnly);
});
});

it('should create timeline with all fields', async () => {
render(
<NewTimelineModal
open={open}
setIsModalOpen={setOpen}
onChange={onChangeMock}
/>,
);

// Arrange
const inputTitle = screen.getByTestId('input-title');
const selectDate = screen.getByTestId('select-date');
const datePicker = screen.getByTestId('date-picker');
// If try to get by testId test doesn't work. Don't know why :(
// const selectContext = screen.getByTestId('select-context');
const selectContext = screen.getByRole('combobox', {
name: /Контекст/i,
});
const textareaDescription = screen.getByTestId('textarea-description');
const buttonSave = screen.getByTestId('button-save');

const context: HistoricalContextUpdate = { id: 1, title: 'context 1', modelState: 0 };
const createJobWithAllFields: TimelineItem = {
id: -1,
title: 'title',
description: 'description',
date: '2024-08-08T00:00:00.000Z',
dateViewPattern: DateViewPattern.DateMonthYear,
historicalContexts: [context],
};

// Act
await waitFor(() => {
user.type(inputTitle, createJobWithAllFields.title);

user.click(selectDate);
user.click(screen.getByTitle('Рік, день місяць')!);
// user.click(document.querySelector('.ant-select-selection-item')!);

user.click(datePicker);
fireEvent.change(datePicker, { target: { value: '2024, 8 August' } });
user.click(document.querySelectorAll('.ant-picker-cell-selected')[0]);

user.click(selectContext);
user.click(screen.getByTitle('context 1'));

user.type(textareaDescription, createJobWithAllFields.description!);
user.click(buttonSave);
});

// Assert
await waitFor(() => {
expect(onChangeMock).toHaveBeenCalled();
expect(addTimelineMock).toHaveBeenCalled();
expect(addTimelineMock).toHaveBeenCalledWith(createJobWithAllFields);
});
});

// TODO: consider adding check for editiong the date type and date itself
it('should edit timeline data', async () => {
render(
<NewTimelineModal
timelineItem={mockTimeLine}
open={open}
setIsModalOpen={setOpen}
onChange={onChangeMock}
/>,
);

const inputTitle = screen.getByTestId('input-title');
const selectContext = screen.getByRole('combobox', {
name: /Контекст/i,
});
const textareaDescription = screen.getByTestId('textarea-description');
const buttonSave = screen.getByTestId('button-save');

const editedTimeLine = {
title: 'edited title',
description: 'edited description',
historicalContexts: [{ id: 2, modelState: 0, title: 'context 2' }],
};

await waitFor(() => {
user.clear(inputTitle);
user.clear(textareaDescription);
});

await waitFor(async () => {
user.type(inputTitle, editedTimeLine.title);
await waitFor(() => {
expect(onChangeMock).toHaveBeenLastCalledWith('title', editedTimeLine.title);
});

user.type(textareaDescription, editedTimeLine.description);
await waitFor(() => {
expect(onChangeMock).toHaveBeenLastCalledWith('description', editedTimeLine.description);
});

user.click(selectContext);
user.click(screen.getByTitle('context 2'));
expect(onChangeMock).toHaveBeenLastCalledWith('historicalContexts', editedTimeLine.historicalContexts);

user.click(buttonSave);
});
});

it('should check text amount restrictions', async () => {
render(
<NewTimelineModal
open={open}
setIsModalOpen={setOpen}
onChange={onChangeMock}
/>,
);

// Arrange
const inputTitle = screen.getByTestId('input-title');
const textareaDescription = screen.getByTestId('textarea-description') as HTMLTextAreaElement;

const titleRestriction = 26;
const descriptionRestriction = 400;
const text = 'String which excides text amount limit';
const longText = text;
const veryLongText = text.repeat(11);

// Act
await waitFor(() => {
user.type(inputTitle, longText);

// user.type() takes too much time to input all the text, so fireEvent.change() partially
// fills description and user.type() tries to exceed text amount restrictions
fireEvent.change(textareaDescription, { target: { value: veryLongText } });
user.type(textareaDescription, longText);
});

// Assert
expect(inputTitle.getAttribute('value')).toHaveLength(titleRestriction);
expect(textareaDescription.value.length).toBe(descriptionRestriction);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import '@features/AdminPage/AdminModal.styles.scss';
import { observer } from 'mobx-react-lite';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import getNewMinNegativeId from '@app/common/utils/newIdForStore';
import useMobx from '@app/stores/root-store';
import useMobx from '@stores/root-store';
import CancelBtn from '@assets/images/utils/Cancel_btn.svg';
import { ModelState } from '@models/enums/model-state';
import dayjs from 'dayjs';
Expand All @@ -14,7 +14,6 @@ import {
Button,
DatePicker, Form, Input, message, Modal, Popover, Select,
} from 'antd';
import TextArea from 'antd/es/input/TextArea';

import createTagValidator from '@/app/common/utils/selectValidation.utility';
import TimelineItem, {
Expand Down Expand Up @@ -249,7 +248,12 @@ const NewTimelineModal: React.FC<NewTimelineModalProps> = observer(({ timelineIt
label="Назва: "
rules={[{ required: true, message: 'Введіть назву', max: MAX_LENGTH.title }]}
>
<Input maxLength={MAX_LENGTH.title} showCount onChange={(e) => onChange('title', e.target.value)} />
<Input
maxLength={MAX_LENGTH.title}
showCount
onChange={(e) => onChange('title', e.target.value)}
data-testid="input-title"
/>
</Form.Item>

<Form.Item>
Expand All @@ -261,6 +265,7 @@ const NewTimelineModal: React.FC<NewTimelineModalProps> = observer(({ timelineIt
setDateTimePickerType(val);
onChange('date', val);
}}
data-testid="select-date"
/>

<Form.Item
Expand All @@ -282,6 +287,7 @@ const NewTimelineModal: React.FC<NewTimelineModalProps> = observer(({ timelineIt
? 'yyyy'
: 'yyyy, mm')}
onChange={(value) => onChange('date', value?.toString())}
data-testid="date-picker"
/>
</Form.Item>
</div>
Expand All @@ -293,6 +299,7 @@ const NewTimelineModal: React.FC<NewTimelineModalProps> = observer(({ timelineIt
label="Контекст: "
validateStatus={errorMessage ? 'error' : ''}
help={errorMessage}
data-testid="select-context"
>
<Select
mode="tags"
Expand Down Expand Up @@ -327,12 +334,18 @@ const NewTimelineModal: React.FC<NewTimelineModalProps> = observer(({ timelineIt
label="Опис: "
rules={[{ required: true, message: 'Введіть опис' }]}
>
<TextArea maxLength={MAX_LENGTH.description} showCount onChange={(e) => onChange('description', e.target.value)} />
<Input.TextArea
maxLength={MAX_LENGTH.description}
showCount
onChange={(e) => onChange('description', e.target.value)}
data-testid="textarea-description"
/>
</Form.Item>
<div className="center">
<Button
className="streetcode-custom-button"
onClick={() => handleOk()}
data-testid="button-save"
>
Зберегти
</Button>
Expand Down

0 comments on commit 15e3436

Please sign in to comment.