refactor(frontend): refactor unit tests

This commit is contained in:
Sergey Krylov 2025-10-09 05:46:35 +03:00
parent 021038f4ad
commit e52dd11a16
73 changed files with 2866 additions and 2361 deletions

View File

@ -1,59 +1,29 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddBankCardFormProps } from './AddBankCardForm.ui';
import AddBankCardForm from './AddBankCardForm.ui';
const renderForm = (props?: Partial<AddBankCardFormProps>) => {
const onSubmit = jest.fn();
render(<AddBankCardForm data-testid="add-balance-card-form" onSubmit={onSubmit} {...props} />);
const nameInputElem = screen.getByLabelText('Название');
const balanceInputElem = screen.getByLabelText('Баланс');
const submitButtonElem = screen.getByText('Добавить');
return {
balanceInputElem,
nameInputElem,
onSubmit,
submitButtonElem,
};
};
import { AddBankCardFormHelper } from '@tests/helpers';
describe('Test AddBankCardForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('add-balance-card-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
AddBankCardFormHelper.renderForm();
const { formElem } = AddBankCardFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
AddBankCardFormHelper.renderForm(options);
const { formElem, ...formElems } = AddBankCardFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
balanceInputElem,
nameInputElem,
onSubmit,
submitButtonElem,
} = renderForm();
const { onSubmit } = AddBankCardFormHelper.renderForm();
await userEvent.type(nameInputElem, 'Тестовая карта');
await userEvent.type(balanceInputElem, '500');
await userEvent.click(submitButtonElem);
await AddBankCardFormHelper.fillForm({
balance: 500,
name: 'Тестовая карта',
});
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({

View File

@ -1,55 +1,18 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteBankCardFormProps } from './DeleteBankCardForm.ui';
import DeleteBankCardForm from './DeleteBankCardForm.ui';
const deletingBankCard: DeleteBankCardFormProps['bankCard'] = {
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Тестовая карта',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteBankCardFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteBankCardForm
bankCard={deletingBankCard}
data-testid="delete-bank-card-form"
onSubmit={onSubmit}
{...props}
/>,
);
const submitButtonElem = screen.getByText('Удалить');
return {
onSubmit,
submitButtonElem,
};
};
import { DeleteBankCardFormHelper } from '@tests/helpers';
describe('Test DeleteExpensesListForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('delete-bank-card-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
DeleteBankCardFormHelper.renderForm();
const { formElem } = DeleteBankCardFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
} = renderForm();
await userEvent.click(submitButtonElem);
const { onSubmit } = DeleteBankCardFormHelper.renderForm();
await DeleteBankCardFormHelper.submitForm();
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith(deletingBankCard);
expect(onSubmit).toHaveBeenCalledWith(DeleteBankCardFormHelper.bankCard);
});
});

View File

@ -1,91 +1,38 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditBankCardFormProps } from './EditBankCardForm.ui';
import EditBankCardForm from './EditBankCardForm.ui';
const editingBankCard = {
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Тестовая карта',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditBankCardFormProps>) => {
const onSubmit = jest.fn();
render(
<EditBankCardForm
bankCard={editingBankCard}
data-testid="edit-bank-card-form"
onSubmit={onSubmit}
{...props}
/>,
);
const titleInputElem = screen.getByLabelText('Название');
const balanceInputElem = screen.getByLabelText('Баланс');
const submitButtonElem = screen.getByText('Сохранить');
return {
balanceInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { EditBankCardFormHelper } from '@tests/helpers';
describe('Test EditBankCardForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('edit-bank-card-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
EditBankCardFormHelper.renderForm();
const { formElem } = EditBankCardFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should inputs have default value', () => {
const {
balanceInputElem,
titleInputElem,
} = renderForm();
expect(titleInputElem).toHaveValue('Тестовая карта');
expect(balanceInputElem).toHaveValue(1000);
EditBankCardFormHelper.renderForm();
const { balanceInputElem, nameInputElem } = EditBankCardFormHelper.getFormElements();
expect(nameInputElem).toHaveValue('Сбербанк');
expect(balanceInputElem).toHaveValue('0');
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
EditBankCardFormHelper.renderForm(options);
const { formElem, ...formElems } = EditBankCardFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
balanceInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
const { onSubmit } = EditBankCardFormHelper.renderForm();
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, 'Новое название карты');
await userEvent.clear(balanceInputElem);
await userEvent.type(balanceInputElem, '5000');
await userEvent.click(submitButtonElem);
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
const data = {
balance: 5000,
name: 'Новое название карты',
});
};
await EditBankCardFormHelper.fillForm(data);
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith(data);
});
});

View File

@ -1,64 +1,28 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddCashFormProps } from './AddCashForm.ui';
import AddCashForm from './AddCashForm.ui';
const renderForm = (props?: Partial<AddCashFormProps>) => {
const onSubmit = jest.fn();
render(<AddCashForm data-testid="add-cash-form" onSubmit={onSubmit} {...props} />);
const nameInputElem = screen.getByLabelText('Название');
const balanceInputElem = screen.getByLabelText('Баланс');
const submitButtonElem = screen.getByText('Добавить');
return {
balanceInputElem,
nameInputElem,
onSubmit,
submitButtonElem,
};
};
import { AddCashFormHelper } from '@tests/helpers';
describe('Test AddCashForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('add-cash-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
AddCashFormHelper.renderForm();
const { formElem } = AddCashFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
AddCashFormHelper.renderForm(options);
const { formElem, ...formElems } = AddCashFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
balanceInputElem,
nameInputElem,
onSubmit,
submitButtonElem,
} = renderForm();
await userEvent.type(nameInputElem, 'Наличные');
await userEvent.type(balanceInputElem, '500');
await userEvent.click(submitButtonElem);
const { onSubmit } = AddCashFormHelper.renderForm();
const data = { balance: 500, name: 'Наличные' };
await AddCashFormHelper.fillForm(data);
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
balance: 500,
name: 'Наличные',
});
expect(onSubmit).toHaveBeenCalledWith(data);
});
});

View File

@ -1,55 +1,19 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteCashFormProps } from './DeleteCashForm.ui';
import DeleteCashForm from './DeleteCashForm.ui';
const deletingCash: DeleteCashFormProps['cash'] = {
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Наличные',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteCashFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteCashForm
cash={deletingCash}
data-testid="delete-cash-form"
onSubmit={onSubmit}
{...props}
/>,
);
const submitButtonElem = screen.getByText('Удалить');
return {
onSubmit,
submitButtonElem,
};
};
import { DeleteCashFormHelper } from '@tests/helpers';
describe('Test DeleteCashForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('delete-cash-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
DeleteCashFormHelper.renderForm();
const { formElem } = DeleteCashFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
} = renderForm();
const { onSubmit } = DeleteCashFormHelper.renderForm();
await userEvent.click(submitButtonElem);
await DeleteCashFormHelper.submitForm();
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith(deletingCash);
expect(onSubmit).toHaveBeenCalledWith(DeleteCashFormHelper.cash);
});
});

View File

@ -1,91 +1,35 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditCashFormProps } from './EditCashForm.ui';
import EditCashForm from './EditCashForm.ui';
const editingCash = {
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Наличные',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditCashFormProps>) => {
const onSubmit = jest.fn();
render(
<EditCashForm
cash={editingCash}
data-testid="edit-bank-card-form"
onSubmit={onSubmit}
{...props}
/>,
);
const titleInputElem = screen.getByLabelText('Название');
const balanceInputElem = screen.getByLabelText('Баланс');
const submitButtonElem = screen.getByText('Сохранить');
return {
balanceInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { EditCashFormHelper } from '@tests/helpers';
describe('Test EditCashForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('edit-bank-card-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
EditCashFormHelper.renderForm();
const { formElem } = EditCashFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should inputs have default value', () => {
const {
balanceInputElem,
titleInputElem,
} = renderForm();
expect(titleInputElem).toHaveValue('Наличные');
expect(balanceInputElem).toHaveValue(1000);
EditCashFormHelper.renderForm();
const { balanceInputElem, nameInputElem } = EditCashFormHelper.getFormElements();
expect(nameInputElem).toHaveValue('Аренда квартиры');
expect(balanceInputElem).toHaveValue('41300');
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
EditCashFormHelper.renderForm(options);
const { formElem, ...formElems } = EditCashFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
balanceInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, 'Новое название наличных');
await userEvent.clear(balanceInputElem);
await userEvent.type(balanceInputElem, '5000');
await userEvent.click(submitButtonElem);
const { onSubmit } = EditCashFormHelper.renderForm();
const data = { balance: 5000, name: 'Новое название наличных' };
await EditCashFormHelper.fillForm(data);
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
balance: 5000,
name: 'Новое название наличных',
});
expect(onSubmit).toHaveBeenCalledWith(data);
});
});

View File

