Migrate more tests to shoehorn

This commit is contained in:
Alejandro Celaya 2023-04-13 22:47:13 +02:00
parent 340f4b8fb5
commit 04e1950591
33 changed files with 218 additions and 246 deletions

View file

@ -1,16 +1,16 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient'; import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient';
import type { ShlinkState } from '../../../src/container/types'; import type { ShlinkState } from '../../../src/container/types';
import type { ShortUrl, ShortUrlData } from '../../../src/short-urls/data'; import type { ShortUrl } from '../../../src/short-urls/data';
import { import {
createShortUrl as createShortUrlCreator, createShortUrl as createShortUrlCreator,
shortUrlCreationReducerCreator, shortUrlCreationReducerCreator,
} from '../../../src/short-urls/reducers/shortUrlCreation'; } from '../../../src/short-urls/reducers/shortUrlCreation';
describe('shortUrlCreationReducer', () => { describe('shortUrlCreationReducer', () => {
const shortUrl = Mock.of<ShortUrl>(); const shortUrl = fromPartial<ShortUrl>({});
const createShortUrlCall = jest.fn(); const createShortUrlCall = jest.fn();
const buildShlinkApiClient = () => Mock.of<ShlinkApiClient>({ createShortUrl: createShortUrlCall }); const buildShlinkApiClient = () => fromPartial<ShlinkApiClient>({ createShortUrl: createShortUrlCall });
const createShortUrl = createShortUrlCreator(buildShlinkApiClient); const createShortUrl = createShortUrlCreator(buildShlinkApiClient);
const { reducer, resetCreateShortUrl } = shortUrlCreationReducerCreator(createShortUrl); const { reducer, resetCreateShortUrl } = shortUrlCreationReducerCreator(createShortUrl);
@ -18,7 +18,7 @@ describe('shortUrlCreationReducer', () => {
describe('reducer', () => { describe('reducer', () => {
it('returns loading on CREATE_SHORT_URL_START', () => { it('returns loading on CREATE_SHORT_URL_START', () => {
expect(reducer(undefined, createShortUrl.pending('', Mock.all<ShortUrlData>()))).toEqual({ expect(reducer(undefined, createShortUrl.pending('', fromPartial({})))).toEqual({
saving: true, saving: true,
saved: false, saved: false,
error: false, error: false,
@ -26,7 +26,7 @@ describe('shortUrlCreationReducer', () => {
}); });
it('returns error on CREATE_SHORT_URL_ERROR', () => { it('returns error on CREATE_SHORT_URL_ERROR', () => {
expect(reducer(undefined, createShortUrl.rejected(null, '', Mock.all<ShortUrlData>()))).toEqual({ expect(reducer(undefined, createShortUrl.rejected(null, '', fromPartial({})))).toEqual({
saving: false, saving: false,
saved: false, saved: false,
error: true, error: true,
@ -34,7 +34,7 @@ describe('shortUrlCreationReducer', () => {
}); });
it('returns result on CREATE_SHORT_URL', () => { it('returns result on CREATE_SHORT_URL', () => {
expect(reducer(undefined, createShortUrl.fulfilled(shortUrl, '', Mock.all<ShortUrlData>()))).toEqual({ expect(reducer(undefined, createShortUrl.fulfilled(shortUrl, '', fromPartial({})))).toEqual({
result: shortUrl, result: shortUrl,
saving: false, saving: false,
saved: true, saved: true,
@ -53,7 +53,7 @@ describe('shortUrlCreationReducer', () => {
describe('createShortUrl', () => { describe('createShortUrl', () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
const getState = () => Mock.all<ShlinkState>(); const getState = () => fromPartial<ShlinkState>({});
it('calls API on success', async () => { it('calls API on success', async () => {
createShortUrlCall.mockResolvedValue(shortUrl); createShortUrlCall.mockResolvedValue(shortUrl);

View file

@ -1,15 +1,15 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient'; import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient';
import type { ProblemDetailsError } from '../../../src/api/types/errors'; import type { ProblemDetailsError } from '../../../src/api/types/errors';
import { import {
deleteShortUrl as deleteShortUrlCretor, deleteShortUrl as deleteShortUrlCreator,
shortUrlDeletionReducerCreator, shortUrlDeletionReducerCreator,
} from '../../../src/short-urls/reducers/shortUrlDeletion'; } from '../../../src/short-urls/reducers/shortUrlDeletion';
describe('shortUrlDeletionReducer', () => { describe('shortUrlDeletionReducer', () => {
const deleteShortUrlCall = jest.fn(); const deleteShortUrlCall = jest.fn();
const buildShlinkApiClient = () => Mock.of<ShlinkApiClient>({ deleteShortUrl: deleteShortUrlCall }); const buildShlinkApiClient = () => fromPartial<ShlinkApiClient>({ deleteShortUrl: deleteShortUrlCall });
const deleteShortUrl = deleteShortUrlCretor(buildShlinkApiClient); const deleteShortUrl = deleteShortUrlCreator(buildShlinkApiClient);
const { reducer, resetDeleteShortUrl } = shortUrlDeletionReducerCreator(deleteShortUrl); const { reducer, resetDeleteShortUrl } = shortUrlDeletionReducerCreator(deleteShortUrl);
beforeEach(jest.clearAllMocks); beforeEach(jest.clearAllMocks);
@ -40,7 +40,9 @@ describe('shortUrlDeletionReducer', () => {
})); }));
it('returns errorData on DELETE_SHORT_URL_ERROR', () => { it('returns errorData on DELETE_SHORT_URL_ERROR', () => {
const errorData = Mock.of<ProblemDetailsError>({ type: 'bar', detail: 'detail', title: 'title', status: 400 }); const errorData = fromPartial<ProblemDetailsError>(
{ type: 'bar', detail: 'detail', title: 'title', status: 400 },
);
const error = errorData as unknown as Error; const error = errorData as unknown as Error;
expect(reducer(undefined, deleteShortUrl.rejected(error, '', { shortCode: '' }))).toEqual({ expect(reducer(undefined, deleteShortUrl.rejected(error, '', { shortCode: '' }))).toEqual({

View file

@ -1,4 +1,4 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient'; import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient';
import type { ShlinkState } from '../../../src/container/types'; import type { ShlinkState } from '../../../src/container/types';
import type { ShortUrl } from '../../../src/short-urls/data'; import type { ShortUrl } from '../../../src/short-urls/data';
@ -7,7 +7,7 @@ import type { ShortUrlsList } from '../../../src/short-urls/reducers/shortUrlsLi
describe('shortUrlDetailReducer', () => { describe('shortUrlDetailReducer', () => {
const getShortUrlCall = jest.fn(); const getShortUrlCall = jest.fn();
const buildShlinkApiClient = () => Mock.of<ShlinkApiClient>({ getShortUrl: getShortUrlCall }); const buildShlinkApiClient = () => fromPartial<ShlinkApiClient>({ getShortUrl: getShortUrlCall });
const { reducer, getShortUrlDetail } = shortUrlDetailReducerCreator(buildShlinkApiClient); const { reducer, getShortUrlDetail } = shortUrlDetailReducerCreator(buildShlinkApiClient);
beforeEach(jest.clearAllMocks); beforeEach(jest.clearAllMocks);
@ -27,7 +27,7 @@ describe('shortUrlDetailReducer', () => {
}); });
it('return short URL on GET_SHORT_URL_DETAIL', () => { it('return short URL on GET_SHORT_URL_DETAIL', () => {
const actionShortUrl = Mock.of<ShortUrl>({ longUrl: 'foo', shortCode: 'bar' }); const actionShortUrl = fromPartial<ShortUrl>({ longUrl: 'foo', shortCode: 'bar' });
const state = reducer( const state = reducer(
{ loading: true, error: false }, { loading: true, error: false },
getShortUrlDetail.fulfilled(actionShortUrl, '', { shortCode: '' }), getShortUrlDetail.fulfilled(actionShortUrl, '', { shortCode: '' }),
@ -42,25 +42,25 @@ describe('shortUrlDetailReducer', () => {
describe('getShortUrlDetail', () => { describe('getShortUrlDetail', () => {
const dispatchMock = jest.fn(); const dispatchMock = jest.fn();
const buildGetState = (shortUrlsList?: ShortUrlsList) => () => Mock.of<ShlinkState>({ shortUrlsList }); const buildGetState = (shortUrlsList?: ShortUrlsList) => () => fromPartial<ShlinkState>({ shortUrlsList });
it.each([ it.each([
[undefined], [undefined],
[Mock.all<ShortUrlsList>()], [fromPartial<ShortUrlsList>({})],
[ [
Mock.of<ShortUrlsList>({ fromPartial<ShortUrlsList>({
shortUrls: { data: [] }, shortUrls: { data: [] },
}), }),
], ],
[ [
Mock.of<ShortUrlsList>({ fromPartial<ShortUrlsList>({
shortUrls: { shortUrls: {
data: [Mock.of<ShortUrl>({ shortCode: 'this_will_not_match' })], data: [{ shortCode: 'this_will_not_match' }],
}, },
}), }),
], ],
])('performs API call when short URL is not found in local state', async (shortUrlsList?: ShortUrlsList) => { ])('performs API call when short URL is not found in local state', async (shortUrlsList?: ShortUrlsList) => {
const resolvedShortUrl = Mock.of<ShortUrl>({ longUrl: 'foo', shortCode: 'abc123' }); const resolvedShortUrl = fromPartial<ShortUrl>({ longUrl: 'foo', shortCode: 'abc123' });
getShortUrlCall.mockResolvedValue(resolvedShortUrl); getShortUrlCall.mockResolvedValue(resolvedShortUrl);
await getShortUrlDetail({ shortCode: 'abc123', domain: '' })(dispatchMock, buildGetState(shortUrlsList), {}); await getShortUrlDetail({ shortCode: 'abc123', domain: '' })(dispatchMock, buildGetState(shortUrlsList), {});
@ -71,12 +71,12 @@ describe('shortUrlDetailReducer', () => {
}); });
it('avoids API calls when short URL is found in local state', async () => { it('avoids API calls when short URL is found in local state', async () => {
const foundShortUrl = Mock.of<ShortUrl>({ longUrl: 'foo', shortCode: 'abc123' }); const foundShortUrl = fromPartial<ShortUrl>({ longUrl: 'foo', shortCode: 'abc123' });
getShortUrlCall.mockResolvedValue(Mock.all<ShortUrl>()); getShortUrlCall.mockResolvedValue(fromPartial<ShortUrl>({}));
await getShortUrlDetail(foundShortUrl)( await getShortUrlDetail(foundShortUrl)(
dispatchMock, dispatchMock,
buildGetState(Mock.of<ShortUrlsList>({ buildGetState(fromPartial({
shortUrls: { shortUrls: {
data: [foundShortUrl], data: [foundShortUrl],
}, },

View file

@ -1,8 +1,7 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkState } from '../../../src/container/types'; import type { ShlinkState } from '../../../src/container/types';
import type { SelectedServer } from '../../../src/servers/data'; import type { SelectedServer } from '../../../src/servers/data';
import type { ShortUrl } from '../../../src/short-urls/data'; import type { ShortUrl } from '../../../src/short-urls/data';
import type { EditShortUrl } from '../../../src/short-urls/reducers/shortUrlEdition';
import { import {
editShortUrl as editShortUrlCreator, editShortUrl as editShortUrlCreator,
shortUrlEditionReducerCreator, shortUrlEditionReducerCreator,
@ -11,7 +10,7 @@ import {
describe('shortUrlEditionReducer', () => { describe('shortUrlEditionReducer', () => {
const longUrl = 'https://shlink.io'; const longUrl = 'https://shlink.io';
const shortCode = 'abc123'; const shortCode = 'abc123';
const shortUrl = Mock.of<ShortUrl>({ longUrl, shortCode }); const shortUrl = fromPartial<ShortUrl>({ longUrl, shortCode });
const updateShortUrl = jest.fn().mockResolvedValue(shortUrl); const updateShortUrl = jest.fn().mockResolvedValue(shortUrl);
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrl }); const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrl });
const editShortUrl = editShortUrlCreator(buildShlinkApiClient); const editShortUrl = editShortUrlCreator(buildShlinkApiClient);
@ -21,7 +20,7 @@ describe('shortUrlEditionReducer', () => {
describe('reducer', () => { describe('reducer', () => {
it('returns loading on EDIT_SHORT_URL_START', () => { it('returns loading on EDIT_SHORT_URL_START', () => {
expect(reducer(undefined, editShortUrl.pending('', Mock.all<EditShortUrl>()))).toEqual({ expect(reducer(undefined, editShortUrl.pending('', fromPartial({})))).toEqual({
saving: true, saving: true,
saved: false, saved: false,
error: false, error: false,
@ -29,7 +28,7 @@ describe('shortUrlEditionReducer', () => {
}); });
it('returns error on EDIT_SHORT_URL_ERROR', () => { it('returns error on EDIT_SHORT_URL_ERROR', () => {
expect(reducer(undefined, editShortUrl.rejected(null, '', Mock.all<EditShortUrl>()))).toEqual({ expect(reducer(undefined, editShortUrl.rejected(null, '', fromPartial({})))).toEqual({
saving: false, saving: false,
saved: false, saved: false,
error: true, error: true,
@ -37,7 +36,7 @@ describe('shortUrlEditionReducer', () => {
}); });
it('returns provided tags and shortCode on SHORT_URL_EDITED', () => { it('returns provided tags and shortCode on SHORT_URL_EDITED', () => {
expect(reducer(undefined, editShortUrl.fulfilled(shortUrl, '', Mock.all<EditShortUrl>()))).toEqual({ expect(reducer(undefined, editShortUrl.fulfilled(shortUrl, '', fromPartial({})))).toEqual({
shortUrl, shortUrl,
saving: false, saving: false,
saved: true, saved: true,
@ -48,7 +47,9 @@ describe('shortUrlEditionReducer', () => {
describe('editShortUrl', () => { describe('editShortUrl', () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
const createGetState = (selectedServer: SelectedServer = null) => () => Mock.of<ShlinkState>({ selectedServer }); const createGetState = (selectedServer: SelectedServer = null) => () => fromPartial<ShlinkState>({
selectedServer,
});
afterEach(jest.clearAllMocks); afterEach(jest.clearAllMocks);

View file

@ -1,10 +1,9 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient'; import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient';
import type { ShlinkPaginator, ShlinkShortUrlsResponse } from '../../../src/api/types'; import type { ShlinkShortUrlsResponse } from '../../../src/api/types';
import type { ShortUrl, ShortUrlData } from '../../../src/short-urls/data'; import type { ShortUrl } from '../../../src/short-urls/data';
import { createShortUrl as createShortUrlCreator } from '../../../src/short-urls/reducers/shortUrlCreation'; import { createShortUrl as createShortUrlCreator } from '../../../src/short-urls/reducers/shortUrlCreation';
import { shortUrlDeleted } from '../../../src/short-urls/reducers/shortUrlDeletion'; import { shortUrlDeleted } from '../../../src/short-urls/reducers/shortUrlDeletion';
import type { EditShortUrl } from '../../../src/short-urls/reducers/shortUrlEdition';
import { editShortUrl as editShortUrlCreator } from '../../../src/short-urls/reducers/shortUrlEdition'; import { editShortUrl as editShortUrlCreator } from '../../../src/short-urls/reducers/shortUrlEdition';
import { import {
listShortUrls as listShortUrlsCreator, listShortUrls as listShortUrlsCreator,
@ -16,7 +15,7 @@ import type { CreateVisit } from '../../../src/visits/types';
describe('shortUrlsListReducer', () => { describe('shortUrlsListReducer', () => {
const shortCode = 'abc123'; const shortCode = 'abc123';
const listShortUrlsMock = jest.fn(); const listShortUrlsMock = jest.fn();
const buildShlinkApiClient = () => Mock.of<ShlinkApiClient>({ listShortUrls: listShortUrlsMock }); const buildShlinkApiClient = () => fromPartial<ShlinkApiClient>({ listShortUrls: listShortUrlsMock });
const listShortUrls = listShortUrlsCreator(buildShlinkApiClient); const listShortUrls = listShortUrlsCreator(buildShlinkApiClient);
const editShortUrl = editShortUrlCreator(buildShlinkApiClient); const editShortUrl = editShortUrlCreator(buildShlinkApiClient);
const createShortUrl = createShortUrlCreator(buildShlinkApiClient); const createShortUrl = createShortUrlCreator(buildShlinkApiClient);
@ -32,7 +31,7 @@ describe('shortUrlsListReducer', () => {
})); }));
it('returns short URLs on LIST_SHORT_URLS', () => it('returns short URLs on LIST_SHORT_URLS', () =>
expect(reducer(undefined, listShortUrls.fulfilled(Mock.of<ShlinkShortUrlsResponse>({ data: [] }), ''))).toEqual({ expect(reducer(undefined, listShortUrls.fulfilled(fromPartial({ data: [] }), ''))).toEqual({
shortUrls: { data: [] }, shortUrls: { data: [] },
loading: false, loading: false,
error: false, error: false,
@ -46,21 +45,19 @@ describe('shortUrlsListReducer', () => {
it('removes matching URL and reduces total on SHORT_URL_DELETED', () => { it('removes matching URL and reduces total on SHORT_URL_DELETED', () => {
const state = { const state = {
shortUrls: Mock.of<ShlinkShortUrlsResponse>({ shortUrls: fromPartial<ShlinkShortUrlsResponse>({
data: [ data: [
Mock.of<ShortUrl>({ shortCode }), { shortCode },
Mock.of<ShortUrl>({ shortCode, domain: 'example.com' }), { shortCode, domain: 'example.com' },
Mock.of<ShortUrl>({ shortCode: 'foo' }), { shortCode: 'foo' },
], ],
pagination: Mock.of<ShlinkPaginator>({ pagination: { totalItems: 10 },
totalItems: 10,
}),
}), }),
loading: false, loading: false,
error: false, error: false,
}; };
expect(reducer(state, shortUrlDeleted(Mock.of<ShortUrl>({ shortCode })))).toEqual({ expect(reducer(state, shortUrlDeleted(fromPartial({ shortCode })))).toEqual({
shortUrls: { shortUrls: {
data: [{ shortCode, domain: 'example.com' }, { shortCode: 'foo' }], data: [{ shortCode, domain: 'example.com' }, { shortCode: 'foo' }],
pagination: { totalItems: 9 }, pagination: { totalItems: 9 },
@ -70,7 +67,7 @@ describe('shortUrlsListReducer', () => {
}); });
}); });
const createNewShortUrlVisit = (visitsCount: number) => Mock.of<CreateVisit>({ const createNewShortUrlVisit = (visitsCount: number) => fromPartial<CreateVisit>({
shortUrl: { shortCode: 'abc123', visitsCount }, shortUrl: { shortCode: 'abc123', visitsCount },
}); });
@ -81,11 +78,11 @@ describe('shortUrlsListReducer', () => {
[[], 10], [[], 10],
])('updates visits count on CREATE_VISITS', (createdVisits, expectedCount) => { ])('updates visits count on CREATE_VISITS', (createdVisits, expectedCount) => {
const state = { const state = {
shortUrls: Mock.of<ShlinkShortUrlsResponse>({ shortUrls: fromPartial<ShlinkShortUrlsResponse>({
data: [ data: [
Mock.of<ShortUrl>({ shortCode, domain: 'example.com', visitsCount: 5 }), { shortCode, domain: 'example.com', visitsCount: 5 },
Mock.of<ShortUrl>({ shortCode, visitsCount: 10 }), { shortCode, visitsCount: 10 },
Mock.of<ShortUrl>({ shortCode: 'foo', visitsCount: 8 }), { shortCode: 'foo', visitsCount: 8 },
], ],
}), }),
loading: false, loading: false,
@ -108,48 +105,46 @@ describe('shortUrlsListReducer', () => {
it.each([ it.each([
[ [
[ [
Mock.of<ShortUrl>({ shortCode }), fromPartial<ShortUrl>({ shortCode }),
Mock.of<ShortUrl>({ shortCode, domain: 'example.com' }), fromPartial<ShortUrl>({ shortCode, domain: 'example.com' }),
Mock.of<ShortUrl>({ shortCode: 'foo' }), fromPartial<ShortUrl>({ shortCode: 'foo' }),
], ],
[{ shortCode: 'newOne' }, { shortCode }, { shortCode, domain: 'example.com' }, { shortCode: 'foo' }], [{ shortCode: 'newOne' }, { shortCode }, { shortCode, domain: 'example.com' }, { shortCode: 'foo' }],
], ],
[ [
[ [
Mock.of<ShortUrl>({ shortCode }), fromPartial<ShortUrl>({ shortCode }),
Mock.of<ShortUrl>({ shortCode: 'code' }), fromPartial<ShortUrl>({ shortCode: 'code' }),
Mock.of<ShortUrl>({ shortCode: 'foo' }), fromPartial<ShortUrl>({ shortCode: 'foo' }),
Mock.of<ShortUrl>({ shortCode: 'bar' }), fromPartial<ShortUrl>({ shortCode: 'bar' }),
Mock.of<ShortUrl>({ shortCode: 'baz' }), fromPartial<ShortUrl>({ shortCode: 'baz' }),
], ],
[{ shortCode: 'newOne' }, { shortCode }, { shortCode: 'code' }, { shortCode: 'foo' }, { shortCode: 'bar' }], [{ shortCode: 'newOne' }, { shortCode }, { shortCode: 'code' }, { shortCode: 'foo' }, { shortCode: 'bar' }],
], ],
[ [
[ [
Mock.of<ShortUrl>({ shortCode }), fromPartial<ShortUrl>({ shortCode }),
Mock.of<ShortUrl>({ shortCode: 'code' }), fromPartial<ShortUrl>({ shortCode: 'code' }),
Mock.of<ShortUrl>({ shortCode: 'foo' }), fromPartial<ShortUrl>({ shortCode: 'foo' }),
Mock.of<ShortUrl>({ shortCode: 'bar' }), fromPartial<ShortUrl>({ shortCode: 'bar' }),
Mock.of<ShortUrl>({ shortCode: 'baz1' }), fromPartial<ShortUrl>({ shortCode: 'baz1' }),
Mock.of<ShortUrl>({ shortCode: 'baz2' }), fromPartial<ShortUrl>({ shortCode: 'baz2' }),
Mock.of<ShortUrl>({ shortCode: 'baz3' }), fromPartial<ShortUrl>({ shortCode: 'baz3' }),
], ],
[{ shortCode: 'newOne' }, { shortCode }, { shortCode: 'code' }, { shortCode: 'foo' }, { shortCode: 'bar' }], [{ shortCode: 'newOne' }, { shortCode }, { shortCode: 'code' }, { shortCode: 'foo' }, { shortCode: 'bar' }],
], ],
])('prepends new short URL and increases total on CREATE_SHORT_URL', (data, expectedData) => { ])('prepends new short URL and increases total on CREATE_SHORT_URL', (data, expectedData) => {
const newShortUrl = Mock.of<ShortUrl>({ shortCode: 'newOne' }); const newShortUrl = fromPartial<ShortUrl>({ shortCode: 'newOne' });
const state = { const state = {
shortUrls: Mock.of<ShlinkShortUrlsResponse>({ shortUrls: fromPartial<ShlinkShortUrlsResponse>({
data, data,
pagination: Mock.of<ShlinkPaginator>({ pagination: { totalItems: 15 },
totalItems: 15,
}),
}), }),
loading: false, loading: false,
error: false, error: false,
}; };
expect(reducer(state, createShortUrl.fulfilled(newShortUrl, '', Mock.all<ShortUrlData>()))).toEqual({ expect(reducer(state, createShortUrl.fulfilled(newShortUrl, '', fromPartial({})))).toEqual({
shortUrls: { shortUrls: {
data: expectedData, data: expectedData,
pagination: { totalItems: 16 }, pagination: { totalItems: 16 },
@ -161,16 +156,16 @@ describe('shortUrlsListReducer', () => {
it.each([ it.each([
((): [ShortUrl, ShortUrl[], ShortUrl[]] => { ((): [ShortUrl, ShortUrl[], ShortUrl[]] => {
const editedShortUrl = Mock.of<ShortUrl>({ shortCode: 'notMatching' }); const editedShortUrl = fromPartial<ShortUrl>({ shortCode: 'notMatching' });
const list = [Mock.of<ShortUrl>({ shortCode: 'foo' }), Mock.of<ShortUrl>({ shortCode: 'bar' })]; const list: ShortUrl[] = [fromPartial({ shortCode: 'foo' }), fromPartial({ shortCode: 'bar' })];
return [editedShortUrl, list, list]; return [editedShortUrl, list, list];
})(), })(),
((): [ShortUrl, ShortUrl[], ShortUrl[]] => { ((): [ShortUrl, ShortUrl[], ShortUrl[]] => {
const editedShortUrl = Mock.of<ShortUrl>({ shortCode: 'matching', longUrl: 'new_one' }); const editedShortUrl = fromPartial<ShortUrl>({ shortCode: 'matching', longUrl: 'new_one' });
const list = [ const list: ShortUrl[] = [
Mock.of<ShortUrl>({ shortCode: 'matching', longUrl: 'old_one' }), fromPartial({ shortCode: 'matching', longUrl: 'old_one' }),
Mock.of<ShortUrl>({ shortCode: 'bar' }), fromPartial({ shortCode: 'bar' }),
]; ];
const expectedList = [editedShortUrl, list[1]]; const expectedList = [editedShortUrl, list[1]];
@ -178,17 +173,15 @@ describe('shortUrlsListReducer', () => {
})(), })(),
])('updates matching short URL on SHORT_URL_EDITED', (editedShortUrl, initialList, expectedList) => { ])('updates matching short URL on SHORT_URL_EDITED', (editedShortUrl, initialList, expectedList) => {
const state = { const state = {
shortUrls: Mock.of<ShlinkShortUrlsResponse>({ shortUrls: fromPartial<ShlinkShortUrlsResponse>({
data: initialList, data: initialList,
pagination: Mock.of<ShlinkPaginator>({ pagination: { totalItems: 15 },
totalItems: 15,
}),
}), }),
loading: false, loading: false,
error: false, error: false,
}; };
const result = reducer(state, editShortUrl.fulfilled(editedShortUrl, '', Mock.of<EditShortUrl>())); const result = reducer(state, editShortUrl.fulfilled(editedShortUrl, '', fromPartial({})));
expect(result.shortUrls?.data).toEqual(expectedList); expect(result.shortUrls?.data).toEqual(expectedList);
}); });

View file

@ -1,8 +1,7 @@
import { screen, waitFor } from '@testing-library/react'; import { screen, waitFor } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { identity } from 'ramda'; import { identity } from 'ramda';
import { Mock } from 'ts-mockery';
import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub';
import type { Settings } from '../../src/settings/reducers/settings';
import type { TagsList } from '../../src/tags/reducers/tagsList'; import type { TagsList } from '../../src/tags/reducers/tagsList';
import type { TagsListProps } from '../../src/tags/TagsList'; import type { TagsListProps } from '../../src/tags/TagsList';
import { TagsList as createTagsList } from '../../src/tags/TagsList'; import { TagsList as createTagsList } from '../../src/tags/TagsList';
@ -13,12 +12,12 @@ describe('<TagsList />', () => {
const TagsListComp = createTagsList(({ sortedTags }) => <>TagsTable ({sortedTags.map((t) => t.visits).join(',')})</>); const TagsListComp = createTagsList(({ sortedTags }) => <>TagsTable ({sortedTags.map((t) => t.visits).join(',')})</>);
const setUp = (tagsList: Partial<TagsList>, excludeBots = false) => renderWithEvents( const setUp = (tagsList: Partial<TagsList>, excludeBots = false) => renderWithEvents(
<TagsListComp <TagsListComp
{...Mock.all<TagsListProps>()} {...fromPartial<TagsListProps>({})}
{...Mock.of<MercureBoundProps>({ mercureInfo: {} })} {...fromPartial<MercureBoundProps>({ mercureInfo: {} })}
forceListTags={identity} forceListTags={identity}
filterTags={filterTags} filterTags={filterTags}
tagsList={Mock.of<TagsList>(tagsList)} tagsList={fromPartial(tagsList)}
settings={Mock.of<Settings>({ visits: { excludeBots } })} settings={fromPartial({ visits: { excludeBots } })}
/>, />,
); );

View file

@ -1,8 +1,6 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { SelectedServer } from '../../src/servers/data';
import type { SimplifiedTag } from '../../src/tags/data';
import { TagsTable as createTagsTable } from '../../src/tags/TagsTable'; import { TagsTable as createTagsTable } from '../../src/tags/TagsTable';
import { rangeOf } from '../../src/utils/utils'; import { rangeOf } from '../../src/utils/utils';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
@ -17,8 +15,8 @@ describe('<TagsTable />', () => {
(useLocation as any).mockReturnValue({ search }); (useLocation as any).mockReturnValue({ search });
return renderWithEvents( return renderWithEvents(
<TagsTable <TagsTable
sortedTags={sortedTags.map((tag) => Mock.of<SimplifiedTag>({ tag }))} sortedTags={sortedTags.map((tag) => fromPartial({ tag }))}
selectedServer={Mock.all<SelectedServer>()} selectedServer={fromPartial({})}
currentOrder={{}} currentOrder={{}}
orderByColumn={() => orderByColumn} orderByColumn={() => orderByColumn}
/>, />,

View file

@ -1,7 +1,6 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { ReachableServer } from '../../src/servers/data';
import { TagsTableRow as createTagsTableRow } from '../../src/tags/TagsTableRow'; import { TagsTableRow as createTagsTableRow } from '../../src/tags/TagsTableRow';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
import { colorGeneratorMock } from '../utils/services/__mocks__/ColorGenerator.mock'; import { colorGeneratorMock } from '../utils/services/__mocks__/ColorGenerator.mock';
@ -18,7 +17,7 @@ describe('<TagsTableRow />', () => {
<tbody> <tbody>
<TagsTableRow <TagsTableRow
tag={{ tag: 'foo&bar', visits: tagStats?.visits ?? 0, shortUrls: tagStats?.shortUrls ?? 0 }} tag={{ tag: 'foo&bar', visits: tagStats?.visits ?? 0, shortUrls: tagStats?.shortUrls ?? 0 }}
selectedServer={Mock.of<ReachableServer>({ id: 'abc123' })} selectedServer={fromPartial({ id: 'abc123' })}
/> />
</tbody> </tbody>
</table> </table>

View file

@ -1,17 +1,15 @@
import { screen, waitFor } from '@testing-library/react'; import { screen, waitFor } from '@testing-library/react';
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ProblemDetailsError } from '../../../src/api/types/errors';
import { EditTagModal as createEditTagModal } from '../../../src/tags/helpers/EditTagModal'; import { EditTagModal as createEditTagModal } from '../../../src/tags/helpers/EditTagModal';
import type { TagEdition } from '../../../src/tags/reducers/tagEdit'; import type { TagEdition } from '../../../src/tags/reducers/tagEdit';
import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator';
import { renderWithEvents } from '../../__helpers__/setUpTest'; import { renderWithEvents } from '../../__helpers__/setUpTest';
describe('<EditTagModal />', () => { describe('<EditTagModal />', () => {
const EditTagModal = createEditTagModal(Mock.of<ColorGenerator>({ getColorForKey: jest.fn(() => 'green') })); const EditTagModal = createEditTagModal(fromPartial({ getColorForKey: jest.fn(() => 'green') }));
const editTag = jest.fn().mockReturnValue(Promise.resolve()); const editTag = jest.fn().mockReturnValue(Promise.resolve());
const toggle = jest.fn(); const toggle = jest.fn();
const setUp = (tagEdit: Partial<TagEdition> = {}) => { const setUp = (tagEdit: Partial<TagEdition> = {}) => {
const edition = Mock.of<TagEdition>(tagEdit); const edition = fromPartial<TagEdition>(tagEdit);
return renderWithEvents( return renderWithEvents(
<EditTagModal isOpen tag="foo" tagEdit={edition} editTag={editTag} tagEdited={jest.fn()} toggle={toggle} />, <EditTagModal isOpen tag="foo" tagEdit={edition} editTag={editTag} tagEdited={jest.fn()} toggle={toggle} />,
); );
@ -43,7 +41,7 @@ describe('<EditTagModal />', () => {
[true, 1], [true, 1],
[false, 0], [false, 0],
])('displays error result in case of error', (error, expectedResultCount) => { ])('displays error result in case of error', (error, expectedResultCount) => {
setUp({ error, errorData: Mock.all<ProblemDetailsError>() }); setUp({ error, errorData: fromPartial({}) });
expect(screen.queryAllByText('Something went wrong while editing the tag :(')).toHaveLength(expectedResultCount); expect(screen.queryAllByText('Something went wrong while editing the tag :(')).toHaveLength(expectedResultCount);
}); });

View file

@ -1,6 +1,6 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { Mock } from 'ts-mockery';
import { Tag } from '../../../src/tags/helpers/Tag'; import { Tag } from '../../../src/tags/helpers/Tag';
import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator';
import { MAIN_COLOR } from '../../../src/utils/theme'; import { MAIN_COLOR } from '../../../src/utils/theme';
@ -24,7 +24,7 @@ describe('<Tag />', () => {
const onClose = jest.fn(); const onClose = jest.fn();
const isColorLightForKey = jest.fn(() => false); const isColorLightForKey = jest.fn(() => false);
const getColorForKey = jest.fn(() => MAIN_COLOR); const getColorForKey = jest.fn(() => MAIN_COLOR);
const colorGenerator = Mock.of<ColorGenerator>({ getColorForKey, isColorLightForKey }); const colorGenerator = fromPartial<ColorGenerator>({ getColorForKey, isColorLightForKey });
const setUp = (text: string, clearable?: boolean, children?: ReactNode) => renderWithEvents( const setUp = (text: string, clearable?: boolean, children?: ReactNode) => renderWithEvents(
<Tag text={text} clearable={clearable} colorGenerator={colorGenerator} onClick={onClick} onClose={onClose}> <Tag text={text} clearable={clearable} colorGenerator={colorGenerator} onClick={onClick} onClose={onClose}>
{children} {children}

View file

@ -1,6 +1,5 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { Settings } from '../../../src/settings/reducers/settings';
import { TagsSelector as createTagsSelector } from '../../../src/tags/helpers/TagsSelector'; import { TagsSelector as createTagsSelector } from '../../../src/tags/helpers/TagsSelector';
import type { TagsList } from '../../../src/tags/reducers/tagsList'; import type { TagsList } from '../../../src/tags/reducers/tagsList';
import { renderWithEvents } from '../../__helpers__/setUpTest'; import { renderWithEvents } from '../../__helpers__/setUpTest';
@ -10,12 +9,12 @@ describe('<TagsSelector />', () => {
const onChange = jest.fn(); const onChange = jest.fn();
const TagsSelector = createTagsSelector(colorGeneratorMock); const TagsSelector = createTagsSelector(colorGeneratorMock);
const tags = ['foo', 'bar']; const tags = ['foo', 'bar'];
const tagsList = Mock.of<TagsList>({ tags: [...tags, 'baz'] }); const tagsList = fromPartial<TagsList>({ tags: [...tags, 'baz'] });
const setUp = () => renderWithEvents( const setUp = () => renderWithEvents(
<TagsSelector <TagsSelector
selectedTags={tags} selectedTags={tags}
tagsList={tagsList} tagsList={tagsList}
settings={Mock.all<Settings>()} settings={fromPartial({})}
listTags={jest.fn()} listTags={jest.fn()}
onChange={onChange} onChange={onChange}
/>, />,

View file

@ -1,11 +1,11 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient'; import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient';
import type { ShlinkState } from '../../../src/container/types'; import type { ShlinkState } from '../../../src/container/types';
import { tagDeleted, tagDeleteReducerCreator } from '../../../src/tags/reducers/tagDelete'; import { tagDeleted, tagDeleteReducerCreator } from '../../../src/tags/reducers/tagDelete';
describe('tagDeleteReducer', () => { describe('tagDeleteReducer', () => {
const deleteTagsCall = jest.fn(); const deleteTagsCall = jest.fn();
const buildShlinkApiClient = () => Mock.of<ShlinkApiClient>({ deleteTags: deleteTagsCall }); const buildShlinkApiClient = () => fromPartial<ShlinkApiClient>({ deleteTags: deleteTagsCall });
const { reducer, deleteTag } = tagDeleteReducerCreator(buildShlinkApiClient); const { reducer, deleteTag } = tagDeleteReducerCreator(buildShlinkApiClient);
beforeEach(jest.clearAllMocks); beforeEach(jest.clearAllMocks);
@ -44,7 +44,7 @@ describe('tagDeleteReducer', () => {
describe('deleteTag', () => { describe('deleteTag', () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
const getState = () => Mock.all<ShlinkState>(); const getState = () => fromPartial<ShlinkState>({});
it('calls API on success', async () => { it('calls API on success', async () => {
const tag = 'foo'; const tag = 'foo';

View file

@ -1,7 +1,6 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient'; import type { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient';
import type { ShlinkState } from '../../../src/container/types'; import type { ShlinkState } from '../../../src/container/types';
import type { EditTag } from '../../../src/tags/reducers/tagEdit';
import { editTag as editTagCreator, tagEdited, tagEditReducerCreator } from '../../../src/tags/reducers/tagEdit'; import { editTag as editTagCreator, tagEdited, tagEditReducerCreator } from '../../../src/tags/reducers/tagEdit';
import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; import type { ColorGenerator } from '../../../src/utils/services/ColorGenerator';
@ -10,14 +9,14 @@ describe('tagEditReducer', () => {
const newName = 'bar'; const newName = 'bar';
const color = '#ff0000'; const color = '#ff0000';
const editTagCall = jest.fn(); const editTagCall = jest.fn();
const buildShlinkApiClient = () => Mock.of<ShlinkApiClient>({ editTag: editTagCall }); const buildShlinkApiClient = () => fromPartial<ShlinkApiClient>({ editTag: editTagCall });
const colorGenerator = Mock.of<ColorGenerator>({ setColorForKey: jest.fn() }); const colorGenerator = fromPartial<ColorGenerator>({ setColorForKey: jest.fn() });
const editTag = editTagCreator(buildShlinkApiClient, colorGenerator); const editTag = editTagCreator(buildShlinkApiClient, colorGenerator);
const { reducer } = tagEditReducerCreator(editTag); const { reducer } = tagEditReducerCreator(editTag);
describe('reducer', () => { describe('reducer', () => {
it('returns loading on EDIT_TAG_START', () => { it('returns loading on EDIT_TAG_START', () => {
expect(reducer(undefined, editTag.pending('', Mock.all<EditTag>()))).toEqual({ expect(reducer(undefined, editTag.pending('', fromPartial({})))).toEqual({
editing: true, editing: true,
edited: false, edited: false,
error: false, error: false,
@ -25,7 +24,7 @@ describe('tagEditReducer', () => {
}); });
it('returns error on EDIT_TAG_ERROR', () => { it('returns error on EDIT_TAG_ERROR', () => {
expect(reducer(undefined, editTag.rejected(null, '', Mock.all<EditTag>()))).toEqual({ expect(reducer(undefined, editTag.rejected(null, '', fromPartial({})))).toEqual({
editing: false, editing: false,
edited: false, edited: false,
error: true, error: true,
@ -33,7 +32,7 @@ describe('tagEditReducer', () => {
}); });
it('returns tag names on EDIT_TAG', () => { it('returns tag names on EDIT_TAG', () => {
expect(reducer(undefined, editTag.fulfilled({ oldName, newName, color }, '', Mock.all<EditTag>()))).toEqual({ expect(reducer(undefined, editTag.fulfilled({ oldName, newName, color }, '', fromPartial({})))).toEqual({
editing: false, editing: false,
edited: true, edited: true,
error: false, error: false,
@ -52,7 +51,7 @@ describe('tagEditReducer', () => {
describe('editTag', () => { describe('editTag', () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
const getState = () => Mock.of<ShlinkState>(); const getState = () => fromPartial<ShlinkState>({});
afterEach(jest.clearAllMocks); afterEach(jest.clearAllMocks);

View file

@ -1,6 +1,6 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ShlinkState } from '../../../src/container/types'; import type { ShlinkState } from '../../../src/container/types';
import type { ShortUrl, ShortUrlData } from '../../../src/short-urls/data'; import type { ShortUrl } from '../../../src/short-urls/data';
import { createShortUrl as createShortUrlCreator } from '../../../src/short-urls/reducers/shortUrlCreation'; import { createShortUrl as createShortUrlCreator } from '../../../src/short-urls/reducers/shortUrlCreation';
import { tagDeleted } from '../../../src/tags/reducers/tagDelete'; import { tagDeleted } from '../../../src/tags/reducers/tagDelete';
import { tagEdited } from '../../../src/tags/reducers/tagEdit'; import { tagEdited } from '../../../src/tags/reducers/tagEdit';
@ -12,10 +12,10 @@ import {
tagsListReducerCreator, tagsListReducerCreator,
} from '../../../src/tags/reducers/tagsList'; } from '../../../src/tags/reducers/tagsList';
import { createNewVisits } from '../../../src/visits/reducers/visitCreation'; import { createNewVisits } from '../../../src/visits/reducers/visitCreation';
import type { CreateVisit, Visit } from '../../../src/visits/types'; import type { CreateVisit } from '../../../src/visits/types';
describe('tagsListReducer', () => { describe('tagsListReducer', () => {
const state = (props: Partial<TagsList>) => Mock.of<TagsList>(props); const state = (props: Partial<TagsList>) => fromPartial<TagsList>(props);
const buildShlinkApiClient = jest.fn(); const buildShlinkApiClient = jest.fn();
const listTags = listTagsCreator(buildShlinkApiClient, true); const listTags = listTagsCreator(buildShlinkApiClient, true);
const createShortUrl = createShortUrlCreator(buildShlinkApiClient); const createShortUrl = createShortUrlCreator(buildShlinkApiClient);
@ -41,7 +41,7 @@ describe('tagsListReducer', () => {
it('returns provided tags as filtered and regular tags on LIST_TAGS', () => { it('returns provided tags as filtered and regular tags on LIST_TAGS', () => {
const tags = ['foo', 'bar', 'baz']; const tags = ['foo', 'bar', 'baz'];
expect(reducer(undefined, listTags.fulfilled(Mock.of<TagsList>({ tags }), ''))).toEqual({ expect(reducer(undefined, listTags.fulfilled(fromPartial({ tags }), ''))).toEqual({
tags, tags,
filteredTags: tags, filteredTags: tags,
loading: false, loading: false,
@ -114,30 +114,30 @@ describe('tagsListReducer', () => {
[['new', 'tag'], ['foo', 'bar', 'baz', 'foo2', 'fo', 'new', 'tag']], [['new', 'tag'], ['foo', 'bar', 'baz', 'foo2', 'fo', 'new', 'tag']],
])('appends new short URL\'s tags to the list of tags on CREATE_SHORT_URL', (shortUrlTags, expectedTags) => { ])('appends new short URL\'s tags to the list of tags on CREATE_SHORT_URL', (shortUrlTags, expectedTags) => {
const tags = ['foo', 'bar', 'baz', 'foo2', 'fo']; const tags = ['foo', 'bar', 'baz', 'foo2', 'fo'];
const payload = Mock.of<ShortUrl>({ tags: shortUrlTags }); const payload = fromPartial<ShortUrl>({ tags: shortUrlTags });
expect(reducer(state({ tags }), createShortUrl.fulfilled(payload, '', Mock.of<ShortUrlData>()))).toEqual({ expect(reducer(state({ tags }), createShortUrl.fulfilled(payload, '', fromPartial({})))).toEqual({
tags: expectedTags, tags: expectedTags,
}); });
}); });
it('increases amounts when visits are created', () => { it('increases amounts when visits are created', () => {
const createdVisits = [ const createdVisits: CreateVisit[] = [
Mock.of<CreateVisit>({ fromPartial({
shortUrl: Mock.of<ShortUrl>({ tags: ['foo', 'bar'] }), shortUrl: { tags: ['foo', 'bar'] },
visit: Mock.of<Visit>({ potentialBot: true }), visit: { potentialBot: true },
}), }),
Mock.of<CreateVisit>({ fromPartial({
shortUrl: Mock.of<ShortUrl>({ tags: ['foo', 'bar'] }), shortUrl: { tags: ['foo', 'bar'] },
visit: Mock.all<Visit>(), visit: {},
}), }),
Mock.of<CreateVisit>({ fromPartial({
shortUrl: Mock.of<ShortUrl>({ tags: ['bar'] }), shortUrl: { tags: ['bar'] },
visit: Mock.all<Visit>(), visit: {},
}), }),
Mock.of<CreateVisit>({ fromPartial({
shortUrl: Mock.of<ShortUrl>({ tags: ['baz'] }), shortUrl: { tags: ['baz'] },
visit: Mock.of<Visit>({ potentialBot: true }), visit: { potentialBot: true },
}), }),
]; ];
const tagStats = (total: number) => ({ const tagStats = (total: number) => ({
@ -197,11 +197,11 @@ describe('tagsListReducer', () => {
describe('listTags', () => { describe('listTags', () => {
const dispatch = jest.fn(); const dispatch = jest.fn();
const getState = jest.fn(() => Mock.all<ShlinkState>()); const getState = jest.fn(() => fromPartial<ShlinkState>({}));
const listTagsMock = jest.fn(); const listTagsMock = jest.fn();
const assertNoAction = async (tagsList: TagsList) => { const assertNoAction = async (tagsList: TagsList) => {
getState.mockReturnValue(Mock.of<ShlinkState>({ tagsList })); getState.mockReturnValue(fromPartial<ShlinkState>({ tagsList }));
await listTagsCreator(buildShlinkApiClient, false)()(dispatch, getState, {}); await listTagsCreator(buildShlinkApiClient, false)()(dispatch, getState, {});

View file

@ -1,12 +1,14 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { DropdownBtnMenuProps } from '../../src/utils/DropdownBtnMenu'; import type { DropdownBtnMenuProps } from '../../src/utils/DropdownBtnMenu';
import { DropdownBtnMenu } from '../../src/utils/DropdownBtnMenu'; import { DropdownBtnMenu } from '../../src/utils/DropdownBtnMenu';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
describe('<DropdownBtnMenu />', () => { describe('<DropdownBtnMenu />', () => {
const setUp = (props: Partial<DropdownBtnMenuProps> = {}) => renderWithEvents( const setUp = (props: Partial<DropdownBtnMenuProps> = {}) => renderWithEvents(
<DropdownBtnMenu {...Mock.of<DropdownBtnMenuProps>({ toggle: jest.fn(), ...props })}>the children</DropdownBtnMenu>, <DropdownBtnMenu {...fromPartial<DropdownBtnMenuProps>({ toggle: jest.fn(), ...props })}>
the children
</DropdownBtnMenu>,
); );
it('renders expected components', () => { it('renders expected components', () => {

View file

@ -1,13 +1,13 @@
import { screen, waitFor } from '@testing-library/react'; import { screen, waitFor } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { parseISO } from 'date-fns'; import { parseISO } from 'date-fns';
import { Mock } from 'ts-mockery';
import type { DateInputProps } from '../../../src/utils/dates/DateInput'; import type { DateInputProps } from '../../../src/utils/dates/DateInput';
import { DateInput } from '../../../src/utils/dates/DateInput'; import { DateInput } from '../../../src/utils/dates/DateInput';
import { renderWithEvents } from '../../__helpers__/setUpTest'; import { renderWithEvents } from '../../__helpers__/setUpTest';
describe('<DateInput />', () => { describe('<DateInput />', () => {
const setUp = (props: Partial<DateInputProps> = {}) => renderWithEvents( const setUp = (props: Partial<DateInputProps> = {}) => renderWithEvents(
<DateInput {...Mock.of<DateInputProps>(props)} />, <DateInput {...fromPartial<DateInputProps>(props)} />,
); );
it('shows calendar icon when input is not clearable', () => { it('shows calendar icon when input is not clearable', () => {

View file

@ -1,5 +1,5 @@
import { screen, waitFor } from '@testing-library/react'; import { screen, waitFor } from '@testing-library/react';
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { DateRangeSelectorProps } from '../../../src/utils/dates/DateRangeSelector'; import type { DateRangeSelectorProps } from '../../../src/utils/dates/DateRangeSelector';
import { DateRangeSelector } from '../../../src/utils/dates/DateRangeSelector'; import { DateRangeSelector } from '../../../src/utils/dates/DateRangeSelector';
import type { DateInterval } from '../../../src/utils/helpers/dateIntervals'; import type { DateInterval } from '../../../src/utils/helpers/dateIntervals';
@ -10,7 +10,7 @@ describe('<DateRangeSelector />', () => {
const setUp = async (props: Partial<DateRangeSelectorProps> = {}) => { const setUp = async (props: Partial<DateRangeSelectorProps> = {}) => {
const result = renderWithEvents( const result = renderWithEvents(
<DateRangeSelector <DateRangeSelector
{...Mock.of<DateRangeSelectorProps>(props)} {...fromPartial<DateRangeSelectorProps>(props)}
defaultText="Default text" defaultText="Default text"
onDatesChange={onDatesChange} onDatesChange={onDatesChange}
/>, />,

View file

@ -1,4 +1,4 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { SemVer, Versions } from '../../../src/utils/helpers/version'; import type { SemVer, Versions } from '../../../src/utils/helpers/version';
import { versionMatch } from '../../../src/utils/helpers/version'; import { versionMatch } from '../../../src/utils/helpers/version';
import type { Empty } from '../../../src/utils/utils'; import type { Empty } from '../../../src/utils/utils';
@ -6,19 +6,19 @@ import type { Empty } from '../../../src/utils/utils';
describe('version', () => { describe('version', () => {
describe('versionMatch', () => { describe('versionMatch', () => {
it.each([ it.each([
[undefined, Mock.all<Versions>(), false], [undefined, fromPartial<Versions>({}), false],
[null, Mock.all<Versions>(), false], [null, fromPartial<Versions>({}), false],
['' as Empty, Mock.all<Versions>(), false], ['' as Empty, fromPartial<Versions>({}), false],
[[], Mock.all<Versions>(), false], [[], fromPartial<Versions>({}), false],
['2.8.3' as SemVer, Mock.all<Versions>(), true], ['2.8.3' as SemVer, fromPartial<Versions>({}), true],
['2.8.3' as SemVer, Mock.of<Versions>({ minVersion: '2.0.0' }), true], ['2.8.3' as SemVer, fromPartial<Versions>({ minVersion: '2.0.0' }), true],
['2.0.0' as SemVer, Mock.of<Versions>({ minVersion: '2.0.0' }), true], ['2.0.0' as SemVer, fromPartial<Versions>({ minVersion: '2.0.0' }), true],
['1.8.0' as SemVer, Mock.of<Versions>({ maxVersion: '1.8.0' }), true], ['1.8.0' as SemVer, fromPartial<Versions>({ maxVersion: '1.8.0' }), true],
['1.7.1' as SemVer, Mock.of<Versions>({ maxVersion: '1.8.0' }), true], ['1.7.1' as SemVer, fromPartial<Versions>({ maxVersion: '1.8.0' }), true],
['1.7.3' as SemVer, Mock.of<Versions>({ minVersion: '1.7.0', maxVersion: '1.8.0' }), true], ['1.7.3' as SemVer, fromPartial<Versions>({ minVersion: '1.7.0', maxVersion: '1.8.0' }), true],
['1.8.3' as SemVer, Mock.of<Versions>({ minVersion: '2.0.0' }), false], ['1.8.3' as SemVer, fromPartial<Versions>({ minVersion: '2.0.0' }), false],
['1.8.3' as SemVer, Mock.of<Versions>({ maxVersion: '1.8.0' }), false], ['1.8.3' as SemVer, fromPartial<Versions>({ maxVersion: '1.8.0' }), false],
['1.8.3' as SemVer, Mock.of<Versions>({ minVersion: '1.7.0', maxVersion: '1.8.0' }), false], ['1.8.3' as SemVer, fromPartial<Versions>({ minVersion: '1.7.0', maxVersion: '1.8.0' }), false],
])('properly matches versions based on what is provided', (version, versionConstraints, expected) => { ])('properly matches versions based on what is provided', (version, versionConstraints, expected) => {
expect(versionMatch(version, versionConstraints)).toEqual(expected); expect(versionMatch(version, versionConstraints)).toEqual(expected);
}); });

View file

@ -1,11 +1,11 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import { ColorGenerator } from '../../../src/utils/services/ColorGenerator'; import { ColorGenerator } from '../../../src/utils/services/ColorGenerator';
import type { LocalStorage } from '../../../src/utils/services/LocalStorage'; import type { LocalStorage } from '../../../src/utils/services/LocalStorage';
import { MAIN_COLOR } from '../../../src/utils/theme'; import { MAIN_COLOR } from '../../../src/utils/theme';
describe('ColorGenerator', () => { describe('ColorGenerator', () => {
let colorGenerator: ColorGenerator; let colorGenerator: ColorGenerator;
const storageMock = Mock.of<LocalStorage>({ const storageMock = fromPartial<LocalStorage>({
set: jest.fn(), set: jest.fn(),
get: jest.fn(), get: jest.fn(),
}); });

View file

@ -1,10 +1,10 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import { LocalStorage } from '../../../src/utils/services/LocalStorage'; import { LocalStorage } from '../../../src/utils/services/LocalStorage';
describe('LocalStorage', () => { describe('LocalStorage', () => {
const getItem = jest.fn((key) => (key === 'shlink.foo' ? JSON.stringify({ foo: 'bar' }) : null)); const getItem = jest.fn((key) => (key === 'shlink.foo' ? JSON.stringify({ foo: 'bar' }) : null));
const setItem = jest.fn(); const setItem = jest.fn();
const localStorageMock = Mock.of<Storage>({ getItem, setItem }); const localStorageMock = fromPartial<Storage>({ getItem, setItem });
let storage: LocalStorage; let storage: LocalStorage;
beforeEach(() => { beforeEach(() => {

View file

@ -1,7 +1,7 @@
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ColorGenerator } from '../../../../src/utils/services/ColorGenerator'; import type { ColorGenerator } from '../../../../src/utils/services/ColorGenerator';
export const colorGeneratorMock = Mock.of<ColorGenerator>({ export const colorGeneratorMock = fromPartial<ColorGenerator>({
getColorForKey: jest.fn(() => 'red'), getColorForKey: jest.fn(() => 'red'),
setColorForKey: jest.fn(), setColorForKey: jest.fn(),
isColorLightForKey: jest.fn(() => false), isColorLightForKey: jest.fn(() => false),

View file

@ -1,13 +1,10 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { formatISO } from 'date-fns'; import { formatISO } from 'date-fns';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { ReportExporter } from '../../src/common/services/ReportExporter';
import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub';
import type { Settings } from '../../src/settings/reducers/settings';
import { DomainVisits as createDomainVisits } from '../../src/visits/DomainVisits'; import { DomainVisits as createDomainVisits } from '../../src/visits/DomainVisits';
import type { DomainVisits } from '../../src/visits/reducers/domainVisits'; import type { DomainVisits } from '../../src/visits/reducers/domainVisits';
import type { Visit } from '../../src/visits/types';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
jest.mock('react-router-dom', () => ({ jest.mock('react-router-dom', () => ({
@ -19,16 +16,16 @@ describe('<DomainVisits />', () => {
const exportVisits = jest.fn(); const exportVisits = jest.fn();
const getDomainVisits = jest.fn(); const getDomainVisits = jest.fn();
const cancelGetDomainVisits = jest.fn(); const cancelGetDomainVisits = jest.fn();
const domainVisits = Mock.of<DomainVisits>({ visits: [Mock.of<Visit>({ date: formatISO(new Date()) })] }); const domainVisits = fromPartial<DomainVisits>({ visits: [{ date: formatISO(new Date()) }] });
const DomainVisits = createDomainVisits(Mock.of<ReportExporter>({ exportVisits })); const DomainVisits = createDomainVisits(fromPartial({ exportVisits }));
const setUp = () => renderWithEvents( const setUp = () => renderWithEvents(
<MemoryRouter> <MemoryRouter>
<DomainVisits <DomainVisits
{...Mock.of<MercureBoundProps>({ mercureInfo: {} })} {...fromPartial<MercureBoundProps>({ mercureInfo: {} })}
getDomainVisits={getDomainVisits} getDomainVisits={getDomainVisits}
cancelGetDomainVisits={cancelGetDomainVisits} cancelGetDomainVisits={cancelGetDomainVisits}
domainVisits={domainVisits} domainVisits={domainVisits}
settings={Mock.all<Settings>()} settings={fromPartial({})}
/> />
</MemoryRouter>, </MemoryRouter>,
); );

View file

@ -1,29 +1,26 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { formatISO } from 'date-fns'; import { formatISO } from 'date-fns';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { ReportExporter } from '../../src/common/services/ReportExporter';
import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub';
import type { Settings } from '../../src/settings/reducers/settings';
import { NonOrphanVisits as createNonOrphanVisits } from '../../src/visits/NonOrphanVisits'; import { NonOrphanVisits as createNonOrphanVisits } from '../../src/visits/NonOrphanVisits';
import type { VisitsInfo } from '../../src/visits/reducers/types'; import type { VisitsInfo } from '../../src/visits/reducers/types';
import type { Visit } from '../../src/visits/types';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
describe('<NonOrphanVisits />', () => { describe('<NonOrphanVisits />', () => {
const exportVisits = jest.fn(); const exportVisits = jest.fn();
const getNonOrphanVisits = jest.fn(); const getNonOrphanVisits = jest.fn();
const cancelGetNonOrphanVisits = jest.fn(); const cancelGetNonOrphanVisits = jest.fn();
const nonOrphanVisits = Mock.of<VisitsInfo>({ visits: [Mock.of<Visit>({ date: formatISO(new Date()) })] }); const nonOrphanVisits = fromPartial<VisitsInfo>({ visits: [{ date: formatISO(new Date()) }] });
const NonOrphanVisits = createNonOrphanVisits(Mock.of<ReportExporter>({ exportVisits })); const NonOrphanVisits = createNonOrphanVisits(fromPartial({ exportVisits }));
const setUp = () => renderWithEvents( const setUp = () => renderWithEvents(
<MemoryRouter> <MemoryRouter>
<NonOrphanVisits <NonOrphanVisits
{...Mock.of<MercureBoundProps>({ mercureInfo: {} })} {...fromPartial<MercureBoundProps>({ mercureInfo: {} })}
getNonOrphanVisits={getNonOrphanVisits} getNonOrphanVisits={getNonOrphanVisits}
cancelGetNonOrphanVisits={cancelGetNonOrphanVisits} cancelGetNonOrphanVisits={cancelGetNonOrphanVisits}
nonOrphanVisits={nonOrphanVisits} nonOrphanVisits={nonOrphanVisits}
settings={Mock.all<Settings>()} settings={fromPartial({})}
/> />
</MemoryRouter>, </MemoryRouter>,
); );

View file

@ -1,28 +1,25 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { formatISO } from 'date-fns'; import { formatISO } from 'date-fns';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { ReportExporter } from '../../src/common/services/ReportExporter';
import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub';
import type { Settings } from '../../src/settings/reducers/settings';
import { OrphanVisits as createOrphanVisits } from '../../src/visits/OrphanVisits'; import { OrphanVisits as createOrphanVisits } from '../../src/visits/OrphanVisits';
import type { VisitsInfo } from '../../src/visits/reducers/types'; import type { VisitsInfo } from '../../src/visits/reducers/types';
import type { Visit } from '../../src/visits/types';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
describe('<OrphanVisits />', () => { describe('<OrphanVisits />', () => {
const getOrphanVisits = jest.fn(); const getOrphanVisits = jest.fn();
const exportVisits = jest.fn(); const exportVisits = jest.fn();
const orphanVisits = Mock.of<VisitsInfo>({ visits: [Mock.of<Visit>({ date: formatISO(new Date()) })] }); const orphanVisits = fromPartial<VisitsInfo>({ visits: [{ date: formatISO(new Date()) }] });
const OrphanVisits = createOrphanVisits(Mock.of<ReportExporter>({ exportVisits })); const OrphanVisits = createOrphanVisits(fromPartial({ exportVisits }));
const setUp = () => renderWithEvents( const setUp = () => renderWithEvents(
<MemoryRouter> <MemoryRouter>
<OrphanVisits <OrphanVisits
{...Mock.of<MercureBoundProps>({ mercureInfo: {} })} {...fromPartial<MercureBoundProps>({ mercureInfo: {} })}
getOrphanVisits={getOrphanVisits} getOrphanVisits={getOrphanVisits}
orphanVisits={orphanVisits} orphanVisits={orphanVisits}
cancelGetOrphanVisits={jest.fn()} cancelGetOrphanVisits={jest.fn()}
settings={Mock.all<Settings>()} settings={fromPartial({})}
/> />
</MemoryRouter>, </MemoryRouter>,
); );

View file

@ -1,33 +1,29 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { formatISO } from 'date-fns'; import { formatISO } from 'date-fns';
import { identity } from 'ramda'; import { identity } from 'ramda';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { ReportExporter } from '../../src/common/services/ReportExporter';
import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub';
import type { Settings } from '../../src/settings/reducers/settings';
import type { ShortUrlDetail } from '../../src/short-urls/reducers/shortUrlDetail';
import type { ShortUrlVisits as ShortUrlVisitsState } from '../../src/visits/reducers/shortUrlVisits'; import type { ShortUrlVisits as ShortUrlVisitsState } from '../../src/visits/reducers/shortUrlVisits';
import type { ShortUrlVisitsProps } from '../../src/visits/ShortUrlVisits'; import type { ShortUrlVisitsProps } from '../../src/visits/ShortUrlVisits';
import { ShortUrlVisits as createShortUrlVisits } from '../../src/visits/ShortUrlVisits'; import { ShortUrlVisits as createShortUrlVisits } from '../../src/visits/ShortUrlVisits';
import type { Visit } from '../../src/visits/types';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
describe('<ShortUrlVisits />', () => { describe('<ShortUrlVisits />', () => {
const getShortUrlVisitsMock = jest.fn(); const getShortUrlVisitsMock = jest.fn();
const exportVisits = jest.fn(); const exportVisits = jest.fn();
const shortUrlVisits = Mock.of<ShortUrlVisitsState>({ visits: [Mock.of<Visit>({ date: formatISO(new Date()) })] }); const shortUrlVisits = fromPartial<ShortUrlVisitsState>({ visits: [{ date: formatISO(new Date()) }] });
const ShortUrlVisits = createShortUrlVisits(Mock.of<ReportExporter>({ exportVisits })); const ShortUrlVisits = createShortUrlVisits(fromPartial({ exportVisits }));
const setUp = () => renderWithEvents( const setUp = () => renderWithEvents(
<MemoryRouter> <MemoryRouter>
<ShortUrlVisits <ShortUrlVisits
{...Mock.all<ShortUrlVisitsProps>()} {...fromPartial<ShortUrlVisitsProps>({})}
{...Mock.of<MercureBoundProps>({ mercureInfo: {} })} {...fromPartial<MercureBoundProps>({ mercureInfo: {} })}
getShortUrlDetail={identity} getShortUrlDetail={identity}
getShortUrlVisits={getShortUrlVisitsMock} getShortUrlVisits={getShortUrlVisitsMock}
shortUrlVisits={shortUrlVisits} shortUrlVisits={shortUrlVisits}
shortUrlDetail={Mock.all<ShortUrlDetail>()} shortUrlDetail={fromPartial({})}
settings={Mock.all<Settings>()} settings={fromPartial({})}
cancelGetShortUrlVisits={() => {}} cancelGetShortUrlVisits={() => {}}
/> />
</MemoryRouter>, </MemoryRouter>,

View file

@ -1,6 +1,6 @@
import { screen, waitFor } from '@testing-library/react'; import { screen, waitFor } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { formatDistance, parseISO } from 'date-fns'; import { formatDistance, parseISO } from 'date-fns';
import { Mock } from 'ts-mockery';
import type { ShortUrlDetail } from '../../src/short-urls/reducers/shortUrlDetail'; import type { ShortUrlDetail } from '../../src/short-urls/reducers/shortUrlDetail';
import type { ShortUrlVisits } from '../../src/visits/reducers/shortUrlVisits'; import type { ShortUrlVisits } from '../../src/visits/reducers/shortUrlVisits';
import { ShortUrlVisitsHeader } from '../../src/visits/ShortUrlVisitsHeader'; import { ShortUrlVisitsHeader } from '../../src/visits/ShortUrlVisitsHeader';
@ -9,12 +9,12 @@ import { renderWithEvents } from '../__helpers__/setUpTest';
describe('<ShortUrlVisitsHeader />', () => { describe('<ShortUrlVisitsHeader />', () => {
const dateCreated = '2018-01-01T10:00:00+00:00'; const dateCreated = '2018-01-01T10:00:00+00:00';
const longUrl = 'https://foo.bar/bar/foo'; const longUrl = 'https://foo.bar/bar/foo';
const shortUrlVisits = Mock.of<ShortUrlVisits>({ const shortUrlVisits = fromPartial<ShortUrlVisits>({
visits: [{}, {}, {}], visits: [{}, {}, {}],
}); });
const goBack = jest.fn(); const goBack = jest.fn();
const setUp = (title?: string | null) => { const setUp = (title?: string | null) => {
const shortUrlDetail = Mock.of<ShortUrlDetail>({ const shortUrlDetail = fromPartial<ShortUrlDetail>({
shortUrl: { shortUrl: {
shortUrl: 'https://s.test/abc123', shortUrl: 'https://s.test/abc123',
longUrl, longUrl,

View file

@ -1,15 +1,11 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { formatISO } from 'date-fns'; import { formatISO } from 'date-fns';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { ReportExporter } from '../../src/common/services/ReportExporter';
import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub'; import type { MercureBoundProps } from '../../src/mercure/helpers/boundToMercureHub';
import type { Settings } from '../../src/settings/reducers/settings';
import type { ColorGenerator } from '../../src/utils/services/ColorGenerator';
import type { TagVisits as TagVisitsStats } from '../../src/visits/reducers/tagVisits'; import type { TagVisits as TagVisitsStats } from '../../src/visits/reducers/tagVisits';
import type { TagVisitsProps } from '../../src/visits/TagVisits'; import type { TagVisitsProps } from '../../src/visits/TagVisits';
import { TagVisits as createTagVisits } from '../../src/visits/TagVisits'; import { TagVisits as createTagVisits } from '../../src/visits/TagVisits';
import type { Visit } from '../../src/visits/types';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
jest.mock('react-router-dom', () => ({ jest.mock('react-router-dom', () => ({
@ -20,19 +16,19 @@ jest.mock('react-router-dom', () => ({
describe('<TagVisits />', () => { describe('<TagVisits />', () => {
const getTagVisitsMock = jest.fn(); const getTagVisitsMock = jest.fn();
const exportVisits = jest.fn(); const exportVisits = jest.fn();
const tagVisits = Mock.of<TagVisitsStats>({ visits: [Mock.of<Visit>({ date: formatISO(new Date()) })] }); const tagVisits = fromPartial<TagVisitsStats>({ visits: [{ date: formatISO(new Date()) }] });
const TagVisits = createTagVisits( const TagVisits = createTagVisits(
Mock.of<ColorGenerator>({ isColorLightForKey: () => false, getColorForKey: () => 'red' }), fromPartial({ isColorLightForKey: () => false, getColorForKey: () => 'red' }),
Mock.of<ReportExporter>({ exportVisits }), fromPartial({ exportVisits }),
); );
const setUp = () => renderWithEvents( const setUp = () => renderWithEvents(
<MemoryRouter> <MemoryRouter>
<TagVisits <TagVisits
{...Mock.all<TagVisitsProps>()} {...fromPartial<TagVisitsProps>({})}
{...Mock.of<MercureBoundProps>({ mercureInfo: {} })} {...fromPartial<MercureBoundProps>({ mercureInfo: {} })}
getTagVisits={getTagVisitsMock} getTagVisits={getTagVisitsMock}
tagVisits={tagVisits} tagVisits={tagVisits}
settings={Mock.all<Settings>()} settings={fromPartial({})}
cancelGetTagVisits={() => {}} cancelGetTagVisits={() => {}}
/> />
</MemoryRouter>, </MemoryRouter>,

View file

@ -1,16 +1,16 @@
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { ColorGenerator } from '../../src/utils/services/ColorGenerator'; import type { ColorGenerator } from '../../src/utils/services/ColorGenerator';
import type { TagVisits } from '../../src/visits/reducers/tagVisits'; import type { TagVisits } from '../../src/visits/reducers/tagVisits';
import { TagVisitsHeader } from '../../src/visits/TagVisitsHeader'; import { TagVisitsHeader } from '../../src/visits/TagVisitsHeader';
describe('<TagVisitsHeader />', () => { describe('<TagVisitsHeader />', () => {
const tagVisits = Mock.of<TagVisits>({ const tagVisits = fromPartial<TagVisits>({
tag: 'foo', tag: 'foo',
visits: [{}, {}, {}, {}], visits: [{}, {}, {}, {}],
}); });
const goBack = jest.fn(); const goBack = jest.fn();
const colorGenerator = Mock.of<ColorGenerator>({ isColorLightForKey: () => false, getColorForKey: () => 'red' }); const colorGenerator = fromPartial<ColorGenerator>({ isColorLightForKey: () => false, getColorForKey: () => 'red' });
const setUp = () => render(<TagVisitsHeader tagVisits={tagVisits} goBack={goBack} colorGenerator={colorGenerator} />); const setUp = () => render(<TagVisitsHeader tagVisits={tagVisits} goBack={goBack} colorGenerator={colorGenerator} />);
it('shows expected visits', () => { it('shows expected visits', () => {

View file

@ -1,10 +1,10 @@
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import type { Visit } from '../../src/visits/types'; import type { Visit } from '../../src/visits/types';
import { VisitsHeader } from '../../src/visits/VisitsHeader'; import { VisitsHeader } from '../../src/visits/VisitsHeader';
describe('<VisitsHeader />', () => { describe('<VisitsHeader />', () => {
const visits = [Mock.all<Visit>(), Mock.all<Visit>(), Mock.all<Visit>()]; const visits: Visit[] = [fromPartial({}), fromPartial({}), fromPartial({})];
const title = 'My header title'; const title = 'My header title';
const goBack = jest.fn(); const goBack = jest.fn();
const setUp = () => render(<VisitsHeader visits={visits} goBack={goBack} title={title} />); const setUp = () => render(<VisitsHeader visits={visits} goBack={goBack} title={title} />);

View file

@ -1,8 +1,7 @@
import { screen, waitFor } from '@testing-library/react'; import { screen, waitFor } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import { createMemoryHistory } from 'history'; import { createMemoryHistory } from 'history';
import { Router } from 'react-router-dom'; import { Router } from 'react-router-dom';
import { Mock } from 'ts-mockery';
import type { Settings } from '../../src/settings/reducers/settings';
import { rangeOf } from '../../src/utils/utils'; import { rangeOf } from '../../src/utils/utils';
import type { VisitsInfo } from '../../src/visits/reducers/types'; import type { VisitsInfo } from '../../src/visits/reducers/types';
import type { Visit } from '../../src/visits/types'; import type { Visit } from '../../src/visits/types';
@ -10,7 +9,7 @@ import { VisitsStats } from '../../src/visits/VisitsStats';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
describe('<VisitsStats />', () => { describe('<VisitsStats />', () => {
const visits = rangeOf(3, () => Mock.of<Visit>({ date: '2020-01-01' })); const visits = rangeOf(3, () => fromPartial<Visit>({ date: '2020-01-01' }));
const getVisitsMock = jest.fn(); const getVisitsMock = jest.fn();
const exportCsv = jest.fn(); const exportCsv = jest.fn();
const setUp = (visitsInfo: Partial<VisitsInfo>, activeRoute = '/by-time') => { const setUp = (visitsInfo: Partial<VisitsInfo>, activeRoute = '/by-time') => {
@ -23,9 +22,9 @@ describe('<VisitsStats />', () => {
<Router location={history.location} navigator={history}> <Router location={history.location} navigator={history}>
<VisitsStats <VisitsStats
getVisits={getVisitsMock} getVisits={getVisitsMock}
visitsInfo={Mock.of<VisitsInfo>(visitsInfo)} visitsInfo={fromPartial(visitsInfo)}
cancelGetVisits={() => {}} cancelGetVisits={() => {}}
settings={Mock.all<Settings>()} settings={fromPartial({})}
exportCsv={exportCsv} exportCsv={exportCsv}
/> />
</Router>, </Router>,

View file

@ -1,5 +1,5 @@
import { screen, waitFor } from '@testing-library/react'; import { screen, waitFor } from '@testing-library/react';
import { Mock } from 'ts-mockery'; import { fromPartial } from '@total-typescript/shoehorn';
import { rangeOf } from '../../src/utils/utils'; import { rangeOf } from '../../src/utils/utils';
import type { NormalizedVisit } from '../../src/visits/types'; import type { NormalizedVisit } from '../../src/visits/types';
import type { VisitsTableProps } from '../../src/visits/VisitsTable'; import type { VisitsTableProps } from '../../src/visits/VisitsTable';
@ -7,7 +7,7 @@ import { VisitsTable } from '../../src/visits/VisitsTable';
import { renderWithEvents } from '../__helpers__/setUpTest'; import { renderWithEvents } from '../__helpers__/setUpTest';
describe('<VisitsTable />', () => { describe('<VisitsTable />', () => {
const matchMedia = () => Mock.of<MediaQueryList>({ matches: false }); const matchMedia = () => fromPartial<MediaQueryList>({ matches: false });
const setSelectedVisits = jest.fn(); const setSelectedVisits = jest.fn();
const setUpFactory = (props: Partial<VisitsTableProps> = {}) => renderWithEvents( const setUpFactory = (props: Partial<VisitsTableProps> = {}) => renderWithEvents(
<VisitsTable <VisitsTable
@ -23,8 +23,8 @@ describe('<VisitsTable />', () => {
const setUpForOrphanVisits = (isOrphanVisits: boolean) => setUpFactory({ isOrphanVisits }); const setUpForOrphanVisits = (isOrphanVisits: boolean) => setUpFactory({ isOrphanVisits });
const setUpWithBots = () => setUpFactory({ const setUpWithBots = () => setUpFactory({
visits: [ visits: [
Mock.of<NormalizedVisit>({ potentialBot: false, date: '2022-05-05' }), fromPartial({ potentialBot: false, date: '2022-05-05' }),
Mock.of<NormalizedVisit>({ potentialBot: true, date: '2022-05-05' }), fromPartial({ potentialBot: true, date: '2022-05-05' }),
], ],
}); });
@ -48,7 +48,7 @@ describe('<VisitsTable />', () => {
[115, 7, 2], // This one will have ellipsis [115, 7, 2], // This one will have ellipsis
])('renders the expected amount of pages', (visitsCount, expectedAmountOfPageItems, expectedDisabledItems) => { ])('renders the expected amount of pages', (visitsCount, expectedAmountOfPageItems, expectedDisabledItems) => {
const { container } = setUp( const { container } = setUp(
rangeOf(visitsCount, () => Mock.of<NormalizedVisit>({ browser: '', date: '2022-01-01', referer: '' })), rangeOf(visitsCount, () => fromPartial<NormalizedVisit>({ browser: '', date: '2022-01-01', referer: '' })),
); );
expect(container.querySelectorAll('.page-item')).toHaveLength(expectedAmountOfPageItems); expect(container.querySelectorAll('.page-item')).toHaveLength(expectedAmountOfPageItems);
expect(container.querySelectorAll('.disabled')).toHaveLength(expectedDisabledItems); expect(container.querySelectorAll('.disabled')).toHaveLength(expectedDisabledItems);
@ -58,7 +58,7 @@ describe('<VisitsTable />', () => {
rangeOf(20, (value) => [value]), rangeOf(20, (value) => [value]),
)('does not render footer when there is only one page to render', (visitsCount) => { )('does not render footer when there is only one page to render', (visitsCount) => {
const { container } = setUp( const { container } = setUp(
rangeOf(visitsCount, () => Mock.of<NormalizedVisit>({ browser: '', date: '2022-01-01', referer: '' })), rangeOf(visitsCount, () => fromPartial<NormalizedVisit>({ browser: '', date: '2022-01-01', referer: '' })),
); );
expect(container.querySelector('tfoot')).not.toBeInTheDocument(); expect(container.querySelector('tfoot')).not.toBeInTheDocument();
@ -66,7 +66,7 @@ describe('<VisitsTable />', () => {
}); });
it('selected rows are highlighted', async () => { it('selected rows are highlighted', async () => {
const visits = rangeOf(10, () => Mock.of<NormalizedVisit>({ browser: '', date: '2022-01-01', referer: '' })); const visits = rangeOf(10, () => fromPartial<NormalizedVisit>({ browser: '', date: '2022-01-01', referer: '' }));
const { container, user } = setUp(visits, [visits[1], visits[2]]); const { container, user } = setUp(visits, [visits[1], visits[2]]);
// Initial situation // Initial situation
@ -86,7 +86,7 @@ describe('<VisitsTable />', () => {
}); });
it('orders visits when column is clicked', async () => { it('orders visits when column is clicked', async () => {
const { user } = setUp(rangeOf(9, (index) => Mock.of<NormalizedVisit>({ const { user } = setUp(rangeOf(9, (index) => fromPartial<NormalizedVisit>({
browser: '', browser: '',
date: `2022-01-0${10 - index}`, date: `2022-01-0${10 - index}`,
referer: `${index}`, referer: `${index}`,
@ -108,8 +108,8 @@ describe('<VisitsTable />', () => {
it('filters list when writing in search box', async () => { it('filters list when writing in search box', async () => {
const { user } = setUp([ const { user } = setUp([
...rangeOf(7, () => Mock.of<NormalizedVisit>({ browser: 'aaa', date: '2022-01-01', referer: 'aaa' })), ...rangeOf(7, () => fromPartial<NormalizedVisit>({ browser: 'aaa', date: '2022-01-01', referer: 'aaa' })),
...rangeOf(2, () => Mock.of<NormalizedVisit>({ browser: 'bbb', date: '2022-01-01', referer: 'bbb' })), ...rangeOf(2, () => fromPartial<NormalizedVisit>({ browser: 'bbb', date: '2022-01-01', referer: 'bbb' })),
]); ]);
const searchField = screen.getByPlaceholderText('Search...'); const searchField = screen.getByPlaceholderText('Search...');
const searchText = async (text: string) => { const searchText = async (text: string) => {

View file

@ -1,14 +1,14 @@
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
import type { Chart, ChartDataset } from 'chart.js'; import type { Chart, ChartDataset } from 'chart.js';
import { Mock } from 'ts-mockery';
import { DoughnutChartLegend } from '../../../src/visits/charts/DoughnutChartLegend'; import { DoughnutChartLegend } from '../../../src/visits/charts/DoughnutChartLegend';
describe('<DoughnutChartLegend />', () => { describe('<DoughnutChartLegend />', () => {
const labels = ['foo', 'bar', 'baz', 'foo2', 'bar2']; const labels = ['foo', 'bar', 'baz', 'foo2', 'bar2'];
const colors = ['green', 'blue', 'yellow']; const colors = ['green', 'blue', 'yellow'];
const defaultColor = 'red'; const defaultColor = 'red';
const datasets = [Mock.of<ChartDataset>({ backgroundColor: colors })]; const datasets = [fromPartial<ChartDataset>({ backgroundColor: colors })];
const chart = Mock.of<Chart>({ const chart = fromPartial<Chart>({
config: { config: {
data: { labels, datasets }, data: { labels, datasets },
options: { defaultColor } as any, options: { defaultColor } as any,

View file

@ -1,7 +1,7 @@
import { screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import { fromPartial } from '@total-typescript/shoehorn';
import { formatISO, subDays, subMonths, subYears } from 'date-fns'; import { formatISO, subDays, subMonths, subYears } from 'date-fns';
import { Mock } from 'ts-mockery';
import { LineChartCard } from '../../../src/visits/charts/LineChartCard'; import { LineChartCard } from '../../../src/visits/charts/LineChartCard';
import type { NormalizedVisit } from '../../../src/visits/types'; import type { NormalizedVisit } from '../../../src/visits/types';
import { setUpCanvas } from '../../__helpers__/setUpTest'; import { setUpCanvas } from '../../__helpers__/setUpTest';
@ -29,7 +29,7 @@ describe('<LineChartCard />', () => {
visits, visits,
expectedActiveIndex, expectedActiveIndex,
) => { ) => {
const { user } = setUp(visits.map((visit) => Mock.of<NormalizedVisit>(visit))); const { user } = setUp(visits.map((visit) => fromPartial(visit)));
await user.click(screen.getByRole('button', { name: /Group by/ })); await user.click(screen.getByRole('button', { name: /Group by/ }));
@ -46,8 +46,8 @@ describe('<LineChartCard />', () => {
it.each([ it.each([
[undefined, undefined], [undefined, undefined],
[[], []], [[], []],
[[Mock.of<NormalizedVisit>({ date: '2016-04-01' })], []], [[fromPartial<NormalizedVisit>({ date: '2016-04-01' })], []],
[[Mock.of<NormalizedVisit>({ date: '2016-04-01' })], [Mock.of<NormalizedVisit>({ date: '2016-04-01' })]], [[fromPartial<NormalizedVisit>({ date: '2016-04-01' })], [fromPartial<NormalizedVisit>({ date: '2016-04-01' })]],
])('renders chart with expected data', (visits, highlightedVisits) => { ])('renders chart with expected data', (visits, highlightedVisits) => {
const { events } = setUp(visits, highlightedVisits); const { events } = setUp(visits, highlightedVisits);
@ -57,8 +57,8 @@ describe('<LineChartCard />', () => {
it('includes stats for visits with no dates if selected', async () => { it('includes stats for visits with no dates if selected', async () => {
const { getEvents, user } = setUp([ const { getEvents, user } = setUp([
Mock.of<NormalizedVisit>({ date: '2016-04-01' }), fromPartial({ date: '2016-04-01' }),
Mock.of<NormalizedVisit>({ date: '2016-01-01' }), fromPartial({ date: '2016-01-01' }),
]); ]);
const eventsBefore = getEvents(); const eventsBefore = getEvents();