mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-03 14:57:22 +03:00
Migrated first short URL reducers to typescript
This commit is contained in:
parent
fefa4e7848
commit
d8f3952920
9 changed files with 134 additions and 35 deletions
|
@ -64,7 +64,8 @@
|
||||||
"max-len": ["error", {
|
"max-len": ["error", {
|
||||||
"code": 120,
|
"code": 120,
|
||||||
"ignoreStrings": true,
|
"ignoreStrings": true,
|
||||||
"ignoreTemplateLiterals": true
|
"ignoreTemplateLiterals": true,
|
||||||
|
"ignoreTrailingComments": true
|
||||||
}],
|
}],
|
||||||
"no-mixed-operators": "off",
|
"no-mixed-operators": "off",
|
||||||
"react/display-name": "off"
|
"react/display-name": "off"
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { MercureInfo } from '../mercure/reducers/mercureInfo';
|
||||||
import { ServersMap } from '../servers/reducers/servers';
|
import { ServersMap } from '../servers/reducers/servers';
|
||||||
import { SelectedServer } from '../servers/data';
|
import { SelectedServer } from '../servers/data';
|
||||||
import { Settings } from '../settings/reducers/settings';
|
import { Settings } from '../settings/reducers/settings';
|
||||||
|
import { ShortUrlMetaEdition } from '../short-urls/reducers/shortUrlMeta';
|
||||||
|
import { ShortUrlCreation } from '../short-urls/reducers/shortUrlCreation';
|
||||||
|
|
||||||
export type ConnectDecorator = (props: string[], actions?: string[]) => any;
|
export type ConnectDecorator = (props: string[], actions?: string[]) => any;
|
||||||
|
|
||||||
|
@ -10,10 +12,10 @@ export interface ShlinkState {
|
||||||
selectedServer: SelectedServer;
|
selectedServer: SelectedServer;
|
||||||
shortUrlsList: any;
|
shortUrlsList: any;
|
||||||
shortUrlsListParams: any;
|
shortUrlsListParams: any;
|
||||||
shortUrlCreationResult: any;
|
shortUrlCreationResult: ShortUrlCreation;
|
||||||
shortUrlDeletion: any;
|
shortUrlDeletion: any;
|
||||||
shortUrlTags: any;
|
shortUrlTags: any;
|
||||||
shortUrlMeta: any;
|
shortUrlMeta: ShortUrlMetaEdition;
|
||||||
shortUrlEdition: any;
|
shortUrlEdition: any;
|
||||||
shortUrlVisits: any;
|
shortUrlVisits: any;
|
||||||
tagVisits: any;
|
tagVisits: any;
|
||||||
|
|
29
src/short-urls/data/index.ts
Normal file
29
src/short-urls/data/index.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { Nullable } from '../../utils/utils';
|
||||||
|
|
||||||
|
export interface ShortUrlData {
|
||||||
|
longUrl: string;
|
||||||
|
tags?: string[];
|
||||||
|
customSlug?: string;
|
||||||
|
shortCodeLength?: number;
|
||||||
|
domain?: string;
|
||||||
|
validSince?: string;
|
||||||
|
validUntil?: string;
|
||||||
|
maxVisits?: number;
|
||||||
|
findIfExists?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShortUrl {
|
||||||
|
shortCode: string;
|
||||||
|
shortUrl: string;
|
||||||
|
longUrl: string;
|
||||||
|
visitsCount: number;
|
||||||
|
meta: Required<Nullable<ShortUrlMeta>>;
|
||||||
|
tags: string[];
|
||||||
|
domain: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShortUrlMeta {
|
||||||
|
validSince?: string;
|
||||||
|
validUntil?: string;
|
||||||
|
maxVisits?: number;
|
||||||
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { createAction, handleActions } from 'redux-actions';
|
import { createAction, handleActions } from 'redux-actions';
|
||||||
|
import { Action, Dispatch } from 'redux';
|
||||||
|
import { ShlinkApiClientBuilder } from '../../utils/services/types';
|
||||||
|
import { GetState } from '../../container/types';
|
||||||
|
import { ShortUrl, ShortUrlData } from '../data';
|
||||||
|
|
||||||
/* eslint-disable padding-line-between-statements */
|
/* eslint-disable padding-line-between-statements */
|
||||||
export const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START';
|
export const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START';
|
||||||
|
@ -8,6 +12,7 @@ export const CREATE_SHORT_URL = 'shlink/createShortUrl/CREATE_SHORT_URL';
|
||||||
export const RESET_CREATE_SHORT_URL = 'shlink/createShortUrl/RESET_CREATE_SHORT_URL';
|
export const RESET_CREATE_SHORT_URL = 'shlink/createShortUrl/RESET_CREATE_SHORT_URL';
|
||||||
/* eslint-enable padding-line-between-statements */
|
/* eslint-enable padding-line-between-statements */
|
||||||
|
|
||||||
|
/** @deprecated Use ShortUrlCreation interface instead */
|
||||||
export const createShortUrlResultType = PropTypes.shape({
|
export const createShortUrlResultType = PropTypes.shape({
|
||||||
result: PropTypes.shape({
|
result: PropTypes.shape({
|
||||||
shortUrl: PropTypes.string,
|
shortUrl: PropTypes.string,
|
||||||
|
@ -16,27 +21,36 @@ export const createShortUrlResultType = PropTypes.shape({
|
||||||
error: PropTypes.bool,
|
error: PropTypes.bool,
|
||||||
});
|
});
|
||||||
|
|
||||||
const initialState = {
|
export interface ShortUrlCreation {
|
||||||
|
result: ShortUrl | null;
|
||||||
|
saving: boolean;
|
||||||
|
error: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: ShortUrlCreation = {
|
||||||
result: null,
|
result: null,
|
||||||
saving: false,
|
saving: false,
|
||||||
error: false,
|
error: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default handleActions({
|
export default handleActions<ShortUrlCreation, any>({
|
||||||
[CREATE_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }),
|
[CREATE_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }),
|
||||||
[CREATE_SHORT_URL_ERROR]: (state) => ({ ...state, saving: false, error: true }),
|
[CREATE_SHORT_URL_ERROR]: (state) => ({ ...state, saving: false, error: true }),
|
||||||
[CREATE_SHORT_URL]: (state, { result }) => ({ result, saving: false, error: false }),
|
[CREATE_SHORT_URL]: (_, { result }: any) => ({ result, saving: false, error: false }),
|
||||||
[RESET_CREATE_SHORT_URL]: () => initialState,
|
[RESET_CREATE_SHORT_URL]: () => initialState,
|
||||||
}, initialState);
|
}, initialState);
|
||||||
|
|
||||||
export const createShortUrl = (buildShlinkApiClient) => (data) => async (dispatch, getState) => {
|
export const createShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (data: ShortUrlData) => async (
|
||||||
|
dispatch: Dispatch,
|
||||||
|
getState: GetState,
|
||||||
|
) => {
|
||||||
dispatch({ type: CREATE_SHORT_URL_START });
|
dispatch({ type: CREATE_SHORT_URL_START });
|
||||||
const { createShortUrl } = buildShlinkApiClient(getState);
|
const { createShortUrl } = buildShlinkApiClient(getState);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await createShortUrl(data);
|
const result = await createShortUrl(data);
|
||||||
|
|
||||||
dispatch({ type: CREATE_SHORT_URL, result });
|
dispatch<Action & { result: ShortUrl }>({ type: CREATE_SHORT_URL, result });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dispatch({ type: CREATE_SHORT_URL_ERROR });
|
dispatch({ type: CREATE_SHORT_URL_ERROR });
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
import { createAction, handleActions } from 'redux-actions';
|
import { createAction, handleActions, Action } from 'redux-actions';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
import { ShortUrlMeta } from '../data';
|
||||||
|
import { ShlinkApiClientBuilder } from '../../utils/services/types';
|
||||||
|
import { GetState } from '../../container/types';
|
||||||
|
|
||||||
/* eslint-disable padding-line-between-statements */
|
/* eslint-disable padding-line-between-statements */
|
||||||
export const EDIT_SHORT_URL_META_START = 'shlink/shortUrlMeta/EDIT_SHORT_URL_META_START';
|
export const EDIT_SHORT_URL_META_START = 'shlink/shortUrlMeta/EDIT_SHORT_URL_META_START';
|
||||||
|
@ -8,12 +12,14 @@ export const SHORT_URL_META_EDITED = 'shlink/shortUrlMeta/SHORT_URL_META_EDITED'
|
||||||
export const RESET_EDIT_SHORT_URL_META = 'shlink/shortUrlMeta/RESET_EDIT_SHORT_URL_META';
|
export const RESET_EDIT_SHORT_URL_META = 'shlink/shortUrlMeta/RESET_EDIT_SHORT_URL_META';
|
||||||
/* eslint-enable padding-line-between-statements */
|
/* eslint-enable padding-line-between-statements */
|
||||||
|
|
||||||
|
/** @deprecated Use ShortUrlMeta interface instead */
|
||||||
export const shortUrlMetaType = PropTypes.shape({
|
export const shortUrlMetaType = PropTypes.shape({
|
||||||
validSince: PropTypes.string,
|
validSince: PropTypes.string,
|
||||||
validUntil: PropTypes.string,
|
validUntil: PropTypes.string,
|
||||||
maxVisits: PropTypes.number,
|
maxVisits: PropTypes.number,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** @deprecated Use ShortUrlMetaEdition interface instead */
|
||||||
export const shortUrlEditMetaType = PropTypes.shape({
|
export const shortUrlEditMetaType = PropTypes.shape({
|
||||||
shortCode: PropTypes.string,
|
shortCode: PropTypes.string,
|
||||||
meta: shortUrlMetaType.isRequired,
|
meta: shortUrlMetaType.isRequired,
|
||||||
|
@ -21,27 +27,47 @@ export const shortUrlEditMetaType = PropTypes.shape({
|
||||||
error: PropTypes.bool.isRequired,
|
error: PropTypes.bool.isRequired,
|
||||||
});
|
});
|
||||||
|
|
||||||
const initialState = {
|
export interface ShortUrlMetaEdition {
|
||||||
|
shortCode: string | null;
|
||||||
|
meta: ShortUrlMeta;
|
||||||
|
saving: boolean;
|
||||||
|
error: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ShortUrlMetaEditedAction {
|
||||||
|
shortCode: string;
|
||||||
|
domain?: string | null;
|
||||||
|
meta: ShortUrlMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: ShortUrlMetaEdition = {
|
||||||
shortCode: null,
|
shortCode: null,
|
||||||
meta: {},
|
meta: {},
|
||||||
saving: false,
|
saving: false,
|
||||||
error: false,
|
error: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default handleActions({
|
export default handleActions<ShortUrlMetaEdition, ShortUrlMetaEditedAction>({
|
||||||
[EDIT_SHORT_URL_META_START]: (state) => ({ ...state, saving: true, error: false }),
|
[EDIT_SHORT_URL_META_START]: (state) => ({ ...state, saving: true, error: false }),
|
||||||
[EDIT_SHORT_URL_META_ERROR]: (state) => ({ ...state, saving: false, error: true }),
|
[EDIT_SHORT_URL_META_ERROR]: (state) => ({ ...state, saving: false, error: true }),
|
||||||
[SHORT_URL_META_EDITED]: (state, { shortCode, meta }) => ({ shortCode, meta, saving: false, error: false }),
|
[SHORT_URL_META_EDITED]: (_, { payload }) => ({ ...payload, saving: false, error: false }),
|
||||||
[RESET_EDIT_SHORT_URL_META]: () => initialState,
|
[RESET_EDIT_SHORT_URL_META]: () => initialState,
|
||||||
}, initialState);
|
}, initialState);
|
||||||
|
|
||||||
export const editShortUrlMeta = (buildShlinkApiClient) => (shortCode, domain, meta) => async (dispatch, getState) => {
|
export const editShortUrlMeta = (buildShlinkApiClient: ShlinkApiClientBuilder) => (
|
||||||
|
shortCode: string,
|
||||||
|
domain: string | null | undefined,
|
||||||
|
meta: ShortUrlMeta,
|
||||||
|
) => async (dispatch: Dispatch, getState: GetState) => {
|
||||||
dispatch({ type: EDIT_SHORT_URL_META_START });
|
dispatch({ type: EDIT_SHORT_URL_META_START });
|
||||||
const { updateShortUrlMeta } = buildShlinkApiClient(getState);
|
const { updateShortUrlMeta } = buildShlinkApiClient(getState);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateShortUrlMeta(shortCode, domain, meta);
|
await updateShortUrlMeta(shortCode, domain, meta);
|
||||||
dispatch({ shortCode, meta, domain, type: SHORT_URL_META_EDITED });
|
dispatch<Action<ShortUrlMetaEditedAction>>({
|
||||||
|
type: SHORT_URL_META_EDITED,
|
||||||
|
payload: { shortCode, meta, domain },
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dispatch({ type: EDIT_SHORT_URL_META_ERROR });
|
dispatch({ type: EDIT_SHORT_URL_META_ERROR });
|
||||||
|
|
|
@ -30,6 +30,7 @@ const initialState = {
|
||||||
error: false,
|
error: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO Make all actions fetch shortCode, domain and prop from payload
|
||||||
const setPropFromActionOnMatchingShortUrl = (prop) => (state, { shortCode, domain, [prop]: propValue }) => assocPath(
|
const setPropFromActionOnMatchingShortUrl = (prop) => (state, { shortCode, domain, [prop]: propValue }) => assocPath(
|
||||||
[ 'shortUrls', 'data' ],
|
[ 'shortUrls', 'data' ],
|
||||||
state.shortUrls.data.map(
|
state.shortUrls.data.map(
|
||||||
|
@ -48,7 +49,13 @@ export default handleActions({
|
||||||
state,
|
state,
|
||||||
),
|
),
|
||||||
[SHORT_URL_TAGS_EDITED]: setPropFromActionOnMatchingShortUrl('tags'),
|
[SHORT_URL_TAGS_EDITED]: setPropFromActionOnMatchingShortUrl('tags'),
|
||||||
[SHORT_URL_META_EDITED]: setPropFromActionOnMatchingShortUrl('meta'),
|
[SHORT_URL_META_EDITED]: (state, { payload: { shortCode, domain, meta } }) => assocPath(
|
||||||
|
[ 'shortUrls', 'data' ],
|
||||||
|
state.shortUrls.data.map(
|
||||||
|
(shortUrl) => shortUrlMatches(shortUrl, shortCode, domain) ? assoc('meta', meta, shortUrl) : shortUrl,
|
||||||
|
),
|
||||||
|
state,
|
||||||
|
),
|
||||||
[SHORT_URL_EDITED]: setPropFromActionOnMatchingShortUrl('longUrl'),
|
[SHORT_URL_EDITED]: setPropFromActionOnMatchingShortUrl('longUrl'),
|
||||||
[CREATE_VISIT]: (state, { shortUrl: { shortCode, domain, visitsCount } }) => assocPath(
|
[CREATE_VISIT]: (state, { shortUrl: { shortCode, domain, visitsCount } }) => assocPath(
|
||||||
[ 'shortUrls', 'data' ],
|
[ 'shortUrls', 'data' ],
|
||||||
|
|
|
@ -21,3 +21,7 @@ export const rangeOf = <T>(size: number, mappingFn: (value: number) => T, startA
|
||||||
export type Empty = null | undefined | '' | never[];
|
export type Empty = null | undefined | '' | never[];
|
||||||
|
|
||||||
export const hasValue = <T>(value: T | Empty): value is T => !isNil(value) && !isEmpty(value);
|
export const hasValue = <T>(value: T | Empty): value is T => !isNil(value) && !isEmpty(value);
|
||||||
|
|
||||||
|
export type Nullable<T> = {
|
||||||
|
[P in keyof T]: T[P] | null
|
||||||
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { Mock } from 'ts-mockery';
|
||||||
import reducer, {
|
import reducer, {
|
||||||
CREATE_SHORT_URL_START,
|
CREATE_SHORT_URL_START,
|
||||||
CREATE_SHORT_URL_ERROR,
|
CREATE_SHORT_URL_ERROR,
|
||||||
|
@ -6,33 +7,40 @@ import reducer, {
|
||||||
createShortUrl,
|
createShortUrl,
|
||||||
resetCreateShortUrl,
|
resetCreateShortUrl,
|
||||||
} from '../../../src/short-urls/reducers/shortUrlCreation';
|
} from '../../../src/short-urls/reducers/shortUrlCreation';
|
||||||
|
import { ShortUrl } from '../../../src/short-urls/data';
|
||||||
|
import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient';
|
||||||
|
import { ShlinkState } from '../../../src/container/types';
|
||||||
|
|
||||||
describe('shortUrlCreationReducer', () => {
|
describe('shortUrlCreationReducer', () => {
|
||||||
|
const shortUrl = Mock.all<ShortUrl>();
|
||||||
|
|
||||||
describe('reducer', () => {
|
describe('reducer', () => {
|
||||||
it('returns loading on CREATE_SHORT_URL_START', () => {
|
it('returns loading on CREATE_SHORT_URL_START', () => {
|
||||||
expect(reducer({}, { type: CREATE_SHORT_URL_START })).toEqual({
|
expect(reducer(undefined, { type: CREATE_SHORT_URL_START } as any)).toEqual({
|
||||||
|
result: null,
|
||||||
saving: true,
|
saving: true,
|
||||||
error: false,
|
error: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns error on CREATE_SHORT_URL_ERROR', () => {
|
it('returns error on CREATE_SHORT_URL_ERROR', () => {
|
||||||
expect(reducer({}, { type: CREATE_SHORT_URL_ERROR })).toEqual({
|
expect(reducer(undefined, { type: CREATE_SHORT_URL_ERROR } as any)).toEqual({
|
||||||
|
result: null,
|
||||||
saving: false,
|
saving: false,
|
||||||
error: true,
|
error: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns result on CREATE_SHORT_URL', () => {
|
it('returns result on CREATE_SHORT_URL', () => {
|
||||||
expect(reducer({}, { type: CREATE_SHORT_URL, result: 'foo' })).toEqual({
|
expect(reducer(undefined, { type: CREATE_SHORT_URL, result: shortUrl } as any)).toEqual({
|
||||||
|
result: shortUrl,
|
||||||
saving: false,
|
saving: false,
|
||||||
error: false,
|
error: false,
|
||||||
result: 'foo',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns default state on RESET_CREATE_SHORT_URL', () => {
|
it('returns default state on RESET_CREATE_SHORT_URL', () => {
|
||||||
expect(reducer({}, { type: RESET_CREATE_SHORT_URL })).toEqual({
|
expect(reducer(undefined, { type: RESET_CREATE_SHORT_URL } as any)).toEqual({
|
||||||
result: null,
|
result: null,
|
||||||
saving: false,
|
saving: false,
|
||||||
error: false,
|
error: false,
|
||||||
|
@ -46,31 +54,30 @@ describe('shortUrlCreationReducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createShortUrl', () => {
|
describe('createShortUrl', () => {
|
||||||
const createApiClientMock = (result) => ({
|
const createApiClientMock = (result: Promise<ShortUrl>) => Mock.of<ShlinkApiClient>({
|
||||||
createShortUrl: jest.fn(() => result),
|
createShortUrl: jest.fn().mockReturnValue(result),
|
||||||
});
|
});
|
||||||
const dispatch = jest.fn();
|
const dispatch = jest.fn();
|
||||||
const getState = () => ({});
|
const getState = () => Mock.all<ShlinkState>();
|
||||||
|
|
||||||
afterEach(jest.resetAllMocks);
|
afterEach(jest.resetAllMocks);
|
||||||
|
|
||||||
it('calls API on success', async () => {
|
it('calls API on success', async () => {
|
||||||
const result = 'foo';
|
const apiClientMock = createApiClientMock(Promise.resolve(shortUrl));
|
||||||
const apiClientMock = createApiClientMock(Promise.resolve(result));
|
const dispatchable = createShortUrl(() => apiClientMock)({ longUrl: 'foo' });
|
||||||
const dispatchable = createShortUrl(() => apiClientMock)({});
|
|
||||||
|
|
||||||
await dispatchable(dispatch, getState);
|
await dispatchable(dispatch, getState);
|
||||||
|
|
||||||
expect(apiClientMock.createShortUrl).toHaveBeenCalledTimes(1);
|
expect(apiClientMock.createShortUrl).toHaveBeenCalledTimes(1);
|
||||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: CREATE_SHORT_URL_START });
|
expect(dispatch).toHaveBeenNthCalledWith(1, { type: CREATE_SHORT_URL_START });
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(2, { type: CREATE_SHORT_URL, result });
|
expect(dispatch).toHaveBeenNthCalledWith(2, { type: CREATE_SHORT_URL, result: shortUrl });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws on error', async () => {
|
it('throws on error', async () => {
|
||||||
const error = 'Error';
|
const error = 'Error';
|
||||||
const apiClientMock = createApiClientMock(Promise.reject(error));
|
const apiClientMock = createApiClientMock(Promise.reject(error));
|
||||||
const dispatchable = createShortUrl(() => apiClientMock)({});
|
const dispatchable = createShortUrl(() => apiClientMock)({ longUrl: 'foo' });
|
||||||
|
|
||||||
expect.assertions(5);
|
expect.assertions(5);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { Mock } from 'ts-mockery';
|
||||||
import reducer, {
|
import reducer, {
|
||||||
EDIT_SHORT_URL_META_START,
|
EDIT_SHORT_URL_META_START,
|
||||||
EDIT_SHORT_URL_META_ERROR,
|
EDIT_SHORT_URL_META_ERROR,
|
||||||
|
@ -7,6 +8,7 @@ import reducer, {
|
||||||
editShortUrlMeta,
|
editShortUrlMeta,
|
||||||
resetShortUrlMeta,
|
resetShortUrlMeta,
|
||||||
} from '../../../src/short-urls/reducers/shortUrlMeta';
|
} from '../../../src/short-urls/reducers/shortUrlMeta';
|
||||||
|
import { ShlinkState } from '../../../src/container/types';
|
||||||
|
|
||||||
describe('shortUrlMetaReducer', () => {
|
describe('shortUrlMetaReducer', () => {
|
||||||
const meta = {
|
const meta = {
|
||||||
|
@ -17,21 +19,25 @@ describe('shortUrlMetaReducer', () => {
|
||||||
|
|
||||||
describe('reducer', () => {
|
describe('reducer', () => {
|
||||||
it('returns loading on EDIT_SHORT_URL_META_START', () => {
|
it('returns loading on EDIT_SHORT_URL_META_START', () => {
|
||||||
expect(reducer({}, { type: EDIT_SHORT_URL_META_START })).toEqual({
|
expect(reducer(undefined, { type: EDIT_SHORT_URL_META_START } as any)).toEqual({
|
||||||
|
meta: {},
|
||||||
|
shortCode: null,
|
||||||
saving: true,
|
saving: true,
|
||||||
error: false,
|
error: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns error on EDIT_SHORT_URL_META_ERROR', () => {
|
it('returns error on EDIT_SHORT_URL_META_ERROR', () => {
|
||||||
expect(reducer({}, { type: EDIT_SHORT_URL_META_ERROR })).toEqual({
|
expect(reducer(undefined, { type: EDIT_SHORT_URL_META_ERROR } as any)).toEqual({
|
||||||
|
meta: {},
|
||||||
|
shortCode: null,
|
||||||
saving: false,
|
saving: false,
|
||||||
error: true,
|
error: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns provided tags and shortCode on SHORT_URL_META_EDITED', () => {
|
it('returns provided tags and shortCode on SHORT_URL_META_EDITED', () => {
|
||||||
expect(reducer({}, { type: SHORT_URL_META_EDITED, meta, shortCode })).toEqual({
|
expect(reducer(undefined, { type: SHORT_URL_META_EDITED, payload: { meta, shortCode } })).toEqual({
|
||||||
meta,
|
meta,
|
||||||
shortCode,
|
shortCode,
|
||||||
saving: false,
|
saving: false,
|
||||||
|
@ -40,7 +46,7 @@ describe('shortUrlMetaReducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('goes back to initial state on RESET_EDIT_SHORT_URL_META', () => {
|
it('goes back to initial state on RESET_EDIT_SHORT_URL_META', () => {
|
||||||
expect(reducer({}, { type: RESET_EDIT_SHORT_URL_META })).toEqual({
|
expect(reducer(undefined, { type: RESET_EDIT_SHORT_URL_META } as any)).toEqual({
|
||||||
meta: {},
|
meta: {},
|
||||||
shortCode: null,
|
shortCode: null,
|
||||||
saving: false,
|
saving: false,
|
||||||
|
@ -53,18 +59,21 @@ describe('shortUrlMetaReducer', () => {
|
||||||
const updateShortUrlMeta = jest.fn().mockResolvedValue({});
|
const updateShortUrlMeta = jest.fn().mockResolvedValue({});
|
||||||
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlMeta });
|
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlMeta });
|
||||||
const dispatch = jest.fn();
|
const dispatch = jest.fn();
|
||||||
|
const getState = () => Mock.all<ShlinkState>();
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
|
|
||||||
it.each([[ undefined ], [ null ], [ 'example.com' ]])('dispatches metadata on success', async (domain) => {
|
it.each([[ undefined ], [ null ], [ 'example.com' ]])('dispatches metadata on success', async (domain) => {
|
||||||
await editShortUrlMeta(buildShlinkApiClient)(shortCode, domain, meta)(dispatch);
|
const payload = { meta, shortCode, domain };
|
||||||
|
|
||||||
|
await editShortUrlMeta(buildShlinkApiClient)(shortCode, domain, meta)(dispatch, getState);
|
||||||
|
|
||||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledTimes(1);
|
expect(updateShortUrlMeta).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledWith(shortCode, domain, meta);
|
expect(updateShortUrlMeta).toHaveBeenCalledWith(shortCode, domain, meta);
|
||||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_META_START });
|
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_META_START });
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(2, { type: SHORT_URL_META_EDITED, meta, shortCode, domain });
|
expect(dispatch).toHaveBeenNthCalledWith(2, { type: SHORT_URL_META_EDITED, payload });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('dispatches error on failure', async () => {
|
it('dispatches error on failure', async () => {
|
||||||
|
@ -73,7 +82,7 @@ describe('shortUrlMetaReducer', () => {
|
||||||
updateShortUrlMeta.mockRejectedValue(error);
|
updateShortUrlMeta.mockRejectedValue(error);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await editShortUrlMeta(buildShlinkApiClient)(shortCode, undefined, meta)(dispatch);
|
await editShortUrlMeta(buildShlinkApiClient)(shortCode, undefined, meta)(dispatch, getState);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e).toBe(error);
|
expect(e).toBe(error);
|
||||||
}
|
}
|
Loading…
Reference in a new issue