@ -1,184 +1,55 @@
import { bankCardList, cashList } from '@mocks/browser/data';
import { getBankCardList, getCashList } from '@mocks/browser/handlers';
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { BankCard } from '@/entity/cards';
import type { CashItem } from '@/entity/cash';
import type { AddExpenseItemFormProps } from './AddExpenseItemForm.ui';
import AddExpenseItemForm from './AddExpenseItemForm.ui';
const getExpenseItemFormElements = () => {
const titleInputElem = screen.getByLabelText('Название');
const descriptionInputElem = screen.getByLabelText('Описание');
const dateInputElem = screen.getByLabelText('Дата');
const amountInputElem = screen.getByLabelText('Сумма');
const countInputElem = screen.getByLabelText('Количество');
const submitButtonElem = screen.getByText('Добавить');
const paymentTypeSelect = screen.getByLabelText('Способ оплаты');
const bankCardSelect = screen.queryByLabelText('Карта');
const cashSelect = screen.queryByLabelText('Наличные');
return {
amountInputElem,
bankCardSelect,
cashSelect,
countInputElem,
dateInputElem,
descriptionInputElem,
paymentTypeSelect,
submitButtonElem,
titleInputElem,
};
};
type ExpenseFormValues = {
amount?: string;
count?: string;
date?: string;
description?: string;
// eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents
paymentId?: BankCard['id'] | CashItem['id'];
paymentType?: 'BANK_CARD' | 'CASH' | 'none';
title?: string;
};
// eslint-disable-next-line jest/no-export
export const fillAddExpenseItemForm = async (data: ExpenseFormValues) => {
const {
amount,
count,
date,
description,
paymentId,
paymentType = 'none',
title,
} = data;
const {
amountInputElem,
// bankCardSelect,
// cashSelect,
countInputElem,
dateInputElem,
descriptionInputElem,
paymentTypeSelect,
titleInputElem,
} = getExpenseItemFormElements();
if (title) {
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, title);
}
if (description) {
await userEvent.clear(descriptionInputElem);
await userEvent.type(descriptionInputElem, description);
}
if (date) {
await userEvent.clear(dateInputElem);
await userEvent.type(dateInputElem, date);
}
if (amount) {
await userEvent.clear(amountInputElem);
await userEvent.type(amountInputElem, amount);
}
if (count) {
await userEvent.clear(countInputElem);
await userEvent.type(countInputElem, count);
}
if (paymentType !== 'none') {
await userEvent.selectOptions(paymentTypeSelect, paymentType);
const { bankCardSelect, cashSelect } = getExpenseItemFormElements();
if (paymentType === 'BANK_CARD' && bankCardSelect && paymentId) {
await userEvent.selectOptions(bankCardSelect, paymentId);
} else if (paymentType === 'CASH' && cashSelect && paymentId) {
await userEvent.selectOptions(cashSelect, paymentId);
}
}
};
const renderForm = (props?: Partial<AddExpenseItemFormProps>) => {
server.use(getBankCardList, getCashList);
const onSubmit = jest.fn();
render(
<AddExpenseItemForm data-testid="add-expense-item-form" onSubmit={onSubmit} {...props} />,
{ wrapper: createReactQueryWrapper() },
);
const {
amountInputElem,
countInputElem,
dateInputElem,
descriptionInputElem,
submitButtonElem,
titleInputElem,
} = getExpenseItemFormElements();
return {
amountInputElem,
countInputElem,
dateInputElem,
descriptionInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { within } from '@testing-library/react';
import { AddExpenseItemFormHelper } from '@tests/helpers';
describe('Test AddExpenseItemForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('add-expense-item-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
AddExpenseItemFormHelper.renderForm();
const { formElem } = AddExpenseItemFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
Object.values(formElems).forEach(assertion);
AddExpenseItemFormHelper.renderForm(options);
const {
bankCardSelect,
bankCardSelectInput,
cashSelect,
cashSelectInput,
formElem,
paymentTypeSelect,
...formElems
} = AddExpenseItemFormHelper.getFormElements();
[
...Object.values(formElems),
within(paymentTypeSelect).getByTestId('payment-type-select-input'),
].forEach(assertion);
});
describe('should call onSubmit with values', () => {
const setup = async () => {
const {
onSubmit,
submitButtonElem,
} = renderForm();
const { onSubmit } = AddExpenseItemFormHelper.renderForm();
await fillAddExpenseItemForm({
await AddExpenseItemFormHelper.fillForm({
amount: '12',
count: '1',
date: '2025-08-29',
date: '29.08.2025',
description: 'Описание элемента',
title: 'Название элемента',
});
}, { autoSubmit: false });
return {
onSubmit,
submitButtonElem,
};
};
test('no payment', async () => {
const { onSubmit, submitButtonElem } = await setup();
await userEvent.click(submitButtonElem);
const { onSubmit } = await setup();
await AddExpenseItemFormHelper.submitForm();
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
@ -193,16 +64,18 @@ describe('Test AddExpenseItemForm', () => {
});
test('bank card payment', async () => {
const { onSubmit, submitButtonElem } = await setup();
await fillAddExpenseItemForm({ paymentType: 'BANK_CARD' });
const { bankCardSelect } = getExpenseItemFormElements();
const { onSubmit } = await setup();
await AddExpenseItemFormHelper.fillForm({ paymentType: 'BANK_CARD' }, { autoSubmit: false });
const { bankCardSelect, bankCardSelectInput } = AddExpenseItemFormHelper.getFormElements();
expect(bankCardSelect).toBeVisible();
expect(bankCardSelect).toBeEnabled();
expect(bankCardSelect).toHaveValue(bankCardList[0].id);
expect(bankCardSelectInput).toBeEnabled();
expect(bankCardSelectInput).toHaveValue(bankCardList[0].id);
await fillAddExpenseItemForm({ paymentId: bankCardList[1].id, paymentType: 'BANK_CARD' });
await AddExpenseItemFormHelper.fillForm({ paymentId: bankCardList[1].id, paymentType: 'BANK_CARD' }, { autoSubmit: false });
expect(bankCardSelectInput).toHaveValue(bankCardList[1].id);
await userEvent.click(submitButtonElem);
await AddExpenseItemFormHelper.submitForm();
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
@ -220,17 +93,15 @@ describe('Test AddExpenseItemForm', () => {
});
test('cash payment', async () => {
const { onSubmit, submitButtonElem } = await setup();
const { onSubmit } = await setup();
await fillAddExpenseItemForm({ paymentType: 'CASH' });
const { cashSelect } = getExpenseItemFormElements();
await AddExpenseItemFormHelper.fillForm({ paymentType: 'CASH' });
const { cashSelect, cashSelectInput } = AddExpenseItemFormHelper.getFormElements();
expect(cashSelect).toBeVisible();
expect(cashSelect).toBeEnabled();
expect(cashSelect).toHaveValue(cashList[0].id);
expect(cashSelectInput).toBeEnabled();
expect(cashSelectInput).toHaveValue(cashList[0].id);
await fillAddExpenseItemForm({ paymentId: cashList[1].id, paymentType: 'CASH' });
await userEvent.click(submitButtonElem);
await AddExpenseItemFormHelper.fillForm({ paymentId: cashList[1].id, paymentType: 'CASH' });
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({

View File

@ -1,61 +1,18 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteExpenseItemFormProps } from './DeleteExpenseItemForm.ui';
import DeleteExpenseItemForm from './DeleteExpenseItemForm.ui';
const deletingItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteExpenseItemFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteExpenseItemForm
data-testid="delete-expense-item-form"
item={deletingItem}
onSubmit={onSubmit}
{...props}
/>,
);
const submitButtonElem = screen.getByText('Удалить');
return {
onSubmit,
submitButtonElem,
};
};
import { DeleteExpenseItemFormHelper } from '@tests/helpers';
describe('Test DeleteExpenseItemForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('delete-expense-item-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
DeleteExpenseItemFormHelper.renderForm();
const { formElem } = DeleteExpenseItemFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
} = renderForm();
await userEvent.click(submitButtonElem);
const { onSubmit } = DeleteExpenseItemFormHelper.renderForm();
await DeleteExpenseItemFormHelper.submitForm();
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith(deletingItem);
expect(onSubmit).toHaveBeenCalledWith(DeleteExpenseItemFormHelper.expenseItem);
});
});

View File

@ -1,116 +1,48 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditExpenseItemFormProps } from './EditExpenseItemForm.ui';
import EditExpenseItemForm from './EditExpenseItemForm.ui';
const editingItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditExpenseItemFormProps>) => {
const onSubmit = jest.fn();
render(
<EditExpenseItemForm
data-testid="edit-expense-item-form"
item={editingItem}
onSubmit={onSubmit}
{...props}
/>,
);
const titleInputElem = screen.getByLabelText('Название');
const descriptionInputElem = screen.getByLabelText('Описание');
const dateInputElem = screen.getByLabelText('Дата');
const amountInputElem = screen.getByLabelText('Сумма');
const countInputElem = screen.getByLabelText('Количество');
const submitButtonElem = screen.getByText('Сохранить');
return {
amountInputElem,
countInputElem,
dateInputElem,
descriptionInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { EditExpenseItemFormHelper } from '@tests/helpers';
describe('Test EditExpenseItemForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('edit-expense-item-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
EditExpenseItemFormHelper.renderForm();
const { formElem } = EditExpenseItemFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should inputs have default value', () => {
EditExpenseItemFormHelper.renderForm();
const {
amountInputElem,
countInputElem,
dateInputElem,
descriptionInputElem,
titleInputElem,
} = renderForm();
} = EditExpenseItemFormHelper.getFormElements();
expect(titleInputElem).toHaveValue('Mock item');
expect(descriptionInputElem).toHaveValue('Mock description');
expect(dateInputElem).toHaveValue('2025-08-22');
expect(amountInputElem).toHaveValue(12);
expect(dateInputElem).toHaveValue('22.08.2025');
expect(amountInputElem).toHaveValue('12');
expect(countInputElem).toHaveValue(12);
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
EditExpenseItemFormHelper.renderForm(options);
const { formElem, ...formElems } = EditExpenseItemFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
amountInputElem,
countInputElem,
dateInputElem,
descriptionInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
const { onSubmit } = EditExpenseItemFormHelper.renderForm();
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, 'Название элемента');
await userEvent.clear(descriptionInputElem);
await userEvent.type(descriptionInputElem, 'Описание элемента');
await userEvent.clear(dateInputElem);
await userEvent.type(dateInputElem, '2025-08-29');
await userEvent.clear(amountInputElem);
await userEvent.type(amountInputElem, '12');
await userEvent.clear(countInputElem);
await userEvent.type(countInputElem, '1');
await userEvent.click(submitButtonElem);
await EditExpenseItemFormHelper.fillForm({
amount: 12,
count: 1,
date: '29.08.2025',
description: 'Описание элемента',
title: 'Название элемента',
});
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({

View File

@ -1,58 +1,28 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddExpenseListFormProps } from './AddExpensesListForm.ui';
import AddExpensesListForm from './AddExpensesListForm.ui';
const renderForm = (props?: Partial<AddExpenseListFormProps>) => {
const onSubmit = jest.fn();
render(<AddExpensesListForm data-testid="add-expense-list-form" onSubmit={onSubmit} {...props} />);
const titleInputElem = screen.getByLabelText('Название');
const submitButtonElem = screen.getByText('Добавить');
return {
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { AddExpensesListFormHelper } from '@tests/helpers';
describe('Test AddExpensesListForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('add-expense-list-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
AddExpensesListFormHelper.renderForm();
const { formElem } = AddExpensesListFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
AddExpensesListFormHelper.renderForm(options);
const { formElem, submitButtonElem, ...formElems } = AddExpensesListFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
const { onSubmit } = AddExpensesListFormHelper.renderForm();
await userEvent.type(titleInputElem, 'Название списка');
await userEvent.click(submitButtonElem);
await AddExpensesListFormHelper.fillForm({ title: 'Название списка' });
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
title: 'Название списка',
});
expect(onSubmit).toHaveBeenCalledWith({ title: 'Название списка' });
});
});

View File

@ -1,55 +1,18 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteExpenseListFormProps } from './DeleteExpensesListForm.ui';
import DeleteExpensesListForm from './DeleteExpensesListForm.ui';
const deletingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteExpenseListFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteExpensesListForm
data-testid="delete-expense-list-form"
list={deletingList}
onSubmit={onSubmit}
{...props}
/>,
);
const submitButtonElem = screen.getByText('Удалить');
return {
onSubmit,
submitButtonElem,
};
};
import { DeleteExpensesListFormHelper } from '@tests/helpers';
describe('Test DeleteExpensesListForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('delete-expense-list-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
DeleteExpensesListFormHelper.renderForm();
const { formElem } = DeleteExpensesListFormHelper.getFormElems();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
} = renderForm();
await userEvent.click(submitButtonElem);
const { onSubmit } = DeleteExpensesListFormHelper.renderForm();
await DeleteExpensesListFormHelper.submitForm();
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith(deletingList);
expect(onSubmit).toHaveBeenCalledWith(DeleteExpensesListFormHelper.expensesList);
});
});

View File

