mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-03 14:57:22 +03:00
Updated dependencies and fixed coding styles
This commit is contained in:
parent
fb2194d2d1
commit
47fb26368b
20 changed files with 3687 additions and 2136 deletions
27
.eslintrc
27
.eslintrc
|
@ -15,17 +15,20 @@
|
|||
"setImmediate": true
|
||||
},
|
||||
"rules": {
|
||||
"max-len": ["error", {
|
||||
"code": 120,
|
||||
"ignoreStrings": true,
|
||||
"ignoreTemplateLiterals": true,
|
||||
"ignoreComments": true
|
||||
}],
|
||||
"no-mixed-operators": "off",
|
||||
"object-shorthand": "off",
|
||||
"react/display-name": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"@typescript-eslint/no-extraneous-class": "off",
|
||||
"@typescript-eslint/require-array-sort-compare": "off"
|
||||
"comma-dangle": "off",
|
||||
"@typescript-eslint/comma-dangle": ["error", "always-multiline"],
|
||||
"@typescript-eslint/method-signature-style": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||
"@typescript-eslint/unbound-method": "off",
|
||||
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||
"@typescript-eslint/no-unsafe-call": "off",
|
||||
"@typescript-eslint/no-unsafe-return": "off",
|
||||
"@typescript-eslint/naming-convention": "off",
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/no-base-to-string": "off",
|
||||
"no-nonoctal-decimal-escape": "off"
|
||||
}
|
||||
}
|
||||
|
|
5655
package-lock.json
generated
5655
package-lock.json
generated
File diff suppressed because it is too large
Load diff
42
package.json
42
package.json
|
@ -7,7 +7,7 @@
|
|||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "npm run lint:css && npm run lint:js",
|
||||
"lint:js": "eslint --ext .js,.ts,.tsx src test scripts config",
|
||||
"lint:js": "eslint --ext .js,.ts,.tsx src test",
|
||||
"lint:js:fix": "npm run lint:js -- --fix",
|
||||
"lint:css": "stylelint src/*.scss src/**/*.scss",
|
||||
"lint:css:fix": "npm run lint:css -- --fix",
|
||||
|
@ -60,34 +60,33 @@
|
|||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.3",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.12.1",
|
||||
"@shlinkio/eslint-config-js-coding-standard": "~1.1.0",
|
||||
"@stryker-mutator/core": "^4.3.1",
|
||||
"@stryker-mutator/jest-runner": "^4.3.1",
|
||||
"@stryker-mutator/typescript-checker": "^4.3.1",
|
||||
"@svgr/webpack": "^5.4.0",
|
||||
"@types/chart.js": "^2.9.27",
|
||||
"@babel/core": "^7.13.8",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.13.8",
|
||||
"@shlinkio/eslint-config-js-coding-standard": "~1.2.0",
|
||||
"@stryker-mutator/core": "^4.4.1",
|
||||
"@stryker-mutator/jest-runner": "^4.4.1",
|
||||
"@stryker-mutator/typescript-checker": "^4.4.1",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"@types/chart.js": "^2.9.31",
|
||||
"@types/classnames": "^2.2.11",
|
||||
"@types/enzyme": "^3.10.8",
|
||||
"@types/jest": "^26.0.15",
|
||||
"@types/leaflet": "^1.5.19",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@types/leaflet": "^1.5.23",
|
||||
"@types/moment": "^2.13.0",
|
||||
"@types/qs": "^6.9.5",
|
||||
"@types/ramda": "^0.27.32",
|
||||
"@types/react": "^16.9.56",
|
||||
"@types/react-autosuggest": "^10.0.1",
|
||||
"@types/ramda": "^0.27.38",
|
||||
"@types/react": "^17.0.2",
|
||||
"@types/react-autosuggest": "^10.1.2",
|
||||
"@types/react-color": "^3.0.4",
|
||||
"@types/react-copy-to-clipboard": "^4.3.0",
|
||||
"@types/react-datepicker": "^3.1.1",
|
||||
"@types/react-dom": "^16.9.9",
|
||||
"@types/react-copy-to-clipboard": "^5.0.0",
|
||||
"@types/react-datepicker": "^3.1.5",
|
||||
"@types/react-dom": "^17.0.1",
|
||||
"@types/react-leaflet": "^2.5.2",
|
||||
"@types/react-redux": "^7.1.11",
|
||||
"@types/react-router-dom": "^5.1.6",
|
||||
"@types/react-redux": "^7.1.16",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"@types/react-tagsinput": "^3.19.7",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@typescript-eslint/parser": "^4.7.0",
|
||||
"@wojtekmaj/enzyme-adapter-react-17": "^0.3.1",
|
||||
"adm-zip": "^0.4.16",
|
||||
"autoprefixer": "^10.0.2",
|
||||
|
@ -107,6 +106,7 @@
|
|||
"enzyme": "^3.11.0",
|
||||
"eslint": "^7.13.0",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"fork-ts-checker-webpack-plugin-alt": "^0.4.14",
|
||||
"fs-extra": "^9.0.1",
|
||||
|
|
|
@ -7,7 +7,7 @@ import { faChevronRight as chevronIcon } from '@fortawesome/free-solid-svg-icons
|
|||
import { ServerWithId } from './data';
|
||||
import './ServersListGroup.scss';
|
||||
|
||||
interface ServersListGroup {
|
||||
interface ServersListGroupProps {
|
||||
servers: ServerWithId[];
|
||||
embedded?: boolean;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ const ServerListItem = ({ id, name }: { id: string; name: string }) => (
|
|||
</ListGroupItem>
|
||||
);
|
||||
|
||||
const ServersListGroup: FC<ServersListGroup> = ({ servers, children, embedded = false }) => (
|
||||
const ServersListGroup: FC<ServersListGroupProps> = ({ servers, children, embedded = false }) => (
|
||||
<>
|
||||
{children && <h5 className="mb-md-3">{children}</h5>}
|
||||
{servers.length > 0 && (
|
||||
|
|
|
@ -7,12 +7,13 @@ import { prettify } from '../../utils/helpers/numbers';
|
|||
import VisitStatsLink, { VisitStatsLinkProps } from './VisitStatsLink';
|
||||
import './ShortUrlVisitsCount.scss';
|
||||
|
||||
// TODO This interface should be called ShortUrlVisitsCountProps, and the component should not have the Comp suffix
|
||||
export interface ShortUrlVisitsCount extends VisitStatsLinkProps {
|
||||
visitsCount: number;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
const ShortUrlVisitsCount = ({ visitsCount, shortUrl, selectedServer, active = false }: ShortUrlVisitsCount) => {
|
||||
const ShortUrlVisitsCountComp = ({ visitsCount, shortUrl, selectedServer, active = false }: ShortUrlVisitsCount) => {
|
||||
const maxVisits = shortUrl?.meta?.maxVisits;
|
||||
const visitsLink = (
|
||||
<VisitStatsLink selectedServer={selectedServer} shortUrl={shortUrl}>
|
||||
|
@ -54,4 +55,4 @@ const ShortUrlVisitsCount = ({ visitsCount, shortUrl, selectedServer, active = f
|
|||
);
|
||||
};
|
||||
|
||||
export default ShortUrlVisitsCount;
|
||||
export default ShortUrlVisitsCountComp;
|
||||
|
|
|
@ -5,11 +5,11 @@ import { buildReducer } from '../../utils/helpers/redux';
|
|||
import { ProblemDetailsError, ShlinkTags } from '../../api/types';
|
||||
import { GetState } from '../../container/types';
|
||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||
import { TagStats } from '../data';
|
||||
import { CreateVisit, Stats } from '../../visits/types';
|
||||
import { parseApiError } from '../../api/utils';
|
||||
import { TagStats } from '../data';
|
||||
import { DeleteTagAction, TAG_DELETED } from './tagDelete';
|
||||
import { EditTagAction, TAG_EDITED } from './tagEdit';
|
||||
import { parseApiError } from '../../api/utils';
|
||||
|
||||
/* eslint-disable padding-line-between-statements */
|
||||
export const LIST_TAGS_START = 'shlink/tagsList/LIST_TAGS_START';
|
||||
|
@ -34,7 +34,6 @@ interface ListTagsAction extends Action<string> {
|
|||
stats: TagsStatsMap;
|
||||
}
|
||||
|
||||
|
||||
interface ListTagsFailedAction extends Action<string> {
|
||||
errorData?: ProblemDetailsError;
|
||||
}
|
||||
|
@ -44,11 +43,11 @@ interface FilterTagsAction extends Action<string> {
|
|||
}
|
||||
|
||||
type ListTagsCombinedAction = ListTagsAction
|
||||
& DeleteTagAction
|
||||
& CreateVisitsAction
|
||||
& EditTagAction
|
||||
& FilterTagsAction
|
||||
& ListTagsFailedAction;
|
||||
& DeleteTagAction
|
||||
& CreateVisitsAction
|
||||
& EditTagAction
|
||||
& FilterTagsAction
|
||||
& ListTagsFailedAction;
|
||||
|
||||
const initialState = {
|
||||
tags: [],
|
||||
|
@ -75,13 +74,13 @@ const increaseVisitsForTags = (tags: TagIncrease[], stats: TagsStatsMap) => tags
|
|||
return stats;
|
||||
}, { ...stats });
|
||||
const calculateVisitsPerTag = (createdVisits: CreateVisit[]): TagIncrease[] => Object.entries(
|
||||
createdVisits.reduce((acc, { shortUrl }) => {
|
||||
createdVisits.reduce<Stats>((acc, { shortUrl }) => {
|
||||
shortUrl?.tags.forEach((tag) => {
|
||||
acc[tag] = (acc[tag] || 0) + 1;
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, {} as Stats),
|
||||
}, {}),
|
||||
);
|
||||
|
||||
export default buildReducer<TagsList, ListTagsCombinedAction>({
|
||||
|
|
|
@ -39,7 +39,7 @@ const DateInput = (props: DateInputProps) => {
|
|||
{...transformProps(props)}
|
||||
dateFormat="yyyy-MM-dd"
|
||||
className={classNames('date-input-container__input form-control', className)}
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error The DatePicker type definition is wrong. It has a ref prop
|
||||
ref={ref}
|
||||
/>
|
||||
{showCalendarIcon && (
|
||||
|
|
|
@ -2,7 +2,7 @@ import { FC } from 'react';
|
|||
import { v4 as uuid } from 'uuid';
|
||||
import { InputType } from 'reactstrap/lib/Input';
|
||||
|
||||
interface FormGroupContainer {
|
||||
interface FormGroupContainerProps {
|
||||
value: string;
|
||||
onChange: (newValue: string) => void;
|
||||
id?: string;
|
||||
|
@ -10,7 +10,7 @@ interface FormGroupContainer {
|
|||
required?: boolean;
|
||||
}
|
||||
|
||||
export const FormGroupContainer: FC<FormGroupContainer> = (
|
||||
export const FormGroupContainer: FC<FormGroupContainerProps> = (
|
||||
{ children, value, onChange, id = uuid(), type = 'text', required = true },
|
||||
) => (
|
||||
<div className="form-group">
|
||||
|
|
|
@ -7,7 +7,7 @@ import './SearchField.scss';
|
|||
const DEFAULT_SEARCH_INTERVAL = 500;
|
||||
let timer: NodeJS.Timeout | null;
|
||||
|
||||
interface SearchField {
|
||||
interface SearchFieldProps {
|
||||
onChange: (value: string) => void;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
|
@ -16,7 +16,7 @@ interface SearchField {
|
|||
}
|
||||
|
||||
const SearchField = (
|
||||
{ onChange, className, placeholder = 'Search...', large = true, noBorder = false }: SearchField,
|
||||
{ onChange, className, placeholder = 'Search...', large = true, noBorder = false }: SearchFieldProps,
|
||||
) => {
|
||||
const [ searchTerm, setSearchTerm ] = useState('');
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ export const intervalToDateRange = (dateInterval?: DateInterval): DateRange => {
|
|||
case 'today':
|
||||
return { startDate: moment().startOf('day'), endDate: moment() };
|
||||
case 'yesterday':
|
||||
const yesterday = moment().subtract(1, 'day');
|
||||
const yesterday = moment().subtract(1, 'day'); // eslint-disable-line no-case-declarations
|
||||
|
||||
return { startDate: yesterday.startOf('day'), endDate: yesterday.endOf('day') };
|
||||
case 'last7Days':
|
||||
|
|
|
@ -34,7 +34,7 @@ export const useToggle = (initialValue = false): ToggleResult => {
|
|||
|
||||
export const useSwipeable = (showSidebar: () => void, hideSidebar: () => void) => {
|
||||
const swipeMenuIfNoModalExists = (callback: () => void) => (e: any) => {
|
||||
const swippedOnVisitsTable = (e.event.composedPath() as HTMLElement[]).some(
|
||||
const swippedOnVisitsTable = (e.event.composedPath() as HTMLElement[]).some( // eslint-disable-lin @typescript-eslint/no-unsafe-call
|
||||
({ classList }) => classList?.contains('visits-table'),
|
||||
);
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import VisitsHeader from './VisitsHeader';
|
||||
import './ShortUrlVisitsHeader.scss';
|
||||
import { VisitsInfo } from './types';
|
||||
import './ShortUrlVisitsHeader.scss';
|
||||
|
||||
interface OrphanVisitsHeader {
|
||||
interface OrphanVisitsHeaderProps {
|
||||
orphanVisits: VisitsInfo;
|
||||
goBack: () => void;
|
||||
}
|
||||
|
||||
export const OrphanVisitsHeader = ({ orphanVisits, goBack }: OrphanVisitsHeader) => {
|
||||
export const OrphanVisitsHeader = ({ orphanVisits, goBack }: OrphanVisitsHeaderProps) => {
|
||||
const { visits } = orphanVisits;
|
||||
|
||||
return <VisitsHeader title="Orphan visits" goBack={goBack} visits={visits} />;
|
||||
|
|
|
@ -4,13 +4,13 @@ import VisitsHeader from './VisitsHeader';
|
|||
import { TagVisits } from './reducers/tagVisits';
|
||||
import './ShortUrlVisitsHeader.scss';
|
||||
|
||||
interface TagVisitsHeader {
|
||||
interface TagVisitsHeaderProps {
|
||||
tagVisits: TagVisits;
|
||||
goBack: () => void;
|
||||
colorGenerator: ColorGenerator;
|
||||
}
|
||||
|
||||
const TagVisitsHeader = ({ tagVisits, goBack, colorGenerator }: TagVisitsHeader) => {
|
||||
const TagVisitsHeader = ({ tagVisits, goBack, colorGenerator }: TagVisitsHeaderProps) => {
|
||||
const { visits, tag } = tagVisits;
|
||||
|
||||
const visitsStatsTitle = (
|
||||
|
|
|
@ -55,7 +55,7 @@ const generateGraphData = (
|
|||
'#DCDCDC',
|
||||
'#463730',
|
||||
],
|
||||
borderColor: isBarChart ? MAIN_COLOR : (isDarkThemeEnabled() ? PRIMARY_DARK_COLOR : PRIMARY_LIGHT_COLOR),
|
||||
borderColor: isBarChart ? MAIN_COLOR : isDarkThemeEnabled() ? PRIMARY_DARK_COLOR : PRIMARY_LIGHT_COLOR,
|
||||
borderWidth: 2,
|
||||
},
|
||||
highlightedData && {
|
||||
|
@ -127,7 +127,7 @@ const DefaultChart = (
|
|||
}, { ...stats }),
|
||||
);
|
||||
const highlightedData = statsAreDefined(highlightedStats) ? fillTheGaps(highlightedStats, labels) : undefined;
|
||||
const [ chartRef, setChartRef ] = useState<HorizontalBar | Doughnut | undefined>()
|
||||
const [ chartRef, setChartRef ] = useState<HorizontalBar | Doughnut | undefined>();
|
||||
|
||||
const options: ChartOptions = {
|
||||
legend: { display: false },
|
||||
|
@ -137,7 +137,6 @@ const DefaultChart = (
|
|||
{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
// @ts-expect-error
|
||||
precision: 0,
|
||||
callback: prettify,
|
||||
max,
|
||||
|
|
|
@ -81,17 +81,18 @@ const groupVisitsByStep = (step: Step, visits: NormalizedVisit[]): Stats => visi
|
|||
{},
|
||||
);
|
||||
|
||||
const visitsToDatasetGroups = (step: Step, visits: NormalizedVisit[]) => visits.reduce(
|
||||
(acc, visit) => {
|
||||
const key = STEP_TO_DATE_FORMAT[step](visit.date);
|
||||
const visitsToDatasetGroups = (step: Step, visits: NormalizedVisit[]) =>
|
||||
visits.reduce<Record<string, NormalizedVisit[]>>(
|
||||
(acc, visit) => {
|
||||
const key = STEP_TO_DATE_FORMAT[step](visit.date);
|
||||
|
||||
acc[key] = acc[key] ?? [];
|
||||
acc[key].push(visit);
|
||||
acc[key] = acc[key] ?? [];
|
||||
acc[key].push(visit);
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, NormalizedVisit[]>,
|
||||
);
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
const generateLabels = (step: Step, visits: NormalizedVisit[]): string[] => {
|
||||
const unit = STEP_TO_DATE_UNIT_MAP[step];
|
||||
|
@ -186,7 +187,6 @@ const LineChartCard = (
|
|||
{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
// @ts-expect-error
|
||||
precision: 0,
|
||||
callback: prettify,
|
||||
},
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Stats, StatsRow } from '../types';
|
|||
import GraphCard from './GraphCard';
|
||||
import { DefaultChartProps } from './DefaultChart';
|
||||
|
||||
const toLowerIfString = (value: any) => type(value) === 'String' ? toLower(value) : value;
|
||||
const toLowerIfString = (value: any) => type(value) === 'String' ? toLower(value) : value; // eslint-disable-line @typescript-eslint/no-unsafe-return
|
||||
const pickKeyFromPair = ([ key ]: StatsRow) => key;
|
||||
const pickValueFromPair = ([ , value ]: StatsRow) => value;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { AxiosInstance, AxiosRequestConfig } from 'axios';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient';
|
||||
import { OptionalString } from '../../../src/utils/utils';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import { ShlinkDomain, ShlinkVisitsOverview } from '../../../src/api/types';
|
||||
import { ShortUrl } from '../../../src/short-urls/data';
|
||||
import { Visit } from '../../../src/visits/types';
|
||||
|
@ -49,7 +49,7 @@ describe('ShlinkApiClient', () => {
|
|||
const { createShortUrl } = new ShlinkApiClient(axiosSpy, '', '');
|
||||
|
||||
await createShortUrl(
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error in case maxVisits is null, it needs to be ignored as if it was undefined
|
||||
{ longUrl: 'bar', customSlug: undefined, maxVisits: null },
|
||||
);
|
||||
|
||||
|
@ -145,7 +145,7 @@ describe('ShlinkApiClient', () => {
|
|||
maxVisits: 50,
|
||||
validSince: '2025-01-01T10:00:00+01:00',
|
||||
};
|
||||
const expectedResp = Mock.of<ShortUrl>()
|
||||
const expectedResp = Mock.of<ShortUrl>();
|
||||
const axiosSpy = createAxiosMock({ data: expectedResp });
|
||||
const { updateShortUrlMeta } = new ShlinkApiClient(axiosSpy, '', '');
|
||||
|
||||
|
@ -259,7 +259,7 @@ describe('ShlinkApiClient', () => {
|
|||
|
||||
describe('listDomains', () => {
|
||||
it('returns domains', async () => {
|
||||
const expectedData = [Mock.all<ShlinkDomain>(), Mock.all<ShlinkDomain>()];
|
||||
const expectedData = [ Mock.all<ShlinkDomain>(), Mock.all<ShlinkDomain>() ];
|
||||
const resp = {
|
||||
domains: { data: expectedData },
|
||||
};
|
||||
|
|
|
@ -46,7 +46,7 @@ describe('ShlinkApiClientBuilder', () => {
|
|||
const apiKey = 'apiKey';
|
||||
const apiClient = buildShlinkApiClient(axiosMock)(server({ url, apiKey }));
|
||||
|
||||
expect(apiClient['baseUrl']).toEqual(url); // eslint-disable-line dot-notation
|
||||
expect(apiClient['apiKey']).toEqual(apiKey); // eslint-disable-line dot-notation
|
||||
expect(apiClient['baseUrl']).toEqual(url); // eslint-disable-line @typescript-eslint/dot-notation
|
||||
expect(apiClient['apiKey']).toEqual(apiKey); // eslint-disable-line @typescript-eslint/dot-notation
|
||||
});
|
||||
});
|
||||
|
|
|
@ -91,14 +91,14 @@ describe('visitsOverviewReducer', () => {
|
|||
|
||||
it('dispatches start and success when promise is resolved', async () => {
|
||||
const resolvedOverview = Mock.of<ShlinkVisitsOverview>({ visitsCount: 50 });
|
||||
const ShlinkApiClient = buildApiClientMock(Promise.resolve(resolvedOverview));
|
||||
const shlinkApiClient = buildApiClientMock(Promise.resolve(resolvedOverview));
|
||||
|
||||
await loadVisitsOverview(() => ShlinkApiClient)()(dispatchMock, getState);
|
||||
await loadVisitsOverview(() => shlinkApiClient)()(dispatchMock, getState);
|
||||
|
||||
expect(dispatchMock).toHaveBeenCalledTimes(2);
|
||||
expect(dispatchMock).toHaveBeenNthCalledWith(1, { type: GET_OVERVIEW_START });
|
||||
expect(dispatchMock).toHaveBeenNthCalledWith(2, { type: GET_OVERVIEW, visitsCount: 50 });
|
||||
expect(ShlinkApiClient.getVisitsOverview).toHaveBeenCalledTimes(1);
|
||||
expect(shlinkApiClient.getVisitsOverview).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Mock } from 'ts-mockery';
|
||||
import { GroupedNewVisits, groupNewVisitsByType } from '../../../src/visits/types/helpers';
|
||||
import { CreateVisit, OrphanVisit, Visit } from '../../../src/visits/types';
|
||||
import { Mock } from 'ts-mockery';
|
||||
|
||||
describe('visitsTypeHelpers', () => {
|
||||
describe('groupNewVisitsByType', () => {
|
||||
|
|
Loading…
Reference in a new issue