Introduce shoehorn as a possible replacement for ts-mockery

This commit is contained in:
Alejandro Celaya
2023-04-13 21:48:29 +02:00
parent f6334c3618
commit 340f4b8fb5
65 changed files with 357 additions and 375 deletions

View File

@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import { Mock } from 'ts-mockery';
import type { Settings } from '../../src/settings/reducers/settings';
import { fromPartial } from '@total-typescript/shoehorn';
import { CreateShortUrl as createShortUrlsCreator } from '../../src/short-urls/CreateShortUrl';
import type { ShortUrlCreation } from '../../src/short-urls/reducers/shortUrlCreation';
@@ -8,7 +7,7 @@ describe('<CreateShortUrl />', () => {
const ShortUrlForm = () => <span>ShortUrlForm</span>;
const CreateShortUrlResult = () => <span>CreateShortUrlResult</span>;
const shortUrlCreation = { validateUrls: true };
const shortUrlCreationResult = Mock.all<ShortUrlCreation>();
const shortUrlCreationResult = fromPartial<ShortUrlCreation>({});
const createShortUrl = jest.fn(async () => Promise.resolve());
const CreateShortUrl = createShortUrlsCreator(ShortUrlForm, CreateShortUrlResult);
const setUp = () => render(
@@ -17,7 +16,7 @@ describe('<CreateShortUrl />', () => {
createShortUrl={createShortUrl}
selectedServer={null}
resetCreateShortUrl={() => {}}
settings={Mock.of<Settings>({ shortUrlCreation })}
settings={fromPartial({ shortUrlCreation })}
/>,
);

View File

@@ -1,8 +1,6 @@
import { render, screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { Settings } from '../../src/settings/reducers/settings';
import type { ShortUrl } from '../../src/short-urls/data';
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';
@@ -13,10 +11,10 @@ describe('<EditShortUrl />', () => {
const setUp = (detail: Partial<ShortUrlDetail> = {}, edition: Partial<ShortUrlEdition> = {}) => render(
<MemoryRouter>
<EditShortUrl
settings={Mock.of<Settings>({ shortUrlCreation })}
settings={fromPartial({ shortUrlCreation })}
selectedServer={null}
shortUrlDetail={Mock.of<ShortUrlDetail>(detail)}
shortUrlEdition={Mock.of<ShortUrlEdition>(edition)}
shortUrlDetail={fromPartial(detail)}
shortUrlEdition={fromPartial(edition)}
getShortUrlDetail={jest.fn()}
editShortUrl={jest.fn(async () => Promise.resolve())}
/>
@@ -38,7 +36,7 @@ describe('<EditShortUrl />', () => {
});
it('renders form when detail properly loads', () => {
setUp({ shortUrl: Mock.of<ShortUrl>({ meta: {} }) });
setUp({ shortUrl: fromPartial({ meta: {} }) });
expect(screen.getByText('ShortUrlForm')).toBeInTheDocument();
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();

View File

@@ -1,12 +1,12 @@
import { render, screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { ShlinkPaginator } from '../../src/api/types';
import { Paginator } from '../../src/short-urls/Paginator';
import { ELLIPSIS } from '../../src/utils/helpers/pagination';
describe('<Paginator />', () => {
const buildPaginator = (pagesCount?: number) => Mock.of<ShlinkPaginator>({ pagesCount, currentPage: 1 });
const buildPaginator = (pagesCount?: number) => fromPartial<ShlinkPaginator>({ pagesCount, currentPage: 1 });
const setUp = (paginator?: ShlinkPaginator, currentQueryString?: string) => render(
<MemoryRouter>
<Paginator serverId="abc123" paginator={paginator} currentQueryString={currentQueryString} />

View File

@@ -1,7 +1,7 @@
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 { Mock } from 'ts-mockery';
import type { ReachableServer, SelectedServer } from '../../src/servers/data';
import type { Mode } from '../../src/short-urls/ShortUrlForm';
import { ShortUrlForm as createShortUrlForm } from '../../src/short-urls/ShortUrlForm';
@@ -51,7 +51,7 @@ describe('<ShortUrlForm />', () => {
ios: 'https://ios.com',
},
},
Mock.of<ReachableServer>({ version: '3.5.0' }),
fromPartial<ReachableServer>({ version: '3.5.0' }),
],
])('saves short URL with data set in form controls', async (extraFields, extraExpectedValues, selectedServer) => {
const { user } = setUp(selectedServer);
@@ -102,7 +102,7 @@ describe('<ShortUrlForm />', () => {
[undefined, false, undefined],
['old title', false, null],
])('sends expected title based on original and new values', async (originalTitle, withNewTitle, expectedSentTitle) => {
const { user } = setUp(Mock.of<ReachableServer>({ version: '2.6.0' }), 'create', originalTitle);
const { user } = setUp(fromPartial({ version: '2.6.0' }), 'create', originalTitle);
await user.type(screen.getByPlaceholderText('URL to be shortened'), 'https://long-domain.com/foo/bar');
await user.clear(screen.getByPlaceholderText('Title'));
@@ -117,10 +117,10 @@ describe('<ShortUrlForm />', () => {
});
it.each([
[Mock.of<ReachableServer>({ version: '3.0.0' }), false],
[Mock.of<ReachableServer>({ version: '3.4.0' }), false],
[Mock.of<ReachableServer>({ version: '3.5.0' }), true],
[Mock.of<ReachableServer>({ version: '3.6.0' }), true],
[fromPartial<ReachableServer>({ version: '3.0.0' }), false],
[fromPartial<ReachableServer>({ version: '3.4.0' }), false],
[fromPartial<ReachableServer>({ version: '3.5.0' }), true],
[fromPartial<ReachableServer>({ 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'];

View File

@@ -1,9 +1,8 @@
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 { Mock } from 'ts-mockery';
import type { ReachableServer, SelectedServer } from '../../src/servers/data';
import type { Settings } from '../../src/settings/reducers/settings';
import { ShortUrlsFilteringBar as filteringBarCreator } from '../../src/short-urls/ShortUrlsFilteringBar';
import { formatDate } from '../../src/utils/helpers/date';
import type { DateRange } from '../../src/utils/helpers/dateIntervals';
@@ -28,10 +27,10 @@ describe('<ShortUrlsFilteringBar />', () => {
return renderWithEvents(
<MemoryRouter>
<ShortUrlsFilteringBar
selectedServer={selectedServer ?? Mock.all<SelectedServer>()}
selectedServer={selectedServer ?? fromPartial({})}
order={{}}
handleOrderBy={handleOrderBy}
settings={Mock.of<Settings>({ visits: {} })}
settings={fromPartial({ visits: {} })}
/>
</MemoryRouter>,
);
@@ -74,12 +73,12 @@ describe('<ShortUrlsFilteringBar />', () => {
});
it.each([
['tags=foo,bar,baz', Mock.of<ReachableServer>({ version: '3.0.0' }), true],
['tags=foo,bar', Mock.of<ReachableServer>({ version: '3.1.0' }), true],
['tags=foo', Mock.of<ReachableServer>({ version: '3.0.0' }), false],
['', Mock.of<ReachableServer>({ version: '3.0.0' }), false],
['tags=foo,bar,baz', Mock.of<ReachableServer>({ version: '2.10.0' }), false],
['', Mock.of<ReachableServer>({ version: '2.10.0' }), false],
['tags=foo,bar,baz', fromPartial<ReachableServer>({ version: '3.0.0' }), true],
['tags=foo,bar', fromPartial<ReachableServer>({ version: '3.1.0' }), true],
['tags=foo', fromPartial<ReachableServer>({ version: '3.0.0' }), false],
['', fromPartial<ReachableServer>({ version: '3.0.0' }), false],
['tags=foo,bar,baz', fromPartial<ReachableServer>({ version: '2.10.0' }), false],
['', fromPartial<ReachableServer>({ version: '2.10.0' }), false],
])(
'renders tags mode toggle if the server supports it and there is more than one tag selected',
(search, selectedServer, shouldHaveComponent) => {
@@ -98,7 +97,7 @@ describe('<ShortUrlsFilteringBar />', () => {
['&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}`, Mock.of<ReachableServer>({ version: '3.0.0' }));
const { user } = setUp(`tags=foo,bar${initialTagsMode}`, fromPartial({ version: '3.0.0' }));
await user.hover(screen.getByLabelText('Change tags mode'));
expect(await screen.findByRole('tooltip')).toHaveTextContent(expectedToggleText);
@@ -109,7 +108,7 @@ describe('<ShortUrlsFilteringBar />', () => {
['&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}`, Mock.of<ReachableServer>({ version: '3.0.0' }));
const { user } = setUp(`tags=foo,bar${initialTagsMode}`, fromPartial({ version: '3.0.0' }));
expect(navigate).not.toHaveBeenCalled();
await user.click(screen.getByLabelText('Change tags mode'));
@@ -127,7 +126,7 @@ describe('<ShortUrlsFilteringBar />', () => {
['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, Mock.of<ReachableServer>({ version: '3.4.0' }));
const { user } = setUp(search, fromPartial({ version: '3.4.0' }));
const toggleFilter = async (name: RegExp) => {
await user.click(screen.getByRole('button', { name: 'Filters' }));
await waitFor(() => screen.findByRole('menu'));

View File

@@ -1,10 +1,9 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { MemoryRouter, useNavigate } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub';
import type { ReachableServer } from '../../src/servers/data';
import type { Settings } from '../../src/settings/reducers/settings';
import type { ShortUrl, ShortUrlsOrder } from '../../src/short-urls/data';
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';
@@ -22,15 +21,15 @@ describe('<ShortUrlsList />', () => {
const ShortUrlsFilteringBar = () => <span>ShortUrlsFilteringBar</span>;
const listShortUrlsMock = jest.fn();
const navigate = jest.fn();
const shortUrlsList = Mock.of<ShortUrlsListModel>({
const shortUrlsList = fromPartial<ShortUrlsListModel>({
shortUrls: {
data: [
Mock.of<ShortUrl>({
{
shortCode: 'testShortCode',
shortUrl: 'https://www.example.com/testShortUrl',
longUrl: 'https://www.example.com/testLongUrl',
tags: ['test tag'],
}),
},
],
pagination: { pagesCount: 3 },
},
@@ -39,11 +38,11 @@ describe('<ShortUrlsList />', () => {
const setUp = (settings: Partial<Settings> = {}, version: SemVer = '3.0.0') => renderWithEvents(
<MemoryRouter>
<ShortUrlsList
{...Mock.of<MercureBoundProps>({ mercureInfo: { loading: true } })}
{...fromPartial<MercureBoundProps>({ mercureInfo: { loading: true } })}
listShortUrls={listShortUrlsMock}
shortUrlsList={shortUrlsList}
selectedServer={Mock.of<ReachableServer>({ id: '1', version })}
settings={Mock.of<Settings>(settings)}
selectedServer={fromPartial({ id: '1', version })}
settings={fromPartial(settings)}
/>
</MemoryRouter>,
);
@@ -81,9 +80,9 @@ describe('<ShortUrlsList />', () => {
});
it.each([
[Mock.of<ShortUrlsOrder>({ field: 'visits', dir: 'ASC' }), 'visits', 'ASC'],
[Mock.of<ShortUrlsOrder>({ field: 'title', dir: 'DESC' }), 'title', 'DESC'],
[Mock.all<ShortUrlsOrder>(), undefined, undefined],
[fromPartial<ShortUrlsOrder>({ field: 'visits', dir: 'ASC' }), 'visits', 'ASC'],
[fromPartial<ShortUrlsOrder>({ field: 'title', dir: 'DESC' }), 'title', 'DESC'],
[fromPartial<ShortUrlsOrder>({}), undefined, undefined],
])('has expected initial ordering based on settings', (defaultOrdering, field, dir) => {
setUp({ shortUrlsList: { defaultOrdering } });
expect(listShortUrlsMock).toHaveBeenCalledWith(expect.objectContaining({
@@ -92,23 +91,23 @@ describe('<ShortUrlsList />', () => {
});
it.each([
[Mock.of<Settings>({
[fromPartial<Settings>({
shortUrlsList: {
defaultOrdering: { field: 'visits', dir: 'ASC' },
},
}), '3.3.0' as SemVer, { field: 'visits', dir: 'ASC' }],
[Mock.of<Settings>({
[fromPartial<Settings>({
shortUrlsList: {
defaultOrdering: { field: 'visits', dir: 'ASC' },
},
visits: { excludeBots: true },
}), '3.3.0' as SemVer, { field: 'visits', dir: 'ASC' }],
[Mock.of<Settings>({
[fromPartial<Settings>({
shortUrlsList: {
defaultOrdering: { field: 'visits', dir: 'ASC' },
},
}), '3.4.0' as SemVer, { field: 'visits', dir: 'ASC' }],
[Mock.of<Settings>({
[fromPartial<Settings>({
shortUrlsList: {
defaultOrdering: { field: 'visits', dir: 'ASC' },
},

View File

@@ -1,6 +1,6 @@
import { fireEvent, screen } from '@testing-library/react';
import { Mock } from 'ts-mockery';
import type { ReachableServer, SelectedServer } from '../../src/servers/data';
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';
@@ -8,7 +8,7 @@ import { ShortUrlsTable as shortUrlsTableCreator } from '../../src/short-urls/Sh
import { renderWithEvents } from '../__helpers__/setUpTest';
describe('<ShortUrlsTable />', () => {
const shortUrlsList = Mock.all<ShortUrlsList>();
const shortUrlsList = fromPartial<ShortUrlsList>({});
const orderByColumn = jest.fn();
const ShortUrlsTable = shortUrlsTableCreator(() => <span>ShortUrlsRow</span>);
const setUp = (server: SelectedServer = null) => renderWithEvents(
@@ -56,7 +56,7 @@ describe('<ShortUrlsTable />', () => {
});
it('should render composed title column', () => {
setUp(Mock.of<ReachableServer>({ version: '2.0.0' }));
setUp(fromPartial({ version: '2.0.0' }));
const { innerHTML } = screen.getAllByRole('columnheader')[2];

View File

@@ -1,6 +1,5 @@
import { screen } from '@testing-library/react';
import { Mock } from 'ts-mockery';
import type { ShortUrl } from '../../../src/short-urls/data';
import { fromPartial } from '@total-typescript/shoehorn';
import { CreateShortUrlResult as createResult } from '../../../src/short-urls/helpers/CreateShortUrlResult';
import type { ShortUrlCreation } from '../../../src/short-urls/reducers/shortUrlCreation';
import type { TimeoutToggle } from '../../../src/utils/helpers/hooks';
@@ -28,14 +27,14 @@ describe('<CreateShortUrlResult />', () => {
it('renders a result message when result is provided', () => {
setUp(
{ result: Mock.of<ShortUrl>({ shortUrl: 'https://s.test/abc123' }), saving: false, saved: true, error: false },
{ result: fromPartial({ shortUrl: 'https://s.test/abc123' }), saving: false, saved: true, error: false },
);
expect(screen.getByText(/The short URL is/)).toHaveTextContent('Great! The short URL is https://s.test/abc123');
});
it('Invokes tooltip timeout when copy to clipboard button is clicked', async () => {
const { user } = setUp(
{ result: Mock.of<ShortUrl>({ shortUrl: 'https://s.test/abc123' }), saving: false, saved: true, error: false },
{ result: fromPartial({ shortUrl: 'https://s.test/abc123' }), saving: false, saved: true, error: false },
);
expect(copyToClipboard).not.toHaveBeenCalled();

View File

@@ -1,6 +1,6 @@
import { screen, waitFor } from '@testing-library/react';
import { Mock } from 'ts-mockery';
import type { InvalidShortUrlDeletion, ProblemDetailsError } from '../../../src/api/types/errors';
import { fromPartial } from '@total-typescript/shoehorn';
import type { InvalidShortUrlDeletion } from '../../../src/api/types/errors';
import { ErrorTypeV2, ErrorTypeV3 } from '../../../src/api/types/errors';
import type { ShortUrl } from '../../../src/short-urls/data';
import { DeleteShortUrlModal } from '../../../src/short-urls/helpers/DeleteShortUrlModal';
@@ -9,7 +9,7 @@ import { renderWithEvents } from '../../__helpers__/setUpTest';
import { TestModalWrapper } from '../../__helpers__/TestModalWrapper';
describe('<DeleteShortUrlModal />', () => {
const shortUrl = Mock.of<ShortUrl>({
const shortUrl = fromPartial<ShortUrl>({
tags: [],
shortCode: 'abc123',
longUrl: 'https://long-domain.com/foo/bar',
@@ -22,7 +22,7 @@ describe('<DeleteShortUrlModal />', () => {
<DeleteShortUrlModal
{...args}
shortUrl={shortUrl}
shortUrlDeletion={Mock.of<ShortUrlDeletion>(shortUrlDeletion)}
shortUrlDeletion={fromPartial(shortUrlDeletion)}
deleteShortUrl={deleteShortUrl}
shortUrlDeleted={shortUrlDeleted}
resetDeleteShortUrl={jest.fn()}
@@ -38,7 +38,7 @@ describe('<DeleteShortUrlModal />', () => {
loading: false,
error: true,
shortCode: 'abc123',
errorData: Mock.of<ProblemDetailsError>({ type: 'OTHER_ERROR' }),
errorData: fromPartial({ type: 'OTHER_ERROR' }),
});
expect(screen.getByText('Something went wrong while deleting the URL :(').parentElement).not.toHaveClass(
'bg-warning',
@@ -46,8 +46,8 @@ describe('<DeleteShortUrlModal />', () => {
});
it.each([
[Mock.of<InvalidShortUrlDeletion>({ type: ErrorTypeV3.INVALID_SHORT_URL_DELETION })],
[Mock.of<InvalidShortUrlDeletion>({ type: ErrorTypeV2.INVALID_SHORT_URL_DELETION })],
[fromPartial<InvalidShortUrlDeletion>({ type: ErrorTypeV3.INVALID_SHORT_URL_DELETION })],
[fromPartial<InvalidShortUrlDeletion>({ type: ErrorTypeV2.INVALID_SHORT_URL_DELETION })],
])('shows specific error when threshold error occurs', (errorData) => {
setUp({ loading: false, error: true, shortCode: 'abc123', errorData });
expect(screen.getByText('Something went wrong while deleting the URL :(').parentElement).toHaveClass('bg-warning');

View File

@@ -1,8 +1,8 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { ReportExporter } from '../../../src/common/services/ReportExporter';
import type { NotFoundServer, ReachableServer, SelectedServer } from '../../../src/servers/data';
import type { NotFoundServer, SelectedServer } from '../../../src/servers/data';
import { ExportShortUrlsBtn as createExportShortUrlsBtn } from '../../../src/short-urls/helpers/ExportShortUrlsBtn';
import { renderWithEvents } from '../../__helpers__/setUpTest';
@@ -10,11 +10,11 @@ describe('<ExportShortUrlsBtn />', () => {
const listShortUrls = jest.fn();
const buildShlinkApiClient = jest.fn().mockReturnValue({ listShortUrls });
const exportShortUrls = jest.fn();
const reportExporter = Mock.of<ReportExporter>({ exportShortUrls });
const reportExporter = fromPartial<ReportExporter>({ exportShortUrls });
const ExportShortUrlsBtn = createExportShortUrlsBtn(buildShlinkApiClient, reportExporter);
const setUp = (amount?: number, selectedServer?: SelectedServer) => renderWithEvents(
<MemoryRouter>
<ExportShortUrlsBtn selectedServer={selectedServer ?? Mock.all<SelectedServer>()} amount={amount} />
<ExportShortUrlsBtn selectedServer={selectedServer ?? fromPartial({})} amount={amount} />
</MemoryRouter>,
);
@@ -31,7 +31,7 @@ describe('<ExportShortUrlsBtn />', () => {
it.each([
[null],
[Mock.of<NotFoundServer>()],
[fromPartial<NotFoundServer>({})],
])('does nothing on click if selected server is not reachable', async (selectedServer) => {
const { user } = setUp(0, selectedServer);
@@ -49,7 +49,7 @@ describe('<ExportShortUrlsBtn />', () => {
[385, 20],
])('loads proper amount of pages based on the amount of results', async (amount, expectedPageLoads) => {
listShortUrls.mockResolvedValue({ data: [] });
const { user } = setUp(amount, Mock.of<ReachableServer>({ id: '123' }));
const { user } = setUp(amount, fromPartial({ id: '123' }));
await user.click(screen.getByRole('button'));

View File

@@ -1,21 +1,18 @@
import { fireEvent, screen } from '@testing-library/react';
import { Mock } from 'ts-mockery';
import type { ImageDownloader } from '../../../src/common/services/ImageDownloader';
import type { ReachableServer } from '../../../src/servers/data';
import type { ShortUrl } from '../../../src/short-urls/data';
import { fromPartial } from '@total-typescript/shoehorn';
import { QrCodeModal as createQrCodeModal } from '../../../src/short-urls/helpers/QrCodeModal';
import type { SemVer } from '../../../src/utils/helpers/version';
import { renderWithEvents } from '../../__helpers__/setUpTest';
describe('<QrCodeModal />', () => {
const saveImage = jest.fn().mockReturnValue(Promise.resolve());
const QrCodeModal = createQrCodeModal(Mock.of<ImageDownloader>({ saveImage }));
const QrCodeModal = createQrCodeModal(fromPartial({ saveImage }));
const shortUrl = 'https://s.test/abc123';
const setUp = (version: SemVer = '2.8.0') => renderWithEvents(
<QrCodeModal
isOpen
shortUrl={Mock.of<ShortUrl>({ shortUrl })}
selectedServer={Mock.of<ReachableServer>({ version })}
shortUrl={fromPartial({ shortUrl })}
selectedServer={fromPartial({ version })}
toggle={() => {}}
/>,
);

View File

@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
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';
@@ -10,11 +10,11 @@ describe('<ShortUrlDetailLink />', () => {
it.each([
[undefined, undefined],
[null, null],
[Mock.of<ReachableServer>({ id: '1' }), null],
[Mock.of<ReachableServer>({ id: '1' }), undefined],
[Mock.of<NotFoundServer>(), Mock.all<ShortUrl>()],
[null, Mock.all<ShortUrl>()],
[undefined, Mock.all<ShortUrl>()],
[fromPartial<ReachableServer>({ id: '1' }), null],
[fromPartial<ReachableServer>({ id: '1' }), undefined],
[fromPartial<NotFoundServer>({}), fromPartial<ShortUrl>({})],
[null, fromPartial<ShortUrl>({})],
[undefined, fromPartial<ShortUrl>({})],
])('only renders a plain span when either server or short URL are not set', (selectedServer, shortUrl) => {
render(
<ShortUrlDetailLink selectedServer={selectedServer} shortUrl={shortUrl} suffix="visits">
@@ -28,26 +28,26 @@ describe('<ShortUrlDetailLink />', () => {
it.each([
[
Mock.of<ReachableServer>({ id: '1' }),
Mock.of<ShortUrl>({ shortCode: 'abc123' }),
fromPartial<ReachableServer>({ id: '1' }),
fromPartial<ShortUrl>({ shortCode: 'abc123' }),
'visits' as LinkSuffix,
'/server/1/short-code/abc123/visits',
],
[
Mock.of<ReachableServer>({ id: '3' }),
Mock.of<ShortUrl>({ shortCode: 'def456', domain: 'example.com' }),
fromPartial<ReachableServer>({ id: '3' }),
fromPartial<ShortUrl>({ shortCode: 'def456', domain: 'example.com' }),
'visits' as LinkSuffix,
'/server/3/short-code/def456/visits?domain=example.com',
],
[
Mock.of<ReachableServer>({ id: '1' }),
Mock.of<ShortUrl>({ shortCode: 'abc123' }),
fromPartial<ReachableServer>({ id: '1' }),
fromPartial<ShortUrl>({ shortCode: 'abc123' }),
'edit' as LinkSuffix,
'/server/1/short-code/abc123/edit',
],
[
Mock.of<ReachableServer>({ id: '3' }),
Mock.of<ShortUrl>({ shortCode: 'def456', domain: 'example.com' }),
fromPartial<ReachableServer>({ id: '3' }),
fromPartial<ShortUrl>({ shortCode: 'def456', domain: 'example.com' }),
'edit' as LinkSuffix,
'/server/3/short-code/def456/edit?domain=example.com',
],

View File

@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Mock } from 'ts-mockery';
import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkVisitsSummary } from '../../../src/api/types';
import type { ShortUrl, ShortUrlMeta } from '../../../src/short-urls/data';
import { ShortUrlStatus } from '../../../src/short-urls/helpers/ShortUrlStatus';
@@ -13,35 +13,35 @@ describe('<ShortUrlStatus />', () => {
it.each([
[
Mock.of<ShortUrlMeta>({ validSince: '2099-01-01T10:30:15' }),
fromPartial<ShortUrlMeta>({ validSince: '2099-01-01T10:30:15' }),
{},
'This short URL will start working on 2099-01-01 10:30.',
],
[
Mock.of<ShortUrlMeta>({ validUntil: '2020-01-01T10:30:15' }),
fromPartial<ShortUrlMeta>({ validUntil: '2020-01-01T10:30:15' }),
{},
'This short URL cannot be visited since 2020-01-01 10:30.',
],
[
Mock.of<ShortUrlMeta>({ maxVisits: 10 }),
Mock.of<ShlinkVisitsSummary>({ total: 10 }),
fromPartial<ShortUrlMeta>({ maxVisits: 10 }),
fromPartial<ShlinkVisitsSummary>({ total: 10 }),
'This short URL cannot be currently visited because it has reached the maximum amount of 10 visits.',
],
[
Mock.of<ShortUrlMeta>({ maxVisits: 1 }),
Mock.of<ShlinkVisitsSummary>({ total: 1 }),
fromPartial<ShortUrlMeta>({ maxVisits: 1 }),
fromPartial<ShlinkVisitsSummary>({ total: 1 }),
'This short URL cannot be currently visited because it has reached the maximum amount of 1 visit.',
],
[{}, {}, 'This short URL can be visited normally.'],
[Mock.of<ShortUrlMeta>({ validUntil: '2099-01-01T10:30:15' }), {}, 'This short URL can be visited normally.'],
[Mock.of<ShortUrlMeta>({ validSince: '2020-01-01T10:30:15' }), {}, 'This short URL can be visited normally.'],
[fromPartial<ShortUrlMeta>({ validUntil: '2099-01-01T10:30:15' }), {}, 'This short URL can be visited normally.'],
[fromPartial<ShortUrlMeta>({ validSince: '2020-01-01T10:30:15' }), {}, 'This short URL can be visited normally.'],
[
Mock.of<ShortUrlMeta>({ maxVisits: 10 }),
Mock.of<ShlinkVisitsSummary>({ total: 1 }),
fromPartial<ShortUrlMeta>({ maxVisits: 10 }),
fromPartial<ShlinkVisitsSummary>({ total: 1 }),
'This short URL can be visited normally.',
],
])('shows expected tooltip', async (meta, visitsSummary, expectedTooltip) => {
const { user } = setUp(Mock.of<ShortUrl>({ meta, visitsSummary }));
const { user } = setUp(fromPartial({ meta, visitsSummary }));
await user.hover(screen.getByRole('img', { hidden: true }));
await waitFor(() => expect(screen.getByRole('tooltip')).toHaveTextContent(expectedTooltip));

View File

@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Mock } from 'ts-mockery';
import { fromPartial } from '@total-typescript/shoehorn';
import type { ShortUrl } from '../../../src/short-urls/data';
import { ShortUrlVisitsCount } from '../../../src/short-urls/helpers/ShortUrlVisitsCount';
@@ -14,7 +14,7 @@ describe('<ShortUrlVisitsCount />', () => {
it.each([undefined, {}])('just returns visits when no limits are provided', (meta) => {
const visitsCount = 45;
const { container } = setUp(visitsCount, Mock.of<ShortUrl>({ meta }));
const { container } = setUp(visitsCount, fromPartial({ meta }));
expect(container.firstChild).toHaveTextContent(`${visitsCount}`);
expect(container.querySelector('.short-urls-visits-count__max-visits-control')).not.toBeInTheDocument();
@@ -24,7 +24,7 @@ describe('<ShortUrlVisitsCount />', () => {
const visitsCount = 45;
const maxVisits = 500;
const meta = { maxVisits };
const { container } = setUp(visitsCount, Mock.of<ShortUrl>({ meta }));
const { container } = setUp(visitsCount, fromPartial({ meta }));
expect(container.firstChild).toHaveTextContent(`/ ${maxVisits}`);
});
@@ -44,7 +44,7 @@ describe('<ShortUrlVisitsCount />', () => {
'This short URL will not accept visits after 2023-05-05 15:30',
], { validSince: '2023-01-01T10:00:00', validUntil: '2023-05-05T15:30:30', maxVisits: 100 }],
])('displays proper amount of tooltip list items', async (expectedListItems, meta) => {
const { user } = setUp(100, Mock.of<ShortUrl>({ meta }));
const { user } = setUp(100, fromPartial({ meta }));
await user.hover(screen.getByRole('img', { hidden: true }));
await waitFor(() => expect(screen.getByRole('list')));

View File

@@ -1,8 +1,8 @@
import { screen } from '@testing-library/react';
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 { Mock } from 'ts-mockery';
import type { ReachableServer } from '../../../src/servers/data';
import type { Settings } from '../../../src/settings/reducers/settings';
import type { ShortUrl, ShortUrlMeta } from '../../../src/short-urls/data';
@@ -28,7 +28,7 @@ jest.mock('react-router-dom', () => ({
describe('<ShortUrlsRow />', () => {
const timeoutToggle = jest.fn(() => true);
const useTimeoutToggle = jest.fn(() => [false, timeoutToggle]) as TimeoutToggle;
const server = Mock.of<ReachableServer>({ url: 'https://s.test' });
const server = fromPartial<ReachableServer>({ url: 'https://s.test' });
const shortUrl: ShortUrl = {
shortCode: 'abc123',
shortUrl: 'https://s.test/abc123',
@@ -60,7 +60,7 @@ describe('<ShortUrlsRow />', () => {
selectedServer={server}
shortUrl={{ ...shortUrl, title, tags, meta: { ...shortUrl.meta, ...meta } }}
onTagClick={() => null}
settings={Mock.of<Settings>(settings)}
settings={fromPartial(settings)}
/>
</tbody>
</table>
@@ -118,13 +118,13 @@ describe('<ShortUrlsRow />', () => {
it.each([
[{}, '', shortUrl.visitsSummary?.total],
[Mock.of<Settings>({ visits: { excludeBots: false } }), '', shortUrl.visitsSummary?.total],
[Mock.of<Settings>({ visits: { excludeBots: true } }), '', shortUrl.visitsSummary?.nonBots],
[Mock.of<Settings>({ visits: { excludeBots: false } }), 'excludeBots=true', shortUrl.visitsSummary?.nonBots],
[Mock.of<Settings>({ visits: { excludeBots: true } }), 'excludeBots=true', shortUrl.visitsSummary?.nonBots],
[fromPartial<Settings>({ visits: { excludeBots: false } }), '', shortUrl.visitsSummary?.total],
[fromPartial<Settings>({ visits: { excludeBots: true } }), '', shortUrl.visitsSummary?.nonBots],
[fromPartial<Settings>({ visits: { excludeBots: false } }), 'excludeBots=true', shortUrl.visitsSummary?.nonBots],
[fromPartial<Settings>({ visits: { excludeBots: true } }), 'excludeBots=true', shortUrl.visitsSummary?.nonBots],
[{}, 'excludeBots=true', shortUrl.visitsSummary?.nonBots],
[Mock.of<Settings>({ visits: { excludeBots: true } }), 'excludeBots=false', shortUrl.visitsSummary?.total],
[Mock.of<Settings>({ visits: { excludeBots: false } }), 'excludeBots=false', shortUrl.visitsSummary?.total],
[fromPartial<Settings>({ visits: { excludeBots: true } }), 'excludeBots=false', shortUrl.visitsSummary?.total],
[fromPartial<Settings>({ visits: { excludeBots: false } }), 'excludeBots=false', shortUrl.visitsSummary?.total],
[{}, 'excludeBots=false', shortUrl.visitsSummary?.total],
])('renders visits count in fifth row', (settings, search, expectedAmount) => {
setUp({ settings }, search);

View File

@@ -1,6 +1,6 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
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';
@@ -8,8 +8,8 @@ import { renderWithEvents } from '../../__helpers__/setUpTest';
describe('<ShortUrlsRowMenu />', () => {
const ShortUrlsRowMenu = createShortUrlsRowMenu(() => <i>DeleteShortUrlModal</i>, () => <i>QrCodeModal</i>);
const selectedServer = Mock.of<ReachableServer>({ id: 'abc123' });
const shortUrl = Mock.of<ShortUrl>({
const selectedServer = fromPartial<ReachableServer>({ id: 'abc123' });
const shortUrl = fromPartial<ShortUrl>({
shortCode: 'abc123',
shortUrl: 'https://s.test/abc123',
});

View File

@@ -1,4 +1,4 @@
import { Mock } from 'ts-mockery';
import { fromPartial } from '@total-typescript/shoehorn';
import type { ShortUrl } from '../../../src/short-urls/data';
import { shortUrlDataFromShortUrl, urlDecodeShortCode, urlEncodeShortCode } from '../../../src/short-urls/helpers';
@@ -8,7 +8,7 @@ describe('helpers', () => {
[undefined, { validateUrls: true }, { longUrl: '', validateUrl: true }],
[undefined, undefined, { longUrl: '', validateUrl: false }],
[
Mock.of<ShortUrl>({ meta: {} }),
fromPartial<ShortUrl>({ meta: {} }),
{ validateUrls: false },
{
longUrl: undefined,