@ -1,78 +1,32 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditExpensesListFormProps } from './EditExpensesListForm.ui';
import EditExpensesListForm from './EditExpensesListForm.ui';
const editingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditExpensesListFormProps>) => {
const onSubmit = jest.fn();
render(
<EditExpensesListForm
data-testid="edit-expense-list-form"
list={editingList}
onSubmit={onSubmit}
{...props}
/>,
);
const titleInputElem = screen.getByLabelText('Название');
const submitButtonElem = screen.getByText('Сохранить');
return {
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { EditExpensesListFormHelper } from '@tests/helpers';
describe('Test EditExpensesListForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('edit-expense-list-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
EditExpensesListFormHelper.renderForm();
const { formElem } = EditExpensesListFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should inputs have default value', () => {
const {
titleInputElem,
} = renderForm();
EditExpensesListFormHelper.renderForm();
const { titleInputElem } = EditExpensesListFormHelper.getFormElements();
expect(titleInputElem).toHaveValue('Mock list');
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
EditExpensesListFormHelper.renderForm(options);
const { formElem, ...formElems } = EditExpensesListFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
const { onSubmit } = EditExpensesListFormHelper.renderForm();
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, 'Название списка');
await userEvent.click(submitButtonElem);
await EditExpensesListFormHelper.fillForm({ title: 'Название списка' });
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({

View File

@ -1,67 +1,31 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddIncomeItemFormProps } from './AddIncomeItemForm.ui';
import AddIncomeItemForm from './AddIncomeItemForm.ui';
const renderForm = (props?: Partial<AddIncomeItemFormProps>) => {
const onSubmit = jest.fn();
render(<AddIncomeItemForm data-testid="add-income-item-form" onSubmit={onSubmit} {...props} />);
const titleInputElem = screen.getByLabelText('Название');
const descriptionInputElem = screen.getByLabelText('Описание');
const dateInputElem = screen.getByLabelText('Дата');
const amountInputElem = screen.getByLabelText('Сумма');
const submitButtonElem = screen.getByText('Добавить');
return {
amountInputElem,
dateInputElem,
descriptionInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { AddIncomeItemFormHelper } from '@tests/helpers';
describe('Test AddIncomeItemForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('add-income-item-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
AddIncomeItemFormHelper.renderForm();
const { formElem } = AddIncomeItemFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
AddIncomeItemFormHelper.renderForm(options);
const { formElem, ...formElems } = AddIncomeItemFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
amountInputElem,
dateInputElem,
descriptionInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
const { onSubmit } = AddIncomeItemFormHelper.renderForm();
await userEvent.type(titleInputElem, 'Название элемента');
await userEvent.type(descriptionInputElem, 'Описание элемента');
await userEvent.type(dateInputElem, '2025-08-29');
await userEvent.type(amountInputElem, '12');
await userEvent.click(submitButtonElem);
await AddIncomeItemFormHelper.fillForm({
amount: 12,
date: '29.08.2025',
description: 'Описание элемента',
title: 'Название элемента',
});
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({

View File

@ -1,59 +1,18 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteIncomeItemFormProps } from './DeleteIncomeItemForm.ui';
import DeleteIncomeItemForm from './DeleteIncomeItemForm.ui';
const deletingItem = {
amount: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteIncomeItemFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteIncomeItemForm
data-testid="delete-income-item-form"
item={deletingItem}
onSubmit={onSubmit}
{...props}
/>,
);
const submitButtonElem = screen.getByText('Удалить');
return {
onSubmit,
submitButtonElem,
};
};
import { DeleteIncomeItemFormHelper } from '@tests/helpers';
describe('Test DeleteIncomeItemForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('delete-income-item-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
DeleteIncomeItemFormHelper.renderForm();
const { formElem } = DeleteIncomeItemFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
} = renderForm();
await userEvent.click(submitButtonElem);
const { onSubmit } = DeleteIncomeItemFormHelper.renderForm();
await DeleteIncomeItemFormHelper.submitForm();
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith(deletingItem);
expect(onSubmit).toHaveBeenCalledWith(DeleteIncomeItemFormHelper.incomeItem);
});
});

View File

@ -1,107 +1,45 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditIncomeItemFormProps } from './EditIncomeItemForm.ui';
import EditIncomeItemForm from './EditIncomeItemForm.ui';
const editingItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditIncomeItemFormProps>) => {
const onSubmit = jest.fn();
render(
<EditIncomeItemForm
data-testid="edit-income-item-form"
item={editingItem}
onSubmit={onSubmit}
{...props}
/>,
);
const titleInputElem = screen.getByLabelText('Название');
const descriptionInputElem = screen.getByLabelText('Описание');
const dateInputElem = screen.getByLabelText('Дата');
const amountInputElem = screen.getByLabelText('Сумма');
const submitButtonElem = screen.getByText('Сохранить');
return {
amountInputElem,
dateInputElem,
descriptionInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { EditIncomeItemFormHelper } from '@tests/helpers';
describe('Test EditIncomeItemForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('edit-income-item-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
EditIncomeItemFormHelper.renderForm();
const { formElem } = EditIncomeItemFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should inputs have default value', () => {
EditIncomeItemFormHelper.renderForm();
const {
amountInputElem,
dateInputElem,
descriptionInputElem,
titleInputElem,
} = renderForm();
} = EditIncomeItemFormHelper.getFormElements();
expect(titleInputElem).toHaveValue('Mock item');
expect(descriptionInputElem).toHaveValue('Mock description');
expect(dateInputElem).toHaveValue('2025-08-22');
expect(dateInputElem).toHaveValue('22.08.2025');
expect(amountInputElem).toHaveValue(12);
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
EditIncomeItemFormHelper.renderForm(options);
const { formElem, ...formElems } = EditIncomeItemFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
amountInputElem,
dateInputElem,
descriptionInputElem,
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
const { onSubmit } = EditIncomeItemFormHelper.renderForm();
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, 'Название элемента');
await userEvent.clear(descriptionInputElem);
await userEvent.type(descriptionInputElem, 'Описание элемента');
await userEvent.clear(dateInputElem);
await userEvent.type(dateInputElem, '2025-08-29');
await userEvent.clear(amountInputElem);
await userEvent.type(amountInputElem, '12');
await userEvent.click(submitButtonElem);
await EditIncomeItemFormHelper.fillForm({
amount: 12,
date: '29.08.2025',
description: 'Описание элемента',
title: 'Название элемента',
});
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({

View File

@ -1,58 +1,27 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddIncomeListFormProps } from './AddIncomeListForm.ui';
import AddIncomeListForm from './AddIncomeListForm.ui';
const renderForm = (props?: Partial<AddIncomeListFormProps>) => {
const onSubmit = jest.fn();
render(<AddIncomeListForm data-testid="add-income-list-form" onSubmit={onSubmit} {...props} />);
const titleInputElem = screen.getByLabelText('Название');
const submitButtonElem = screen.getByText('Добавить');
return {
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { AddIncomeListFormHelper } from '@tests/helpers';
describe('Test AddIncomeListForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('add-income-list-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
AddIncomeListFormHelper.renderForm();
const { formElem } = AddIncomeListFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
AddIncomeListFormHelper.renderForm(options);
const { formElem, ...formElems } = AddIncomeListFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
await userEvent.type(titleInputElem, 'Название списка');
await userEvent.click(submitButtonElem);
const { onSubmit } = AddIncomeListFormHelper.renderForm();
await AddIncomeListFormHelper.fillForm({ title: 'Название списка' });
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
title: 'Название списка',
});
expect(onSubmit).toHaveBeenCalledWith({ title: 'Название списка' });
});
});

View File

@ -1,55 +1,18 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteIncomeListFormProps } from './DeleteIncomeListForm.ui';
import DeleteIncomeListForm from './DeleteIncomeListForm.ui';
const deletingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteIncomeListFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteIncomeListForm
data-testid="delete-income-list-form"
list={deletingList}
onSubmit={onSubmit}
{...props}
/>,
);
const submitButtonElem = screen.getByText('Удалить');
return {
onSubmit,
submitButtonElem,
};
};
import { DeleteIncomeListFormHelper } from '@tests/helpers';
describe('Test DeleteIncomeListForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('delete-income-list-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
DeleteIncomeListFormHelper.renderForm();
const { formElem } = DeleteIncomeListFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
} = renderForm();
await userEvent.click(submitButtonElem);
const { onSubmit } = DeleteIncomeListFormHelper.renderForm();
await DeleteIncomeListFormHelper.submitForm();
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith(deletingList);
expect(onSubmit).toHaveBeenCalledWith(DeleteIncomeListFormHelper.incomeList);
});
});

View File

@ -1,82 +1,34 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditExpensesListFormProps } from './EditIncomeListForm.ui';
import EditIncomeListForm from './EditIncomeListForm.ui';
const editingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditExpensesListFormProps>) => {
const onSubmit = jest.fn();
render(
<EditIncomeListForm
data-testid="edit-income-list-form"
list={editingList}
onSubmit={onSubmit}
{...props}
/>,
);
const titleInputElem = screen.getByLabelText('Название');
const submitButtonElem = screen.getByText('Сохранить');
return {
onSubmit,
submitButtonElem,
titleInputElem,
};
};
import { EditIncomeListFormHelper } from '@tests/helpers';
describe('Test EditIncomeListForm', () => {
test('should render form', () => {
renderForm();
const form = screen.getByTestId('edit-income-list-form');
expect(form).toBeInTheDocument();
expect(form).toBeVisible();
EditIncomeListFormHelper.renderForm();
const { formElem } = EditIncomeListFormHelper.getFormElements();
expect(formElem).toBeInTheDocument();
expect(formElem).toBeVisible();
});
test('should inputs have default value', () => {
const {
titleInputElem,
} = renderForm();
EditIncomeListFormHelper.renderForm();
const { titleInputElem } = EditIncomeListFormHelper.getFormElements();
expect(titleInputElem).toHaveValue('Mock list');
});
test.each([
['enabled', {}, (el: HTMLElement) => {
expect(el).toBeEnabled();
}],
['disabled', { disabled: true }, (el: HTMLElement) => {
expect(el).toBeDisabled();
}],
['enabled', {}, (el: HTMLElement) => { expect(el).toBeEnabled(); }],
['disabled', { disabled: true }, (el: HTMLElement) => { expect(el).toBeDisabled(); }],
])('should render fields %s', (_state, options, assertion) => {
const { onSubmit, ...formElems } = renderForm(options);
EditIncomeListFormHelper.renderForm(options);
const { formElem, ...formElems } = EditIncomeListFormHelper.getFormElements();
Object.values(formElems).forEach(assertion);
});
test('should call onSubmit with values', async () => {
const {
onSubmit,
submitButtonElem,
titleInputElem,
} = renderForm();
const { onSubmit } = EditIncomeListFormHelper.renderForm();
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, 'Название списка');
await userEvent.click(submitButtonElem);
await EditIncomeListFormHelper.fillForm({ title: 'Название списка' });
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit).toHaveBeenCalledWith({
title: 'Название списка',
});
expect(onSubmit).toHaveBeenCalledWith({ title: 'Название списка' });
});
});

View File

