Skip to content

Commit

Permalink
feat(tests): modify record income and expense creation tests
Browse files Browse the repository at this point in the history
  • Loading branch information
letehaha committed Jan 8, 2024
1 parent fcdd26d commit 97fd4c4
Show file tree
Hide file tree
Showing 15 changed files with 2,311 additions and 23 deletions.
42 changes: 42 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"vue-router": "^4.2.5"
},
"devDependencies": {
"@pinia/testing": "^0.1.3",
"@storybook/addon-actions": "^7.6.7",
"@storybook/addon-docs": "^7.6.7",
"@storybook/addon-essentials": "^7.6.7",
Expand Down
4 changes: 4 additions & 0 deletions src/api/currencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ export const addUserCurrencies = async (
) => (
api.post('/user/currencies', { currencies })
);

export const loadUserBaseCurrency = (): Promise<UserCurrencyModel> => (
api.get('/user/currencies/base')
);
1 change: 1 addition & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './monobank';
export * from './auth';
export * from './transactions';
export * from './stats';
export * from './currencies';
9 changes: 8 additions & 1 deletion src/components/fields/category-select-field.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
'category-select-field--active': isDropdownOpened,
}"
class="category-select-field"
data-test="category-select-field"
>
<FieldLabel
:label="label"
Expand All @@ -16,13 +17,14 @@
<div
v-bind="$attrs"
class="category-select-field__input"
title="Select category"
@click="() => toggleDropdown()"
>
<template v-if="selectedValue">
<CategoryCircle :category="selectedValue" />
</template>

{{ selectedValue.name || placeholder }}
{{ selectedValue?.name || placeholder }}
<div class="category-select-field__arrow" />
</div>
<div
Expand All @@ -32,6 +34,7 @@
<div
ref="DOMList"
class="category-select-field__dropdown-values"
role="listbox"
>
<!-- Show top parent category at the top of list of child categories -->
<div class="category-select-field__search-field">
Expand All @@ -58,6 +61,8 @@
:class="{
'category-select-field__dropdown-item--highlighed': selectedValue.id === topLevelCategory.id,
}"
role="option"
:aria-selected="selectedValue.id === topLevelCategory.id"
@click="selectItem(topLevelCategory, true)"
>
<CategoryCircle :category="topLevelCategory" />
Expand Down Expand Up @@ -86,6 +91,8 @@
:class="{
'category-select-field__dropdown-item--highlighed': selectedValue.id === item.id,
}"
role="option"
:aria-selected="selectedValue.id === item.id"
@click="selectItem(item)"
>
<CategoryCircle :category="item" />
Expand Down
86 changes: 86 additions & 0 deletions src/components/modals/modify-record/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { mount } from '@vue/test-utils';
import { router } from '@/routes';
import { createTestingPinia } from '@pinia/testing';
import { VueQueryPlugin } from '@tanstack/vue-query';
import * as dataMocks from '@tests/mocks';
import * as apiMethods from '@/api';
import { TRANSACTION_TYPES } from 'shared-types';
import FormComponent from './index.vue';

