diff --git a/shlink-web-component/src/overview/helpers/VisitsHighlightCard.tsx b/shlink-web-component/src/overview/helpers/VisitsHighlightCard.tsx index 1617eb2e..6da51057 100644 --- a/shlink-web-component/src/overview/helpers/VisitsHighlightCard.tsx +++ b/shlink-web-component/src/overview/helpers/VisitsHighlightCard.tsx @@ -14,7 +14,7 @@ export const VisitsHighlightCard: FC = ({ loading, exc {excludeBots ? 'Plus' : 'Including'} {prettify(visitsSummary.bots)} potential bot visits + ? <>{excludeBots ? 'Plus' : 'Including'} {prettify(visitsSummary.bots)} potential bot visits : undefined } {...rest} diff --git a/shlink-web-component/test/__helpers__/TestModalWrapper.tsx b/shlink-web-component/test/__helpers__/TestModalWrapper.tsx index a673827b..00ceaffe 100644 --- a/shlink-web-component/test/__helpers__/TestModalWrapper.tsx +++ b/shlink-web-component/test/__helpers__/TestModalWrapper.tsx @@ -1,5 +1,5 @@ import type { FC, ReactElement } from 'react'; -import { useToggle } from '../../src/utils/helpers/hooks'; +import { useToggle } from '../../../shlink-frontend-kit/src'; interface RenderModalArgs { isOpen: boolean; diff --git a/shlink-web-component/test/common/AsideMenu.test.tsx b/shlink-web-component/test/common/AsideMenu.test.tsx index fac3fe61..0b0d7bbb 100644 --- a/shlink-web-component/test/common/AsideMenu.test.tsx +++ b/shlink-web-component/test/common/AsideMenu.test.tsx @@ -1,12 +1,11 @@ import { render, screen } from '@testing-library/react'; -import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router'; import { AsideMenu } from '../../src/common/AsideMenu'; describe('', () => { const setUp = () => render( - + , ); diff --git a/shlink-web-component/test/common/ShlinkApiError.test.tsx b/shlink-web-component/test/common/ShlinkApiError.test.tsx index ab299b54..8d614e66 100644 --- a/shlink-web-component/test/common/ShlinkApiError.test.tsx +++ b/shlink-web-component/test/common/ShlinkApiError.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { InvalidArgumentError, ProblemDetailsError } from '../../src/api/types/errors'; -import { ErrorTypeV2, ErrorTypeV3 } from '../../src/api/types/errors'; +import type { InvalidArgumentError, ProblemDetailsError } from '../../src/api-contract'; +import { ErrorTypeV2, ErrorTypeV3 } from '../../src/api-contract'; import type { ShlinkApiErrorProps } from '../../src/common/ShlinkApiError'; import { ShlinkApiError } from '../../src/common/ShlinkApiError'; diff --git a/shlink-web-component/test/domains/DomainRow.test.tsx b/shlink-web-component/test/domains/DomainRow.test.tsx index f3d6bc3e..967b77ec 100644 --- a/shlink-web-component/test/domains/DomainRow.test.tsx +++ b/shlink-web-component/test/domains/DomainRow.test.tsx @@ -1,6 +1,6 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkDomainRedirects } from '../../src/api/types'; +import type { ShlinkDomainRedirects } from '../../src/api-contract'; import type { Domain } from '../../src/domains/data'; import { DomainRow } from '../../src/domains/DomainRow'; @@ -21,7 +21,6 @@ describe('', () => { diff --git a/shlink-web-component/test/domains/helpers/DomainDropdown.test.tsx b/shlink-web-component/test/domains/helpers/DomainDropdown.test.tsx index 0895731a..4044f98b 100644 --- a/shlink-web-component/test/domains/helpers/DomainDropdown.test.tsx +++ b/shlink-web-component/test/domains/helpers/DomainDropdown.test.tsx @@ -1,26 +1,29 @@ import { screen, waitForElementToBeRemoved } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; -import type { SelectedServer } from '../../../../src/servers/data'; -import type { SemVer } from '../../../../src/utils/helpers/version'; import type { Domain } from '../../../src/domains/data'; import { DomainDropdown } from '../../../src/domains/helpers/DomainDropdown'; +import { FeaturesProvider } from '../../../src/utils/features'; +import { RoutesPrefixProvider } from '../../../src/utils/routesPrefix'; import { renderWithEvents } from '../../__helpers__/setUpTest'; describe('', () => { const editDomainRedirects = vi.fn().mockResolvedValue(undefined); - const setUp = (domain?: Domain, selectedServer?: SelectedServer) => renderWithEvents( + const setUp = ({ domain, withVisits = true }: { domain?: Domain; withVisits?: boolean } = {}) => renderWithEvents( - + + + + + , ); it('renders expected menu items', () => { - setUp(); + setUp({ withVisits: false }); expect(screen.queryByText('Visit stats')).not.toBeInTheDocument(); expect(screen.getByText('Edit redirects')).toBeInTheDocument(); @@ -30,37 +33,17 @@ describe('', () => { [true, '_DEFAULT'], [false, ''], ])('points first link to the proper section', (isDefault, expectedLink) => { - setUp( - fromPartial({ domain: 'foo.com', isDefault }), - fromPartial({ version: '3.1.0', id: '123' }), - ); + setUp({ domain: fromPartial({ domain: 'foo.com', isDefault }) }); expect(screen.getByText('Visit stats')).toHaveAttribute('href', `/server/123/domain/foo.com${expectedLink}/visits`); }); - it.each([ - [true, '2.9.0' as SemVer, false], - [true, '2.10.0' as SemVer, true], - [false, '2.9.0' as SemVer, true], - ])('allows editing certain the domains', (isDefault, serverVersion, canBeEdited) => { - setUp( - fromPartial({ domain: 'foo.com', isDefault }), - fromPartial({ version: serverVersion, id: '123' }), - ); - - if (canBeEdited) { - expect(screen.getByText('Edit redirects')).not.toHaveAttribute('disabled'); - } else { - expect(screen.getByText('Edit redirects')).toHaveAttribute('disabled'); - } - }); - it.each([ ['foo.com'], ['bar.org'], ['baz.net'], ])('displays modal when editing redirects', async (domain) => { - const { user } = setUp(fromPartial({ domain, isDefault: false })); + const { user } = setUp({ domain: fromPartial({ domain, isDefault: false }) }); expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); expect(screen.queryByRole('form')).not.toBeInTheDocument(); diff --git a/shlink-web-component/test/domains/reducers/domainRedirects.test.ts b/shlink-web-component/test/domains/reducers/domainRedirects.test.ts index a0f8dd7f..8a7a42e0 100644 --- a/shlink-web-component/test/domains/reducers/domainRedirects.test.ts +++ b/shlink-web-component/test/domains/reducers/domainRedirects.test.ts @@ -1,6 +1,6 @@ import { fromPartial } from '@total-typescript/shoehorn'; import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkDomainRedirects } from '../../../src/api/types'; +import type { ShlinkDomainRedirects } from '../../../src/api-contract'; import { editDomainRedirects } from '../../../src/domains/reducers/domainRedirects'; describe('domainRedirectsReducer', () => { diff --git a/shlink-web-component/test/domains/reducers/domainsList.test.ts b/shlink-web-component/test/domains/reducers/domainsList.test.ts index bb3d4ca1..ed4afc89 100644 --- a/shlink-web-component/test/domains/reducers/domainsList.test.ts +++ b/shlink-web-component/test/domains/reducers/domainsList.test.ts @@ -1,8 +1,6 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; -import type { ShlinkDomainRedirects } from '../../../src/api/types'; -import { parseApiError } from '../../../src/api/utils'; +import type { ShlinkApiClient, ShlinkDomainRedirects } from '../../../src/api-contract'; +import { parseApiError } from '../../../src/api-contract/utils'; import type { Domain } from '../../../src/domains/data'; import type { EditDomainRedirects } from '../../../src/domains/reducers/domainRedirects'; import { editDomainRedirects } from '../../../src/domains/reducers/domainRedirects'; @@ -17,35 +15,35 @@ describe('domainsListReducer', () => { const getState = vi.fn(); const listDomains = vi.fn(); const health = vi.fn(); - const buildShlinkApiClient = () => fromPartial({ listDomains, health }); + const apiClientFactory = () => fromPartial({ listDomains, health }); const filteredDomains: Domain[] = [ fromPartial({ domain: 'foo', status: 'validating' }), fromPartial({ domain: 'Boo', status: 'validating' }), ]; const domains: Domain[] = [...filteredDomains, fromPartial({ domain: 'bar', status: 'validating' })]; const error = { type: 'NOT_FOUND', status: 404 } as unknown as Error; - const editDomainRedirectsThunk = editDomainRedirects(buildShlinkApiClient); + const editDomainRedirectsThunk = editDomainRedirects(apiClientFactory); const { reducer, listDomains: listDomainsAction, checkDomainHealth, filterDomains } = domainsListReducerCreator( - buildShlinkApiClient, + apiClientFactory, editDomainRedirectsThunk, ); describe('reducer', () => { it('returns loading on LIST_DOMAINS_START', () => { - expect(reducer(undefined, listDomainsAction.pending(''))).toEqual( + expect(reducer(undefined, listDomainsAction.pending('', {}))).toEqual( { domains: [], filteredDomains: [], loading: true, error: false }, ); }); it('returns error on LIST_DOMAINS_ERROR', () => { - expect(reducer(undefined, listDomainsAction.rejected(error, ''))).toEqual( + expect(reducer(undefined, listDomainsAction.rejected(error, '', {}))).toEqual( { domains: [], filteredDomains: [], loading: false, error: true, errorData: parseApiError(error) }, ); }); it('returns domains on LIST_DOMAINS', () => { expect( - reducer(undefined, listDomainsAction.fulfilled({ domains }, '')), + reducer(undefined, listDomainsAction.fulfilled({ domains }, '', {})), ).toEqual({ domains, filteredDomains: domains, loading: false, error: false }); }); @@ -93,7 +91,7 @@ describe('domainsListReducer', () => { it('dispatches domains once loaded', async () => { listDomains.mockResolvedValue({ data: domains }); - await listDomainsAction()(dispatch, getState, {}); + await listDomainsAction({})(dispatch, getState, {}); expect(dispatch).toHaveBeenCalledTimes(2); expect(dispatch).toHaveBeenLastCalledWith(expect.objectContaining({ @@ -116,33 +114,13 @@ describe('domainsListReducer', () => { describe('checkDomainHealth', () => { const domain = 'example.com'; - it('dispatches invalid status when selected server does not have all required data', async () => { - getState.mockReturnValue(fromPartial({ - selectedServer: {}, - })); - - await checkDomainHealth(domain)(dispatch, getState, {}); - - expect(getState).toHaveBeenCalledTimes(1); - expect(health).not.toHaveBeenCalled(); - expect(dispatch).toHaveBeenLastCalledWith(expect.objectContaining({ - payload: { domain, status: 'invalid' }, - })); - }); - it('dispatches invalid status when health endpoint returns an error', async () => { - getState.mockReturnValue(fromPartial({ - selectedServer: { - url: 'https://myerver.com', - apiKey: '123', - }, - })); health.mockRejectedValue({}); await checkDomainHealth(domain)(dispatch, getState, {}); - expect(getState).toHaveBeenCalledTimes(1); expect(health).toHaveBeenCalledTimes(1); + expect(health).toHaveBeenCalledWith(domain); expect(dispatch).toHaveBeenLastCalledWith(expect.objectContaining({ payload: { domain, status: 'invalid' }, })); @@ -155,18 +133,12 @@ describe('domainsListReducer', () => { healthStatus, expectedStatus, ) => { - getState.mockReturnValue(fromPartial({ - selectedServer: { - url: 'https://myerver.com', - apiKey: '123', - }, - })); health.mockResolvedValue({ status: healthStatus }); await checkDomainHealth(domain)(dispatch, getState, {}); - expect(getState).toHaveBeenCalledTimes(1); expect(health).toHaveBeenCalledTimes(1); + expect(health).toHaveBeenCalledWith(domain); expect(dispatch).toHaveBeenLastCalledWith(expect.objectContaining({ payload: { domain, status: expectedStatus }, })); diff --git a/shlink-web-component/test/mercure/reducers/mercureInfo.test.ts b/shlink-web-component/test/mercure/reducers/mercureInfo.test.ts index 092d78b0..acf3441d 100644 --- a/shlink-web-component/test/mercure/reducers/mercureInfo.test.ts +++ b/shlink-web-component/test/mercure/reducers/mercureInfo.test.ts @@ -1,6 +1,6 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { GetState } from '../../../../src/container/types'; +import type { Settings } from '../../../src'; +import type { ShlinkApiClient } from '../../../src/api-contract'; import { mercureInfoReducerCreator } from '../../../src/mercure/reducers/mercureInfo'; describe('mercureInfoReducer', () => { @@ -14,21 +14,21 @@ describe('mercureInfoReducer', () => { describe('reducer', () => { it('returns loading on GET_MERCURE_INFO_START', () => { - expect(reducer(undefined, loadMercureInfo.pending(''))).toEqual({ + expect(reducer(undefined, loadMercureInfo.pending('', {}))).toEqual({ loading: true, error: false, }); }); it('returns error on GET_MERCURE_INFO_ERROR', () => { - expect(reducer(undefined, loadMercureInfo.rejected(null, ''))).toEqual({ + expect(reducer(undefined, loadMercureInfo.rejected(null, '', {}))).toEqual({ loading: false, error: true, }); }); it('returns mercure info on GET_MERCURE_INFO', () => { - expect(reducer(undefined, loadMercureInfo.fulfilled(mercureInfo, ''))).toEqual( + expect(reducer(undefined, loadMercureInfo.fulfilled(mercureInfo, '', {}))).toEqual( expect.objectContaining({ ...mercureInfo, loading: false, error: false }), ); }); @@ -36,17 +36,15 @@ describe('mercureInfoReducer', () => { describe('loadMercureInfo', () => { const dispatch = vi.fn(); - const createGetStateMock = (enabled: boolean): GetState => vi.fn().mockReturnValue({ - settings: { - realTimeUpdates: { enabled }, - }, + const createSettings = (enabled: boolean): Settings => fromPartial({ + realTimeUpdates: { enabled }, }); it('dispatches error when real time updates are disabled', async () => { getMercureInfo.mockResolvedValue(mercureInfo); - const getState = createGetStateMock(false); + const settings = createSettings(false); - await loadMercureInfo()(dispatch, getState, {}); + await loadMercureInfo(settings)(dispatch, vi.fn(), {}); expect(getMercureInfo).not.toHaveBeenCalled(); expect(dispatch).toHaveBeenCalledTimes(2); @@ -57,9 +55,9 @@ describe('mercureInfoReducer', () => { it('calls API on success', async () => { getMercureInfo.mockResolvedValue(mercureInfo); - const getState = createGetStateMock(true); + const settings = createSettings(true); - await loadMercureInfo()(dispatch, getState, {}); + await loadMercureInfo(settings)(dispatch, vi.fn(), {}); expect(getMercureInfo).toHaveBeenCalledTimes(1); expect(dispatch).toHaveBeenCalledTimes(2); diff --git a/shlink-web-component/test/overview/Overview.test.tsx b/shlink-web-component/test/overview/Overview.test.tsx index ec6c2fb6..9b4cf5d2 100644 --- a/shlink-web-component/test/overview/Overview.test.tsx +++ b/shlink-web-component/test/overview/Overview.test.tsx @@ -4,6 +4,8 @@ import { MemoryRouter } from 'react-router-dom'; import type { MercureInfo } from '../../src/mercure/reducers/mercureInfo'; import { Overview as overviewCreator } from '../../src/overview/Overview'; import { prettify } from '../../src/utils/helpers/numbers'; +import { RoutesPrefixProvider } from '../../src/utils/routesPrefix'; +import { SettingsProvider } from '../../src/utils/settings'; import { renderWithEvents } from '../__helpers__/setUpTest'; describe('', () => { @@ -16,26 +18,28 @@ describe('', () => { const shortUrls = { pagination: { totalItems: 83710 }, }; - const serverId = '123'; + const routesPrefix = '/server/123'; const setUp = (loading = false, excludeBots = false) => renderWithEvents( - ({})} - settings={fromPartial({ visits: { excludeBots } })} - /> + + + ({})} + /> + + , ); @@ -75,12 +79,13 @@ describe('', () => { const links = screen.getAllByRole('link'); - expect(links).toHaveLength(5); - expect(links[0]).toHaveAttribute('href', `/server/${serverId}/orphan-visits`); - expect(links[1]).toHaveAttribute('href', `/server/${serverId}/list-short-urls/1`); - expect(links[2]).toHaveAttribute('href', `/server/${serverId}/manage-tags`); - expect(links[3]).toHaveAttribute('href', `/server/${serverId}/create-short-url`); - expect(links[4]).toHaveAttribute('href', `/server/${serverId}/list-short-urls/1`); + expect(links).toHaveLength(6); + expect(links[0]).toHaveAttribute('href', `${routesPrefix}/non-orphan-visits`); + expect(links[1]).toHaveAttribute('href', `${routesPrefix}/orphan-visits`); + expect(links[2]).toHaveAttribute('href', `${routesPrefix}/list-short-urls/1`); + expect(links[3]).toHaveAttribute('href', `${routesPrefix}/manage-tags`); + expect(links[4]).toHaveAttribute('href', `${routesPrefix}/create-short-url`); + expect(links[5]).toHaveAttribute('href', `${routesPrefix}/list-short-urls/1`); }); it.each([ diff --git a/shlink-web-component/test/overview/helpers/HighlightCard.test.tsx b/shlink-web-component/test/overview/helpers/HighlightCard.test.tsx index 501d81ab..3306b77e 100644 --- a/shlink-web-component/test/overview/helpers/HighlightCard.test.tsx +++ b/shlink-web-component/test/overview/helpers/HighlightCard.test.tsx @@ -1,27 +1,17 @@ import { screen, waitFor } from '@testing-library/react'; -import type { ReactNode } from 'react'; +import type { PropsWithChildren } from 'react'; import { MemoryRouter } from 'react-router-dom'; import type { HighlightCardProps } from '../../../src/overview/helpers/HighlightCard'; import { HighlightCard } from '../../../src/overview/helpers/HighlightCard'; import { renderWithEvents } from '../../__helpers__/setUpTest'; describe('', () => { - const setUp = (props: HighlightCardProps & { children?: ReactNode }) => renderWithEvents( + const setUp = (props: PropsWithChildren>) => renderWithEvents( - + , ); - it.each([ - [undefined], - [''], - ])('does not render icon when there is no link', (link) => { - setUp({ title: 'foo', link }); - - expect(screen.queryByRole('img', { hidden: true })).not.toBeInTheDocument(); - expect(screen.queryByRole('link')).not.toBeInTheDocument(); - }); - it.each([ ['foo'], ['bar'], diff --git a/shlink-web-component/test/overview/helpers/VisitsHighlightCard.test.tsx b/shlink-web-component/test/overview/helpers/VisitsHighlightCard.test.tsx index 00b385b5..1428de12 100644 --- a/shlink-web-component/test/overview/helpers/VisitsHighlightCard.test.tsx +++ b/shlink-web-component/test/overview/helpers/VisitsHighlightCard.test.tsx @@ -1,18 +1,21 @@ import { screen, waitFor } from '@testing-library/react'; +import { MemoryRouter } from 'react-router'; import type { VisitsHighlightCardProps } from '../../../src/overview/helpers/VisitsHighlightCard'; import { VisitsHighlightCard } from '../../../src/overview/helpers/VisitsHighlightCard'; import { renderWithEvents } from '../../__helpers__/setUpTest'; describe('', () => { const setUp = (props: Partial = {}) => renderWithEvents( - , + + + , ); it.each([ diff --git a/shlink-web-component/test/short-urls/CreateShortUrl.test.tsx b/shlink-web-component/test/short-urls/CreateShortUrl.test.tsx index 8027f3b3..36eb835e 100644 --- a/shlink-web-component/test/short-urls/CreateShortUrl.test.tsx +++ b/shlink-web-component/test/short-urls/CreateShortUrl.test.tsx @@ -2,6 +2,7 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { CreateShortUrl as createShortUrlsCreator } from '../../src/short-urls/CreateShortUrl'; import type { ShortUrlCreation } from '../../src/short-urls/reducers/shortUrlCreation'; +import { SettingsProvider } from '../../src/utils/settings'; describe('', () => { const ShortUrlForm = () => ShortUrlForm; @@ -11,13 +12,13 @@ describe('', () => { const createShortUrl = vi.fn(async () => Promise.resolve()); const CreateShortUrl = createShortUrlsCreator(ShortUrlForm, CreateShortUrlResult); const setUp = () => render( - {}} - settings={fromPartial({ shortUrlCreation })} - />, + + {}} + /> + , ); it('renders computed initial state', () => { diff --git a/shlink-web-component/test/short-urls/EditShortUrl.test.tsx b/shlink-web-component/test/short-urls/EditShortUrl.test.tsx index 560f110e..05a0f619 100644 --- a/shlink-web-component/test/short-urls/EditShortUrl.test.tsx +++ b/shlink-web-component/test/short-urls/EditShortUrl.test.tsx @@ -4,20 +4,21 @@ import { MemoryRouter } from 'react-router-dom'; import { EditShortUrl as createEditShortUrl } from '../../src/short-urls/EditShortUrl'; import type { ShortUrlDetail } from '../../src/short-urls/reducers/shortUrlDetail'; import type { ShortUrlEdition } from '../../src/short-urls/reducers/shortUrlEdition'; +import { SettingsProvider } from '../../src/utils/settings'; describe('', () => { const shortUrlCreation = { validateUrls: true }; const EditShortUrl = createEditShortUrl(() => ShortUrlForm); const setUp = (detail: Partial = {}, edition: Partial = {}) => render( - Promise.resolve())} - /> + + Promise.resolve())} + /> + , ); diff --git a/shlink-web-component/test/short-urls/Paginator.test.tsx b/shlink-web-component/test/short-urls/Paginator.test.tsx index cde9462c..36921ede 100644 --- a/shlink-web-component/test/short-urls/Paginator.test.tsx +++ b/shlink-web-component/test/short-urls/Paginator.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; -import type { ShlinkPaginator } from '../../src/api/types'; +import type { ShlinkPaginator } from '../../src/api-contract'; import { Paginator } from '../../src/short-urls/Paginator'; import { ELLIPSIS } from '../../src/utils/helpers/pagination'; @@ -9,7 +9,7 @@ describe('', () => { const buildPaginator = (pagesCount?: number) => fromPartial({ pagesCount, currentPage: 1 }); const setUp = (paginator?: ShlinkPaginator, currentQueryString?: string) => render( - + , ); diff --git a/shlink-web-component/test/short-urls/ShortUrlForm.test.tsx b/shlink-web-component/test/short-urls/ShortUrlForm.test.tsx index 82dbb72c..51b7d4bb 100644 --- a/shlink-web-component/test/short-urls/ShortUrlForm.test.tsx +++ b/shlink-web-component/test/short-urls/ShortUrlForm.test.tsx @@ -2,25 +2,26 @@ import { screen } from '@testing-library/react'; import type { UserEvent } from '@testing-library/user-event/setup/setup'; import { fromPartial } from '@total-typescript/shoehorn'; import { formatISO } from 'date-fns'; -import type { ReachableServer, SelectedServer } from '../../../src/servers/data'; import type { OptionalString } from '../../../src/utils/utils'; import type { Mode } from '../../src/short-urls/ShortUrlForm'; import { ShortUrlForm as createShortUrlForm } from '../../src/short-urls/ShortUrlForm'; import { parseDate } from '../../src/utils/dates/helpers/date'; +import { FeaturesProvider } from '../../src/utils/features'; import { renderWithEvents } from '../__helpers__/setUpTest'; describe('', () => { const createShortUrl = vi.fn(async () => Promise.resolve()); const ShortUrlForm = createShortUrlForm(() => TagsSelector, () => DomainSelector); - const setUp = (selectedServer: SelectedServer = null, mode: Mode = 'create', title?: OptionalString) => + const setUp = (withDeviceLongUrls = false, mode: Mode = 'create', title?: OptionalString) => renderWithEvents( - , + + + , ); it.each([ @@ -29,14 +30,14 @@ describe('', () => { await user.type(screen.getByPlaceholderText('Custom slug'), 'my-slug'); }, { customSlug: 'my-slug' }, - null, + false, ], [ async (user: UserEvent) => { await user.type(screen.getByPlaceholderText('Short code length'), '15'); }, { shortCodeLength: '15' }, - null, + false, ], [ async (user: UserEvent) => { @@ -49,10 +50,10 @@ describe('', () => { ios: 'https://ios.com', }, }, - fromPartial({ version: '3.5.0' }), + true, ], - ])('saves short URL with data set in form controls', async (extraFields, extraExpectedValues, selectedServer) => { - const { user } = setUp(selectedServer); + ])('saves short URL with data set in form controls', async (extraFields, extraExpectedValues, withDeviceLongUrls) => { + const { user } = setUp(withDeviceLongUrls); const validSince = parseDate('2017-01-01', 'yyyy-MM-dd'); const validUntil = parseDate('2017-01-06', 'yyyy-MM-dd'); @@ -83,7 +84,7 @@ describe('', () => { ])( 'renders expected amount of cards based on server capabilities and mode', (mode, expectedAmountOfCards) => { - setUp(null, mode); + setUp(false, mode); const cards = screen.queryAllByRole('heading'); expect(cards).toHaveLength(expectedAmountOfCards); @@ -100,7 +101,7 @@ describe('', () => { [undefined, false, undefined], ['old title', false, null], ])('sends expected title based on original and new values', async (originalTitle, withNewTitle, expectedSentTitle) => { - const { user } = setUp(fromPartial({ version: '2.6.0' }), 'create', originalTitle); + const { user } = setUp(false, 'create', originalTitle); await user.type(screen.getByPlaceholderText('URL to be shortened'), 'https://long-domain.com/foo/bar'); await user.clear(screen.getByPlaceholderText('Title')); @@ -114,19 +115,10 @@ describe('', () => { })); }); - it.each([ - [fromPartial({ version: '3.0.0' }), false], - [fromPartial({ version: '3.4.0' }), false], - [fromPartial({ version: '3.5.0' }), true], - [fromPartial({ version: '3.6.0' }), true], - ])('shows device-specific long URLs only for servers supporting it', (selectedServer, fieldsExist) => { - setUp(selectedServer); - const placeholders = ['Android-specific redirection', 'iOS-specific redirection', 'Desktop-specific redirection']; + it('shows device-specific long URLs only when supported', () => { + setUp(true); - if (fieldsExist) { - placeholders.forEach((placeholder) => expect(screen.getByPlaceholderText(placeholder)).toBeInTheDocument()); - } else { - placeholders.forEach((placeholder) => expect(screen.queryByPlaceholderText(placeholder)).not.toBeInTheDocument()); - } + const placeholders = ['Android-specific redirection', 'iOS-specific redirection', 'Desktop-specific redirection']; + placeholders.forEach((placeholder) => expect(screen.getByPlaceholderText(placeholder)).toBeInTheDocument()); }); }); diff --git a/shlink-web-component/test/short-urls/ShortUrlsFilteringBar.test.tsx b/shlink-web-component/test/short-urls/ShortUrlsFilteringBar.test.tsx index d4137682..a01cf169 100644 --- a/shlink-web-component/test/short-urls/ShortUrlsFilteringBar.test.tsx +++ b/shlink-web-component/test/short-urls/ShortUrlsFilteringBar.test.tsx @@ -2,10 +2,12 @@ import { screen, waitFor } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { endOfDay, formatISO, startOfDay } from 'date-fns'; import { MemoryRouter, useLocation, useNavigate } from 'react-router-dom'; -import type { ReachableServer, SelectedServer } from '../../../src/servers/data'; import { ShortUrlsFilteringBar as filteringBarCreator } from '../../src/short-urls/ShortUrlsFilteringBar'; import { formatIsoDate } from '../../src/utils/dates/helpers/date'; import type { DateRange } from '../../src/utils/dates/helpers/dateIntervals'; +import { FeaturesProvider } from '../../src/utils/features'; +import { RoutesPrefixProvider } from '../../src/utils/routesPrefix'; +import { SettingsProvider } from '../../src/utils/settings'; import { renderWithEvents } from '../__helpers__/setUpTest'; vi.mock('react-router-dom', async () => ({ @@ -20,18 +22,19 @@ describe('', () => { const navigate = vi.fn(); const handleOrderBy = vi.fn(); const now = new Date(); - const setUp = (search = '', selectedServer?: SelectedServer) => { + const setUp = (search = '', filterDisabledUrls = true) => { (useLocation as any).mockReturnValue({ search }); (useNavigate as any).mockReturnValue(navigate); return renderWithEvents( - + + + + + + + , ); }; @@ -71,16 +74,14 @@ describe('', () => { }); it.each([ - ['tags=foo,bar,baz', fromPartial({ version: '3.0.0' }), true], - ['tags=foo,bar', fromPartial({ version: '3.1.0' }), true], - ['tags=foo', fromPartial({ version: '3.0.0' }), false], - ['', fromPartial({ version: '3.0.0' }), false], - ['tags=foo,bar,baz', fromPartial({ version: '2.10.0' }), false], - ['', fromPartial({ version: '2.10.0' }), false], + { search: 'tags=foo,bar,baz', shouldHaveComponent: true }, + { search: 'tags=foo,bar', shouldHaveComponent: true }, + { search: 'tags=foo', shouldHaveComponent: false }, + { search: '', shouldHaveComponent: false }, ])( - 'renders tags mode toggle if the server supports it and there is more than one tag selected', - (search, selectedServer, shouldHaveComponent) => { - setUp(search, selectedServer); + 'renders tags mode toggle if there is more than one tag selected', + ({ search, shouldHaveComponent }) => { + setUp(search); if (shouldHaveComponent) { expect(screen.getByLabelText('Change tags mode')).toBeInTheDocument(); @@ -95,7 +96,7 @@ describe('', () => { ['&tagsMode=all', 'With all the tags.'], ['&tagsMode=any', 'With any of the tags.'], ])('expected tags mode tooltip title', async (initialTagsMode, expectedToggleText) => { - const { user } = setUp(`tags=foo,bar${initialTagsMode}`, fromPartial({ version: '3.0.0' })); + const { user } = setUp(`tags=foo,bar${initialTagsMode}`, true); await user.hover(screen.getByLabelText('Change tags mode')); expect(await screen.findByRole('tooltip')).toHaveTextContent(expectedToggleText); @@ -106,7 +107,7 @@ describe('', () => { ['&tagsMode=all', 'tagsMode=any'], ['&tagsMode=any', 'tagsMode=all'], ])('redirects to first page when tags mode changes', async (initialTagsMode, expectedRedirectTagsMode) => { - const { user } = setUp(`tags=foo,bar${initialTagsMode}`, fromPartial({ version: '3.0.0' })); + const { user } = setUp(`tags=foo,bar${initialTagsMode}`, true); expect(navigate).not.toHaveBeenCalled(); await user.click(screen.getByLabelText('Change tags mode')); @@ -124,7 +125,7 @@ describe('', () => { ['excludePastValidUntil=false', /Exclude enabled in the past/, 'excludePastValidUntil=true'], ['excludePastValidUntil=true', /Exclude enabled in the past/, 'excludePastValidUntil=false'], ])('allows to toggle filters through filtering dropdown', async (search, menuItemName, expectedQuery) => { - const { user } = setUp(search, fromPartial({ version: '3.4.0' })); + const { user } = setUp(search, true); const toggleFilter = async (name: RegExp) => { await user.click(screen.getByRole('button', { name: 'Filters' })); await waitFor(() => screen.findByRole('menu')); diff --git a/shlink-web-component/test/short-urls/ShortUrlsList.test.tsx b/shlink-web-component/test/short-urls/ShortUrlsList.test.tsx index 7ef098ca..f299c6ec 100644 --- a/shlink-web-component/test/short-urls/ShortUrlsList.test.tsx +++ b/shlink-web-component/test/short-urls/ShortUrlsList.test.tsx @@ -1,13 +1,14 @@ import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter, useNavigate } from 'react-router-dom'; -import type { SemVer } from '../../../src/utils/helpers/version'; import type { Settings } from '../../src'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; import type { ShortUrlsOrder } from '../../src/short-urls/data'; import type { ShortUrlsList as ShortUrlsListModel } from '../../src/short-urls/reducers/shortUrlsList'; import { ShortUrlsList as createShortUrlsList } from '../../src/short-urls/ShortUrlsList'; import type { ShortUrlsTableType } from '../../src/short-urls/ShortUrlsTable'; +import { FeaturesProvider } from '../../src/utils/features'; +import { SettingsProvider } from '../../src/utils/settings'; import { renderWithEvents } from '../__helpers__/setUpTest'; vi.mock('react-router-dom', async () => ({ @@ -35,15 +36,17 @@ describe('', () => { }, }); const ShortUrlsList = createShortUrlsList(ShortUrlsTable, ShortUrlsFilteringBar); - const setUp = (settings: Partial = {}, version: SemVer = '3.0.0') => renderWithEvents( + const setUp = (settings: Partial = {}, excludeBotsOnShortUrls = true) => renderWithEvents( - ({ mercureInfo: { loading: true } })} - listShortUrls={listShortUrlsMock} - shortUrlsList={shortUrlsList} - selectedServer={fromPartial({ id: '1', version })} - settings={fromPartial(settings)} - /> + + + ({ mercureInfo: { loading: true } })} + listShortUrls={listShortUrlsMock} + shortUrlsList={shortUrlsList} + /> + + , ); @@ -93,26 +96,26 @@ describe('', () => { shortUrlsList: { defaultOrdering: { field: 'visits', dir: 'ASC' }, }, - }), '3.3.0' as SemVer, { field: 'visits', dir: 'ASC' }], + }), false, { field: 'visits', dir: 'ASC' }], [fromPartial({ shortUrlsList: { defaultOrdering: { field: 'visits', dir: 'ASC' }, }, visits: { excludeBots: true }, - }), '3.3.0' as SemVer, { field: 'visits', dir: 'ASC' }], + }), false, { field: 'visits', dir: 'ASC' }], [fromPartial({ shortUrlsList: { defaultOrdering: { field: 'visits', dir: 'ASC' }, }, - }), '3.4.0' as SemVer, { field: 'visits', dir: 'ASC' }], + }), true, { field: 'visits', dir: 'ASC' }], [fromPartial({ shortUrlsList: { defaultOrdering: { field: 'visits', dir: 'ASC' }, }, visits: { excludeBots: true }, - }), '3.4.0' as SemVer, { field: 'nonBotVisits', dir: 'ASC' }], - ])('parses order by based on server version and config', (settings, serverVersion, expectedOrderBy) => { - setUp(settings, serverVersion); + }), true, { field: 'nonBotVisits', dir: 'ASC' }], + ])('parses order by based on supported features version and config', (settings, excludeBotsOnShortUrls, expectedOrderBy) => { + setUp(settings, excludeBotsOnShortUrls); expect(listShortUrlsMock).toHaveBeenCalledWith(expect.objectContaining({ orderBy: expectedOrderBy })); }); }); diff --git a/shlink-web-component/test/short-urls/ShortUrlsTable.test.tsx b/shlink-web-component/test/short-urls/ShortUrlsTable.test.tsx index 9676a643..7fc32db0 100644 --- a/shlink-web-component/test/short-urls/ShortUrlsTable.test.tsx +++ b/shlink-web-component/test/short-urls/ShortUrlsTable.test.tsx @@ -1,6 +1,5 @@ import { fireEvent, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { SelectedServer } from '../../../src/servers/data'; import type { ShortUrlsOrderableFields } from '../../src/short-urls/data'; import { SHORT_URLS_ORDERABLE_FIELDS } from '../../src/short-urls/data'; import type { ShortUrlsList } from '../../src/short-urls/reducers/shortUrlsList'; @@ -11,8 +10,8 @@ describe('', () => { const shortUrlsList = fromPartial({}); const orderByColumn = vi.fn(); const ShortUrlsTable = shortUrlsTableCreator(() => ShortUrlsRow); - const setUp = (server: SelectedServer = null) => renderWithEvents( - orderByColumn} />, + const setUp = () => renderWithEvents( + orderByColumn} />, ); it('should render inner table by default', () => { @@ -54,7 +53,7 @@ describe('', () => { }); it('should render composed title column', () => { - setUp(fromPartial({ version: '2.0.0' })); + setUp(); const { innerHTML } = screen.getAllByRole('columnheader')[2]; diff --git a/shlink-web-component/test/short-urls/helpers/ExportShortUrlsBtn.test.tsx b/shlink-web-component/test/short-urls/helpers/ExportShortUrlsBtn.test.tsx index 9c9e692b..cf7956d0 100644 --- a/shlink-web-component/test/short-urls/helpers/ExportShortUrlsBtn.test.tsx +++ b/shlink-web-component/test/short-urls/helpers/ExportShortUrlsBtn.test.tsx @@ -1,7 +1,6 @@ import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; -import type { NotFoundServer, SelectedServer } from '../../../../src/servers/data'; import type { ShortUrl } from '../../../src/short-urls/data'; import { ExportShortUrlsBtn as createExportShortUrlsBtn } from '../../../src/short-urls/helpers/ExportShortUrlsBtn'; import type { ReportExporter } from '../../../src/utils/services/ReportExporter'; @@ -13,9 +12,9 @@ describe('', () => { const exportShortUrls = vi.fn(); const reportExporter = fromPartial({ exportShortUrls }); const ExportShortUrlsBtn = createExportShortUrlsBtn(buildShlinkApiClient, reportExporter); - const setUp = (amount?: number, selectedServer?: SelectedServer) => renderWithEvents( + const setUp = (amount?: number) => renderWithEvents( - + , ); @@ -28,17 +27,6 @@ describe('', () => { expect(screen.getByText(/Export/)).toHaveTextContent(`Export (${expectedAmount})`); }); - it.each([ - [null], - [fromPartial({})], - ])('does nothing on click if selected server is not reachable', async (selectedServer) => { - const { user } = setUp(0, selectedServer); - - await user.click(screen.getByRole('button')); - expect(listShortUrls).not.toHaveBeenCalled(); - expect(exportShortUrls).not.toHaveBeenCalled(); - }); - it.each([ [10, 1], [30, 2], @@ -48,7 +36,7 @@ describe('', () => { [385, 20], ])('loads proper amount of pages based on the amount of results', async (amount, expectedPageLoads) => { listShortUrls.mockResolvedValue({ data: [] }); - const { user } = setUp(amount, fromPartial({ id: '123' })); + const { user } = setUp(amount); await user.click(screen.getByRole('button')); @@ -63,7 +51,7 @@ describe('', () => { tags: [], })], }); - const { user } = setUp(undefined, fromPartial({ id: '123' })); + const { user } = setUp(); await user.click(screen.getByRole('button')); diff --git a/shlink-web-component/test/short-urls/helpers/QrCodeModal.test.tsx b/shlink-web-component/test/short-urls/helpers/QrCodeModal.test.tsx index bda32c22..2e54ba47 100644 --- a/shlink-web-component/test/short-urls/helpers/QrCodeModal.test.tsx +++ b/shlink-web-component/test/short-urls/helpers/QrCodeModal.test.tsx @@ -1,6 +1,5 @@ import { fireEvent, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { SemVer } from '../../../../src/utils/helpers/version'; import { QrCodeModal as createQrCodeModal } from '../../../src/short-urls/helpers/QrCodeModal'; import { renderWithEvents } from '../../__helpers__/setUpTest'; @@ -8,11 +7,10 @@ describe('', () => { const saveImage = vi.fn().mockReturnValue(Promise.resolve()); const QrCodeModal = createQrCodeModal(fromPartial({ saveImage })); const shortUrl = 'https://s.test/abc123'; - const setUp = (version: SemVer = '2.8.0') => renderWithEvents( + const setUp = () => renderWithEvents( {}} />, ); @@ -63,16 +61,14 @@ describe('', () => { }); it('shows expected components based on server version', () => { - const { container } = setUp(); + setUp(); const dropdowns = screen.getAllByRole('button'); - const firstCol = container.parentNode?.querySelectorAll('.d-grid').item(0); - expect(dropdowns).toHaveLength(2 + 1); // Add one because of the close button - expect(firstCol).toHaveClass('col-md-4'); + expect(dropdowns).toHaveLength(2 + 2); // Add two because of the close and download buttons }); it('saves the QR code image when clicking the Download button', async () => { - const { user } = setUp('2.9.0'); + const { user } = setUp(); expect(saveImage).not.toHaveBeenCalled(); await user.click(screen.getByRole('button', { name: /^Download/ })); diff --git a/shlink-web-component/test/short-urls/helpers/ShortUrlDetailLink.test.tsx b/shlink-web-component/test/short-urls/helpers/ShortUrlDetailLink.test.tsx index 5b2a37c7..bf4fac57 100644 --- a/shlink-web-component/test/short-urls/helpers/ShortUrlDetailLink.test.tsx +++ b/shlink-web-component/test/short-urls/helpers/ShortUrlDetailLink.test.tsx @@ -1,23 +1,22 @@ import { render, screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; -import type { NotFoundServer, ReachableServer } from '../../../../src/servers/data'; import type { ShortUrl } from '../../../src/short-urls/data'; import type { LinkSuffix } from '../../../src/short-urls/helpers/ShortUrlDetailLink'; import { ShortUrlDetailLink } from '../../../src/short-urls/helpers/ShortUrlDetailLink'; +import { RoutesPrefixProvider } from '../../../src/utils/routesPrefix'; describe('', () => { it.each([ - [undefined, undefined], - [null, null], - [fromPartial({ id: '1' }), null], - [fromPartial({ id: '1' }), undefined], - [fromPartial({}), fromPartial({})], - [null, fromPartial({})], - [undefined, fromPartial({})], - ])('only renders a plain span when either server or short URL are not set', (selectedServer, shortUrl) => { + [false, undefined], + [false, null], + [true, null], + [true, undefined], + [false, fromPartial({})], + [false, fromPartial({})], + ])('only renders a plain span when either server or short URL are not set', (asLink, shortUrl) => { render( - + Something , ); @@ -28,35 +27,37 @@ describe('', () => { it.each([ [ - fromPartial({ id: '1' }), + '/server/1', fromPartial({ shortCode: 'abc123' }), 'visits' as LinkSuffix, '/server/1/short-code/abc123/visits', ], [ - fromPartial({ id: '3' }), + '/foobar', fromPartial({ shortCode: 'def456', domain: 'example.com' }), 'visits' as LinkSuffix, - '/server/3/short-code/def456/visits?domain=example.com', + '/foobar/short-code/def456/visits?domain=example.com', ], [ - fromPartial({ id: '1' }), + '/server/1', fromPartial({ shortCode: 'abc123' }), 'edit' as LinkSuffix, '/server/1/short-code/abc123/edit', ], [ - fromPartial({ id: '3' }), + '/server/3', fromPartial({ shortCode: 'def456', domain: 'example.com' }), 'edit' as LinkSuffix, '/server/3/short-code/def456/edit?domain=example.com', ], - ])('renders link with expected query when', (selectedServer, shortUrl, suffix, expectedLink) => { + ])('renders link with expected query when', (routesPrefix, shortUrl, suffix, expectedLink) => { render( - - Something - + + + Something + + , ); expect(screen.getByRole('link')).toHaveProperty('href', expect.stringContaining(expectedLink)); diff --git a/shlink-web-component/test/short-urls/helpers/ShortUrlStatus.test.tsx b/shlink-web-component/test/short-urls/helpers/ShortUrlStatus.test.tsx index 7755bfc8..b87d2446 100644 --- a/shlink-web-component/test/short-urls/helpers/ShortUrlStatus.test.tsx +++ b/shlink-web-component/test/short-urls/helpers/ShortUrlStatus.test.tsx @@ -1,7 +1,7 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkVisitsSummary } from '../../../src/api/types'; +import type { ShlinkVisitsSummary } from '../../../src/api-contract'; import type { ShortUrl, ShortUrlMeta } from '../../../src/short-urls/data'; import { ShortUrlStatus } from '../../../src/short-urls/helpers/ShortUrlStatus'; diff --git a/shlink-web-component/test/short-urls/helpers/ShortUrlsRow.test.tsx b/shlink-web-component/test/short-urls/helpers/ShortUrlsRow.test.tsx index 6ec8db84..080082fa 100644 --- a/shlink-web-component/test/short-urls/helpers/ShortUrlsRow.test.tsx +++ b/shlink-web-component/test/short-urls/helpers/ShortUrlsRow.test.tsx @@ -3,18 +3,17 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { addDays, formatISO, subDays } from 'date-fns'; import { last } from 'ramda'; import { MemoryRouter, useLocation } from 'react-router-dom'; -import type { ReachableServer } from '../../../../src/servers/data'; -import type { TimeoutToggle } from '../../../../src/utils/helpers/hooks'; -import type { OptionalString } from '../../../../src/utils/utils'; import type { Settings } from '../../../src'; import type { ShortUrl, ShortUrlMeta } from '../../../src/short-urls/data'; import { ShortUrlsRow as createShortUrlsRow } from '../../../src/short-urls/helpers/ShortUrlsRow'; import { now, parseDate } from '../../../src/utils/dates/helpers/date'; +import type { TimeoutToggle } from '../../../src/utils/helpers/hooks'; +import { SettingsProvider } from '../../../src/utils/settings'; import { renderWithEvents } from '../../__helpers__/setUpTest'; import { colorGeneratorMock } from '../../utils/services/__mocks__/ColorGenerator.mock'; interface SetUpOptions { - title?: OptionalString; + title?: string | null; tags?: string[]; meta?: ShortUrlMeta; settings?: Partial; @@ -28,7 +27,6 @@ vi.mock('react-router-dom', async () => ({ describe('', () => { const timeoutToggle = vi.fn(() => true); const useTimeoutToggle = vi.fn(() => [false, timeoutToggle]) as TimeoutToggle; - const server = fromPartial({ url: 'https://s.test' }); const shortUrl: ShortUrl = { shortCode: 'abc123', shortUrl: 'https://s.test/abc123', @@ -54,16 +52,16 @@ describe('', () => { (useLocation as any).mockReturnValue({ search }); return renderWithEvents( - - - null} - settings={fromPartial(settings)} - /> - -
+ + + + null} + /> + +
+
, ); }; diff --git a/shlink-web-component/test/short-urls/helpers/ShortUrlsRowMenu.test.tsx b/shlink-web-component/test/short-urls/helpers/ShortUrlsRowMenu.test.tsx index c11dc46c..84b60a55 100644 --- a/shlink-web-component/test/short-urls/helpers/ShortUrlsRowMenu.test.tsx +++ b/shlink-web-component/test/short-urls/helpers/ShortUrlsRowMenu.test.tsx @@ -1,21 +1,19 @@ import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; -import type { ReachableServer } from '../../../../src/servers/data'; import type { ShortUrl } from '../../../src/short-urls/data'; import { ShortUrlsRowMenu as createShortUrlsRowMenu } from '../../../src/short-urls/helpers/ShortUrlsRowMenu'; import { renderWithEvents } from '../../__helpers__/setUpTest'; describe('', () => { const ShortUrlsRowMenu = createShortUrlsRowMenu(() => DeleteShortUrlModal, () => QrCodeModal); - const selectedServer = fromPartial({ id: 'abc123' }); const shortUrl = fromPartial({ shortCode: 'abc123', shortUrl: 'https://s.test/abc123', }); const setUp = () => renderWithEvents( - + , ); diff --git a/shlink-web-component/test/short-urls/reducers/shortUrlCreation.test.ts b/shlink-web-component/test/short-urls/reducers/shortUrlCreation.test.ts index 1db2102f..460f80eb 100644 --- a/shlink-web-component/test/short-urls/reducers/shortUrlCreation.test.ts +++ b/shlink-web-component/test/short-urls/reducers/shortUrlCreation.test.ts @@ -1,6 +1,5 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; +import type { ShlinkApiClient } from '../../../src/api-contract'; import type { ShortUrl } from '../../../src/short-urls/data'; import { createShortUrl as createShortUrlCreator, @@ -51,11 +50,10 @@ describe('shortUrlCreationReducer', () => { describe('createShortUrl', () => { const dispatch = vi.fn(); - const getState = () => fromPartial({}); it('calls API on success', async () => { createShortUrlCall.mockResolvedValue(shortUrl); - await createShortUrl({ longUrl: 'foo' })(dispatch, getState, {}); + await createShortUrl({ longUrl: 'foo' })(dispatch, vi.fn(), {}); expect(createShortUrlCall).toHaveBeenCalledTimes(1); expect(dispatch).toHaveBeenCalledTimes(2); diff --git a/shlink-web-component/test/short-urls/reducers/shortUrlDeletion.test.ts b/shlink-web-component/test/short-urls/reducers/shortUrlDeletion.test.ts index faf12a55..4762118c 100644 --- a/shlink-web-component/test/short-urls/reducers/shortUrlDeletion.test.ts +++ b/shlink-web-component/test/short-urls/reducers/shortUrlDeletion.test.ts @@ -1,6 +1,6 @@ import { fromPartial } from '@total-typescript/shoehorn'; import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ProblemDetailsError } from '../../../src/api/types/errors'; +import type { ProblemDetailsError } from '../../../src/api-contract'; import { deleteShortUrl as deleteShortUrlCreator, shortUrlDeletionReducerCreator, diff --git a/shlink-web-component/test/short-urls/reducers/shortUrlDetail.test.ts b/shlink-web-component/test/short-urls/reducers/shortUrlDetail.test.ts index c4f1caeb..7d870f4b 100644 --- a/shlink-web-component/test/short-urls/reducers/shortUrlDetail.test.ts +++ b/shlink-web-component/test/short-urls/reducers/shortUrlDetail.test.ts @@ -1,6 +1,6 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; +import type { ShlinkApiClient } from '../../../src/api-contract'; +import type { RootState } from '../../../src/container/store'; import type { ShortUrl } from '../../../src/short-urls/data'; import { shortUrlDetailReducerCreator } from '../../../src/short-urls/reducers/shortUrlDetail'; import type { ShortUrlsList } from '../../../src/short-urls/reducers/shortUrlsList'; @@ -40,7 +40,7 @@ describe('shortUrlDetailReducer', () => { describe('getShortUrlDetail', () => { const dispatchMock = vi.fn(); - const buildGetState = (shortUrlsList?: ShortUrlsList) => () => fromPartial({ shortUrlsList }); + const buildGetState = (shortUrlsList?: ShortUrlsList) => () => fromPartial({ shortUrlsList }); it.each([ [undefined], diff --git a/shlink-web-component/test/short-urls/reducers/shortUrlEdition.test.ts b/shlink-web-component/test/short-urls/reducers/shortUrlEdition.test.ts index 259189ea..9a0b22c2 100644 --- a/shlink-web-component/test/short-urls/reducers/shortUrlEdition.test.ts +++ b/shlink-web-component/test/short-urls/reducers/shortUrlEdition.test.ts @@ -1,6 +1,4 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkState } from '../../../../src/container/types'; -import type { SelectedServer } from '../../../../src/servers/data'; import type { ShortUrl } from '../../../src/short-urls/data'; import { editShortUrl as editShortUrlCreator, @@ -45,12 +43,9 @@ describe('shortUrlEditionReducer', () => { describe('editShortUrl', () => { const dispatch = vi.fn(); - const createGetState = (selectedServer: SelectedServer = null) => () => fromPartial({ - selectedServer, - }); it.each([[undefined], [null], ['example.com']])('dispatches short URL on success', async (domain) => { - await editShortUrl({ shortCode, domain, data: { longUrl } })(dispatch, createGetState(), {}); + await editShortUrl({ shortCode, domain, data: { longUrl } })(dispatch, vi.fn(), {}); expect(buildShlinkApiClient).toHaveBeenCalledTimes(1); expect(updateShortUrl).toHaveBeenCalledTimes(1); diff --git a/shlink-web-component/test/short-urls/reducers/shortUrlsList.test.ts b/shlink-web-component/test/short-urls/reducers/shortUrlsList.test.ts index 6e79ccc0..a8bb7108 100644 --- a/shlink-web-component/test/short-urls/reducers/shortUrlsList.test.ts +++ b/shlink-web-component/test/short-urls/reducers/shortUrlsList.test.ts @@ -1,6 +1,5 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkShortUrlsResponse } from '../../../src/api/types'; +import type { ShlinkApiClient, ShlinkShortUrlsResponse } from '../../../src/api-contract'; import type { ShortUrl } from '../../../src/short-urls/data'; import { createShortUrl as createShortUrlCreator } from '../../../src/short-urls/reducers/shortUrlCreation'; import { shortUrlDeleted } from '../../../src/short-urls/reducers/shortUrlDeletion'; @@ -187,7 +186,7 @@ describe('shortUrlsListReducer', () => { describe('listShortUrls', () => { const dispatch = vi.fn(); - const getState = vi.fn().mockReturnValue({ selectedServer: {} }); + const getState = vi.fn(); it('dispatches proper actions if API client request succeeds', async () => { listShortUrlsMock.mockResolvedValue({}); diff --git a/shlink-web-component/test/tags/TagsList.test.tsx b/shlink-web-component/test/tags/TagsList.test.tsx index d53e52d4..0f7271d5 100644 --- a/shlink-web-component/test/tags/TagsList.test.tsx +++ b/shlink-web-component/test/tags/TagsList.test.tsx @@ -5,20 +5,22 @@ import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercure import type { TagsList } from '../../src/tags/reducers/tagsList'; import type { TagsListProps } from '../../src/tags/TagsList'; import { TagsList as createTagsList } from '../../src/tags/TagsList'; +import { SettingsProvider } from '../../src/utils/settings'; import { renderWithEvents } from '../__helpers__/setUpTest'; describe('', () => { const filterTags = vi.fn(); const TagsListComp = createTagsList(({ sortedTags }) => <>TagsTable ({sortedTags.map((t) => t.visits).join(',')})); const setUp = (tagsList: Partial, excludeBots = false) => renderWithEvents( - ({})} - {...fromPartial({ mercureInfo: {} })} - forceListTags={identity} - filterTags={filterTags} - tagsList={fromPartial(tagsList)} - settings={fromPartial({ visits: { excludeBots } })} - />, + + ({})} + {...fromPartial({ mercureInfo: {} })} + forceListTags={identity} + filterTags={filterTags} + tagsList={fromPartial(tagsList)} + /> + , ); it('shows a loading message when tags are being loaded', () => { diff --git a/shlink-web-component/test/tags/TagsTable.test.tsx b/shlink-web-component/test/tags/TagsTable.test.tsx index b7a1350e..12894b98 100644 --- a/shlink-web-component/test/tags/TagsTable.test.tsx +++ b/shlink-web-component/test/tags/TagsTable.test.tsx @@ -19,7 +19,6 @@ describe('', () => { return renderWithEvents( fromPartial({ tag }))} - selectedServer={fromPartial({})} currentOrder={{}} orderByColumn={() => orderByColumn} />, diff --git a/shlink-web-component/test/tags/TagsTableRow.test.tsx b/shlink-web-component/test/tags/TagsTableRow.test.tsx index ec2c4e8a..f0fb3927 100644 --- a/shlink-web-component/test/tags/TagsTableRow.test.tsx +++ b/shlink-web-component/test/tags/TagsTableRow.test.tsx @@ -1,7 +1,7 @@ import { screen } from '@testing-library/react'; -import { fromPartial } from '@total-typescript/shoehorn'; import { MemoryRouter } from 'react-router-dom'; import { TagsTableRow as createTagsTableRow } from '../../src/tags/TagsTableRow'; +import { RoutesPrefixProvider } from '../../src/utils/routesPrefix'; import { renderWithEvents } from '../__helpers__/setUpTest'; import { colorGeneratorMock } from '../utils/services/__mocks__/ColorGenerator.mock'; @@ -13,14 +13,15 @@ describe('', () => { ); const setUp = (tagStats?: { visits?: number; shortUrls?: number }) => renderWithEvents( - - - - -
+ + + + + +
+
, ); diff --git a/shlink-web-component/test/tags/helpers/TagsSelector.test.tsx b/shlink-web-component/test/tags/helpers/TagsSelector.test.tsx index 08bb3058..29de7d5c 100644 --- a/shlink-web-component/test/tags/helpers/TagsSelector.test.tsx +++ b/shlink-web-component/test/tags/helpers/TagsSelector.test.tsx @@ -2,6 +2,7 @@ import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { TagsSelector as createTagsSelector } from '../../../src/tags/helpers/TagsSelector'; import type { TagsList } from '../../../src/tags/reducers/tagsList'; +import { SettingsProvider } from '../../../src/utils/settings'; import { renderWithEvents } from '../../__helpers__/setUpTest'; import { colorGeneratorMock } from '../../utils/services/__mocks__/ColorGenerator.mock'; @@ -11,13 +12,14 @@ describe('', () => { const tags = ['foo', 'bar']; const tagsList = fromPartial({ tags: [...tags, 'baz'] }); const setUp = () => renderWithEvents( - , + + + , ); it('has an input for tags', () => { diff --git a/shlink-web-component/test/tags/reducers/tagDelete.test.ts b/shlink-web-component/test/tags/reducers/tagDelete.test.ts index c0d7a5b2..59a4fb14 100644 --- a/shlink-web-component/test/tags/reducers/tagDelete.test.ts +++ b/shlink-web-component/test/tags/reducers/tagDelete.test.ts @@ -1,6 +1,5 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; +import type { ShlinkApiClient } from '../../../src/api-contract'; import { tagDeleted, tagDeleteReducerCreator } from '../../../src/tags/reducers/tagDelete'; describe('tagDeleteReducer', () => { @@ -42,13 +41,12 @@ describe('tagDeleteReducer', () => { describe('deleteTag', () => { const dispatch = vi.fn(); - const getState = () => fromPartial({}); it('calls API on success', async () => { const tag = 'foo'; deleteTagsCall.mockResolvedValue(undefined); - await deleteTag(tag)(dispatch, getState, {}); + await deleteTag(tag)(dispatch, vi.fn(), {}); expect(deleteTagsCall).toHaveBeenCalledTimes(1); expect(deleteTagsCall).toHaveBeenNthCalledWith(1, [tag]); diff --git a/shlink-web-component/test/tags/reducers/tagEdit.test.ts b/shlink-web-component/test/tags/reducers/tagEdit.test.ts index d0056114..cd61f9df 100644 --- a/shlink-web-component/test/tags/reducers/tagEdit.test.ts +++ b/shlink-web-component/test/tags/reducers/tagEdit.test.ts @@ -1,6 +1,5 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; +import type { ShlinkApiClient } from '../../../src/api-contract'; import { editTag as editTagCreator, tagEdited, tagEditReducerCreator } from '../../../src/tags/reducers/tagEdit'; import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; @@ -51,12 +50,11 @@ describe('tagEditReducer', () => { describe('editTag', () => { const dispatch = vi.fn(); - const getState = () => fromPartial({}); it('calls API on success', async () => { editTagCall.mockResolvedValue(undefined); - await editTag({ oldName, newName, color })(dispatch, getState, {}); + await editTag({ oldName, newName, color })(dispatch, vi.fn(), {}); expect(editTagCall).toHaveBeenCalledTimes(1); expect(editTagCall).toHaveBeenCalledWith(oldName, newName); diff --git a/shlink-web-component/test/tags/reducers/tagsList.test.ts b/shlink-web-component/test/tags/reducers/tagsList.test.ts index 276a7366..f7d45a76 100644 --- a/shlink-web-component/test/tags/reducers/tagsList.test.ts +++ b/shlink-web-component/test/tags/reducers/tagsList.test.ts @@ -1,5 +1,5 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkState } from '../../../../src/container/types'; +import type { RootState } from '../../../src/container/store'; import type { ShortUrl } from '../../../src/short-urls/data'; import { createShortUrl as createShortUrlCreator } from '../../../src/short-urls/reducers/shortUrlCreation'; import { tagDeleted } from '../../../src/tags/reducers/tagDelete'; @@ -195,11 +195,11 @@ describe('tagsListReducer', () => { describe('listTags', () => { const dispatch = vi.fn(); - const getState = vi.fn(() => fromPartial({})); + const getState = vi.fn(() => fromPartial({})); const listTagsMock = vi.fn(); const assertNoAction = async (tagsList: TagsList) => { - getState.mockReturnValue(fromPartial({ tagsList })); + getState.mockReturnValue(fromPartial({ tagsList })); await listTagsCreator(buildShlinkApiClient, false)()(dispatch, getState, {}); @@ -218,7 +218,7 @@ describe('tagsListReducer', () => { const tags = ['foo', 'bar', 'baz']; listTagsMock.mockResolvedValue({ tags, stats: [] }); - buildShlinkApiClient.mockReturnValue({ listTags: listTagsMock }); + buildShlinkApiClient.mockReturnValue({ tagsStats: listTagsMock }); await listTags()(dispatch, getState, {}); diff --git a/shlink-web-component/test/utils/dates/helpers/date.test.ts b/shlink-web-component/test/utils/dates/helpers/date.test.ts index 64122aea..a9e9c4ae 100644 --- a/shlink-web-component/test/utils/dates/helpers/date.test.ts +++ b/shlink-web-component/test/utils/dates/helpers/date.test.ts @@ -1,23 +1,9 @@ import { addDays, formatISO, subDays } from 'date-fns'; -import { formatDate, formatIsoDate, isBeforeOrEqual, isBetween, parseDate } from '../../../../src/utils/dates/helpers/date'; +import { formatIsoDate, isBeforeOrEqual, isBetween, parseDate } from '../../../../src/utils/dates/helpers/date'; describe('date', () => { const now = new Date(); - describe('formatDate', () => { - it.each([ - [parseDate('2020-03-05 10:00:10', 'yyyy-MM-dd HH:mm:ss'), 'dd/MM/yyyy', '05/03/2020'], - [parseDate('2020-03-05 10:00:10', 'yyyy-MM-dd HH:mm:ss'), 'yyyy-MM', '2020-03'], - [parseDate('2020-03-05 10:00:10', 'yyyy-MM-dd HH:mm:ss'), undefined, '2020-03-05'], - ['2020-03-05 10:00:10', 'dd-MM-yyyy', '2020-03-05 10:00:10'], - ['2020-03-05 10:00:10', undefined, '2020-03-05 10:00:10'], - [undefined, undefined, undefined], - [null, undefined, null], - ])('formats date as expected', (date, format, expected) => { - expect(formatDate(format)(date)).toEqual(expected); - }); - }); - describe('formatIsoDate', () => { it.each([ [ diff --git a/shlink-web-component/test/utils/services/ColorGenerator.test.ts b/shlink-web-component/test/utils/services/ColorGenerator.test.ts index 700b2d30..43027b87 100644 --- a/shlink-web-component/test/utils/services/ColorGenerator.test.ts +++ b/shlink-web-component/test/utils/services/ColorGenerator.test.ts @@ -1,7 +1,7 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { LocalStorage } from '../../../../src/utils/services/LocalStorage'; import { MAIN_COLOR } from '../../../../src/utils/theme'; import { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; +import type { LocalStorage } from '../../../src/utils/services/LocalStorage'; describe('ColorGenerator', () => { let colorGenerator: ColorGenerator; diff --git a/shlink-web-component/test/utils/table/TableOrderIcon.test.tsx b/shlink-web-component/test/utils/table/TableOrderIcon.test.tsx index 9da07451..f9179927 100644 --- a/shlink-web-component/test/utils/table/TableOrderIcon.test.tsx +++ b/shlink-web-component/test/utils/table/TableOrderIcon.test.tsx @@ -1,5 +1,5 @@ import { render } from '@testing-library/react'; -import type { OrderDir } from '../../../../shlink-frontend-kit/src/ordering/ordering'; +import type { OrderDir } from '../../../../shlink-frontend-kit/src'; import { TableOrderIcon } from '../../../src/utils/table/TableOrderIcon'; describe('', () => { diff --git a/shlink-web-component/test/visits/DomainVisits.test.tsx b/shlink-web-component/test/visits/DomainVisits.test.tsx index b87f29d6..50cc6c81 100644 --- a/shlink-web-component/test/visits/DomainVisits.test.tsx +++ b/shlink-web-component/test/visits/DomainVisits.test.tsx @@ -3,6 +3,7 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { formatISO } from 'date-fns'; import { MemoryRouter } from 'react-router-dom'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; +import { SettingsProvider } from '../../src/utils/settings'; import { DomainVisits as createDomainVisits } from '../../src/visits/DomainVisits'; import type { DomainVisits } from '../../src/visits/reducers/domainVisits'; import { renderWithEvents } from '../__helpers__/setUpTest'; @@ -20,13 +21,14 @@ describe('', () => { const DomainVisits = createDomainVisits(fromPartial({ exportVisits })); const setUp = () => renderWithEvents( - ({ mercureInfo: {} })} - getDomainVisits={getDomainVisits} - cancelGetDomainVisits={cancelGetDomainVisits} - domainVisits={domainVisits} - settings={fromPartial({})} - /> + + ({ mercureInfo: {} })} + getDomainVisits={getDomainVisits} + cancelGetDomainVisits={cancelGetDomainVisits} + domainVisits={domainVisits} + /> + , ); diff --git a/shlink-web-component/test/visits/NonOrphanVisits.test.tsx b/shlink-web-component/test/visits/NonOrphanVisits.test.tsx index fb024b52..4a51b5fd 100644 --- a/shlink-web-component/test/visits/NonOrphanVisits.test.tsx +++ b/shlink-web-component/test/visits/NonOrphanVisits.test.tsx @@ -3,6 +3,7 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { formatISO } from 'date-fns'; import { MemoryRouter } from 'react-router-dom'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; +import { SettingsProvider } from '../../src/utils/settings'; import { NonOrphanVisits as createNonOrphanVisits } from '../../src/visits/NonOrphanVisits'; import type { VisitsInfo } from '../../src/visits/reducers/types'; import { renderWithEvents } from '../__helpers__/setUpTest'; @@ -15,13 +16,14 @@ describe('', () => { const NonOrphanVisits = createNonOrphanVisits(fromPartial({ exportVisits })); const setUp = () => renderWithEvents( - ({ mercureInfo: {} })} - getNonOrphanVisits={getNonOrphanVisits} - cancelGetNonOrphanVisits={cancelGetNonOrphanVisits} - nonOrphanVisits={nonOrphanVisits} - settings={fromPartial({})} - /> + + ({ mercureInfo: {} })} + getNonOrphanVisits={getNonOrphanVisits} + cancelGetNonOrphanVisits={cancelGetNonOrphanVisits} + nonOrphanVisits={nonOrphanVisits} + /> + , ); diff --git a/shlink-web-component/test/visits/OrphanVisits.test.tsx b/shlink-web-component/test/visits/OrphanVisits.test.tsx index 53bad336..6b9903a1 100644 --- a/shlink-web-component/test/visits/OrphanVisits.test.tsx +++ b/shlink-web-component/test/visits/OrphanVisits.test.tsx @@ -3,6 +3,7 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { formatISO } from 'date-fns'; import { MemoryRouter } from 'react-router-dom'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; +import { SettingsProvider } from '../../src/utils/settings'; import { OrphanVisits as createOrphanVisits } from '../../src/visits/OrphanVisits'; import type { VisitsInfo } from '../../src/visits/reducers/types'; import { renderWithEvents } from '../__helpers__/setUpTest'; @@ -14,13 +15,14 @@ describe('', () => { const OrphanVisits = createOrphanVisits(fromPartial({ exportVisits })); const setUp = () => renderWithEvents( - ({ mercureInfo: {} })} - getOrphanVisits={getOrphanVisits} - orphanVisits={orphanVisits} - cancelGetOrphanVisits={vi.fn()} - settings={fromPartial({})} - /> + + ({ mercureInfo: {} })} + getOrphanVisits={getOrphanVisits} + orphanVisits={orphanVisits} + cancelGetOrphanVisits={vi.fn()} + /> + , ); diff --git a/shlink-web-component/test/visits/ShortUrlVisits.test.tsx b/shlink-web-component/test/visits/ShortUrlVisits.test.tsx index cf6014a9..5569c976 100644 --- a/shlink-web-component/test/visits/ShortUrlVisits.test.tsx +++ b/shlink-web-component/test/visits/ShortUrlVisits.test.tsx @@ -4,6 +4,7 @@ import { formatISO } from 'date-fns'; import { identity } from 'ramda'; import { MemoryRouter } from 'react-router-dom'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; +import { SettingsProvider } from '../../src/utils/settings'; import type { ShortUrlVisits as ShortUrlVisitsState } from '../../src/visits/reducers/shortUrlVisits'; import type { ShortUrlVisitsProps } from '../../src/visits/ShortUrlVisits'; import { ShortUrlVisits as createShortUrlVisits } from '../../src/visits/ShortUrlVisits'; @@ -16,16 +17,17 @@ describe('', () => { const ShortUrlVisits = createShortUrlVisits(fromPartial({ exportVisits })); const setUp = () => renderWithEvents( - ({})} - {...fromPartial({ mercureInfo: {} })} - getShortUrlDetail={identity} - getShortUrlVisits={getShortUrlVisitsMock} - shortUrlVisits={shortUrlVisits} - shortUrlDetail={fromPartial({})} - settings={fromPartial({})} - cancelGetShortUrlVisits={() => {}} - /> + + ({})} + {...fromPartial({ mercureInfo: {} })} + getShortUrlDetail={identity} + getShortUrlVisits={getShortUrlVisitsMock} + shortUrlVisits={shortUrlVisits} + shortUrlDetail={fromPartial({})} + cancelGetShortUrlVisits={() => {}} + /> + , ); diff --git a/shlink-web-component/test/visits/TagVisits.test.tsx b/shlink-web-component/test/visits/TagVisits.test.tsx index 72b28df3..4c1a7a60 100644 --- a/shlink-web-component/test/visits/TagVisits.test.tsx +++ b/shlink-web-component/test/visits/TagVisits.test.tsx @@ -3,6 +3,7 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { formatISO } from 'date-fns'; import { MemoryRouter } from 'react-router'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; +import { SettingsProvider } from '../../src/utils/settings'; import type { TagVisits as TagVisitsStats } from '../../src/visits/reducers/tagVisits'; import type { TagVisitsProps } from '../../src/visits/TagVisits'; import { TagVisits as createTagVisits } from '../../src/visits/TagVisits'; @@ -23,14 +24,15 @@ describe('', () => { ); const setUp = () => renderWithEvents( - ({})} - {...fromPartial({ mercureInfo: {} })} - getTagVisits={getTagVisitsMock} - tagVisits={tagVisits} - settings={fromPartial({})} - cancelGetTagVisits={() => {}} - /> + + ({})} + {...fromPartial({ mercureInfo: {} })} + getTagVisits={getTagVisitsMock} + tagVisits={tagVisits} + cancelGetTagVisits={() => {}} + /> + , ); diff --git a/shlink-web-component/test/visits/VisitsStats.test.tsx b/shlink-web-component/test/visits/VisitsStats.test.tsx index 044b856d..6d094597 100644 --- a/shlink-web-component/test/visits/VisitsStats.test.tsx +++ b/shlink-web-component/test/visits/VisitsStats.test.tsx @@ -3,6 +3,7 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { createMemoryHistory } from 'history'; import { Router } from 'react-router-dom'; import { rangeOf } from '../../src/utils/helpers'; +import { SettingsProvider } from '../../src/utils/settings'; import type { VisitsInfo } from '../../src/visits/reducers/types'; import type { Visit } from '../../src/visits/types'; import { VisitsStats } from '../../src/visits/VisitsStats'; @@ -20,13 +21,14 @@ describe('', () => { history, ...renderWithEvents( - {}} - settings={fromPartial({})} - exportCsv={exportCsv} - /> + + {}} + exportCsv={exportCsv} + /> + , ), }; diff --git a/shlink-web-component/test/visits/reducers/domainVisits.test.ts b/shlink-web-component/test/visits/reducers/domainVisits.test.ts index 7b12c6e6..7942078b 100644 --- a/shlink-web-component/test/visits/reducers/domainVisits.test.ts +++ b/shlink-web-component/test/visits/reducers/domainVisits.test.ts @@ -1,9 +1,8 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { addDays, formatISO, subDays } from 'date-fns'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; import { rangeOf } from '../../../../src/utils/utils'; -import type { ShlinkVisits } from '../../../src/api/types'; +import type { ShlinkApiClient, ShlinkVisits } from '../../../src/api-contract'; +import type { RootState } from '../../../src/container/store'; import type { ShortUrl } from '../../../src/short-urls/data'; import { formatIsoDate } from '../../../src/utils/dates/helpers/date'; import type { DateInterval } from '../../../src/utils/dates/helpers/dateIntervals'; @@ -151,7 +150,7 @@ describe('domainVisitsReducer', () => { describe('getDomainVisits', () => { const dispatchMock = vi.fn(); - const getState = () => fromPartial({ + const getState = () => fromPartial({ domainVisits: { cancelLoad: false }, }); const domain = 'foo.com'; diff --git a/shlink-web-component/test/visits/reducers/nonOrphanVisits.test.ts b/shlink-web-component/test/visits/reducers/nonOrphanVisits.test.ts index 6df4a7b1..fc872af6 100644 --- a/shlink-web-component/test/visits/reducers/nonOrphanVisits.test.ts +++ b/shlink-web-component/test/visits/reducers/nonOrphanVisits.test.ts @@ -1,9 +1,8 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { addDays, formatISO, subDays } from 'date-fns'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; import { rangeOf } from '../../../../src/utils/utils'; -import type { ShlinkVisits } from '../../../src/api/types'; +import type { ShlinkApiClient, ShlinkVisits } from '../../../src/api-contract'; +import type { RootState } from '../../../src/container/store'; import { formatIsoDate } from '../../../src/utils/dates/helpers/date'; import type { DateInterval } from '../../../src/utils/dates/helpers/dateIntervals'; import { @@ -118,7 +117,7 @@ describe('nonOrphanVisitsReducer', () => { describe('getNonOrphanVisits', () => { const dispatchMock = vi.fn(); - const getState = () => fromPartial({ + const getState = () => fromPartial({ orphanVisits: { cancelLoad: false }, }); diff --git a/shlink-web-component/test/visits/reducers/orphanVisits.test.ts b/shlink-web-component/test/visits/reducers/orphanVisits.test.ts index 7afc1e22..5dd1c530 100644 --- a/shlink-web-component/test/visits/reducers/orphanVisits.test.ts +++ b/shlink-web-component/test/visits/reducers/orphanVisits.test.ts @@ -1,9 +1,8 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { addDays, formatISO, subDays } from 'date-fns'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; import { rangeOf } from '../../../../src/utils/utils'; -import type { ShlinkVisits } from '../../../src/api/types'; +import type { ShlinkApiClient, ShlinkVisits } from '../../../src/api-contract'; +import type { RootState } from '../../../src/container/store'; import { formatIsoDate } from '../../../src/utils/dates/helpers/date'; import type { DateInterval } from '../../../src/utils/dates/helpers/dateIntervals'; import { @@ -118,7 +117,7 @@ describe('orphanVisitsReducer', () => { describe('getOrphanVisits', () => { const dispatchMock = vi.fn(); - const getState = () => fromPartial({ + const getState = () => fromPartial({ orphanVisits: { cancelLoad: false }, }); diff --git a/shlink-web-component/test/visits/reducers/shortUrlVisits.test.ts b/shlink-web-component/test/visits/reducers/shortUrlVisits.test.ts index b6571c49..89d15b0c 100644 --- a/shlink-web-component/test/visits/reducers/shortUrlVisits.test.ts +++ b/shlink-web-component/test/visits/reducers/shortUrlVisits.test.ts @@ -1,9 +1,8 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { addDays, formatISO, subDays } from 'date-fns'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; import { rangeOf } from '../../../../src/utils/utils'; -import type { ShlinkVisits } from '../../../src/api/types'; +import type { ShlinkApiClient, ShlinkVisits } from '../../../src/api-contract'; +import type { RootState } from '../../../src/container/store'; import { formatIsoDate } from '../../../src/utils/dates/helpers/date'; import type { DateInterval } from '../../../src/utils/dates/helpers/dateIntervals'; import type { @@ -142,7 +141,7 @@ describe('shortUrlVisitsReducer', () => { describe('getShortUrlVisits', () => { const dispatchMock = vi.fn(); - const getState = () => fromPartial({ + const getState = () => fromPartial({ shortUrlVisits: { cancelLoad: false }, }); diff --git a/shlink-web-component/test/visits/reducers/tagVisits.test.ts b/shlink-web-component/test/visits/reducers/tagVisits.test.ts index 2395f826..b078fc7a 100644 --- a/shlink-web-component/test/visits/reducers/tagVisits.test.ts +++ b/shlink-web-component/test/visits/reducers/tagVisits.test.ts @@ -1,9 +1,8 @@ import { fromPartial } from '@total-typescript/shoehorn'; import { addDays, formatISO, subDays } from 'date-fns'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; import { rangeOf } from '../../../../src/utils/utils'; -import type { ShlinkVisits } from '../../../src/api/types'; +import type { ShlinkApiClient, ShlinkVisits } from '../../../src/api-contract'; +import type { RootState } from '../../../src/container/store'; import { formatIsoDate } from '../../../src/utils/dates/helpers/date'; import type { DateInterval } from '../../../src/utils/dates/helpers/dateIntervals'; import type { @@ -142,7 +141,7 @@ describe('tagVisitsReducer', () => { describe('getTagVisits', () => { const dispatchMock = vi.fn(); - const getState = () => fromPartial({ + const getState = () => fromPartial({ tagVisits: { cancelLoad: false }, }); const tag = 'foo'; diff --git a/shlink-web-component/test/visits/reducers/visitsOverview.test.ts b/shlink-web-component/test/visits/reducers/visitsOverview.test.ts index 8ff9004e..5b6f3569 100644 --- a/shlink-web-component/test/visits/reducers/visitsOverview.test.ts +++ b/shlink-web-component/test/visits/reducers/visitsOverview.test.ts @@ -1,7 +1,6 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkApiClient } from '../../../../src/api/services/ShlinkApiClient'; -import type { ShlinkState } from '../../../../src/container/types'; -import type { ShlinkVisitsOverview } from '../../../src/api/types'; +import type { ShlinkApiClient, ShlinkVisitsOverview } from '../../../src/api-contract'; +import type { RootState } from '../../../src/container/store'; import { createNewVisits } from '../../../src/visits/reducers/visitCreation'; import type { PartialVisitsSummary, @@ -25,7 +24,7 @@ describe('visitsOverviewReducer', () => { it('returns loading on GET_OVERVIEW_START', () => { const { loading } = reducer( state({ loading: false, error: false }), - loadVisitsOverview.pending(''), + loadVisitsOverview.pending('', {}), ); expect(loading).toEqual(true); @@ -34,7 +33,7 @@ describe('visitsOverviewReducer', () => { it('stops loading and returns error on GET_OVERVIEW_ERROR', () => { const { loading, error } = reducer( state({ loading: true, error: false }), - loadVisitsOverview.rejected(null, ''), + loadVisitsOverview.rejected(null, '', {}), ); expect(loading).toEqual(false); @@ -44,7 +43,7 @@ describe('visitsOverviewReducer', () => { it('return visits overview on GET_OVERVIEW', () => { const action = loadVisitsOverview.fulfilled(fromPartial({ nonOrphanVisits: { total: 100 }, - }), 'requestId'); + }), 'requestId', {}); const { loading, error, nonOrphanVisits } = reducer(state({ loading: true, error: false }), action); expect(loading).toEqual(false); @@ -127,7 +126,7 @@ describe('visitsOverviewReducer', () => { describe('loadVisitsOverview', () => { const dispatchMock = vi.fn(); - const getState = () => fromPartial({}); + const getState = () => fromPartial({}); it.each([ [ @@ -155,7 +154,7 @@ describe('visitsOverviewReducer', () => { const resolvedOverview = fromPartial(serverResult); getVisitsOverview.mockResolvedValue(resolvedOverview); - await loadVisitsOverview()(dispatchMock, getState, {}); + await loadVisitsOverview(buildApiClientMock)(dispatchMock, getState, {}); expect(dispatchMock).toHaveBeenCalledTimes(2); expect(dispatchMock).toHaveBeenNthCalledWith(2, expect.objectContaining({ payload: dispatchedPayload })); diff --git a/shlink-web-component/test/visits/types/helpers.test.ts b/shlink-web-component/test/visits/types/helpers.test.ts index 9b8d52f7..291d9fcf 100644 --- a/shlink-web-component/test/visits/types/helpers.test.ts +++ b/shlink-web-component/test/visits/types/helpers.test.ts @@ -1,5 +1,5 @@ import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkVisitsParams } from '../../../src/api/types'; +import type { ShlinkVisitsParams } from '../../../src/api-contract'; import { formatIsoDate, parseDate } from '../../../src/utils/dates/helpers/date'; import type { CreateVisit, OrphanVisit, VisitsParams } from '../../../src/visits/types'; import type { GroupedNewVisits } from '../../../src/visits/types/helpers'; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index ab0f5e48..badf0ba0 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,4 +1,4 @@ -import { pipe } from 'ramda'; +import { pipe, range } from 'ramda'; import type { SyntheticEvent } from 'react'; type Optional = T | null | undefined; @@ -9,3 +9,6 @@ export const handleEventPreventingDefault = (handler: () => T) => pipe( (e: SyntheticEvent) => e.preventDefault(), handler, ); + +export const rangeOf = (size: number, mappingFn: (value: number) => T, startAt = 1): T[] => + range(startAt, size + 1).map(mappingFn);