@ -1,72 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddBankCardBody, AddBankCardResponse } from '@/entity/cards';
import AddBankCardButton from './AddBankCardButton.ui';
const renderButton = () => {
render(
<AddBankCardButton data-testid="test-button" />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('test-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const fillForm = async (data: AddBankCardBody) => {
await userEvent.type(screen.getByLabelText('Название'), data.name);
await userEvent.type(screen.getByLabelText('Баланс'), String(data.balance));
};
const submitHandler = (requestSpy: jest.Mock) => http.post<never, AddBankCardBody, AddBankCardResponse>(
'/bank-card',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
balance: 999,
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
name: 'Название карты',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
import { screen, waitFor } from '@testing-library/react';
import { AddBankCardButtonHelper, AddBankCardFormHelper } from '@tests/helpers';
describe('Test AddBankCardButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = AddBankCardButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Добавить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await AddBankCardButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -78,18 +28,18 @@ describe('Test AddBankCardButton', () => {
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = within(modalElem).getByText('Добавить');
server.use(AddBankCardButtonHelper.submitHandler(requestSpy));
modalElem = (await AddBankCardButtonHelper.openModal()).modalElem;
submitButtonElem = AddBankCardFormHelper.getFormElements().submitButtonElem;
await fillForm({
await AddBankCardFormHelper.fillForm({
balance: 999,
name: 'Тестовая карта',
});
}, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await AddBankCardFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
balance: 999,
@ -99,8 +49,10 @@ describe('Test AddBankCardButton', () => {
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await AddBankCardFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,75 +1,35 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { BankCard } from '@/entity/cards';
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
import DeleteBankCardButton from './DeleteBankCardButton.ui';
const deletingBankCard: BankCard = {
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Тестовая карта',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
const testId = 'delete-bank-card-button';
render(
<DeleteBankCardButton bankCard={deletingBankCard} data-testid={testId} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId(testId);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseListPath>(`/bank-card/${deletingBankCard.id}`, () => HttpResponse.json(deletingBankCard));
import { screen, waitFor } from '@testing-library/react';
import { DeleteBankCardButtonHelper, DeleteBankCardFormHelper } from '@tests/helpers';
describe('Test DeleteBankCardButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = DeleteBankCardButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Удалить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await DeleteBankCardButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
});
test('should close modal after submit', async () => {
server.use(submitHandler);
const { modalElem } = await openModal();
const submitButtonElem = within(modalElem).getByText('Удалить');
server.use(DeleteBankCardButtonHelper.submitHandler);
const { modalElem } = await DeleteBankCardButtonHelper.openModal();
const { submitButtonElem } = DeleteBankCardFormHelper.getFormElements();
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await DeleteBankCardFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});

View File

@ -1,92 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
BankCard,
EditBankCardBody,
EditBankCardPath,
EditBankCardResponse,
} from '@/entity/cards';
import EditBankCardButton from './EditBankCardButton.ui';
const editingBankCard: BankCard = {
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Тестовая карта',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const fillForm = async (data: EditBankCardBody) => {
const nameInputElem = screen.getByLabelText('Название');
const balanceInputElem = screen.getByLabelText('Баланс');
await userEvent.clear(nameInputElem);
await userEvent.type(nameInputElem, data.name);
await userEvent.clear(balanceInputElem);
await userEvent.type(balanceInputElem, String(data.balance));
};
const renderButton = () => {
const testId = 'edit-bank-card-button';
render(
<EditBankCardButton bankCard={editingBankCard} data-testid={testId} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId(testId);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<EditBankCardPath, EditBankCardBody, EditBankCardResponse>(
`/bank-card/${editingBankCard.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Тестовая карта',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
import { screen, waitFor } from '@testing-library/react';
import { EditBankCardButtonHelper, EditBankCardFormHelper } from '@tests/helpers';
describe('Test EditBankCardButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = EditBankCardButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Редактировать');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await EditBankCardButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -98,18 +28,18 @@ describe('Test EditBankCardButton', () => {
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = within(modalElem).getByText('Сохранить');
server.use(EditBankCardButtonHelper.submitHandler(requestSpy));
modalElem = (await EditBankCardButtonHelper.openModal()).modalElem;
submitButtonElem = EditBankCardFormHelper.getFormElements().submitButtonElem;
await fillForm({
await EditBankCardFormHelper.fillForm({
balance: 999,
name: 'Тестовая карта',
});
}, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await EditBankCardFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
balance: 999,
@ -119,8 +49,10 @@ describe('Test EditBankCardButton', () => {
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await EditBankCardFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,72 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AdCashResponse, AddCashBody } from '@/entity/cash';
import AddCashButton from './AddCashButton.ui';
const renderButton = () => {
render(
<AddCashButton data-testid="test-button" />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('test-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const fillForm = async (data: AddCashBody) => {
await userEvent.type(screen.getByLabelText('Название'), data.name);
await userEvent.type(screen.getByLabelText('Баланс'), String(data.balance));
};
const submitHandler = (requestSpy: jest.Mock) => http.post<never, AddCashBody, AdCashResponse>(
'/cash',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
balance: 999,
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
name: 'Наличные',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
import { screen, waitFor } from '@testing-library/react';
import { AddCashButtonHelper, AddCashFormHelper } from '@tests/helpers';
describe('Test AddCashButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = AddCashButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Добавить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await AddCashButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -78,18 +28,18 @@ describe('Test AddCashButton', () => {
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = within(modalElem).getByText('Добавить');
server.use(AddCashButtonHelper.submitHandler(requestSpy));
modalElem = (await AddCashButtonHelper.openModal()).modalElem;
submitButtonElem = AddCashFormHelper.getFormElements().submitButtonElem;
await fillForm({
await AddCashFormHelper.fillForm({
balance: 999,
name: 'Наличные',
});
}, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await AddCashFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
balance: 999,
@ -99,8 +49,10 @@ describe('Test AddCashButton', () => {
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await AddCashFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,75 +1,37 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { CashItem } from '@/entity/cash';
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
import DeleteCashButton from './DeleteCashButton.ui';
const deletingCash: CashItem = {
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Наличные',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
const testId = 'delete-cash-button';
render(
<DeleteCashButton cash={deletingCash} data-testid={testId} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId(testId);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseListPath>(`/cash/${deletingCash.id}`, () => HttpResponse.json(deletingCash));
import { DeleteCashButtonHelper, DeleteCashFormHelper } from '@tests/helpers';
describe('Test DeleteCashButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = DeleteCashButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Удалить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await DeleteCashButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
});
test('should close modal after submit', async () => {
server.use(submitHandler);
const { modalElem } = await openModal();
const submitButtonElem = within(modalElem).getByText('Удалить');
server.use(DeleteCashButtonHelper.submitHandler);
const { modalElem } = await DeleteCashButtonHelper.openModal();
const { submitButtonElem } = DeleteCashFormHelper.getFormElements();
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});

View File

@ -1,92 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
CashItem,
EditCashBody,
EditCashPath,
EditCashResponse,
} from '@/entity/cash';
import EditCashButton from './EditCashButton.ui';
const editingCash: CashItem = {
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Наличные',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const fillForm = async (data: EditCashBody) => {
const nameInputElem = screen.getByLabelText('Название');
const balanceInputElem = screen.getByLabelText('Баланс');
await userEvent.clear(nameInputElem);
await userEvent.type(nameInputElem, data.name);
await userEvent.clear(balanceInputElem);
await userEvent.type(balanceInputElem, String(data.balance));
};
const renderButton = () => {
const testId = 'edit-cash-button';
render(
<EditCashButton cash={editingCash} data-testid={testId} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId(testId);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<EditCashPath, EditCashBody, EditCashResponse>(
`/cash/${editingCash.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
balance: 1000,
createdAt: '2025-08-29T07:57:40.503Z',
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
name: 'Наличные',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
import { screen, waitFor } from '@testing-library/react';
import { EditCashButtonHelper, EditCashFormHelper } from '@tests/helpers';
describe('Test EditCashButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = EditCashButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Редактировать');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await EditCashButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -98,18 +28,18 @@ describe('Test EditCashButton', () => {
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = within(modalElem).getByText('Сохранить');
server.use(EditCashButtonHelper.submitHandler(requestSpy));
modalElem = (await EditCashButtonHelper.openModal()).modalElem;
submitButtonElem = EditCashFormHelper.getFormElements().submitButtonElem;
await fillForm({
await EditCashFormHelper.fillForm({
balance: 999,
name: 'Наличные',
});
}, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await EditCashFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
balance: 999,
@ -119,8 +49,10 @@ describe('Test EditCashButton', () => {
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await EditCashFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,85 +1,22 @@
import { getBankCardList, getCashList } from '@mocks/browser/handlers';
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
AddExpenseItemBody,
AddExpenseItemPath,
AddExpenseItemSuccessResponse,
} from '@/entity/expenses/item';
import { fillAddExpenseItemForm } from '@/entity/expenses/item/ui/AddExpenseItemForm/AddExpenseItemForm.test';
import AddExpenseItemButton from './AddExpenseItemButton.ui';
const renderButton = () => {
server.use(getBankCardList, getCashList);
render(
<AddExpenseItemButton data-testid="test-button" listId="123" />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('test-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.post<
AddExpenseItemPath,
AddExpenseItemBody,
AddExpenseItemSuccessResponse
>(
'/expenses/list/123/items',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
import { screen, waitFor } from '@testing-library/react';
import { AddExpenseItemButtonHelper, AddExpenseItemFormHelper } from '@tests/helpers';
describe('Test AddExpenseItemButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = AddExpenseItemButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Добавить элемент');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await AddExpenseItemButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -87,25 +24,23 @@ describe('Test AddExpenseItemButton', () => {
describe('should close modal after submit and send request', () => {
let modalElem: HTMLElement;
let submitButtonElem: HTMLElement;
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = screen.getByText('Добавить');
server.use(AddExpenseItemButtonHelper.submitHandler(requestSpy));
modalElem = (await AddExpenseItemButtonHelper.openModal()).modalElem;
await fillAddExpenseItemForm({
await AddExpenseItemFormHelper.fillForm({
amount: '12',
count: '1',
date: '2025-08-29',
date: '29.08.2025',
description: 'Описание элемента',
title: 'Название элемента',
});
}, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await AddExpenseItemFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
amount: 12,
@ -119,9 +54,10 @@ describe('Test AddExpenseItemButton', () => {
});
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await AddExpenseItemFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,79 +1,37 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteExpenseItemPath } from '@/entity/expenses/item';
import DeleteExpenseItemButton from './DeleteExpenseItemButton.ui';
const deletedItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<DeleteExpenseItemButton data-testid="delete-expense-item-button" item={deletedItem} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('delete-expense-item-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseItemPath>(`/expenses/list/${deletedItem.expenseListId}/items/${deletedItem.id}`, () => HttpResponse.json(deletedItem));
import { DeleteExpenseItemButtonHelper, DeleteExpenseItemFormHelper } from '@tests/helpers';
describe('Test DeleteExpenseItemButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = DeleteExpenseItemButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Удалить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await DeleteExpenseItemButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
});
test('should close modal after submit', async () => {
server.use(submitHandler);
const { modalElem } = await openModal();
const submitButtonElem = within(modalElem).getByText('Удалить');
server.use(DeleteExpenseItemButtonHelper.submitHandler);
const { modalElem } = await DeleteExpenseItemButtonHelper.openModal();
const { submitButtonElem } = DeleteExpenseItemFormHelper.getFormElements();
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});

View File

@ -1,105 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
EditExpenseItemBody,
EditExpenseItemPath,
EditExpenseItemSuccessResponse,
} from '@/entity/expenses/item';
import EditExpenseItemButton from './EditExpenseItemButton.ui';
const editingItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<EditExpenseItemButton data-testid="edit-expense-item-button" item={editingItem} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('edit-expense-item-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditExpenseItemPath,
EditExpenseItemBody,
EditExpenseItemSuccessResponse
>(
`/expenses/list/${editingItem.expenseListId}/items/${editingItem.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(editingItem);
},
);
const fillForm = async (data: { amount: string; count: string; date: string; description: string; title: string }) => {
const titleInputElem = screen.getByLabelText('Название');
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, data.title);
const descriptionInputElem = screen.getByLabelText('Описание');
await userEvent.clear(descriptionInputElem);
await userEvent.type(descriptionInputElem, data.description);
const dateInputElem = screen.getByLabelText('Дата');
await userEvent.clear(dateInputElem);
await userEvent.type(dateInputElem, data.date);
const amountInputElem = screen.getByLabelText('Сумма');
await userEvent.clear(amountInputElem);
await userEvent.type(amountInputElem, data.amount);
const countInputElem = screen.getByLabelText('Количество');
await userEvent.clear(countInputElem);
await userEvent.type(countInputElem, data.count);
};
import { screen, waitFor } from '@testing-library/react';
import { EditExpenseItemButtonHelper, EditExpenseItemFormHelper } from '@tests/helpers';
describe('TestEditExpenseItemButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = EditExpenseItemButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Редактировать');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await EditExpenseItemButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -107,25 +24,23 @@ describe('TestEditExpenseItemButton', () => {
describe('should close modal after submit and send request', () => {
let modalElem: HTMLElement;
let submitButtonElem: HTMLElement;
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = screen.getByText('Сохранить');
server.use(EditExpenseItemButtonHelper.submitHandler(requestSpy));
modalElem = (await EditExpenseItemButtonHelper.openModal()).modalElem;
await fillForm({
amount: '12',
count: '1',
date: '2025-08-29',
await EditExpenseItemFormHelper.fillForm({
amount: 12,
count: 1,
date: '29.08.2025',
description: 'Описание элемента',
title: 'Название элемента',
});
}, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await EditExpenseItemFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
amount: 12,
@ -138,9 +53,10 @@ describe('TestEditExpenseItemButton', () => {
});
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await EditExpenseItemFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,71 +1,24 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddExpenseListBody, AddExpenseListSuccessResponse } from '@/entity/expenses/list';
import AddExpensesListButton from './AddExpensesListButton.ui';
const renderButton = () => {
render(
<AddExpensesListButton data-testid="test-button" />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('test-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const fillForm = async (data: { title: string }) => {
await userEvent.type(screen.getByLabelText('Название'), data.title);
};
const submitHandler = (requestSpy: jest.Mock) => http.post<never, AddExpenseListBody, AddExpenseListSuccessResponse>(
'/expenses/list',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
import { screen, waitFor } from '@testing-library/react';
import { AddExpensesListButtonHelper, AddExpensesListFormHelper } from '@tests/helpers';
describe('Test AddExpensesListButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
test('should correct render button', async () => {
const { buttonElem } = AddExpensesListButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Добавить');
const modal = screen.queryByRole('dialog');
expect(modal).not.toBeInTheDocument();
const modal = screen.queryByRole('presentation');
await waitFor(() => {
expect(modal).not.toBeInTheDocument();
});
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await AddExpensesListButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -73,31 +26,26 @@ describe('Test AddExpensesListButton', () => {
describe('should close modal after submit and send request', () => {
let modalElem: HTMLElement;
let submitButtonElem: HTMLElement;
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = within(modalElem).getByText('Добавить');
server.use(AddExpensesListButtonHelper.submitHandler(requestSpy));
modalElem = (await AddExpensesListButtonHelper.openModal()).modalElem;
await fillForm({
title: 'Название списка',
});
await AddExpensesListFormHelper.fillForm({ title: 'Название списка' }, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await AddExpensesListFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
title: 'Название списка',
});
expect(requestSpy).toHaveBeenCalledWith({ title: 'Название списка' });
});
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await AddExpensesListFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,73 +1,39 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
import DeleteExpensesListButton from './DeleteExpensesListButton.ui';
const deletingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<DeleteExpensesListButton data-testid="delete-expense-list-button" list={deletingList} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('delete-expense-list-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseListPath>(`/expenses/list/${deletingList.id}`, () => HttpResponse.json(deletingList));
import { DeleteExpensesListButtonHelper, DeleteExpensesListFormHelper } from '@tests/helpers';
describe('Test DeleteExpensesListButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
test('should correct render button', async () => {
const { buttonElem } = DeleteExpensesListButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Удалить');
const modal = screen.queryByRole('dialog');
expect(modal).not.toBeInTheDocument();
const modal = screen.queryByRole('presentation');
await waitFor(() => {
expect(modal).not.toBeInTheDocument();
});
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await DeleteExpensesListButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
});
test('should close modal after submit', async () => {
server.use(submitHandler);
const { modalElem } = await openModal();
const submitButtonElem = within(modalElem).getByText('Удалить');
server.use(DeleteExpensesListButtonHelper.submitHandler);
const { modalElem } = await DeleteExpensesListButtonHelper.openModal();
const { submitButtonElem } = DeleteExpensesListFormHelper.getFormElems();
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});

View File

@ -1,83 +1,24 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
EditExpenseListBody,
EditExpenseListPath,
EditExpenseListSuccessResponse,
} from '@/entity/expenses/list';
import EditExpensesListButton from './EditExpensesListButton.ui';
const editingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<EditExpensesListButton data-testid="edit-expense-list-button" list={editingList} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('edit-expense-list-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditExpenseListPath,
EditExpenseListBody,
EditExpenseListSuccessResponse
>(
`/expenses/list/${editingList.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(editingList);
},
);
const fillForm = async (data: { title: string }) => {
const titleInputElem = screen.getByLabelText('Название');
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, data.title);
};
import { screen, waitFor } from '@testing-library/react';
import { EditExpensesListButtonHelper, EditExpensesListFormHelper } from '@tests/helpers';
describe('Test EditExpensesListButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
test('should correct render button', async () => {
const { buttonElem } = EditExpensesListButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Редактировать');
const modal = screen.queryByRole('dialog');
expect(modal).not.toBeInTheDocument();
const modal = screen.queryByRole('presentation');
await waitFor(() => {
expect(modal).not.toBeInTheDocument();
});
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await EditExpensesListButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -85,21 +26,17 @@ describe('Test EditExpensesListButton', () => {
describe('should close modal after submit and send request', () => {
let modalElem: HTMLElement;
let submitButtonElem: HTMLElement;
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = screen.getByText('Сохранить');
server.use(EditExpensesListButtonHelper.submitHandler(requestSpy));
modalElem = (await EditExpensesListButtonHelper.openModal()).modalElem;
await fillForm({
title: 'Название списка',
});
await EditExpensesListFormHelper.fillForm({ title: 'Название списка' }, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await EditExpensesListFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
title: 'Название списка',
@ -107,9 +44,10 @@ describe('Test EditExpensesListButton', () => {
});
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await EditExpensesListFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,82 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddIncomeItemBody, AddIncomeItemPath, AddIncomeItemSuccessResponse } from '@/entity/incomes/item';
import AddIncomeItemButton from './AddIncomeItemButton.ui';
const renderButton = () => {
render(
<AddIncomeItemButton data-testid="test-button" listId="123" />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('test-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const fillForm = async (data: { amount: string; date: string; description: string; title: string }) => {
await userEvent.type(screen.getByLabelText('Название'), data.title);
await userEvent.type(screen.getByLabelText('Описание'), data.description);
await userEvent.type(screen.getByLabelText('Дата'), data.date);
await userEvent.type(screen.getByLabelText('Сумма'), data.amount);
};
const submitHandler = (requestSpy: jest.Mock) => http.post<
AddIncomeItemPath,
AddIncomeItemBody,
AddIncomeItemSuccessResponse
>(
'/incomes/list/123/items',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
amount: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
import { screen, waitFor } from '@testing-library/react';
import { AddIncomeItemButtonHelper, AddIncomeItemFormHelper } from '@tests/helpers';
describe('Test AddIncomeItemButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = AddIncomeItemButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Добавить элемент');
expect(buttonElem).toHaveTextContent('Добавить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await AddIncomeItemButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -84,24 +24,22 @@ describe('Test AddIncomeItemButton', () => {
describe('should close modal after submit and send request', () => {
let modalElem: HTMLElement;
let submitButtonElem: HTMLElement;
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = screen.getByText('Добавить');
server.use(AddIncomeItemButtonHelper.submitHandler(requestSpy));
modalElem = (await AddIncomeItemButtonHelper.openModal()).modalElem;
await fillForm({
amount: '12',
date: '2025-08-29',
await AddIncomeItemFormHelper.fillForm({
amount: 12,
date: '29.08.2025',
description: 'Описание элемента',
title: 'Название элемента',
});
}, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await AddIncomeItemFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
amount: 12,
@ -113,9 +51,10 @@ describe('Test AddIncomeItemButton', () => {
});
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await AddIncomeItemFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,77 +1,37 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteIncomeItemPath, IncomeListItem } from '@/entity/incomes/item';
import DeleteIncomeItemButton from './DeleteIncomeItemButton.ui';
const deletedItem: IncomeListItem = {
amount: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<DeleteIncomeItemButton data-testid="delete-income-item-button" item={deletedItem} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('delete-income-item-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteIncomeItemPath>(`/incomes/list/${deletedItem.incomeListId}/items/${deletedItem.id}`, () => HttpResponse.json(deletedItem));
import { DeleteIncomeItemButtonHelper, DeleteIncomeItemFormHelper } from '@tests/helpers';
describe('Test DeleteIncomeItemButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = DeleteIncomeItemButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Удалить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await DeleteIncomeItemButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
});
test('should close modal after submit', async () => {
server.use(submitHandler);
const { modalElem } = await openModal();
const submitButtonElem = within(modalElem).getByText('Удалить');
server.use(DeleteIncomeItemButtonHelper.submitHandler);
const { modalElem } = await DeleteIncomeItemButtonHelper.openModal();
const { submitButtonElem } = DeleteIncomeItemFormHelper.getFormElements();
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});

View File

@ -1,100 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
EditIncomeItemBody,
EditIncomeItemPath,
EditIncomeItemSuccessResponse,
IncomeListItem,
} from '@/entity/incomes/item';
import EditIncomeItemButton from './EditIncomeItemButton.ui';
const editingItem: IncomeListItem = {
amount: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<EditIncomeItemButton data-testid="edit-income-item-button" item={editingItem} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('edit-income-item-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditIncomeItemPath,
EditIncomeItemBody,
EditIncomeItemSuccessResponse
>(
`/incomes/list/${editingItem.incomeListId}/items/${editingItem.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(editingItem);
},
);
const fillForm = async (data: { amount: string; date: string; description: string; title: string }) => {
const titleInputElem = screen.getByLabelText('Название');
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, data.title);
const descriptionInputElem = screen.getByLabelText('Описание');
await userEvent.clear(descriptionInputElem);
await userEvent.type(descriptionInputElem, data.description);
const dateInputElem = screen.getByLabelText('Дата');
await userEvent.clear(dateInputElem);
await userEvent.type(dateInputElem, data.date);
const amountInputElem = screen.getByLabelText('Сумма');
await userEvent.clear(amountInputElem);
await userEvent.type(amountInputElem, data.amount);
};
import { screen, waitFor } from '@testing-library/react';
import { EditIncomeItemButtonHelper, EditIncomeItemFormHelper } from '@tests/helpers';
describe('TestEditIncomeItemButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = EditIncomeItemButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Редактировать');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await EditIncomeItemButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -102,24 +24,22 @@ describe('TestEditIncomeItemButton', () => {
describe('should close modal after submit and send request', () => {
let modalElem: HTMLElement;
let submitButtonElem: HTMLElement;
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = screen.getByText('Сохранить');
server.use(EditIncomeItemButtonHelper.submitHandler(requestSpy));
modalElem = (await EditIncomeItemButtonHelper.openModal()).modalElem;
await fillForm({
amount: '12',
date: '2025-08-29',
await EditIncomeItemFormHelper.fillForm({
amount: 12,
date: '29.08.2025',
description: 'Описание элемента',
title: 'Название элемента',
});
}, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await EditIncomeItemFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
amount: 12,
@ -131,9 +51,10 @@ describe('TestEditIncomeItemButton', () => {
});
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await EditIncomeItemFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,71 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddExpenseListBody, AddExpenseListSuccessResponse } from '@/entity/expenses/list';
import AddIncomeListButton from './AddIncomeListButton.ui';
const renderButton = () => {
render(
<AddIncomeListButton data-testid="test-button" />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('test-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const fillForm = async (data: { title: string }) => {
await userEvent.type(screen.getByLabelText('Название'), data.title);
};
const submitHandler = (requestSpy: jest.Mock) => http.post<never, AddExpenseListBody, AddExpenseListSuccessResponse>(
'/incomes/list',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
import { screen, waitFor } from '@testing-library/react';
import { AddIncomeListButtonHelper, AddIncomeListFormHelper } from '@tests/helpers';
describe('Test AddIncomeListButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = AddIncomeListButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Добавить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await AddIncomeListButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -73,31 +24,26 @@ describe('Test AddIncomeListButton', () => {
describe('should close modal after submit and send request', () => {
let modalElem: HTMLElement;
let submitButtonElem: HTMLElement;
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = within(modalElem).getByText('Добавить');
server.use(AddIncomeListButtonHelper.submitHandler(requestSpy));
modalElem = (await AddIncomeListButtonHelper.openModal()).modalElem;
await fillForm({
title: 'Название списка',
});
await AddIncomeListFormHelper.fillForm({ title: 'Название списка' }, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await AddIncomeListFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
title: 'Название списка',
});
expect(requestSpy).toHaveBeenCalledWith({ title: 'Название списка' });
});
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await AddIncomeListFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -1,74 +1,37 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen, within } from '@testing-library/react';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
import type { IncomeList } from '@/entity/incomes/list';
import DeleteIncomeListButton from './DeleteIncomeListButton.ui';
const deletingList: IncomeList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<DeleteIncomeListButton data-testid="delete-income-list-button" list={deletingList} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('delete-income-list-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseListPath>(`/incomes/list/${deletingList.id}`, () => HttpResponse.json(deletingList));
import { DeleteIncomeListButtonHelper, DeleteIncomeListFormHelper } from '@tests/helpers';
describe('Test DeleteIncomeListButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = DeleteIncomeListButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Удалить');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await DeleteIncomeListButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
});
test('should close modal after submit', async () => {
server.use(submitHandler);
const { modalElem } = await openModal();
const submitButtonElem = within(modalElem).getByText('Удалить');
server.use(DeleteIncomeListButtonHelper.submitHandler);
const { modalElem } = await DeleteIncomeListButtonHelper.openModal();
const { submitButtonElem } = DeleteIncomeListFormHelper.getFormElements();
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});

View File

@ -1,83 +1,22 @@
import { server } from '@mocks/jest/server';
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
EditExpenseListBody,
EditExpenseListPath,
EditExpenseListSuccessResponse,
} from '@/entity/expenses/list';
import EditIncomeListButton from './EditIncomeListButton.ui';
const editingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: null,
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<EditIncomeListButton data-testid="edit-expense-list-button" list={editingList} />,
{ wrapper: createReactQueryWrapper() },
);
const buttonElem = screen.getByTestId('edit-expense-list-button');
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('dialog');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditExpenseListPath,
EditExpenseListBody,
EditExpenseListSuccessResponse
>(
`/incomes/list/${editingList.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(editingList);
},
);
const fillForm = async (data: { title: string }) => {
const titleInputElem = screen.getByLabelText('Название');
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, data.title);
};
import { screen, waitFor } from '@testing-library/react';
import { EditIncomeListButtonHelper, EditIncomeListFormHelper } from '@tests/helpers';
describe('Test EditIncomeListButton', () => {
test('should correct render button', () => {
const { buttonElem } = renderButton();
const { buttonElem } = EditIncomeListButtonHelper.renderButton();
expect(buttonElem).toBeInTheDocument();
expect(buttonElem).toBeVisible();
expect(buttonElem).toBeEnabled();
expect(buttonElem).toHaveTextContent('Редактировать');
const modal = screen.queryByRole('dialog');
const modal = screen.queryByRole('presentation');
expect(modal).not.toBeInTheDocument();
});
test('should open modal after click', async () => {
const { modalElem } = await openModal();
const { modalElem } = await EditIncomeListButtonHelper.openModal();
expect(modalElem).toBeInTheDocument();
expect(modalElem).toBeVisible();
@ -85,31 +24,26 @@ describe('Test EditIncomeListButton', () => {
describe('should close modal after submit and send request', () => {
let modalElem: HTMLElement;
let submitButtonElem: HTMLElement;
const requestSpy = jest.fn();
beforeEach(async () => {
server.use(submitHandler(requestSpy));
modalElem = (await openModal()).modalElem;
submitButtonElem = screen.getByText('Сохранить');
server.use(EditIncomeListButtonHelper.submitHandler(requestSpy));
modalElem = (await EditIncomeListButtonHelper.openModal()).modalElem;
await fillForm({
title: 'Название списка',
});
await EditIncomeListFormHelper.fillForm({ title: 'Название списка' }, { autoSubmit: false });
});
test('should send correct request', async () => {
await userEvent.click(submitButtonElem);
await EditIncomeListFormHelper.submitForm();
expect(requestSpy).toHaveBeenCalledTimes(1);
expect(requestSpy).toHaveBeenCalledWith({
title: 'Название списка',
});
expect(requestSpy).toHaveBeenCalledWith({ title: 'Название списка' });
});
test('should close modal after submit', async () => {
expect(submitButtonElem).toBeEnabled();
await userEvent.click(submitButtonElem);
expect(modalElem).not.toBeInTheDocument();
await EditIncomeListFormHelper.submitForm();
await waitFor(() => {
expect(modalElem).not.toBeInTheDocument();
});
});
});
});

View File

@ -0,0 +1,55 @@
import { bankCardList } from '@mocks/browser/data';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddBankCardBody, AddBankCardResponse } from '@/entity/cards';
import { AddBankCardButton } from '@/features/bank-cards/AddBankCardButton';
import { DataTestId } from '@/shared/constants';
const bankCard = bankCardList[0];
const renderButton = () => {
render(
<AddBankCardButton />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.ADD_BANK_CARD_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.post<
never,
AddBankCardBody,
AddBankCardResponse
>(
'/bank-card',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(bankCard);
},
);
export const AddBankCardButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,61 @@
import { typeTextField } from '@mocks/jest/helpers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddBankCardFormProps, AddBankCardFormValues } from '@/entity/cards';
import { AddBankCardForm } from '@/entity/cards';
import { DataTestId } from '@/shared/constants';
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.ADD_BANK_CARD_FORM);
const nameInputElem = screen.getByLabelText(/Название/);
const balanceInputElem = screen.getByLabelText(/Баланс/);
const submitButtonElem = screen.getByTestId(DataTestId.ADD_BANK_CARD_SUBMIT_BUTTON);
return {
balanceInputElem,
formElem,
nameInputElem,
submitButtonElem,
};
};
const renderForm = (props?: Partial<AddBankCardFormProps>) => {
const onSubmit = jest.fn();
render(<AddBankCardForm onSubmit={onSubmit} {...props} />);
return {
onSubmit,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: AddBankCardFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const { balance, name } = data;
const { autoSubmit = true } = options;
const { balanceInputElem, nameInputElem } = getFormElements();
await typeTextField(balanceInputElem, balance.toString());
await typeTextField(nameInputElem, name);
if (autoSubmit) {
await submitForm();
}
};
export const AddBankCardFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,46 @@
import { bankCardList } from '@mocks/browser/data';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
import { DeleteBankCardButton } from '@/features/bank-cards/DeleteBankCardButton';
import { DataTestId } from '@/shared/constants';
const bankCard = bankCardList[0];
const renderButton = () => {
render(
<DeleteBankCardButton bankCard={bankCard} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.DELETE_BANK_CARD_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseListPath>(
`/bank-card/${bankCard.id}`,
() => HttpResponse.json(bankCard),
);
export const DeleteBankCardButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,48 @@
import { bankCardList } from '@mocks/browser/data';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteBankCardFormProps } from '@/entity/cards';
import { DeleteBankCardForm } from '@/entity/cards';
import { DataTestId } from '@/shared/constants';
const bankCard = bankCardList[0];
const renderForm = (props?: Partial<DeleteBankCardFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteBankCardForm
bankCard={bankCard}
onSubmit={onSubmit}
{...props}
/>,
);
return {
onSubmit,
};
};
function getFormElements() {
const formElem = screen.getByTestId(DataTestId.DELETE_BANK_CARD_FORM);
const submitButtonElem = screen.getByTestId(DataTestId.DELETE_BANK_CARD_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
};
}
async function submitForm() {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
}
export const DeleteBankCardFormHelper = {
bankCard,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,59 @@
import { bankCardList } from '@mocks/browser/data';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
EditBankCardBody,
EditBankCardPath,
EditBankCardResponse,
} from '@/entity/cards';
import { EditBankCardButton } from '@/features/bank-cards/EditBankCardButton';
import { DataTestId } from '@/shared/constants';
const bankCard = bankCardList[0];
const renderButton = () => {
render(
<EditBankCardButton bankCard={bankCard} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.EDIT_BANK_CARD_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditBankCardPath,
EditBankCardBody,
EditBankCardResponse
>(
`/bank-card/${bankCard.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(bankCard);
},
);
export const EditBankCardButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,69 @@
import { bankCardList } from '@mocks/browser/data';
import { typeTextField } from '@mocks/jest/helpers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditBankCardFormProps, EditBankCardFormValues } from '@/entity/cards';
import { EditBankCardForm } from '@/entity/cards';
import { DataTestId } from '@/shared/constants';
const bankCard = bankCardList[0];
const renderForm = (props?: Partial<EditBankCardFormProps>) => {
const onSubmit = jest.fn();
render(
<EditBankCardForm
bankCard={bankCard}
onSubmit={onSubmit}
{...props}
/>,
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.EDIT_BANK_CARD_FORM);
const nameInputElem = screen.getByLabelText(/Название/);
const balanceInputElem = screen.getByLabelText(/Баланс/);
const submitButtonElem = screen.getByRole('button', { name: /Сохранить/i });
return {
balanceInputElem,
formElem,
nameInputElem,
submitButtonElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: EditBankCardFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const { balance, name } = data;
const { autoSubmit = true } = options;
const { balanceInputElem, nameInputElem } = getFormElements();
await typeTextField(balanceInputElem, balance.toString());
await typeTextField(nameInputElem, name);
if (autoSubmit) {
await submitForm();
}
};
export const EditBankCardFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,55 @@
import { cashList } from '@mocks/browser/data';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AdCashResponse, AddCashBody } from '@/entity/cash';
import { AddCashButton } from '@/features/cash/AddCashButton';
import { DataTestId } from '@/shared/constants';
const cash = cashList[0];
const renderButton = () => {
render(
<AddCashButton />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.ADD_CASH_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.post<
never,
AddCashBody,
AdCashResponse
>(
'/cash',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(cash);
},
);
export const AddCashButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,61 @@
import { typeTextField } from '@mocks/jest/helpers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddCashFormProps, AddCashFormValues } from '@/entity/cash';
import { AddCashForm } from '@/entity/cash';
import { DataTestId } from '@/shared/constants';
const renderForm = (props?: Partial<AddCashFormProps>) => {
const onSubmit = jest.fn();
render(<AddCashForm onSubmit={onSubmit} {...props} />);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.ADD_CASH_FORM);
const nameInputElem = screen.getByLabelText(/Название/);
const balanceInputElem = screen.getByLabelText(/Баланс/);
const submitButtonElem = screen.getByTestId(DataTestId.ADD_CASH_SUBMIT_BUTTON);
return {
balanceInputElem,
formElem,
nameInputElem,
submitButtonElem,
};
};
async function submitForm() {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
}
const fillForm = async (
data: AddCashFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const { balance, name } = data;
const { autoSubmit = true } = options;
const { balanceInputElem, nameInputElem, submitButtonElem } = getFormElements();
await typeTextField(balanceInputElem, balance.toString());
await typeTextField(nameInputElem, name);
if (autoSubmit) {
await userEvent.click(submitButtonElem);
}
};
export const AddCashFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,46 @@
import { cashList } from '@mocks/browser/data';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
import { DeleteCashButton } from '@/features/cash/DeleteCashButton';
import { DataTestId } from '@/shared/constants';
const cash = cashList[0];
const renderButton = () => {
render(
<DeleteCashButton cash={cash} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.DELETE_CASH_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseListPath>(
`/cash/${cash.id}`,
() => HttpResponse.json(cash),
);
export const DeleteCashButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,48 @@
import { cashList } from '@mocks/browser/data';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteCashFormProps } from '@/entity/cash';
import { DeleteCashForm } from '@/entity/cash';
import { DataTestId } from '@/shared/constants';
const cash = cashList[0];
const renderForm = (props?: Partial<DeleteCashFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteCashForm
cash={cash}
onSubmit={onSubmit}
{...props}
/>,
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.DELETE_CASH_FORM);
const submitButtonElem = screen.getByTestId(DataTestId.DELETE_CASH_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
export const DeleteCashFormHelper = {
cash,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,59 @@
import { cashList } from '@mocks/browser/data';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
EditCashBody,
EditCashPath,
EditCashResponse,
} from '@/entity/cash';
import { EditCashButton } from '@/features/cash/EditCashButton';
import { DataTestId } from '@/shared/constants';
const cash = cashList[0];
const renderButton = () => {
render(
<EditCashButton cash={cash} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.EDIT_CASH_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditCashPath,
EditCashBody,
EditCashResponse
>(
`/cash/${cash.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(cash);
},
);
export const EditCashButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,69 @@
import { cashList } from '@mocks/browser/data';
import { typeTextField } from '@mocks/jest/helpers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditCashFormProps, EditCashFormValues } from '@/entity/cash';
import { EditCashForm } from '@/entity/cash';
import { DataTestId } from '@/shared/constants';
const cash = cashList[0];
const renderForm = (props?: Partial<EditCashFormProps>) => {
const onSubmit = jest.fn();
render(
<EditCashForm
cash={cash}
onSubmit={onSubmit}
{...props}
/>,
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.EDIT_CASH_FORM);
const nameInputElem = screen.getByLabelText(/Название/);
const balanceInputElem = screen.getByLabelText(/Баланс/);
const submitButtonElem = screen.getByRole('button', { name: /Сохранить/i });
return {
balanceInputElem,
formElem,
nameInputElem,
submitButtonElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: EditCashFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const { balance, name } = data;
const { autoSubmit = true } = options;
const { balanceInputElem, nameInputElem } = getFormElements();
await typeTextField(balanceInputElem, balance.toString());
await typeTextField(nameInputElem, name);
if (autoSubmit) {
await submitForm();
}
};
export const EditCashFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,69 @@
import { getBankCardList, getCashList } from '@mocks/browser/handlers';
import { server } from '@mocks/jest/server';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddExpenseItemBody, AddExpenseItemPath, AddExpenseItemSuccessResponse } from '@/entity/expenses/item';
import { AddExpenseItemButton } from '@/features/expenses/items/AddExpenseItemButton';
import { DataTestId } from '@/shared/constants';
const expenseItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
server.use(getBankCardList, getCashList);
render(
<AddExpenseItemButton listId="123" />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.ADD_EXPENSE_ITEM_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.post<
AddExpenseItemPath,
AddExpenseItemBody,
AddExpenseItemSuccessResponse
>(
'/expenses/list/123/items',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(expenseItem);
},
);
export const AddExpenseItemButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,144 @@
import { getBankCardList, getCashList } from '@mocks/browser/handlers';
import { selectOption, typeDateField, typeTextField } from '@mocks/jest/helpers';
import { server } from '@mocks/jest/server';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { BankCard } from '@/entity/cards';
import type { CashItem } from '@/entity/cash';
import type { AddExpenseItemFormProps } from '@/entity/expenses/item';
import { AddExpenseItemForm } from '@/entity/expenses/item';
import { DataTestId } from '@/shared/constants';
const renderForm = (props?: Partial<AddExpenseItemFormProps>) => {
server.use(getBankCardList, getCashList);
const onSubmit = jest.fn();
render(
<AddExpenseItemForm onSubmit={onSubmit} {...props} />,
{ wrapper: createAppWrapper() },
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.ADD_EXPENSE_ITEM_FORM);
const titleInputElem = screen.getByLabelText(/Название/);
const descriptionInputElem = screen.getByLabelText(/Описание/);
const dateInputElem = screen.getAllByLabelText(/Дата/i)[1];
const amountInputElem = screen.getByLabelText(/Сумма/);
const countInputElem = screen.getByLabelText(/Количество/);
const submitButtonElem = screen.getByTestId(DataTestId.ADD_EXPENSE_ITEM_SUBMIT_BUTTON);
const paymentTypeSelect = screen.getByTestId('payment-type-select');
const bankCardSelect = screen.queryByTestId('bank-card-select');
const bankCardSelectInput = screen.queryByTestId('bank-card-select-input');
const cashSelect = screen.queryByTestId('cash-select');
const cashSelectInput = screen.queryByTestId('cash-select-input');
return {
amountInputElem,
bankCardSelect,
bankCardSelectInput,
cashSelect,
cashSelectInput,
countInputElem,
dateInputElem,
descriptionInputElem,
formElem,
paymentTypeSelect,
submitButtonElem,
titleInputElem,
};
};
type ExpenseFormValues = {
amount?: string;
count?: string;
date?: string;
description?: string;
// eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents
paymentId?: BankCard['id'] | CashItem['id'];
paymentType?: 'BANK_CARD' | 'CASH' | 'none';
title?: string;
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: ExpenseFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const {
amount,
count,
date,
description,
paymentId,
paymentType = 'none',
title,
} = data;
const { autoSubmit = true } = options;
const {
amountInputElem,
countInputElem,
dateInputElem,
descriptionInputElem,
paymentTypeSelect,
titleInputElem,
} = getFormElements();
await typeTextField(titleInputElem, title);
await typeTextField(descriptionInputElem, description);
await typeTextField(amountInputElem, amount);
await typeTextField(countInputElem, count);
await typeDateField(dateInputElem, date);
if (paymentType !== 'none') {
switch (paymentType) {
case 'BANK_CARD':
await selectOption(paymentTypeSelect, 'BANK_CARD');
break;
case 'CASH':
await selectOption(paymentTypeSelect, 'CASH');
break;
default:
break;
}
if (!paymentId) {
return;
}
const { bankCardSelect, cashSelect } = getFormElements();
switch (paymentType) {
case 'BANK_CARD':
await selectOption(bankCardSelect, paymentId);
break;
case 'CASH':
await selectOption(cashSelect, paymentId);
break;
default:
break;
}
}
if (autoSubmit) {
await submitForm();
}
};
export const AddExpenseItemFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,57 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteExpenseItemPath } from '@/entity/expenses/item';
import { DeleteExpenseItemButton } from '@/features/expenses/items/DeleteExpenseItemButton';
import { DataTestId } from '@/shared/constants';
const expenseItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<DeleteExpenseItemButton item={expenseItem} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.DELETE_EXPENSE_ITEM_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseItemPath>(
`/expenses/list/${expenseItem.expenseListId}/items/${expenseItem.id}`,
() => HttpResponse.json(expenseItem),
);
export const DeleteExpenseItemButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,59 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteExpenseItemFormProps } from '@/entity/expenses/item';
import { DeleteExpenseItemForm } from '@/entity/expenses/item';
import { DataTestId } from '@/shared/constants';
const expenseItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteExpenseItemFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteExpenseItemForm
item={expenseItem}
onSubmit={onSubmit}
{...props}
/>,
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.DELETE_EXPENSE_ITEM_FORM);
const submitButtonElem = screen.getByTestId(DataTestId.DELETE_EXPENSE_ITEM_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
export const DeleteExpenseItemFormHelper = {
expenseItem,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,70 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
EditExpenseItemBody,
EditExpenseItemPath,
EditExpenseItemSuccessResponse,
} from '@/entity/expenses/item';
import { EditExpenseItemButton } from '@/features/expenses/items/EditExpenseItemButton';
import { DataTestId } from '@/shared/constants';
const expenseItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<EditExpenseItemButton item={expenseItem} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.EDIT_EXPENSE_ITEM_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditExpenseItemPath,
EditExpenseItemBody,
EditExpenseItemSuccessResponse
>(
`/expenses/list/${expenseItem.expenseListId}/items/${expenseItem.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(expenseItem);
},
);
export const EditExpenseItemButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,103 @@
import { typeDateField, typeTextField } from '@mocks/jest/helpers';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditExpenseItemFormProps, EditExpenseItemFormValues } from '@/entity/expenses/item';
import { EditExpenseItemForm } from '@/entity/expenses/item';
import { DataTestId } from '@/shared/constants';
const expenseItem = {
amount: 12,
count: 12,
createdAt: '2025-08-22T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
payment: null,
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditExpenseItemFormProps>) => {
const onSubmit = jest.fn();
render(
<EditExpenseItemForm
item={expenseItem}
onSubmit={onSubmit}
{...props}
/>,
{ wrapper: createAppWrapper() },
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.EDIT_EXPENSE_ITEM_FORM);
const titleInputElem = screen.getByLabelText(/Название/);
const descriptionInputElem = screen.getByLabelText(/Описание/);
const dateInputElem = screen.getAllByLabelText(/Дата/i)[1];
const amountInputElem = screen.getByLabelText(/Сумма/);
const countInputElem = screen.getByLabelText(/Количество/);
const submitButtonElem = screen.getByRole('button', { name: /Сохранить/i });
return {
amountInputElem,
countInputElem,
dateInputElem,
descriptionInputElem,
formElem,
submitButtonElem,
titleInputElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: Omit<EditExpenseItemFormValues, 'currency'>,
options: { autoSubmit?: boolean } = {},
) => {
const {
amount,
count,
date,
description,
title,
} = data;
const { autoSubmit = true } = options;
const {
amountInputElem,
countInputElem,
dateInputElem,
descriptionInputElem,
titleInputElem,
} = getFormElements();
await typeTextField(titleInputElem, title);
await typeTextField(descriptionInputElem, description);
await typeTextField(amountInputElem, amount.toString());
await typeTextField(countInputElem, count.toString());
await typeDateField(dateInputElem, date);
if (autoSubmit) {
await submitForm();
}
};
export const EditExpenseItemFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,58 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddExpenseListBody, AddExpenseListSuccessResponse } from '@/entity/expenses/list';
import { AddExpensesListButton } from '@/features/expenses/list/AddExpensesListButton';
import { DataTestId } from '@/shared/constants';
const renderButton = () => {
render(
<AddExpensesListButton />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.ADD_EXPENSES_LIST_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.post<
never,
AddExpenseListBody,
AddExpenseListSuccessResponse
>(
'/expenses/list',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
export const AddExpensesListButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,59 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddExpenseListFormProps, AddExpenseListFormValues } from '@/entity/expenses/list';
import { AddExpensesListForm } from '@/entity/expenses/list';
import { DataTestId } from '@/shared/constants';
const renderForm = (props?: Partial<AddExpenseListFormProps>) => {
const onSubmit = jest.fn();
render(<AddExpensesListForm onSubmit={onSubmit} {...props} />);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.ADD_EXPENSES_LIST_FORM);
const titleInputElem = screen.getByLabelText(/Название/i);
const submitButtonElem = screen.getByTestId(DataTestId.ADD_EXPENSES_LIST_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
titleInputElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: AddExpenseListFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const { title } = data;
const { autoSubmit = true } = options;
const { titleInputElem } = getFormElements();
if (title) {
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, title);
}
if (autoSubmit) {
await submitForm();
}
};
export const AddExpensesListFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,51 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
import { DeleteExpensesListButton } from '@/features/expenses/list/DeleteExpensesListButton';
import { DataTestId } from '@/shared/constants';
const expenseList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<DeleteExpensesListButton list={expenseList} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.DELETE_EXPENSES_LIST_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseListPath>(
`/expenses/list/${expenseList.id}`,
() => HttpResponse.json(expenseList),
);
export const DeleteExpensesListButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,53 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteExpenseListFormProps } from '@/entity/expenses/list';
import { DeleteExpensesListForm } from '@/entity/expenses/list';
import { DataTestId } from '@/shared/constants';
const expensesList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteExpenseListFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteExpensesListForm
list={expensesList}
onSubmit={onSubmit}
{...props}
/>,
);
return {
onSubmit,
};
};
const getFormElems = () => {
const formElem = screen.getByTestId(DataTestId.DELETE_EXPENSES_LIST_FORM);
const submitButtonElem = screen.getByTestId(DataTestId.DELETE_EXPENSES_LIST_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElems();
await userEvent.click(submitButtonElem);
};
export const DeleteExpensesListFormHelper = {
expensesList,
getFormElems,
renderForm,
submitForm,
};

View File

@ -0,0 +1,60 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { EditExpenseListBody, EditExpenseListPath, EditExpenseListSuccessResponse } from '@/entity/expenses/list';
import { EditExpensesListButton } from '@/features/expenses/list/EditExpensesListButton';
import { DataTestId } from '@/shared/constants';
const expenseList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<EditExpensesListButton list={expenseList} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.EDIT_EXPENSES_LIST_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditExpenseListPath,
EditExpenseListBody,
EditExpenseListSuccessResponse
>(
`/expenses/list/${expenseList.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(expenseList);
},
);
export const EditExpensesListButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,71 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditExpenseListFormValues, EditExpensesListFormProps } from '@/entity/expenses/list';
import { EditExpensesListForm } from '@/entity/expenses/list';
import { DataTestId } from '@/shared/constants';
const expenseList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditExpensesListFormProps>) => {
const onSubmit = jest.fn();
render(
<EditExpensesListForm
list={expenseList}
onSubmit={onSubmit}
{...props}
/>,
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.EDIT_EXPENSES_LIST_FORM);
const titleInputElem = screen.getByLabelText(/Название/);
const submitButtonElem = screen.getByRole('button', { name: /Сохранить/ });
return {
formElem,
submitButtonElem,
titleInputElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
export const fillForm = async (
data: EditExpenseListFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const { title } = data;
const { autoSubmit = true } = options;
const { titleInputElem } = getFormElements();
await userEvent.clear(titleInputElem);
await userEvent.type(titleInputElem, title);
if (autoSubmit) {
await submitForm();
}
};
export const EditExpensesListFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,62 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddIncomeItemBody, AddIncomeItemPath, AddIncomeItemSuccessResponse } from '@/entity/incomes/item';
import { AddIncomeItemButton } from '@/features/incomes/items/AddIncomeItemButton';
import { DataTestId } from '@/shared/constants';
const renderButton = () => {
render(
<AddIncomeItemButton listId="123" />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.ADD_INCOME_ITEM_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.post<
AddIncomeItemPath,
AddIncomeItemBody,
AddIncomeItemSuccessResponse
>(
'/incomes/list/123/items',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
amount: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
export const AddIncomeItemButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,80 @@
import { typeDateField, typeTextField } from '@mocks/jest/helpers';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddIncomeItemFormProps, AddIncomeItemFormValues } from '@/entity/incomes/item';
import { AddIncomeItemForm } from '@/entity/incomes/item';
import { DataTestId } from '@/shared/constants';
const renderForm = (props?: Partial<AddIncomeItemFormProps>) => {
const onSubmit = jest.fn();
render(
<AddIncomeItemForm onSubmit={onSubmit} {...props} />,
{ wrapper: createAppWrapper() },
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.ADD_INCOME_ITEM_FORM);
const titleInputElem = screen.getByLabelText(/Название/i);
const descriptionInputElem = screen.getByLabelText(/Описание/);
const dateInputElem = screen.getAllByLabelText(/Дата/i)[1];
const amountInputElem = screen.getByLabelText(/Сумма/i);
const submitButtonElem = screen.getByTestId(DataTestId.ADD_INCOME_ITEM_SUBMIT_BUTTON);
return {
amountInputElem,
dateInputElem,
descriptionInputElem,
formElem,
submitButtonElem,
titleInputElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: Omit<AddIncomeItemFormValues, 'currency'>,
options: { autoSubmit?: boolean } = {},
) => {
const {
amount,
date,
description,
title,
} = data;
const { autoSubmit = true } = options;
const {
amountInputElem,
dateInputElem,
descriptionInputElem,
titleInputElem,
} = getFormElements();
await typeTextField(titleInputElem, title);
await typeTextField(descriptionInputElem, description);
await typeDateField(dateInputElem, date);
await typeTextField(amountInputElem, amount.toString());
if (autoSubmit) {
await submitForm();
}
};
export const AddIncomeItemFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,55 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteIncomeItemPath, IncomeListItem } from '@/entity/incomes/item';
import { DeleteIncomeItemButton } from '@/features/incomes/items/DeleteIncomeItemButton';
import { DataTestId } from '@/shared/constants';
const iconmeItem: IncomeListItem = {
amount: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<DeleteIncomeItemButton item={iconmeItem} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.DELETE_INCOME_ITEM_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteIncomeItemPath>(
`/incomes/list/${iconmeItem.incomeListId}/items/${iconmeItem.id}`,
() => HttpResponse.json(iconmeItem),
);
export const DeleteIncomeItemButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,61 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteIncomeItemFormProps } from '@/entity/incomes/item';
import { DeleteIncomeItemForm } from '@/entity/incomes/item';
import { DataTestId } from '@/shared/constants';
const incomeItem = {
amount: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteIncomeItemFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteIncomeItemForm
item={incomeItem}
onSubmit={onSubmit}
{...props}
/>,
);
const submitButtonElem = screen.getByText('Удалить');
return {
onSubmit,
submitButtonElem,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.DELETE_INCOME_ITEM_FORM);
const submitButtonElem = screen.getByTestId(DataTestId.DELETE_INCOME_ITEM_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
export const DeleteIncomeItemFormHelper = {
getFormElements,
incomeItem,
renderForm,
submitForm,
};

View File

@ -0,0 +1,69 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type {
EditIncomeItemBody,
EditIncomeItemPath,
EditIncomeItemSuccessResponse,
IncomeListItem,
} from '@/entity/incomes/item';
import { EditIncomeItemButton } from '@/features/incomes/items/EditIncomeItemButton';
import { DataTestId } from '@/shared/constants';
const incomeItem: IncomeListItem = {
amount: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<EditIncomeItemButton item={incomeItem} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.EDIT_INCOME_ITEM_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditIncomeItemPath,
EditIncomeItemBody,
EditIncomeItemSuccessResponse
>(
`/incomes/list/${incomeItem.incomeListId}/items/${incomeItem.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(incomeItem);
},
);
export const EditIncomeItemButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,97 @@
import { typeDateField, typeTextField } from '@mocks/jest/helpers';
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { EditIncomeItemFormProps, EditIncomeItemFormValues } from '@/entity/incomes/item';
import { EditIncomeItemForm } from '@/entity/incomes/item';
import { DataTestId } from '@/shared/constants';
const incomeItem = {
amount: 12,
count: 12,
createdAt: '2025-08-29T07:57:40.503Z',
currency: 'RUB',
date: '2025-08-22T00:00:03.000Z',
description: 'Mock description',
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
title: 'Mock item',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditIncomeItemFormProps>) => {
const onSubmit = jest.fn();
render(
<EditIncomeItemForm
item={incomeItem}
onSubmit={onSubmit}
{...props}
/>,
{ wrapper: createAppWrapper() },
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.EDIT_INCOME_ITEM_FORM);
const titleInputElem = screen.getByLabelText(/Название/i);
const descriptionInputElem = screen.getByLabelText(/Описание/i);
const dateInputElem = screen.getAllByLabelText(/Дата/i)[1];
const amountInputElem = screen.getByLabelText(/Сумма/i);
const submitButtonElem = screen.getByTestId(DataTestId.EDIT_INCOME_ITEM_SUBMIT_BUTTON);
return {
amountInputElem,
dateInputElem,
descriptionInputElem,
formElem,
submitButtonElem,
titleInputElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: Omit<EditIncomeItemFormValues, 'currency'>,
options: { autoSubmit?: boolean } = {},
) => {
const {
amount,
date,
description,
title,
} = data;
const { autoSubmit = true } = options;
const {
amountInputElem,
dateInputElem,
descriptionInputElem,
titleInputElem,
} = getFormElements();
await typeTextField(titleInputElem, title);
await typeTextField(descriptionInputElem, description);
await typeDateField(dateInputElem, date);
await typeTextField(amountInputElem, amount.toString());
if (autoSubmit) {
await submitForm();
}
};
export const EditIncomeItemFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,58 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { AddExpenseListBody, AddExpenseListSuccessResponse } from '@/entity/expenses/list';
import { AddIncomeListButton } from '@/features/incomes/list/AddIncomeListButton';
import { DataTestId } from '@/shared/constants';
const renderButton = () => {
render(
<AddIncomeListButton />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.ADD_INCOME_LIST_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.post<
never,
AddExpenseListBody,
AddExpenseListSuccessResponse
>(
'/incomes/list',
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json({
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
});
},
);
export const AddIncomeListButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,57 @@
import { typeTextField } from '@mocks/jest/helpers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddIncomeListFormProps, AddIncomeListFormValues } from '@/entity/incomes/list';
import { AddIncomeListForm } from '@/entity/incomes/list';
import { DataTestId } from '@/shared/constants';
const renderForm = (props?: Partial<AddIncomeListFormProps>) => {
const onSubmit = jest.fn();
render(<AddIncomeListForm onSubmit={onSubmit} {...props} />);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.ADD_INCOME_LIST_FORM);
const titleInputElem = screen.getByLabelText(/Название/);
const submitButtonElem = screen.getByTestId(DataTestId.ADD_INCOME_LIST_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
titleInputElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: AddIncomeListFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const { title } = data;
const { autoSubmit = true } = options;
const { titleInputElem } = getFormElements();
await typeTextField(titleInputElem, title);
if (autoSubmit) {
await submitForm();
}
};
export const AddIncomeListFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,52 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
import type { IncomeList } from '@/entity/incomes/list';
import { DeleteIncomeListButton } from '@/features/incomes/list/DeleteIncomeListButton';
import { DataTestId } from '@/shared/constants';
const incomeList: IncomeList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<DeleteIncomeListButton list={incomeList} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.DELETE_INCOME_LIST_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = http.delete<DeleteExpenseListPath>(
`/incomes/list/${incomeList.id}`,
() => HttpResponse.json(incomeList),
);
export const DeleteIncomeListButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,57 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { DeleteIncomeListFormProps } from '@/entity/incomes/list';
import { DeleteIncomeListForm } from '@/entity/incomes/list';
import { DataTestId } from '@/shared/constants';
const incomeList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<DeleteIncomeListFormProps>) => {
const onSubmit = jest.fn();
render(
<DeleteIncomeListForm
data-testid="delete-income-list-form"
list={incomeList}
onSubmit={onSubmit}
{...props}
/>,
);
const submitButtonElem = screen.getByText('Удалить');
return {
onSubmit,
submitButtonElem,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.DELETE_INCOME_LIST_FORM);
const submitButtonElem = screen.getByTestId(DataTestId.DELETE_INCOME_LIST_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
export const DeleteIncomeListFormHelper = {
getFormElements,
incomeList,
renderForm,
submitForm,
};

View File

@ -0,0 +1,60 @@
import { createAppWrapper } from '@mocks/jest/wrappers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import type { EditExpenseListBody, EditExpenseListPath, EditExpenseListSuccessResponse } from '@/entity/expenses/list';
import { EditIncomeListButton } from '@/features/incomes/list/EditIncomeListButton';
import { DataTestId } from '@/shared/constants';
const editingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: null,
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderButton = () => {
render(
<EditIncomeListButton list={editingList} />,
{ wrapper: createAppWrapper() },
);
const buttonElem = screen.getByTestId(DataTestId.EDIT_INCOME_LIST_BUTTON);
return {
buttonElem,
};
};
const openModal = async () => {
const { buttonElem } = renderButton();
await userEvent.click(buttonElem);
const modalElem = screen.getByRole('presentation');
return {
modalElem,
};
};
const submitHandler = (requestSpy: jest.Mock) => http.patch<
EditExpenseListPath,
EditExpenseListBody,
EditExpenseListSuccessResponse
>(
`/incomes/list/${editingList.id}`,
async ({ request }) => {
const body = await request.json();
requestSpy(body);
return HttpResponse.json(editingList);
},
);
export const EditIncomeListButtonHelper = {
openModal,
renderButton,
submitHandler,
};

View File

@ -0,0 +1,71 @@
import { typeTextField } from '@mocks/jest/helpers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import type { AddIncomeListFormValues, EditIncomeListFormProps } from '@/entity/incomes/list';
import { EditIncomeListForm } from '@/entity/incomes/list';
import { DataTestId } from '@/shared/constants';
const editingList = {
createdAt: '2025-08-29T07:57:40.503Z',
id: '10cc093c-3875-4d33-a40a-df526266e262',
items: [],
title: 'Mock list',
updatedAt: '2025-08-29T07:57:40.503Z',
};
const renderForm = (props?: Partial<EditIncomeListFormProps>) => {
const onSubmit = jest.fn();
render(
<EditIncomeListForm
list={editingList}
onSubmit={onSubmit}
{...props}
/>,
);
return {
onSubmit,
};
};
const getFormElements = () => {
const formElem = screen.getByTestId(DataTestId.EDIT_INCOME_LIST_FORM);
const titleInputElem = screen.getByLabelText(/Название/);
const submitButtonElem = screen.getByTestId(DataTestId.EDIT_INCOME_LIST_SUBMIT_BUTTON);
return {
formElem,
submitButtonElem,
titleInputElem,
};
};
const submitForm = async () => {
const { submitButtonElem } = getFormElements();
await userEvent.click(submitButtonElem);
};
const fillForm = async (
data: AddIncomeListFormValues,
options: { autoSubmit?: boolean } = {},
) => {
const { title } = data;
const { autoSubmit = true } = options;
const { titleInputElem } = getFormElements();
await typeTextField(titleInputElem, title);
if (autoSubmit) {
await submitForm();
}
};
export const EditIncomeListFormHelper = {
fillForm,
getFormElements,
renderForm,
submitForm,
};

View File

@ -0,0 +1,37 @@
/* eslint-disable import/max-dependencies */
export { AddBankCardButtonHelper } from './bank-card/AddBankCardButton';
export { AddBankCardFormHelper } from './bank-card/AddBankCardForm';
export { DeleteBankCardButtonHelper } from './bank-card/DeleteBankCardButton';
export { DeleteBankCardFormHelper } from './bank-card/DeleteBankCardForm';
export { EditBankCardButtonHelper } from './bank-card/EditBankCardButton';
export { EditBankCardFormHelper } from './bank-card/EditBankCardForm';
export { AddCashButtonHelper } from './cash/AddCashButton';
export { AddCashFormHelper } from './cash/AddCashForm';
export { DeleteCashButtonHelper } from './cash/DeleteCashButton';
export { DeleteCashFormHelper } from './cash/DeleteCashForm';
export { EditCashButtonHelper } from './cash/EditCashButton';
export { EditCashFormHelper } from './cash/EditCashForm';
export { AddExpenseItemButtonHelper } from './expense/item/AddExpenseItemButton';
export { AddExpenseItemFormHelper } from './expense/item/AddExpenseItemForm';
export { DeleteExpenseItemButtonHelper } from './expense/item/DeleteExpenseItemButton';
export { DeleteExpenseItemFormHelper } from './expense/item/DeleteExpenseItemForm';
export { EditExpenseItemButtonHelper } from './expense/item/EditExpenseItemButton';
export { EditExpenseItemFormHelper } from './expense/item/EditExpenseItemForm';
export { AddExpensesListButtonHelper } from './expense/list/AddExpensesListButton';
export { AddExpensesListFormHelper } from './expense/list/AddExpensesListForm';
export { DeleteExpensesListButtonHelper } from './expense/list/DeleteExpensesListButton';
export { DeleteExpensesListFormHelper } from './expense/list/DeleteExpensesListForm';
export { EditExpensesListButtonHelper } from './expense/list/EditExpensesListButton';
export { EditExpensesListFormHelper } from './expense/list/EditExpensesListForm';
export { AddIncomeItemButtonHelper } from './income/item/AddIncomeItemButton';
export { AddIncomeItemFormHelper } from './income/item/AddIncomeItemForm';
export { DeleteIncomeItemButtonHelper } from './income/item/DeleteIncomeItemButton';
export { DeleteIncomeItemFormHelper } from './income/item/DeleteIncomeItemForm';
export { EditIncomeItemButtonHelper } from './income/item/EditIncomeItemButton';
export { EditIncomeItemFormHelper } from './income/item/EditIncomeItemForm';
export { AddIncomeListButtonHelper } from './income/list/AddIncomeListButton';
export { AddIncomeListFormHelper } from './income/list/AddIncomeListForm';
export { DeleteIncomeListButtonHelper } from './income/list/DeleteIncomeListButton';
export { DeleteIncomeListFormHelper } from './income/list/DeleteIncomeListForm';
export { EditIncomeListButtonHelper } from './income/list/EditIncomeListButton';
export { EditIncomeListFormHelper } from './income/list/EditIncomeListForm';