From 1b03d043189fa10a4e51da1ebe5f0e2b2e230b6d Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Wed, 26 Aug 2020 18:55:40 +0200 Subject: [PATCH] Migrated more short-url reducers to TS --- .eslintrc | 5 ++- package-lock.json | 6 +-- package.json | 2 +- src/container/types.ts | 16 +++++--- src/short-urls/helpers/DeleteShortUrlModal.js | 2 +- ...hortUrlDeletion.js => shortUrlDeletion.ts} | 38 +++++++++++++++---- ...{shortUrlEdition.js => shortUrlEdition.ts} | 33 +++++++++++++--- .../{shortUrlTags.js => shortUrlTags.ts} | 35 +++++++++++++---- src/short-urls/reducers/shortUrlsList.js | 1 - ...lsListParams.js => shortUrlsListParams.ts} | 21 ++++++++-- src/utils/services/types.ts | 9 +++++ ...etion.test.js => shortUrlDeletion.test.ts} | 9 +++-- ...dition.test.js => shortUrlEdition.test.ts} | 18 ++++++--- ...rtUrlTags.test.js => shortUrlTags.test.ts} | 22 ++++++++--- ...ms.test.js => shortUrlsListParams.test.ts} | 9 +++-- 15 files changed, 169 insertions(+), 57 deletions(-) rename src/short-urls/reducers/{shortUrlDeletion.js => shortUrlDeletion.ts} (52%) rename src/short-urls/reducers/{shortUrlEdition.js => shortUrlEdition.ts} (50%) rename src/short-urls/reducers/{shortUrlTags.js => shortUrlTags.ts} (52%) rename src/short-urls/reducers/{shortUrlsListParams.js => shortUrlsListParams.ts} (51%) rename test/short-urls/reducers/{shortUrlDeletion.test.js => shortUrlDeletion.test.ts} (94%) rename test/short-urls/reducers/{shortUrlEdition.test.js => shortUrlEdition.test.ts} (78%) rename test/short-urls/reducers/{shortUrlTags.test.js => shortUrlTags.test.ts} (79%) rename test/short-urls/reducers/{shortUrlsListParams.test.js => shortUrlsListParams.test.ts} (66%) diff --git a/.eslintrc b/.eslintrc index ef7e0b47..dd2b27c9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -31,7 +31,8 @@ "max-len": ["error", { "code": 120, "ignoreStrings": true, - "ignoreTemplateLiterals": true + "ignoreTemplateLiterals": true, + "ignoreComments": true }], "no-mixed-operators": "off", "comma-dangle": ["error", "always-multiline"], @@ -65,7 +66,7 @@ "code": 120, "ignoreStrings": true, "ignoreTemplateLiterals": true, - "ignoreTrailingComments": true + "ignoreComments": true }], "no-mixed-operators": "off", "react/display-name": "off" diff --git a/package-lock.json b/package-lock.json index e67e9e4e..27beeeee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22452,9 +22452,9 @@ } }, "typescript": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", - "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz", + "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", "dev": true }, "uglify-es": { diff --git a/package.json b/package.json index 8454ae72..68dbdc47 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "terser-webpack-plugin": "^2.1.2", "ts-jest": "^26.0.0", "ts-mockery": "^1.2.0", - "typescript": "^3.9.3", + "typescript": "^4.0.2", "url-loader": "^2.2.0", "webpack": "^4.41.0", "webpack-dev-server": "^3.8.2", diff --git a/src/container/types.ts b/src/container/types.ts index 618826dd..1018b5e9 100644 --- a/src/container/types.ts +++ b/src/container/types.ts @@ -4,19 +4,21 @@ import { SelectedServer } from '../servers/data'; 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; +import { ShortUrlDeletion } from '../short-urls/reducers/shortUrlDeletion'; +import { ShortUrlEdition } from '../short-urls/reducers/shortUrlEdition'; +import { ShortUrlsListParams } from '../short-urls/reducers/shortUrlsListParams'; +import { ShortUrlTags } from '../short-urls/reducers/shortUrlTags'; export interface ShlinkState { servers: ServersMap; selectedServer: SelectedServer; shortUrlsList: any; - shortUrlsListParams: any; + shortUrlsListParams: ShortUrlsListParams; shortUrlCreationResult: ShortUrlCreation; - shortUrlDeletion: any; - shortUrlTags: any; + shortUrlDeletion: ShortUrlDeletion; + shortUrlTags: ShortUrlTags; shortUrlMeta: ShortUrlMetaEdition; - shortUrlEdition: any; + shortUrlEdition: ShortUrlEdition; shortUrlVisits: any; tagVisits: any; shortUrlDetail: any; @@ -27,4 +29,6 @@ export interface ShlinkState { settings: Settings; } +export type ConnectDecorator = (props: string[], actions?: string[]) => any; + export type GetState = () => ShlinkState; diff --git a/src/short-urls/helpers/DeleteShortUrlModal.js b/src/short-urls/helpers/DeleteShortUrlModal.js index a41df3f9..dbc598ed 100644 --- a/src/short-urls/helpers/DeleteShortUrlModal.js +++ b/src/short-urls/helpers/DeleteShortUrlModal.js @@ -22,7 +22,7 @@ const DeleteShortUrlModal = ({ shortUrl, toggle, isOpen, shortUrlDeletion, reset useEffect(() => resetDeleteShortUrl, []); const { error, errorData } = shortUrlDeletion; - const errorCode = error && (errorData.type || errorData.error); + const errorCode = error && errorData && (errorData.type || errorData.error); const hasThresholdError = errorCode === THRESHOLD_REACHED; const hasErrorOtherThanThreshold = error && errorCode !== THRESHOLD_REACHED; const close = pipe(resetDeleteShortUrl, toggle); diff --git a/src/short-urls/reducers/shortUrlDeletion.js b/src/short-urls/reducers/shortUrlDeletion.ts similarity index 52% rename from src/short-urls/reducers/shortUrlDeletion.js rename to src/short-urls/reducers/shortUrlDeletion.ts index a878d07f..86b701cf 100644 --- a/src/short-urls/reducers/shortUrlDeletion.js +++ b/src/short-urls/reducers/shortUrlDeletion.ts @@ -1,6 +1,9 @@ -import { createAction, handleActions } from 'redux-actions'; import PropTypes from 'prop-types'; +import { Action, Dispatch } from 'redux'; import { apiErrorType } from '../../utils/services/ShlinkApiClient'; +import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; +import { ProblemDetailsError, ShlinkApiClientBuilder } from '../../utils/services/types'; +import { GetState } from '../../container/types'; /* eslint-disable padding-line-between-statements */ export const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START'; @@ -9,6 +12,7 @@ export const SHORT_URL_DELETED = 'shlink/deleteShortUrl/SHORT_URL_DELETED'; export const RESET_DELETE_SHORT_URL = 'shlink/deleteShortUrl/RESET_DELETE_SHORT_URL'; /* eslint-enable padding-line-between-statements */ +/** @deprecated Use ShortUrlDeletion interface */ export const shortUrlDeletionType = PropTypes.shape({ shortCode: PropTypes.string.isRequired, loading: PropTypes.bool.isRequired, @@ -16,32 +20,50 @@ export const shortUrlDeletionType = PropTypes.shape({ errorData: apiErrorType.isRequired, }); -const initialState = { +export interface ShortUrlDeletion { + shortCode: string; + loading: boolean; + error: boolean; + errorData?: ProblemDetailsError; +} + +interface DeleteShortUrlAction extends Action { + shortCode: string; + domain?: string | null; +} + +interface DeleteShortUrlErrorAction extends Action { + errorData: ProblemDetailsError; +} + +const initialState: ShortUrlDeletion = { shortCode: '', loading: false, error: false, - errorData: {}, }; -export default handleActions({ +export default buildReducer({ [DELETE_SHORT_URL_START]: (state) => ({ ...state, loading: true, error: false }), [DELETE_SHORT_URL_ERROR]: (state, { errorData }) => ({ ...state, errorData, loading: false, error: true }), [SHORT_URL_DELETED]: (state, { shortCode }) => ({ ...state, shortCode, loading: false, error: false }), [RESET_DELETE_SHORT_URL]: () => initialState, }, initialState); -export const deleteShortUrl = (buildShlinkApiClient) => (shortCode, domain) => async (dispatch, getState) => { +export const deleteShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => ( + shortCode: string, + domain?: string | null, +) => async (dispatch: Dispatch, getState: GetState) => { dispatch({ type: DELETE_SHORT_URL_START }); const { deleteShortUrl } = buildShlinkApiClient(getState); try { await deleteShortUrl(shortCode, domain); - dispatch({ type: SHORT_URL_DELETED, shortCode, domain }); + dispatch({ type: SHORT_URL_DELETED, shortCode, domain }); } catch (e) { - dispatch({ type: DELETE_SHORT_URL_ERROR, errorData: e.response.data }); + dispatch({ type: DELETE_SHORT_URL_ERROR, errorData: e.response.data }); throw e; } }; -export const resetDeleteShortUrl = createAction(RESET_DELETE_SHORT_URL); +export const resetDeleteShortUrl = buildActionCreator(RESET_DELETE_SHORT_URL); diff --git a/src/short-urls/reducers/shortUrlEdition.js b/src/short-urls/reducers/shortUrlEdition.ts similarity index 50% rename from src/short-urls/reducers/shortUrlEdition.js rename to src/short-urls/reducers/shortUrlEdition.ts index 4c545b6d..8b1a0634 100644 --- a/src/short-urls/reducers/shortUrlEdition.js +++ b/src/short-urls/reducers/shortUrlEdition.ts @@ -1,5 +1,8 @@ -import { handleActions } from 'redux-actions'; import PropTypes from 'prop-types'; +import { Action, Dispatch } from 'redux'; +import { buildReducer } from '../../utils/helpers/redux'; +import { ShlinkApiClientBuilder } from '../../utils/services/types'; +import { GetState } from '../../container/types'; /* eslint-disable padding-line-between-statements */ export const EDIT_SHORT_URL_START = 'shlink/shortUrlEdition/EDIT_SHORT_URL_START'; @@ -7,6 +10,7 @@ export const EDIT_SHORT_URL_ERROR = 'shlink/shortUrlEdition/EDIT_SHORT_URL_ERROR export const SHORT_URL_EDITED = 'shlink/shortUrlEdition/SHORT_URL_EDITED'; /* eslint-enable padding-line-between-statements */ +/** @deprecated Use ShortUrlEdition interface instead */ export const ShortUrlEditionType = PropTypes.shape({ shortCode: PropTypes.string, longUrl: PropTypes.string, @@ -14,26 +18,43 @@ export const ShortUrlEditionType = PropTypes.shape({ error: PropTypes.bool.isRequired, }); -const initialState = { +export interface ShortUrlEdition { + shortCode: string | null; + longUrl: string | null; + saving: boolean; + error: boolean; +} + +export interface ShortUrlEditedAction extends Action { + shortCode: string; + longUrl: string; + domain: string | undefined | null; +} + +const initialState: ShortUrlEdition = { shortCode: null, longUrl: null, saving: false, error: false, }; -export default handleActions({ +export default buildReducer({ [EDIT_SHORT_URL_START]: (state) => ({ ...state, saving: true, error: false }), [EDIT_SHORT_URL_ERROR]: (state) => ({ ...state, saving: false, error: true }), - [SHORT_URL_EDITED]: (state, { shortCode, longUrl }) => ({ shortCode, longUrl, saving: false, error: false }), + [SHORT_URL_EDITED]: (_, { shortCode, longUrl }) => ({ shortCode, longUrl, saving: false, error: false }), }, initialState); -export const editShortUrl = (buildShlinkApiClient) => (shortCode, domain, longUrl) => async (dispatch, getState) => { +export const editShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => ( + shortCode: string, + domain: string | undefined | null, + longUrl: string, +) => async (dispatch: Dispatch, getState: GetState) => { dispatch({ type: EDIT_SHORT_URL_START }); const { updateShortUrlMeta } = buildShlinkApiClient(getState); try { await updateShortUrlMeta(shortCode, domain, { longUrl }); - dispatch({ shortCode, longUrl, domain, type: SHORT_URL_EDITED }); + dispatch({ shortCode, longUrl, domain, type: SHORT_URL_EDITED }); } catch (e) { dispatch({ type: EDIT_SHORT_URL_ERROR }); diff --git a/src/short-urls/reducers/shortUrlTags.js b/src/short-urls/reducers/shortUrlTags.ts similarity index 52% rename from src/short-urls/reducers/shortUrlTags.js rename to src/short-urls/reducers/shortUrlTags.ts index 46c91d54..4890271d 100644 --- a/src/short-urls/reducers/shortUrlTags.js +++ b/src/short-urls/reducers/shortUrlTags.ts @@ -1,5 +1,8 @@ -import { createAction, handleActions } from 'redux-actions'; import PropTypes from 'prop-types'; +import { Action, Dispatch } from 'redux'; +import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; +import { ShlinkApiClientBuilder } from '../../utils/services/types'; +import { GetState } from '../../container/types'; /* eslint-disable padding-line-between-statements */ export const EDIT_SHORT_URL_TAGS_START = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS_START'; @@ -8,6 +11,7 @@ export const SHORT_URL_TAGS_EDITED = 'shlink/shortUrlTags/SHORT_URL_TAGS_EDITED' export const RESET_EDIT_SHORT_URL_TAGS = 'shlink/shortUrlTags/RESET_EDIT_SHORT_URL_TAGS'; /* eslint-enable padding-line-between-statements */ +/** @deprecated Use ShortUrlTags interface */ export const shortUrlTagsType = PropTypes.shape({ shortCode: PropTypes.string, tags: PropTypes.arrayOf(PropTypes.string).isRequired, @@ -15,28 +19,45 @@ export const shortUrlTagsType = PropTypes.shape({ error: PropTypes.bool.isRequired, }); -const initialState = { +export interface ShortUrlTags { + shortCode: string | null; + tags: string[]; + saving: boolean; + error: boolean; +} + +export interface EditShortUrlTagsAction extends Action { + shortCode: string; + tags: string[]; + domain: string | null | undefined; +} + +const initialState: ShortUrlTags = { shortCode: null, tags: [], saving: false, error: false, }; -export default handleActions({ +export default buildReducer({ [EDIT_SHORT_URL_TAGS_START]: (state) => ({ ...state, saving: true, error: false }), [EDIT_SHORT_URL_TAGS_ERROR]: (state) => ({ ...state, saving: false, error: true }), - [SHORT_URL_TAGS_EDITED]: (state, { shortCode, tags }) => ({ shortCode, tags, saving: false, error: false }), + [SHORT_URL_TAGS_EDITED]: (_, { shortCode, tags }) => ({ shortCode, tags, saving: false, error: false }), [RESET_EDIT_SHORT_URL_TAGS]: () => initialState, }, initialState); -export const editShortUrlTags = (buildShlinkApiClient) => (shortCode, domain, tags) => async (dispatch, getState) => { +export const editShortUrlTags = (buildShlinkApiClient: ShlinkApiClientBuilder) => ( + shortCode: string, + domain: string | null | undefined, + tags: string[], +) => async (dispatch: Dispatch, getState: GetState) => { dispatch({ type: EDIT_SHORT_URL_TAGS_START }); const { updateShortUrlTags } = buildShlinkApiClient(getState); try { const normalizedTags = await updateShortUrlTags(shortCode, domain, tags); - dispatch({ tags: normalizedTags, shortCode, domain, type: SHORT_URL_TAGS_EDITED }); + dispatch({ tags: normalizedTags, shortCode, domain, type: SHORT_URL_TAGS_EDITED }); } catch (e) { dispatch({ type: EDIT_SHORT_URL_TAGS_ERROR }); @@ -44,4 +65,4 @@ export const editShortUrlTags = (buildShlinkApiClient) => (shortCode, domain, ta } }; -export const resetShortUrlsTags = createAction(RESET_EDIT_SHORT_URL_TAGS); +export const resetShortUrlsTags = buildActionCreator(RESET_EDIT_SHORT_URL_TAGS); diff --git a/src/short-urls/reducers/shortUrlsList.js b/src/short-urls/reducers/shortUrlsList.js index d7ca6080..90d2b1c8 100644 --- a/src/short-urls/reducers/shortUrlsList.js +++ b/src/short-urls/reducers/shortUrlsList.js @@ -30,7 +30,6 @@ const initialState = { error: false, }; -// TODO Make all actions fetch shortCode, domain and prop from payload const setPropFromActionOnMatchingShortUrl = (prop) => (state, { shortCode, domain, [prop]: propValue }) => assocPath( [ 'shortUrls', 'data' ], state.shortUrls.data.map( diff --git a/src/short-urls/reducers/shortUrlsListParams.js b/src/short-urls/reducers/shortUrlsListParams.ts similarity index 51% rename from src/short-urls/reducers/shortUrlsListParams.js rename to src/short-urls/reducers/shortUrlsListParams.ts index 6a6aa5e2..770f81f0 100644 --- a/src/short-urls/reducers/shortUrlsListParams.js +++ b/src/short-urls/reducers/shortUrlsListParams.ts @@ -1,9 +1,11 @@ -import { createAction, handleActions } from 'redux-actions'; import PropTypes from 'prop-types'; +import { Action } from 'redux'; +import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; import { LIST_SHORT_URLS } from './shortUrlsList'; export const RESET_SHORT_URL_PARAMS = 'shlink/shortUrlsListParams/RESET_SHORT_URL_PARAMS'; +/** @deprecated Use ShortUrlsListParams interface instead */ export const shortUrlsListParamsType = PropTypes.shape({ page: PropTypes.string, tags: PropTypes.arrayOf(PropTypes.string), @@ -13,11 +15,24 @@ export const shortUrlsListParamsType = PropTypes.shape({ orderBy: PropTypes.object, }); +export interface ShortUrlsListParams { + page: string; + tags?: string[]; + searchTerm?: string; + startDate?: string; + endDate?: string; + orderBy?: object; +} + +interface ListShortUrlsAction extends Action { + params: ShortUrlsListParams; +} + const initialState = { page: '1' }; -export default handleActions({ +export default buildReducer({ [LIST_SHORT_URLS]: (state, { params }) => ({ ...state, ...params }), [RESET_SHORT_URL_PARAMS]: () => initialState, }, initialState); -export const resetShortUrlParams = createAction(RESET_SHORT_URL_PARAMS); +export const resetShortUrlParams = buildActionCreator(RESET_SHORT_URL_PARAMS); diff --git a/src/utils/services/types.ts b/src/utils/services/types.ts index 15e3972b..048ce954 100644 --- a/src/utils/services/types.ts +++ b/src/utils/services/types.ts @@ -14,3 +14,12 @@ export interface ShlinkHealth { status: 'pass' | 'fail'; version: string; } + +export interface ProblemDetailsError { + type: string; + detail: string; + title: string; + status: number; + error?: string; // Deprecated + message?: string; // Deprecated +} diff --git a/test/short-urls/reducers/shortUrlDeletion.test.js b/test/short-urls/reducers/shortUrlDeletion.test.ts similarity index 94% rename from test/short-urls/reducers/shortUrlDeletion.test.js rename to test/short-urls/reducers/shortUrlDeletion.test.ts index c8437c25..d4fccee3 100644 --- a/test/short-urls/reducers/shortUrlDeletion.test.js +++ b/test/short-urls/reducers/shortUrlDeletion.test.ts @@ -1,3 +1,4 @@ +import { Mock } from 'ts-mockery'; import reducer, { DELETE_SHORT_URL_ERROR, DELETE_SHORT_URL_START, @@ -6,15 +7,17 @@ import reducer, { resetDeleteShortUrl, deleteShortUrl, } from '../../../src/short-urls/reducers/shortUrlDeletion'; +import { ProblemDetailsError } from '../../../src/utils/services/types'; describe('shortUrlDeletionReducer', () => { describe('reducer', () => { + + it('returns loading on DELETE_SHORT_URL_START', () => expect(reducer(undefined, { type: DELETE_SHORT_URL_START })).toEqual({ shortCode: '', loading: true, error: false, - errorData: {}, })); it('returns default on RESET_DELETE_SHORT_URL', () => @@ -22,7 +25,6 @@ describe('shortUrlDeletionReducer', () => { shortCode: '', loading: false, error: false, - errorData: {}, })); it('returns shortCode on SHORT_URL_DELETED', () => @@ -30,11 +32,10 @@ describe('shortUrlDeletionReducer', () => { shortCode: 'foo', loading: false, error: false, - errorData: {}, })); it('returns errorData on DELETE_SHORT_URL_ERROR', () => { - const errorData = { foo: 'bar' }; + const errorData = Mock.of({ type: 'bar' }); expect(reducer(undefined, { type: DELETE_SHORT_URL_ERROR, errorData })).toEqual({ shortCode: '', diff --git a/test/short-urls/reducers/shortUrlEdition.test.js b/test/short-urls/reducers/shortUrlEdition.test.ts similarity index 78% rename from test/short-urls/reducers/shortUrlEdition.test.js rename to test/short-urls/reducers/shortUrlEdition.test.ts index a64f5492..18500bab 100644 --- a/test/short-urls/reducers/shortUrlEdition.test.js +++ b/test/short-urls/reducers/shortUrlEdition.test.ts @@ -1,9 +1,12 @@ +import { Mock } from 'ts-mockery'; import reducer, { EDIT_SHORT_URL_START, EDIT_SHORT_URL_ERROR, SHORT_URL_EDITED, editShortUrl, + ShortUrlEditedAction, } from '../../../src/short-urls/reducers/shortUrlEdition'; +import { ShlinkState } from '../../../src/container/types'; describe('shortUrlEditionReducer', () => { const longUrl = 'https://shlink.io'; @@ -11,21 +14,25 @@ describe('shortUrlEditionReducer', () => { describe('reducer', () => { it('returns loading on EDIT_SHORT_URL_START', () => { - expect(reducer({}, { type: EDIT_SHORT_URL_START })).toEqual({ + expect(reducer(undefined, Mock.of({ type: EDIT_SHORT_URL_START }))).toEqual({ + longUrl: null, + shortCode: null, saving: true, error: false, }); }); it('returns error on EDIT_SHORT_URL_ERROR', () => { - expect(reducer({}, { type: EDIT_SHORT_URL_ERROR })).toEqual({ + expect(reducer(undefined, Mock.of({ type: EDIT_SHORT_URL_ERROR }))).toEqual({ + longUrl: null, + shortCode: null, saving: false, error: true, }); }); it('returns provided tags and shortCode on SHORT_URL_EDITED', () => { - expect(reducer({}, { type: SHORT_URL_EDITED, longUrl, shortCode })).toEqual({ + expect(reducer(undefined, { type: SHORT_URL_EDITED, longUrl, shortCode, domain: null })).toEqual({ longUrl, shortCode, saving: false, @@ -38,11 +45,12 @@ describe('shortUrlEditionReducer', () => { const updateShortUrlMeta = jest.fn().mockResolvedValue({}); const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlMeta }); const dispatch = jest.fn(); + const getState = () => Mock.of(); afterEach(jest.clearAllMocks); it.each([[ undefined ], [ null ], [ 'example.com' ]])('dispatches long URL on success', async (domain) => { - await editShortUrl(buildShlinkApiClient)(shortCode, domain, longUrl)(dispatch); + await editShortUrl(buildShlinkApiClient)(shortCode, domain, longUrl)(dispatch, getState); expect(buildShlinkApiClient).toHaveBeenCalledTimes(1); expect(updateShortUrlMeta).toHaveBeenCalledTimes(1); @@ -58,7 +66,7 @@ describe('shortUrlEditionReducer', () => { updateShortUrlMeta.mockRejectedValue(error); try { - await editShortUrl(buildShlinkApiClient)(shortCode, undefined, longUrl)(dispatch); + await editShortUrl(buildShlinkApiClient)(shortCode, undefined, longUrl)(dispatch, getState); } catch (e) { expect(e).toBe(error); } diff --git a/test/short-urls/reducers/shortUrlTags.test.js b/test/short-urls/reducers/shortUrlTags.test.ts similarity index 79% rename from test/short-urls/reducers/shortUrlTags.test.js rename to test/short-urls/reducers/shortUrlTags.test.ts index 9be9f5ef..8542ac2d 100644 --- a/test/short-urls/reducers/shortUrlTags.test.js +++ b/test/short-urls/reducers/shortUrlTags.test.ts @@ -1,3 +1,4 @@ +import { Mock } from 'ts-mockery'; import reducer, { EDIT_SHORT_URL_TAGS_ERROR, EDIT_SHORT_URL_TAGS_START, @@ -5,29 +6,37 @@ import reducer, { resetShortUrlsTags, SHORT_URL_TAGS_EDITED, editShortUrlTags, + EditShortUrlTagsAction, } from '../../../src/short-urls/reducers/shortUrlTags'; +import { ShlinkState } from '../../../src/container/types'; describe('shortUrlTagsReducer', () => { const tags = [ 'foo', 'bar', 'baz' ]; const shortCode = 'abc123'; describe('reducer', () => { + const action = (type: string) => Mock.of({ type }); + it('returns loading on EDIT_SHORT_URL_TAGS_START', () => { - expect(reducer({}, { type: EDIT_SHORT_URL_TAGS_START })).toEqual({ + expect(reducer(undefined, action(EDIT_SHORT_URL_TAGS_START))).toEqual({ + tags: [], + shortCode: null, saving: true, error: false, }); }); it('returns error on EDIT_SHORT_URL_TAGS_ERROR', () => { - expect(reducer({}, { type: EDIT_SHORT_URL_TAGS_ERROR })).toEqual({ + expect(reducer(undefined, action(EDIT_SHORT_URL_TAGS_ERROR))).toEqual({ + tags: [], + shortCode: null, saving: false, error: true, }); }); it('returns provided tags and shortCode on SHORT_URL_TAGS_EDITED', () => { - expect(reducer({}, { type: SHORT_URL_TAGS_EDITED, tags, shortCode })).toEqual({ + expect(reducer(undefined, { type: SHORT_URL_TAGS_EDITED, tags, shortCode, domain: null })).toEqual({ tags, shortCode, saving: false, @@ -36,7 +45,7 @@ describe('shortUrlTagsReducer', () => { }); it('goes back to initial state on RESET_EDIT_SHORT_URL_TAGS', () => { - expect(reducer({}, { type: RESET_EDIT_SHORT_URL_TAGS })).toEqual({ + expect(reducer(undefined, action(RESET_EDIT_SHORT_URL_TAGS))).toEqual({ tags: [], shortCode: null, saving: false, @@ -53,6 +62,7 @@ describe('shortUrlTagsReducer', () => { const updateShortUrlTags = jest.fn(); const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlTags }); const dispatch = jest.fn(); + const getState = () => Mock.all(); afterEach(jest.clearAllMocks); @@ -61,7 +71,7 @@ describe('shortUrlTagsReducer', () => { updateShortUrlTags.mockResolvedValue(normalizedTags); - await editShortUrlTags(buildShlinkApiClient)(shortCode, domain, tags)(dispatch); + await editShortUrlTags(buildShlinkApiClient)(shortCode, domain, tags)(dispatch, getState); expect(buildShlinkApiClient).toHaveBeenCalledTimes(1); expect(updateShortUrlTags).toHaveBeenCalledTimes(1); @@ -80,7 +90,7 @@ describe('shortUrlTagsReducer', () => { updateShortUrlTags.mockRejectedValue(error); try { - await editShortUrlTags(buildShlinkApiClient)(shortCode, undefined, tags)(dispatch); + await editShortUrlTags(buildShlinkApiClient)(shortCode, undefined, tags)(dispatch, getState); } catch (e) { expect(e).toBe(error); } diff --git a/test/short-urls/reducers/shortUrlsListParams.test.js b/test/short-urls/reducers/shortUrlsListParams.test.ts similarity index 66% rename from test/short-urls/reducers/shortUrlsListParams.test.js rename to test/short-urls/reducers/shortUrlsListParams.test.ts index 5c032e95..08778deb 100644 --- a/test/short-urls/reducers/shortUrlsListParams.test.js +++ b/test/short-urls/reducers/shortUrlsListParams.test.ts @@ -1,21 +1,22 @@ import reducer, { RESET_SHORT_URL_PARAMS, resetShortUrlParams, + ShortUrlsListParams, } from '../../../src/short-urls/reducers/shortUrlsListParams'; import { LIST_SHORT_URLS } from '../../../src/short-urls/reducers/shortUrlsList'; describe('shortUrlsListParamsReducer', () => { describe('reducer', () => { - const defaultState = { page: '1' }; + const defaultState: ShortUrlsListParams = { page: '1' }; it('returns params when action is LIST_SHORT_URLS', () => - expect(reducer(defaultState, { type: LIST_SHORT_URLS, params: { searchTerm: 'foo' } })).toEqual({ - ...defaultState, + expect(reducer(undefined, { type: LIST_SHORT_URLS, params: { searchTerm: 'foo', page: '2' } })).toEqual({ + page: '2', searchTerm: 'foo', })); it('returns default value when action is RESET_SHORT_URL_PARAMS', () => - expect(reducer(defaultState, { type: RESET_SHORT_URL_PARAMS })).toEqual(defaultState)); + expect(reducer(undefined, { type: RESET_SHORT_URL_PARAMS, params: defaultState })).toEqual(defaultState)); }); describe('resetShortUrlParams', () => {