describe('transactions create/update/delete form', () => {
beforeAll(() => {
// jsdom doesn't implement this method so we're adding our own
Element.prototype.scrollTo = () => {};
});
afterEach(() => {
vi.resetAllMocks();
});

const mountComponent = () => mount(FormComponent, {
global: {
plugins: [
createTestingPinia({
initialState: {
user: { user: dataMocks.USER },
currencies: {
currencies: dataMocks.USER_CURRENCIES,
systemCurrencies: dataMocks.SYSTEM_CURRENCIES,
baseCurrency: dataMocks.USER_BASE_CURRENCY,
},
categories: {
categories: dataMocks.USER_CATEGORIES,
},
},
}),
VueQueryPlugin,
router,
],
directives: {
'click-outside': () => {},
},
},
});

describe('transaction creation', () => {
test.each([
['income transaction', 'button[aria-label="Select income"]', TRANSACTION_TYPES.income],
['expense transaction', 'button[aria-label="Select expense"]', TRANSACTION_TYPES.expense],
])('%s', async (_, formTypeSelector, expected) => {
vi.spyOn(apiMethods, 'loadAccounts').mockReturnValue(Promise.resolve(dataMocks.ACCOUNTS));
const createTxSpy = vi.spyOn(apiMethods, 'createTransaction');

const wrapper = mountComponent();

await wrapper.find(formTypeSelector).trigger('click');

const amountField = wrapper.find<HTMLInputElement>('input[placeholder="Amount"]');
await amountField.setValue(10);

const accountField = wrapper.find('[title="Select account"]');
await accountField.trigger('click');
const desiredAccountBtn = wrapper.find('button[role="option"]');
await desiredAccountBtn.trigger('click');

const categoryField = wrapper.find('[title="Select category"]');
await categoryField.trigger('click');
let desiredCategoryBtn = wrapper.find('[data-test="category-select-field"] button[role="option"]');
await desiredCategoryBtn.trigger('click');
// Since that's how category selector works, we need to select it one more time
desiredCategoryBtn = wrapper.find('[data-test="category-select-field"] button[role="option"]');
await desiredCategoryBtn.trigger('click');

const submitBtn = wrapper.find('[aria-label="Create transaction"]');
await submitBtn.trigger('click');

expect(createTxSpy).toHaveBeenCalledWith({
amount: '10',
note: null,
time: expect.any(String),
transactionType: expected,
paymentType: expect.any(String),
accountId: dataMocks.ACCOUNTS[0].id,
categoryId: dataMocks.USER_CATEGORIES[0].id,
});
});
});
});
24 changes: 6 additions & 18 deletions src/components/modals/modify-record/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,27 @@ import {
import { storeToRefs } from 'pinia';
import { useQueryClient } from '@tanstack/vue-query';
import {
type AccountModel,
TRANSACTION_TYPES,
PAYMENT_TYPES,
type TransactionModel,
ACCOUNT_TYPES,
type CategoryModel,
TRANSACTION_TRANSFER_NATURE,
} from 'shared-types';
import { useAccountsStore, useCategoriesStore, useCurrenciesStore } from '@/stores';
import { createTransaction, editTransaction, deleteTransaction } from '@/api/transactions';
import { type VerbosePaymentType, VERBOSE_PAYMENT_TYPES, OUT_OF_WALLET_ACCOUNT_MOCK } from '@/common/const';
import { createTransaction, editTransaction, deleteTransaction } from '@/api';
import { VERBOSE_PAYMENT_TYPES, OUT_OF_WALLET_ACCOUNT_MOCK, VUE_QUERY_TX_CHANGE_QUERY } from '@/common/const';
import InputField from '@/components/fields/input-field.vue';
import SelectField from '@/components/fields/select-field.vue';
import CategorySelectField from '@/components/fields/category-select-field.vue';
import TextareaField from '@/components/fields/textarea-field.vue';
import DateField from '@/components/fields/date-field.vue';
import UiButton from '@/components/common/ui-button.vue';
import { EVENTS as MODAL_EVENTS } from '@/components/modal-center/ui-modal.vue';
import { VUE_QUERY_TX_CHANGE_QUERY } from '@/common/const';
import FormHeader from './form-header.vue';
import TypeSelector from './type-selector.vue';
import FormRow from './form-row.vue';
import AccountField from './account-field.vue';
import { FORM_TYPES } from './types';
import { FORM_TYPES, UI_FORM_STRUCT } from './types';
import {
getDestinationAccount,
getDestinationAmount,
Expand Down Expand Up @@ -65,17 +62,7 @@ const queryClient = useQueryClient();
const isFormCreation = computed(() => !props.transaction);
const form = ref<{
amount: number;
account: AccountModel;
toAccount?: AccountModel;
category: CategoryModel;
time: string;
paymentType: VerbosePaymentType;
note?: string;
type: FORM_TYPES;
targetAmount?: number;
}>({
const form = ref<UI_FORM_STRUCT>({
amount: null,
account: null,
toAccount: null,
Expand Down Expand Up @@ -519,10 +506,11 @@ onMounted(() => {
modify-record__action
modify-record__action--submit
"
:aria-label="isFormCreation ? 'Create transaction' : 'Edit transaction'"
:disabled="isLoading"
@click="submit"
>
{{ isLoading ? 'Loading...' : transaction ? 'Edit' : 'Submit' }}
{{ isLoading ? 'Loading...' : isFormCreation ? 'Submit' : 'Edit' }}
</ui-button>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions src/components/modals/modify-record/type-selector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
'type-selector__item--disabled': isExpenseDisabled,
'type-selector__item--active': selectedTransactionType === FORM_TYPES.expense,
}"
aria-label="Select expense"
:aria-selected="selectedTransactionType === FORM_TYPES.expense"
@click="selectTransactionType(FORM_TYPES.expense)"
>
Expense
Expand All @@ -20,6 +22,8 @@
'type-selector__item--disabled': isIncomeDisabled,
'type-selector__item--active': selectedTransactionType === FORM_TYPES.income,
}"
aria-label="Select income"
:aria-selected="selectedTransactionType === FORM_TYPES.income"
@click="selectTransactionType(FORM_TYPES.income)"
>
Income
Expand All @@ -30,6 +34,8 @@
:class="{
'type-selector__item--active': selectedTransactionType === FORM_TYPES.transfer,
}"
aria-label="Select transfer"
:aria-selected="selectedTransactionType === FORM_TYPES.transfer"
@click="selectTransactionType(FORM_TYPES.transfer)"
>
Transfer
Expand Down
15 changes: 15 additions & 0 deletions src/components/modals/modify-record/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import { AccountModel, CategoryModel } from 'shared-types';
import type { VerbosePaymentType } from '@/common/const';

export enum FORM_TYPES {
income = 'income',
expense = 'expense',
transfer = 'transfer',
}

export interface UI_FORM_STRUCT {
amount: number;
account: AccountModel;
toAccount?: AccountModel;
category: CategoryModel;
time: string;
paymentType: VerbosePaymentType;
note?: string;
type: FORM_TYPES;
targetAmount?: number;
}
11 changes: 7 additions & 4 deletions src/stores/currencies.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
import { api } from '@/api/_api';
import {
getAllCurrencies,
loadUserCurrencies,
setBaseUserCurrency,
loadUserBaseCurrency,
} from '@/api/currencies';
import { CurrencyModel, UserCurrencyModel } from 'shared-types';

Expand All @@ -31,17 +31,20 @@ export const useCurrenciesStore = defineStore('currencies', () => {
);

const loadCurrencies = async () => {
currencies.value = await loadUserCurrencies();
const [userCurrencies, systemOnes] = await Promise.all(
[loadUserCurrencies(), getAllCurrencies()],
);

systemCurrencies.value = await getAllCurrencies();
currencies.value = userCurrencies;
systemCurrencies.value = systemOnes;
};

const getCurrency = (currencyId: number) => (
currencies.value.find(currency => currency.currencyId === currencyId)
);

const loadBaseCurrency = async () => {
const result: UserCurrencyModel = await api.get('/user/currencies/base');
const result = await loadUserBaseCurrency();

if (result) {
baseCurrency.value = result;
Expand Down
Loading

0 comments on commit 97fd4c4

Please sign in to comment.