mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-11 02:37:22 +03:00
Ensured all data can be set when editing a short URL
This commit is contained in:
parent
a019bd30df
commit
eea76d88c3
15 changed files with 73 additions and 64 deletions
|
@ -12,7 +12,7 @@ import {
|
||||||
ShlinkTagsResponse,
|
ShlinkTagsResponse,
|
||||||
ShlinkVisits,
|
ShlinkVisits,
|
||||||
ShlinkVisitsParams,
|
ShlinkVisitsParams,
|
||||||
ShlinkShortUrlMeta,
|
ShlinkShortUrlData,
|
||||||
ShlinkDomain,
|
ShlinkDomain,
|
||||||
ShlinkDomainsResponse,
|
ShlinkDomainsResponse,
|
||||||
ShlinkVisitsOverview,
|
ShlinkVisitsOverview,
|
||||||
|
@ -67,7 +67,7 @@ export default class ShlinkApiClient {
|
||||||
this.performRequest(`/short-urls/${shortCode}`, 'DELETE', { domain })
|
this.performRequest(`/short-urls/${shortCode}`, 'DELETE', { domain })
|
||||||
.then(() => {});
|
.then(() => {});
|
||||||
|
|
||||||
/* @deprecated. If using Shlink 2.6.0 or greater, use updateShortUrlMeta instead */
|
/* @deprecated. If using Shlink 2.6.0 or greater, use updateShortUrl instead */
|
||||||
public readonly updateShortUrlTags = async (
|
public readonly updateShortUrlTags = async (
|
||||||
shortCode: string,
|
shortCode: string,
|
||||||
domain: OptionalString,
|
domain: OptionalString,
|
||||||
|
@ -76,12 +76,12 @@ export default class ShlinkApiClient {
|
||||||
this.performRequest<{ tags: string[] }>(`/short-urls/${shortCode}/tags`, 'PUT', { domain }, { tags })
|
this.performRequest<{ tags: string[] }>(`/short-urls/${shortCode}/tags`, 'PUT', { domain }, { tags })
|
||||||
.then(({ data }) => data.tags);
|
.then(({ data }) => data.tags);
|
||||||
|
|
||||||
public readonly updateShortUrlMeta = async (
|
public readonly updateShortUrl = async (
|
||||||
shortCode: string,
|
shortCode: string,
|
||||||
domain: OptionalString,
|
domain: OptionalString,
|
||||||
meta: ShlinkShortUrlMeta,
|
data: ShlinkShortUrlData,
|
||||||
): Promise<ShortUrl> =>
|
): Promise<ShortUrl> =>
|
||||||
this.performRequest<ShortUrl>(`/short-urls/${shortCode}`, 'PATCH', { domain }, meta)
|
this.performRequest<ShortUrl>(`/short-urls/${shortCode}`, 'PATCH', { domain }, data)
|
||||||
.then(({ data }) => data);
|
.then(({ data }) => data);
|
||||||
|
|
||||||
public readonly listTags = async (): Promise<ShlinkTags> =>
|
public readonly listTags = async (): Promise<ShlinkTags> =>
|
||||||
|
|
|
@ -57,8 +57,10 @@ export interface ShlinkVisitsParams {
|
||||||
endDate?: string;
|
endDate?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ShlinkShortUrlMeta extends ShortUrlMeta {
|
export interface ShlinkShortUrlData extends ShortUrlMeta {
|
||||||
longUrl?: string;
|
longUrl?: string;
|
||||||
|
title?: string;
|
||||||
|
validateUrl?: boolean;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,14 @@ import { Result } from '../utils/Result';
|
||||||
import { ShlinkApiError } from '../api/ShlinkApiError';
|
import { ShlinkApiError } from '../api/ShlinkApiError';
|
||||||
import { ShortUrlFormProps } from './ShortUrlForm';
|
import { ShortUrlFormProps } from './ShortUrlForm';
|
||||||
import { ShortUrlDetail } from './reducers/shortUrlDetail';
|
import { ShortUrlDetail } from './reducers/shortUrlDetail';
|
||||||
import { ShortUrl, ShortUrlData } from './data';
|
import { EditShortUrlData, ShortUrl, ShortUrlData } from './data';
|
||||||
|
|
||||||
interface EditShortUrlConnectProps extends RouteComponentProps<{ shortCode: string }> {
|
interface EditShortUrlConnectProps extends RouteComponentProps<{ shortCode: string }> {
|
||||||
settings: Settings;
|
settings: Settings;
|
||||||
selectedServer: SelectedServer;
|
selectedServer: SelectedServer;
|
||||||
shortUrlDetail: ShortUrlDetail;
|
shortUrlDetail: ShortUrlDetail;
|
||||||
getShortUrlDetail: (shortCode: string, domain: OptionalString) => void;
|
getShortUrlDetail: (shortCode: string, domain: OptionalString) => void;
|
||||||
|
editShortUrl: (shortUrl: string, domain: OptionalString, data: EditShortUrlData) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getInitialState = (shortUrl?: ShortUrl, settings?: ShortUrlCreationSettings): ShortUrlData => {
|
const getInitialState = (shortUrl?: ShortUrl, settings?: ShortUrlCreationSettings): ShortUrlData => {
|
||||||
|
@ -44,6 +45,7 @@ export const EditShortUrl = (ShortUrlForm: FC<ShortUrlFormProps>) => ({
|
||||||
selectedServer,
|
selectedServer,
|
||||||
shortUrlDetail,
|
shortUrlDetail,
|
||||||
getShortUrlDetail,
|
getShortUrlDetail,
|
||||||
|
editShortUrl,
|
||||||
}: EditShortUrlConnectProps) => {
|
}: EditShortUrlConnectProps) => {
|
||||||
const { loading, error, errorData, shortUrl } = shortUrlDetail;
|
const { loading, error, errorData, shortUrl } = shortUrlDetail;
|
||||||
const { domain } = parseQuery<{ domain?: string }>(search);
|
const { domain } = parseQuery<{ domain?: string }>(search);
|
||||||
|
@ -70,7 +72,7 @@ export const EditShortUrl = (ShortUrlForm: FC<ShortUrlFormProps>) => ({
|
||||||
saving={false}
|
saving={false}
|
||||||
selectedServer={selectedServer}
|
selectedServer={selectedServer}
|
||||||
mode="edit"
|
mode="edit"
|
||||||
onSave={async (shortUrlData) => Promise.resolve(console.log(shortUrlData))}
|
onSave={async (shortUrlData) => shortUrl && editShortUrl(shortUrl.shortCode, shortUrl.domain, shortUrlData)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { FC, useEffect, useState } from 'react';
|
||||||
import { InputType } from 'reactstrap/lib/Input';
|
import { InputType } from 'reactstrap/lib/Input';
|
||||||
import { Button, FormGroup, Input, Row } from 'reactstrap';
|
import { Button, FormGroup, Input, Row } from 'reactstrap';
|
||||||
import { isEmpty, pipe, replace, trim } from 'ramda';
|
import { isEmpty, pipe, replace, trim } from 'ramda';
|
||||||
import * as m from 'moment';
|
import m from 'moment';
|
||||||
import DateInput, { DateInputProps } from '../utils/DateInput';
|
import DateInput, { DateInputProps } from '../utils/DateInput';
|
||||||
import {
|
import {
|
||||||
supportsListingDomains,
|
supportsListingDomains,
|
||||||
|
@ -46,8 +46,9 @@ export const ShortUrlForm = (
|
||||||
const reset = () => setShortUrlData(initialState);
|
const reset = () => setShortUrlData(initialState);
|
||||||
const submit = handleEventPreventingDefault(async () => onSave({
|
const submit = handleEventPreventingDefault(async () => onSave({
|
||||||
...shortUrlData,
|
...shortUrlData,
|
||||||
validSince: formatIsoDate(shortUrlData.validSince) ?? undefined,
|
validSince: formatIsoDate(shortUrlData.validSince) ?? null,
|
||||||
validUntil: formatIsoDate(shortUrlData.validUntil) ?? undefined,
|
validUntil: formatIsoDate(shortUrlData.validUntil) ?? null,
|
||||||
|
maxVisits: !hasValue(shortUrlData.maxVisits) ? null : Number(shortUrlData.maxVisits),
|
||||||
}).then(() => !isEdit && reset()).catch(() => {}));
|
}).then(() => !isEdit && reset()).catch(() => {}));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -69,7 +70,7 @@ export const ShortUrlForm = (
|
||||||
const renderDateInput = (id: DateFields, placeholder: string, props: Partial<DateInputProps> = {}) => (
|
const renderDateInput = (id: DateFields, placeholder: string, props: Partial<DateInputProps> = {}) => (
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<DateInput
|
<DateInput
|
||||||
selected={shortUrlData[id] as m.Moment | null}
|
selected={shortUrlData[id] ? m(shortUrlData[id]) : null}
|
||||||
placeholderText={placeholder}
|
placeholderText={placeholder}
|
||||||
isClearable
|
isClearable
|
||||||
onChange={(date) => setShortUrlData({ ...shortUrlData, [id]: date })}
|
onChange={(date) => setShortUrlData({ ...shortUrlData, [id]: date })}
|
||||||
|
@ -148,8 +149,8 @@ export const ShortUrlForm = (
|
||||||
<div className="col-sm-6 mb-3">
|
<div className="col-sm-6 mb-3">
|
||||||
<SimpleCard title="Limit access to the short URL">
|
<SimpleCard title="Limit access to the short URL">
|
||||||
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
||||||
{renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlData.validUntil as m.Moment | undefined })}
|
{renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlData.validUntil ? m(shortUrlData.validUntil) : undefined })}
|
||||||
{renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlData.validSince as m.Moment | undefined })}
|
{renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlData.validSince ? m(shortUrlData.validSince) : undefined })}
|
||||||
</SimpleCard>
|
</SimpleCard>
|
||||||
</div>
|
</div>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
import * as m from 'moment';
|
import * as m from 'moment';
|
||||||
import { Nullable, OptionalString } from '../../utils/utils';
|
import { Nullable, OptionalString } from '../../utils/utils';
|
||||||
|
|
||||||
export interface ShortUrlData {
|
export interface EditShortUrlData {
|
||||||
longUrl: string;
|
longUrl?: string;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
customSlug?: string;
|
|
||||||
title?: string;
|
title?: string;
|
||||||
|
validSince?: m.Moment | string | null;
|
||||||
|
validUntil?: m.Moment | string | null;
|
||||||
|
maxVisits?: number | null;
|
||||||
|
validateUrl?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShortUrlData extends EditShortUrlData {
|
||||||
|
longUrl: string;
|
||||||
|
customSlug?: string;
|
||||||
shortCodeLength?: number;
|
shortCodeLength?: number;
|
||||||
domain?: string;
|
domain?: string;
|
||||||
validSince?: m.Moment | string;
|
|
||||||
validUntil?: m.Moment | string;
|
|
||||||
maxVisits?: number;
|
|
||||||
findIfExists?: boolean;
|
findIfExists?: boolean;
|
||||||
validateUrl?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ShortUrl {
|
export interface ShortUrl {
|
||||||
|
|
|
@ -3,13 +3,13 @@ import { Modal, ModalBody, ModalFooter, ModalHeader, FormGroup, Input, Button }
|
||||||
import { ExternalLink } from 'react-external-link';
|
import { ExternalLink } from 'react-external-link';
|
||||||
import { ShortUrlEdition } from '../reducers/shortUrlEdition';
|
import { ShortUrlEdition } from '../reducers/shortUrlEdition';
|
||||||
import { handleEventPreventingDefault, hasValue, OptionalString } from '../../utils/utils';
|
import { handleEventPreventingDefault, hasValue, OptionalString } from '../../utils/utils';
|
||||||
import { ShortUrlModalProps } from '../data';
|
import { EditShortUrlData, ShortUrlModalProps } from '../data';
|
||||||
import { Result } from '../../utils/Result';
|
import { Result } from '../../utils/Result';
|
||||||
import { ShlinkApiError } from '../../api/ShlinkApiError';
|
import { ShlinkApiError } from '../../api/ShlinkApiError';
|
||||||
|
|
||||||
interface EditShortUrlModalProps extends ShortUrlModalProps {
|
interface EditShortUrlModalProps extends ShortUrlModalProps {
|
||||||
shortUrlEdition: ShortUrlEdition;
|
shortUrlEdition: ShortUrlEdition;
|
||||||
editShortUrl: (shortUrl: string, domain: OptionalString, longUrl: string) => Promise<void>;
|
editShortUrl: (shortUrl: string, domain: OptionalString, data: EditShortUrlData) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditShortUrlModal = ({ isOpen, toggle, shortUrl, shortUrlEdition, editShortUrl }: EditShortUrlModalProps) => {
|
const EditShortUrlModal = ({ isOpen, toggle, shortUrl, shortUrlEdition, editShortUrl }: EditShortUrlModalProps) => {
|
||||||
|
@ -17,7 +17,7 @@ const EditShortUrlModal = ({ isOpen, toggle, shortUrl, shortUrlEdition, editShor
|
||||||
const url = shortUrl?.shortUrl ?? '';
|
const url = shortUrl?.shortUrl ?? '';
|
||||||
const [ longUrl, setLongUrl ] = useState(shortUrl.longUrl);
|
const [ longUrl, setLongUrl ] = useState(shortUrl.longUrl);
|
||||||
|
|
||||||
const doEdit = async () => editShortUrl(shortUrl.shortCode, shortUrl.domain, longUrl).then(toggle);
|
const doEdit = async () => editShortUrl(shortUrl.shortCode, shortUrl.domain, { longUrl }).then(toggle);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} toggle={toggle} centered size="lg">
|
<Modal isOpen={isOpen} toggle={toggle} centered size="lg">
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Action, Dispatch } from 'redux';
|
||||||
import { buildReducer } from '../../utils/helpers/redux';
|
import { buildReducer } from '../../utils/helpers/redux';
|
||||||
import { GetState } from '../../container/types';
|
import { GetState } from '../../container/types';
|
||||||
import { OptionalString } from '../../utils/utils';
|
import { OptionalString } from '../../utils/utils';
|
||||||
import { ShortUrlIdentifier } from '../data';
|
import { EditShortUrlData, ShortUrlIdentifier } from '../data';
|
||||||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||||
import { ProblemDetailsError } from '../../api/types';
|
import { ProblemDetailsError } from '../../api/types';
|
||||||
import { parseApiError } from '../../api/utils';
|
import { parseApiError } from '../../api/utils';
|
||||||
|
@ -45,13 +45,16 @@ export default buildReducer<ShortUrlEdition, ShortUrlEditedAction & ShortUrlEdit
|
||||||
export const editShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (
|
export const editShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => (
|
||||||
shortCode: string,
|
shortCode: string,
|
||||||
domain: OptionalString,
|
domain: OptionalString,
|
||||||
longUrl: string,
|
data: EditShortUrlData,
|
||||||
) => async (dispatch: Dispatch, getState: GetState) => {
|
) => async (dispatch: Dispatch, getState: GetState) => {
|
||||||
dispatch({ type: EDIT_SHORT_URL_START });
|
dispatch({ type: EDIT_SHORT_URL_START });
|
||||||
const { updateShortUrlMeta } = buildShlinkApiClient(getState);
|
|
||||||
|
// TODO Pass tags to the updateTags function if server version is lower than 2.6
|
||||||
|
const { updateShortUrl } = buildShlinkApiClient(getState);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateShortUrlMeta(shortCode, domain, { longUrl });
|
const { longUrl } = await updateShortUrl(shortCode, domain, data as any); // FIXME Parse dates
|
||||||
|
|
||||||
dispatch<ShortUrlEditedAction>({ shortCode, longUrl, domain, type: SHORT_URL_EDITED });
|
dispatch<ShortUrlEditedAction>({ shortCode, longUrl, domain, type: SHORT_URL_EDITED });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dispatch<ShortUrlEditionFailedAction>({ type: EDIT_SHORT_URL_ERROR, errorData: parseApiError(e) });
|
dispatch<ShortUrlEditionFailedAction>({ type: EDIT_SHORT_URL_ERROR, errorData: parseApiError(e) });
|
||||||
|
|
|
@ -50,10 +50,10 @@ export const editShortUrlMeta = (buildShlinkApiClient: ShlinkApiClientBuilder) =
|
||||||
meta: ShortUrlMeta,
|
meta: ShortUrlMeta,
|
||||||
) => async (dispatch: Dispatch, getState: GetState) => {
|
) => async (dispatch: Dispatch, getState: GetState) => {
|
||||||
dispatch({ type: EDIT_SHORT_URL_META_START });
|
dispatch({ type: EDIT_SHORT_URL_META_START });
|
||||||
const { updateShortUrlMeta } = buildShlinkApiClient(getState);
|
const { updateShortUrl } = buildShlinkApiClient(getState);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateShortUrlMeta(shortCode, domain, meta);
|
await updateShortUrl(shortCode, domain, meta);
|
||||||
dispatch<ShortUrlMetaEditedAction>({ shortCode, meta, domain, type: SHORT_URL_META_EDITED });
|
dispatch<ShortUrlMetaEditedAction>({ shortCode, meta, domain, type: SHORT_URL_META_EDITED });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dispatch<ShortUrlMetaEditionFailedAction>({ type: EDIT_SHORT_URL_META_ERROR, errorData: parseApiError(e) });
|
dispatch<ShortUrlMetaEditionFailedAction>({ type: EDIT_SHORT_URL_META_ERROR, errorData: parseApiError(e) });
|
||||||
|
|
|
@ -54,12 +54,12 @@ export const editShortUrlTags = (buildShlinkApiClient: ShlinkApiClientBuilder) =
|
||||||
dispatch({ type: EDIT_SHORT_URL_TAGS_START });
|
dispatch({ type: EDIT_SHORT_URL_TAGS_START });
|
||||||
const { selectedServer } = getState();
|
const { selectedServer } = getState();
|
||||||
const tagsInPatch = supportsTagsInPatch(selectedServer);
|
const tagsInPatch = supportsTagsInPatch(selectedServer);
|
||||||
const { updateShortUrlTags, updateShortUrlMeta } = buildShlinkApiClient(getState);
|
const { updateShortUrlTags, updateShortUrl } = buildShlinkApiClient(getState);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const normalizedTags = await (
|
const normalizedTags = await (
|
||||||
tagsInPatch
|
tagsInPatch
|
||||||
? updateShortUrlMeta(shortCode, domain, { tags }).then(prop('tags'))
|
? updateShortUrl(shortCode, domain, { tags }).then(prop('tags'))
|
||||||
: updateShortUrlTags(shortCode, domain, tags)
|
: updateShortUrlTags(shortCode, domain, tags)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||||
bottle.serviceFactory('EditShortUrl', EditShortUrl, 'ShortUrlForm');
|
bottle.serviceFactory('EditShortUrl', EditShortUrl, 'ShortUrlForm');
|
||||||
bottle.decorator(
|
bottle.decorator(
|
||||||
'EditShortUrl',
|
'EditShortUrl',
|
||||||
connect([ 'shortUrlDetail', 'selectedServer', 'settings' ], [ 'getShortUrlDetail' ]),
|
connect([ 'shortUrlDetail', 'selectedServer', 'settings' ], [ 'getShortUrlDetail', 'editShortUrl' ]),
|
||||||
);
|
);
|
||||||
|
|
||||||
bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal);
|
bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal);
|
||||||
|
|
|
@ -48,10 +48,7 @@ describe('ShlinkApiClient', () => {
|
||||||
const axiosSpy = createAxiosMock({ data: shortUrl });
|
const axiosSpy = createAxiosMock({ data: shortUrl });
|
||||||
const { createShortUrl } = new ShlinkApiClient(axiosSpy, '', '');
|
const { createShortUrl } = new ShlinkApiClient(axiosSpy, '', '');
|
||||||
|
|
||||||
await createShortUrl(
|
await createShortUrl({ longUrl: 'bar', customSlug: undefined, maxVisits: null });
|
||||||
// @ts-expect-error in case maxVisits is null, it needs to be ignored as if it was undefined
|
|
||||||
{ longUrl: 'bar', customSlug: undefined, maxVisits: null },
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(axiosSpy).toHaveBeenCalledWith(expect.objectContaining({ data: { longUrl: 'bar' } }));
|
expect(axiosSpy).toHaveBeenCalledWith(expect.objectContaining({ data: { longUrl: 'bar' } }));
|
||||||
});
|
});
|
||||||
|
@ -139,7 +136,7 @@ describe('ShlinkApiClient', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('updateShortUrlMeta', () => {
|
describe('updateShortUrl', () => {
|
||||||
it.each(shortCodesWithDomainCombinations)('properly updates short URL meta', async (shortCode, domain) => {
|
it.each(shortCodesWithDomainCombinations)('properly updates short URL meta', async (shortCode, domain) => {
|
||||||
const meta = {
|
const meta = {
|
||||||
maxVisits: 50,
|
maxVisits: 50,
|
||||||
|
@ -147,9 +144,9 @@ describe('ShlinkApiClient', () => {
|
||||||
};
|
};
|
||||||
const expectedResp = Mock.of<ShortUrl>();
|
const expectedResp = Mock.of<ShortUrl>();
|
||||||
const axiosSpy = createAxiosMock({ data: expectedResp });
|
const axiosSpy = createAxiosMock({ data: expectedResp });
|
||||||
const { updateShortUrlMeta } = new ShlinkApiClient(axiosSpy, '', '');
|
const { updateShortUrl } = new ShlinkApiClient(axiosSpy, '', '');
|
||||||
|
|
||||||
const result = await updateShortUrlMeta(shortCode, domain, meta);
|
const result = await updateShortUrl(shortCode, domain, meta);
|
||||||
|
|
||||||
expect(expectedResp).toEqual(result);
|
expect(expectedResp).toEqual(result);
|
||||||
expect(axiosSpy).toHaveBeenCalledWith(expect.objectContaining({
|
expect(axiosSpy).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
|
|
|
@ -50,7 +50,7 @@ describe('<ShortUrlForm />', () => {
|
||||||
domain: 'example.com',
|
domain: 'example.com',
|
||||||
validSince: validSince.format(),
|
validSince: validSince.format(),
|
||||||
validUntil: validUntil.format(),
|
validUntil: validUntil.format(),
|
||||||
maxVisits: '20',
|
maxVisits: 20,
|
||||||
findIfExists: false,
|
findIfExists: false,
|
||||||
shortCodeLength: 15,
|
shortCodeLength: 15,
|
||||||
validateUrl: true,
|
validateUrl: true,
|
||||||
|
|
|
@ -42,19 +42,19 @@ describe('shortUrlEditionReducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('editShortUrl', () => {
|
describe('editShortUrl', () => {
|
||||||
const updateShortUrlMeta = jest.fn().mockResolvedValue({});
|
const updateShortUrl = jest.fn().mockResolvedValue({ longUrl });
|
||||||
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlMeta });
|
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrl });
|
||||||
const dispatch = jest.fn();
|
const dispatch = jest.fn();
|
||||||
const getState = () => Mock.of<ShlinkState>();
|
const getState = () => Mock.of<ShlinkState>();
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
|
|
||||||
it.each([[ undefined ], [ null ], [ 'example.com' ]])('dispatches long URL on success', async (domain) => {
|
it.each([[ undefined ], [ null ], [ 'example.com' ]])('dispatches long URL on success', async (domain) => {
|
||||||
await editShortUrl(buildShlinkApiClient)(shortCode, domain, longUrl)(dispatch, getState);
|
await editShortUrl(buildShlinkApiClient)(shortCode, domain, { longUrl })(dispatch, getState);
|
||||||
|
|
||||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledTimes(1);
|
expect(updateShortUrl).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledWith(shortCode, domain, { longUrl });
|
expect(updateShortUrl).toHaveBeenCalledWith(shortCode, domain, { longUrl });
|
||||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_START });
|
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_START });
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(2, { type: SHORT_URL_EDITED, longUrl, shortCode, domain });
|
expect(dispatch).toHaveBeenNthCalledWith(2, { type: SHORT_URL_EDITED, longUrl, shortCode, domain });
|
||||||
|
@ -63,17 +63,17 @@ describe('shortUrlEditionReducer', () => {
|
||||||
it('dispatches error on failure', async () => {
|
it('dispatches error on failure', async () => {
|
||||||
const error = new Error();
|
const error = new Error();
|
||||||
|
|
||||||
updateShortUrlMeta.mockRejectedValue(error);
|
updateShortUrl.mockRejectedValue(error);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await editShortUrl(buildShlinkApiClient)(shortCode, undefined, longUrl)(dispatch, getState);
|
await editShortUrl(buildShlinkApiClient)(shortCode, undefined, { longUrl })(dispatch, getState);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e).toBe(error);
|
expect(e).toBe(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledTimes(1);
|
expect(updateShortUrl).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledWith(shortCode, undefined, { longUrl });
|
expect(updateShortUrl).toHaveBeenCalledWith(shortCode, undefined, { longUrl });
|
||||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_START });
|
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_START });
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(2, { type: EDIT_SHORT_URL_ERROR });
|
expect(dispatch).toHaveBeenNthCalledWith(2, { type: EDIT_SHORT_URL_ERROR });
|
||||||
|
|
|
@ -56,8 +56,8 @@ describe('shortUrlMetaReducer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('editShortUrlMeta', () => {
|
describe('editShortUrlMeta', () => {
|
||||||
const updateShortUrlMeta = jest.fn().mockResolvedValue({});
|
const updateShortUrl = jest.fn().mockResolvedValue({});
|
||||||
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlMeta });
|
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrl });
|
||||||
const dispatch = jest.fn();
|
const dispatch = jest.fn();
|
||||||
const getState = () => Mock.all<ShlinkState>();
|
const getState = () => Mock.all<ShlinkState>();
|
||||||
|
|
||||||
|
@ -67,8 +67,8 @@ describe('shortUrlMetaReducer', () => {
|
||||||
await editShortUrlMeta(buildShlinkApiClient)(shortCode, domain, meta)(dispatch, getState);
|
await editShortUrlMeta(buildShlinkApiClient)(shortCode, domain, meta)(dispatch, getState);
|
||||||
|
|
||||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledTimes(1);
|
expect(updateShortUrl).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledWith(shortCode, domain, meta);
|
expect(updateShortUrl).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, meta, shortCode, domain });
|
||||||
|
@ -77,7 +77,7 @@ describe('shortUrlMetaReducer', () => {
|
||||||
it('dispatches error on failure', async () => {
|
it('dispatches error on failure', async () => {
|
||||||
const error = new Error();
|
const error = new Error();
|
||||||
|
|
||||||
updateShortUrlMeta.mockRejectedValue(error);
|
updateShortUrl.mockRejectedValue(error);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await editShortUrlMeta(buildShlinkApiClient)(shortCode, undefined, meta)(dispatch, getState);
|
await editShortUrlMeta(buildShlinkApiClient)(shortCode, undefined, meta)(dispatch, getState);
|
||||||
|
@ -86,8 +86,8 @@ describe('shortUrlMetaReducer', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledTimes(1);
|
expect(updateShortUrl).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledWith(shortCode, undefined, meta);
|
expect(updateShortUrl).toHaveBeenCalledWith(shortCode, undefined, 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: EDIT_SHORT_URL_META_ERROR });
|
expect(dispatch).toHaveBeenNthCalledWith(2, { type: EDIT_SHORT_URL_META_ERROR });
|
||||||
|
|
|
@ -61,8 +61,8 @@ describe('shortUrlTagsReducer', () => {
|
||||||
|
|
||||||
describe('editShortUrlTags', () => {
|
describe('editShortUrlTags', () => {
|
||||||
const updateShortUrlTags = jest.fn();
|
const updateShortUrlTags = jest.fn();
|
||||||
const updateShortUrlMeta = jest.fn();
|
const updateShortUrl = jest.fn();
|
||||||
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlTags, updateShortUrlMeta });
|
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlTags, updateShortUrl });
|
||||||
const dispatch = jest.fn();
|
const dispatch = jest.fn();
|
||||||
const buildGetState = (selectedServer?: SelectedServer) => () => Mock.of<ShlinkState>({ selectedServer });
|
const buildGetState = (selectedServer?: SelectedServer) => () => Mock.of<ShlinkState>({ selectedServer });
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ describe('shortUrlTagsReducer', () => {
|
||||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlTags).toHaveBeenCalledTimes(1);
|
expect(updateShortUrlTags).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlTags).toHaveBeenCalledWith(shortCode, domain, tags);
|
expect(updateShortUrlTags).toHaveBeenCalledWith(shortCode, domain, tags);
|
||||||
expect(updateShortUrlMeta).not.toHaveBeenCalled();
|
expect(updateShortUrl).not.toHaveBeenCalled();
|
||||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_TAGS_START });
|
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_TAGS_START });
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(
|
expect(dispatch).toHaveBeenNthCalledWith(
|
||||||
|
@ -87,10 +87,10 @@ describe('shortUrlTagsReducer', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls updateShortUrlMeta when server is version 2.6.0 or above', async () => {
|
it('calls updateShortUrl when server is version 2.6.0 or above', async () => {
|
||||||
const normalizedTags = [ 'bar', 'foo' ];
|
const normalizedTags = [ 'bar', 'foo' ];
|
||||||
|
|
||||||
updateShortUrlMeta.mockResolvedValue({ tags: normalizedTags });
|
updateShortUrl.mockResolvedValue({ tags: normalizedTags });
|
||||||
|
|
||||||
await editShortUrlTags(buildShlinkApiClient)(shortCode, undefined, tags)(
|
await editShortUrlTags(buildShlinkApiClient)(shortCode, undefined, tags)(
|
||||||
dispatch,
|
dispatch,
|
||||||
|
@ -98,8 +98,8 @@ describe('shortUrlTagsReducer', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledTimes(1);
|
expect(updateShortUrl).toHaveBeenCalledTimes(1);
|
||||||
expect(updateShortUrlMeta).toHaveBeenCalledWith(shortCode, undefined, { tags });
|
expect(updateShortUrl).toHaveBeenCalledWith(shortCode, undefined, { tags });
|
||||||
expect(updateShortUrlTags).not.toHaveBeenCalled();
|
expect(updateShortUrlTags).not.toHaveBeenCalled();
|
||||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_TAGS_START });
|
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_TAGS_START });
|
||||||
|
|
Loading…
Reference in a new issue