From 08d8f6b9c5cbd36458d9f8b44c23dab1ef9b686b Mon Sep 17 00:00:00 2001 From: Daniel Bisgrove Date: Wed, 16 Oct 2024 08:46:57 -0400 Subject: [PATCH] Adding tests to transactions pages --- .../[[...financialAccount]].page.test.tsx | 160 ++++++++ .../AccountTransactions.test.tsx | 346 ++++++++++++++++++ .../AccountTransactions.tsx | 53 +-- .../AccountTransactionsMocks.ts | 66 ++++ .../FinancialAccounts.test.tsx | 73 ++-- .../FinancialAccountsMocks.ts | 41 +++ .../Header/Header.test.tsx | 174 +++++++++ .../FinancialAccountsReport/Header/Header.tsx | 2 +- 8 files changed, 840 insertions(+), 75 deletions(-) create mode 100644 pages/accountLists/[accountListId]/reports/financialAccounts/[[...financialAccount]].page.test.tsx create mode 100644 src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactions.test.tsx create mode 100644 src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactionsMocks.ts create mode 100644 src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccountsMocks.ts create mode 100644 src/components/Reports/FinancialAccountsReport/Header/Header.test.tsx diff --git a/pages/accountLists/[accountListId]/reports/financialAccounts/[[...financialAccount]].page.test.tsx b/pages/accountLists/[accountListId]/reports/financialAccounts/[[...financialAccount]].page.test.tsx new file mode 100644 index 0000000000..dd032cc244 --- /dev/null +++ b/pages/accountLists/[accountListId]/reports/financialAccounts/[[...financialAccount]].page.test.tsx @@ -0,0 +1,160 @@ +import React from 'react'; +import { ThemeProvider } from '@mui/material/styles'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon'; +import { render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { SnackbarProvider } from 'notistack'; +import { I18nextProvider } from 'react-i18next'; +import TestRouter from '__tests__/util/TestRouter'; +import { GqlMockedProvider } from '__tests__/util/graphqlMocking'; +import { + defaultFinancialAccount, + defaultFinancialAccountSummary, +} from 'src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummaryMock'; +import { FinancialAccountSummaryQuery } from 'src/components/Reports/FinancialAccountsReport/AccountSummary/financialAccountSummary.generated'; +import { FinancialAccountQuery } from 'src/components/Reports/FinancialAccountsReport/Context/FinancialAccount.generated'; +import { FinancialAccountsQuery } from 'src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccounts.generated'; +import { FinancialAccountsMock } from 'src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccountsMocks'; +import i18n from 'src/lib/i18n'; +import theme from 'src/theme'; +import FinancialAccountsPage from './[[...financialAccount]].page'; + +const accountListId = 'account-list-1'; +const financialAccountId = 'financialAccountId'; +const defaultRouter = { + query: { accountListId }, + isReady: true, +}; + +const Components = ({ router = defaultRouter }: { router?: object }) => ( + + + + + + + mocks={{ + FinancialAccountSummary: defaultFinancialAccountSummary, + FinancialAccount: defaultFinancialAccount, + ...FinancialAccountsMock, + }} + > + + + + + + + +); + +describe('Financial Accounts Page', () => { + it('should show initial financial accounts page', async () => { + const { findByText } = render(); + + expect(await findByText('Responsibility Centers')).toBeInTheDocument(); + + expect(await findByText('Test Account')).toBeInTheDocument(); + }); + + it('should show the summary page for a financial account', async () => { + const { findByText, findByRole, getByText, queryByText } = render( + , + ); + + expect(await findByText('Account 1')).toBeInTheDocument(); + + expect(queryByText('Responsibility Centers')).not.toBeInTheDocument(); + + expect( + await findByRole('heading', { name: 'Category' }), + ).toBeInTheDocument(); + + expect(getByText('Opening Balance')).toBeInTheDocument(); + }); + + it('should show the transactions page for a financial account', async () => { + const { findByText, findByRole, getByText, queryByText, queryByRole } = + render( + , + ); + + expect(await findByText('Account 1')).toBeInTheDocument(); + + expect( + await findByRole('button', { name: 'Export CSV' }), + ).toBeInTheDocument(); + + expect(getByText('Totals for Period')).toBeInTheDocument(); + + expect(queryByText('Responsibility Centers')).not.toBeInTheDocument(); + expect( + queryByRole('heading', { name: 'Category' }), + ).not.toBeInTheDocument(); + }); + + it('should open filters on load and set initial date Range filter', async () => { + const { findByRole } = render( + , + ); + + expect( + await findByRole('heading', { name: 'Filter (1)' }), + ).toBeInTheDocument(); + }); + + it('should open and close filters and menu', async () => { + const { findByRole, getByRole, queryByRole } = render( + , + ); + + // Filters + expect( + await findByRole('heading', { name: 'Filter (1)' }), + ).toBeInTheDocument(); + userEvent.click(getByRole('img', { name: 'Close' })); + expect( + queryByRole('heading', { name: 'Filter (1)' }), + ).not.toBeInTheDocument(); + + // Menu + userEvent.click(getByRole('img', { name: 'Toggle Menu Panel' })); + expect(getByRole('heading', { name: 'Reports' })).toBeInTheDocument(); + userEvent.click(getByRole('img', { name: 'Close' })); + expect(queryByRole('heading', { name: 'Reports' })).not.toBeInTheDocument(); + }); +}); diff --git a/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactions.test.tsx b/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactions.test.tsx new file mode 100644 index 0000000000..08ac0fb3e8 --- /dev/null +++ b/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactions.test.tsx @@ -0,0 +1,346 @@ +import React from 'react'; +import { ThemeProvider } from '@mui/material/styles'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { SnackbarProvider } from 'notistack'; +import { I18nextProvider } from 'react-i18next'; +import TestRouter from '__tests__/util/TestRouter'; +import { GqlMockedProvider } from '__tests__/util/graphqlMocking'; +import { + FinancialAccountTransactionFilters, + FinancialAccountsWrapper, +} from 'pages/accountLists/[accountListId]/reports/financialAccounts/Wrapper'; +import { Panel } from 'pages/accountLists/[accountListId]/reports/helpers'; +import { defaultFinancialAccount } from 'src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummaryMock'; +import i18n from 'src/lib/i18n'; +import theme from 'src/theme'; +import { FinancialAccountQuery } from '../Context/FinancialAccount.generated'; +import { + FinancialAccountContext, + FinancialAccountType, +} from '../Context/FinancialAccountsContext'; +import { + AccountTransactions, + defaultEndDate, + defaultStartDate, +} from './AccountTransactions'; +import { financialAccountEntriesMock } from './AccountTransactionsMocks'; +import { FinancialAccountEntriesQuery } from './financialAccountTransactions.generated'; + +const accountListId = 'account-list-1'; +const financialAccountId = 'financialAccountId'; +const defaultSearchTerm = ''; +const setActiveFilters = jest.fn(); +const setPanelOpen = jest.fn(); +const defaultActiveFilters = {}; +const defaultRouter = { + query: { accountListId }, + isReady: true, +}; +const mutationSpy = jest.fn(); + +interface ComponentsProps { + activeFilters?: FinancialAccountTransactionFilters; + searchTerm?: string; + router?: object; +} + +const Components = ({ + searchTerm = defaultSearchTerm, + activeFilters = defaultActiveFilters, + router = defaultRouter, +}: ComponentsProps) => ( + + + + + + + mocks={{ + FinancialAccount: defaultFinancialAccount, + FinancialAccountEntries: financialAccountEntriesMock, + }} + onCall={mutationSpy} + > + + + + + + + + + + + +); + +describe('Financial Account Transactions', () => { + describe('Resetting filters', () => { + it('should reset the activeFilters with the filters from the url filters', () => { + render( + , + ); + + expect(setActiveFilters).not.toHaveBeenCalledWith({ + dateRange: { + min: defaultStartDate, + max: defaultEndDate, + }, + }); + + expect(setActiveFilters).toHaveBeenCalledWith({ + categoryId: 'newCategoryId', + }); + expect(setPanelOpen).toHaveBeenCalledWith(Panel.Filters); + }); + + it('should set filters to default date range if no activeFilters or url filters', () => { + render(); + + expect(setActiveFilters).toHaveBeenCalledWith({ + dateRange: { + min: defaultStartDate, + max: defaultEndDate, + }, + }); + }); + }); + + it('should render data correctly', async () => { + const { findAllByText, getAllByText, getByText } = render(); + + expect(await findAllByText('category1Name')).toHaveLength(2); + expect(getAllByText('category1Code')).toHaveLength(2); + + // Header + expect(getByText('Closing Balance')).toBeInTheDocument(); + expect(getByText('UAH 280,414')).toBeInTheDocument(); + + // Row 1 + expect(getByText('8/9/2024')).toBeInTheDocument(); + expect(getByText('description3')).toBeInTheDocument(); + expect(getByText('code3')).toBeInTheDocument(); + expect(getByText('UAH 7,048')).toBeInTheDocument(); + + // Row 2 + expect(getByText('8/8/2024')).toBeInTheDocument(); + expect(getByText('description1')).toBeInTheDocument(); + expect(getByText('code1')).toBeInTheDocument(); + expect(getByText('UAH 15,008')).toBeInTheDocument(); + + // Row 3 + expect(getByText('8/7/2024')).toBeInTheDocument(); + expect(getByText('description2')).toBeInTheDocument(); + expect(getByText('code2')).toBeInTheDocument(); + expect(getByText('UAH 37')).toBeInTheDocument(); + + // Footer + expect(getByText('Opening Balance')).toBeInTheDocument(); + expect(getByText('UAH 202,240')).toBeInTheDocument(); + + // Totals + expect(getByText('Income:')).toBeInTheDocument(); + expect(getByText('UAH 307,519')).toBeInTheDocument(); + + expect(getByText('Expenses:')).toBeInTheDocument(); + expect(getByText('UAH 229,344')).toBeInTheDocument(); + + expect(getByText('Differences:')).toBeInTheDocument(); + expect(getByText('UAH 78,175')).toBeInTheDocument(); + }); + + it('should render closing and opening dates correctly when using filtered dates', async () => { + const { getByText, findByText } = render( + , + ); + + // Closing balance date + expect(await findByText('8/1/2024')).toBeInTheDocument(); + // Opening balance date + expect(getByText('9/30/2024')).toBeInTheDocument(); + }); + + describe('GraphQL query variables', () => { + it('should use date filters', async () => { + render( + , + ); + + await waitFor(() => { + expect(mutationSpy).toHaveGraphqlOperation('FinancialAccountEntries', { + input: { + accountListId, + financialAccountId, + dateRange: '2024-08-01..2024-09-30', + categoryId: '', + wildcardSearch: '', + }, + }); + }); + }); + + it('should use date and category filters', async () => { + render( + , + ); + + await waitFor(() => { + expect(mutationSpy).toHaveGraphqlOperation('FinancialAccountEntries', { + input: { + accountListId, + financialAccountId, + dateRange: '2024-08-01..2024-09-30', + categoryId: 'test123', + wildcardSearch: '', + }, + }); + }); + }); + + it('should use date, category and search filters', async () => { + render( + , + ); + + await waitFor(() => { + expect(mutationSpy).toHaveGraphqlOperation('FinancialAccountEntries', { + input: { + accountListId, + financialAccountId, + dateRange: '2024-08-01..2024-09-30', + categoryId: 'test123', + wildcardSearch: 'searchTerm', + }, + }); + }); + }); + }); + + describe('Export CSV', () => { + it('should disable export CSV button when loading', async () => { + const { getByRole } = render(); + + expect(getByRole('button', { name: 'Export CSV' })).toBeDisabled(); + + await waitFor(() => { + expect(getByRole('button', { name: 'Export CSV' })).toBeEnabled(); + }); + }); + + it('should export CSV', async () => { + const { getByRole } = render(); + + await waitFor(() => { + expect(getByRole('button', { name: 'Export CSV' })).toBeEnabled(); + }); + + const link = document.createElement('a'); + + const createElementSpy = jest.spyOn(document, 'createElement'); + const appendChildSpy = jest.spyOn(document.body, 'appendChild'); + const removeChildSpy = jest.spyOn(document.body, 'removeChild'); + const clickSpy = jest.fn(); + const setAttributeSpy = jest.fn(); + + link.setAttribute = setAttributeSpy; + link.click = clickSpy; + + createElementSpy.mockReturnValue(link); + + fireEvent.click(getByRole('button', { name: 'Export CSV' })); + + const csvContentArray = [ + ['Date', 'Payee', 'Memo', 'Outflow', 'Inflow'], + ['8/9/2024', 'description1', 'category1Name', '', 'UAH 7,048'], + ['8/8/2024', 'description2', 'category1Name', 'UAH 15,008', ''], + ['8/7/2024', 'description3', 'category2Name', '', 'UAH 37'], + ]; + + const csvContent = + 'data:text/csv;charset=utf-8,' + + csvContentArray + .map((row) => + row + .map((field) => `"${String(field).replace(/"/g, '""')}"`) + .join(','), + ) + .join('\n'); + + await waitFor(() => { + expect(createElementSpy).toHaveBeenCalledWith('a'); + expect(appendChildSpy).toHaveBeenCalled(); + expect(setAttributeSpy).toHaveBeenCalledWith( + 'href', + encodeURI(csvContent), + ); + expect(clickSpy).toHaveBeenCalled(); + expect(removeChildSpy).toHaveBeenCalled(); + }); + + createElementSpy.mockRestore(); + appendChildSpy.mockRestore(); + removeChildSpy.mockRestore(); + }); + }); +}); diff --git a/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactions.tsx b/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactions.tsx index 336f890a18..3a60253bff 100644 --- a/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactions.tsx +++ b/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactions.tsx @@ -38,8 +38,8 @@ const formatDateRange = (startDate?: DateTime, endDate?: DateTime) => { }; const defaultDateRange = formatDateRange(); -const defaultStartDate = defaultDateRange.split('..')[0]; -const defaultEndDate = defaultDateRange.split('..')[1]; +export const defaultStartDate = defaultDateRange.split('..')[0]; +export const defaultEndDate = defaultDateRange.split('..')[1]; export const AccountTransactions: React.FC = () => { const { query } = useRouter(); @@ -118,28 +118,33 @@ export const AccountTransactions: React.FC = () => { t('Outflow'), t('Inflow'), ]; - const convertDataToArray = data.financialAccountEntries.entries.map( - (entry) => [ - entry.entryDate - ? dateFormatShort(DateTime.fromISO(entry.entryDate), locale) - : 'No entry date', - entry.description ?? '', - entry.category?.name ?? entry.category?.code ?? '', - entry.type === FinancialAccountEntryTypeEnum.Debit - ? currencyFormat( - formatNumber(entry.amount), - entry.currency, - locale, - ).replace(/[\xA0\u2000-\u200B\uFEFF]/g, ' ') - : '', - entry.type === FinancialAccountEntryTypeEnum.Credit - ? currencyFormat( - formatNumber(entry.amount), - entry.currency, - locale, - ).replace(/[\xA0\u2000-\u200B\uFEFF]/g, ' ') - : '', - ], + const convertDataToArray = data.financialAccountEntries.entries.reduce( + (array, entry) => { + return [ + ...array, + [ + entry.entryDate + ? dateFormatShort(DateTime.fromISO(entry.entryDate), locale) + : 'No entry date', + entry.description ?? '', + entry.category?.name ?? entry.category?.code ?? '', + entry.type === FinancialAccountEntryTypeEnum.Debit + ? currencyFormat( + formatNumber(entry.amount), + entry.currency, + locale, + ).replace(/[\xA0\u2000-\u200B\uFEFF]/g, ' ') + : '', + entry.type === FinancialAccountEntryTypeEnum.Credit + ? currencyFormat( + formatNumber(entry.amount), + entry.currency, + locale, + ).replace(/[\xA0\u2000-\u200B\uFEFF]/g, ' ') + : '', + ], + ]; + }, [columnHeaders], ); diff --git a/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactionsMocks.ts b/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactionsMocks.ts new file mode 100644 index 0000000000..261958348f --- /dev/null +++ b/src/components/Reports/FinancialAccountsReport/AccountTransactions/AccountTransactionsMocks.ts @@ -0,0 +1,66 @@ +import { FinancialAccountEntryTypeEnum } from './AccountTransactionTable/AccountTransactionTable'; +import { FinancialAccountEntriesQuery } from './financialAccountTransactions.generated'; + +export const financialAccountEntriesMock: FinancialAccountEntriesQuery = { + financialAccountEntries: { + entries: [ + { + __typename: 'FinancialAccountEntry', + id: 'entry1', + amount: '-7047.28', + currency: 'UAH', + code: 'code1', + description: 'description1', + entryDate: '2024-08-09', + type: FinancialAccountEntryTypeEnum.Credit, + category: { + __typename: 'FinancialAccountCategory', + id: 'category1', + code: 'category1Code', + name: 'category1Name', + }, + }, + { + __typename: 'FinancialAccountEntry', + id: 'entry2', + amount: '15008.0', + currency: 'UAH', + code: 'code2', + description: 'description2', + entryDate: '2024-08-08', + type: FinancialAccountEntryTypeEnum.Debit, + category: { + __typename: 'FinancialAccountCategory', + id: 'category1', + code: 'category1Code', + name: 'category1Name', + }, + }, + { + __typename: 'FinancialAccountEntry', + id: 'entry3', + amount: '-36.2', + currency: 'UAH', + code: 'code3', + description: 'description3', + entryDate: '2024-08-07', + type: FinancialAccountEntryTypeEnum.Credit, + category: { + __typename: 'FinancialAccountCategory', + id: 'category2', + code: 'category2Code', + name: 'category2Name', + }, + }, + ], + metaData: { + __typename: 'FinancialAccountMetaData', + credits: '-307518.87', + debits: '229344.0', + difference: '-78174.87', + currency: 'UAH', + closingBalance: '-280413.99', + openingBalance: '-202239.12', + }, + }, +}; diff --git a/src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccounts.test.tsx b/src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccounts.test.tsx index 9edb1681f0..36dec7adad 100644 --- a/src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccounts.test.tsx +++ b/src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccounts.test.tsx @@ -11,10 +11,12 @@ import { FinancialAccountType, } from '../Context/FinancialAccountsContext'; import { FinancialAccounts } from './FinancialAccounts'; +import { FinancialAccountsQuery } from './FinancialAccounts.generated'; import { - FinancialAccountsDocument, - FinancialAccountsQuery, -} from './FinancialAccounts.generated'; + FinancialAccountsEmptyMock, + FinancialAccountsErrorMock, + FinancialAccountsMock, +} from './FinancialAccountsMocks'; jest.mock('next/router', () => ({ useRouter: () => { @@ -29,46 +31,6 @@ const accountListId = '111'; const onNavListToggle = jest.fn(); const mutationSpy = jest.fn(); -const mocks = { - FinancialAccounts: { - financialAccounts: { - nodes: [ - { - active: true, - balance: { - conversionDate: '2021-02-02', - convertedAmount: 3500, - convertedCurrency: 'CAD', - }, - code: '13212', - id: 'test-id-111', - name: 'Test Account', - organization: { - id: '111-2222-3333', - name: 'test org 01', - }, - updatedAt: '2021-02-02', - }, - ], - }, - }, -}; - -const errorMock = { - request: { - query: FinancialAccountsDocument, - }, - error: { name: 'error', message: 'Error loading data. Try again.' }, -}; - -const emptyMocks = { - FinancialAccounts: { - financialAccounts: { - nodes: [], - }, - }, -}; - interface ComponentsProps { mocks?: ApolloErgonoMockMap; designationAccounts?: string[]; @@ -91,7 +53,7 @@ const Components: React.FC = ({ } > {useErrorMockedProvider ? ( - + ) : ( @@ -112,7 +74,7 @@ describe('FinancialAccounts', () => { }); it('default', async () => { const { getByText, getByTestId, queryByTestId } = render( - , + , ); await waitFor(() => { @@ -127,7 +89,9 @@ describe('FinancialAccounts', () => { }); it('renders nav list icon and onclick triggers onNavListToggle', async () => { - const { getByTestId } = render(); + const { getByTestId } = render( + , + ); expect(getByTestId('ReportsFilterIcon')).toBeInTheDocument(); userEvent.click(getByTestId('ReportsFilterIcon')); @@ -135,7 +99,9 @@ describe('FinancialAccounts', () => { }); it('loading', async () => { - const { queryByTestId, getByText } = render(); + const { queryByTestId, getByText } = render( + , + ); expect(getByText('Responsibility Centers')).toBeInTheDocument(); expect(queryByTestId('LoadingFinancialAccounts')).toBeInTheDocument(); @@ -153,7 +119,9 @@ describe('FinancialAccounts', () => { }); it('empty', async () => { - const { queryByTestId } = render(); + const { queryByTestId } = render( + , + ); await waitFor(() => { expect(queryByTestId('LoadingFinancialAccounts')).not.toBeInTheDocument(); @@ -163,7 +131,12 @@ describe('FinancialAccounts', () => { }); it('filters report by designation account', async () => { - render(); + render( + , + ); await waitFor(() => expect(mutationSpy).toHaveGraphqlOperation('FinancialAccounts', { @@ -173,7 +146,7 @@ describe('FinancialAccounts', () => { }); it('does not filter report by designation account', async () => { - render(); + render(); await waitFor(() => expect(mutationSpy).toHaveGraphqlOperation('FinancialAccounts', { diff --git a/src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccountsMocks.ts b/src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccountsMocks.ts new file mode 100644 index 0000000000..ca3105ab66 --- /dev/null +++ b/src/components/Reports/FinancialAccountsReport/FinancialAccounts/FinancialAccountsMocks.ts @@ -0,0 +1,41 @@ +import { FinancialAccountsDocument } from './FinancialAccounts.generated'; + +export const FinancialAccountsMock = { + FinancialAccounts: { + financialAccounts: { + nodes: [ + { + active: true, + balance: { + conversionDate: '2021-02-02', + convertedAmount: 3500, + convertedCurrency: 'CAD', + }, + code: '13212', + id: 'test-id-111', + name: 'Test Account', + organization: { + id: '111-2222-3333', + name: 'test org 01', + }, + updatedAt: '2021-02-02', + }, + ], + }, + }, +}; + +export const FinancialAccountsErrorMock = { + request: { + query: FinancialAccountsDocument, + }, + error: { name: 'error', message: 'Error loading data. Try again.' }, +}; + +export const FinancialAccountsEmptyMock = { + FinancialAccounts: { + financialAccounts: { + nodes: [], + }, + }, +}; diff --git a/src/components/Reports/FinancialAccountsReport/Header/Header.test.tsx b/src/components/Reports/FinancialAccountsReport/Header/Header.test.tsx new file mode 100644 index 0000000000..911dd68608 --- /dev/null +++ b/src/components/Reports/FinancialAccountsReport/Header/Header.test.tsx @@ -0,0 +1,174 @@ +import React from 'react'; +import { ThemeProvider } from '@mui/material/styles'; +import { LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon'; +import { render, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { SnackbarProvider } from 'notistack'; +import { I18nextProvider } from 'react-i18next'; +import TestRouter from '__tests__/util/TestRouter'; +import { GqlMockedProvider } from '__tests__/util/graphqlMocking'; +import { FinancialAccountsWrapper } from 'pages/accountLists/[accountListId]/reports/financialAccounts/Wrapper'; +import { defaultFinancialAccount } from 'src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummaryMock'; +import i18n from 'src/lib/i18n'; +import theme from 'src/theme'; +import { FinancialAccountQuery } from '../Context/FinancialAccount.generated'; +import { + FinancialAccountContext, + FinancialAccountType, +} from '../Context/FinancialAccountsContext'; +import { FinancialAccountHeader, FinancialAccountHeaderProps } from './Header'; + +const accountListId = 'account-list-1'; +const financialAccountId = 'financialAccountId'; +const handleNavListToggle = jest.fn(); +const defaultHasActiveFilters = false; +const handleFilterListToggle = jest.fn(); +const defaultSearchTerm = ''; +const setSearchTerm = jest.fn(); +const router = { + query: { accountListId }, + isReady: true, +}; + +interface ComponentsProps extends FinancialAccountHeaderProps { + hasActiveFilters?: boolean; + searchTerm?: string; +} +const Components = ({ + hasActiveFilters = defaultHasActiveFilters, + searchTerm = defaultSearchTerm, + onTransactionPage, + disableExportCSV, + handleExportCSV, +}: ComponentsProps) => ( + + + + + + + mocks={{ + FinancialAccount: defaultFinancialAccount, + }} + > + + + + + + + + + + + +); + +describe('Financial Account Header', () => { + describe('Summary view', () => { + it('should show initial view without transactions header', async () => { + const { findByText, getByRole, getByText, queryByRole } = render( + , + ); + + expect(await findByText('Account 1')).toBeInTheDocument(); + expect(getByRole('link', { name: 'Summary' })).toBeInTheDocument(); + expect(getByRole('link', { name: 'Transactions' })).toBeInTheDocument(); + expect(getByText('$1,000')).toBeInTheDocument(); + + expect(getByText('accountCode - Organization 1')).toBeInTheDocument(); + + expect( + queryByRole('button', { + name: 'Export CSV', + }), + ).not.toBeInTheDocument(); + + expect( + getByRole('img', { name: 'Toggle Menu Panel' }), + ).toBeInTheDocument(); + }); + + it('should have correct links for Summary and Transaction', async () => { + const { findByRole, getByRole } = render(); + + expect(await findByRole('link', { name: 'Summary' })).toHaveAttribute( + 'href', + '/accountLists/account-list-1/reports/financialAccounts/financialAccountId', + ); + expect(getByRole('link', { name: 'Transactions' })).toHaveAttribute( + 'href', + '/accountLists/account-list-1/reports/financialAccounts/financialAccountId/entries', + ); + }); + }); + + describe('Transactions view', () => { + const handleExportCSV = jest.fn(); + + it('should show transactions header', async () => { + const { findByText, findByRole, getByTestId, getByRole } = render( + , + ); + + expect(await findByText('Account 1')).toBeInTheDocument(); + + expect( + await findByRole('button', { name: 'Export CSV' }), + ).toBeInTheDocument(); + + expect(getByTestId('SearchIcon')).toBeInTheDocument(); + + expect( + getByRole('img', { name: 'Toggle Filter Panel' }), + ).toBeInTheDocument(); + }); + + it('should export CSV on click of the button', async () => { + const { findByRole } = render( + , + ); + + const exportButton = await findByRole('button', { name: 'Export CSV' }); + + userEvent.click(exportButton); + + expect(handleExportCSV).toHaveBeenCalled(); + }); + + it('should update search on type', async () => { + const { getByTestId } = render(); + + const view = getByTestId('FinancialAccountHeader'); + + const searchInput = within(view).getByRole('textbox'); + + userEvent.type(searchInput, 'test'); + + expect(setSearchTerm).toHaveBeenCalledWith('test'); + }); + }); +}); diff --git a/src/components/Reports/FinancialAccountsReport/Header/Header.tsx b/src/components/Reports/FinancialAccountsReport/Header/Header.tsx index 42cf1394ce..a5a1bd3cbf 100644 --- a/src/components/Reports/FinancialAccountsReport/Header/Header.tsx +++ b/src/components/Reports/FinancialAccountsReport/Header/Header.tsx @@ -69,7 +69,7 @@ const HeaderActions = styled(Box)(({ theme }) => ({ width: 'calc(100% - 150px)', })); -interface FinancialAccountHeaderProps { +export interface FinancialAccountHeaderProps { onTransactionPage?: boolean; disableExportCSV?: boolean; handleExportCSV?: () => void;