Merge pull request #166 from acelaya-forks/feature/fix-create-short-url

Ensured server version is properly parsed to avoid errors due to inva…
This commit is contained in:
Alejandro Celaya 2019-10-18 17:48:02 +02:00 committed by GitHub
commit e9fc2bb73a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 13 deletions

View file

@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).
## 2.2.1 - 2019-10-18
#### Added
* *Nothing*
#### Changed
* *Nothing*
#### Deprecated
* *Nothing*
#### Removed
* *Nothing*
#### Fixed
* [#165](https://github.com/shlinkio/shlink-web-client/issues/165) Fixed error thrown when opening "create" page while using a Shlink version which does not return a valid SemVer version (like `latest` docker image, or any development instance).
## 2.2.0 - 2019-10-05
#### Added

View file

@ -1,9 +1,14 @@
import { createAction, handleActions } from 'redux-actions';
import { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListParams';
import { versionIsValidSemVer } from '../../utils/utils';
/* eslint-disable padding-line-between-statements */
export const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER';
export const RESET_SELECTED_SERVER = 'shlink/selectedServer/RESET_SELECTED_SERVER';
export const MIN_FALLBACK_VERSION = '1.0.0';
export const MAX_FALLBACK_VERSION = '999.999.999';
export const LATEST_VERSION_CONSTRAINT = 'latest';
/* eslint-enable padding-line-between-statements */
const initialState = null;
@ -15,7 +20,10 @@ export const selectServer = ({ findServerById }, buildShlinkApiClient) => (serve
const selectedServer = findServerById(serverId);
const { health } = await buildShlinkApiClient(selectedServer);
const { version } = await health().catch(() => ({ version: '1.0.0' }));
const version = await health()
.then(({ version }) => version === LATEST_VERSION_CONSTRAINT ? MAX_FALLBACK_VERSION : version)
.then((version) => !versionIsValidSemVer(version) ? MIN_FALLBACK_VERSION : version)
.catch(() => MIN_FALLBACK_VERSION);
dispatch({
type: SELECT_SERVER,

View file

@ -60,3 +60,11 @@ export const compareVersions = (firstVersion, operator, secondVersion) => compar
secondVersion,
operator
);
export const versionIsValidSemVer = (version) => {
try {
return compareVersions(version, '=', version);
} catch (e) {
return false;
}
};

View file

@ -1,8 +1,11 @@
import each from 'jest-each';
import reducer, {
selectServer,
resetSelectedServer,
RESET_SELECTED_SERVER,
SELECT_SERVER,
MAX_FALLBACK_VERSION,
MIN_FALLBACK_VERSION,
} from '../../../src/servers/reducers/selectedServer';
import { RESET_SHORT_URL_PARAMS } from '../../../src/short-urls/reducers/shortUrlsListParams';
@ -34,26 +37,25 @@ describe('selectedServerReducer', () => {
findServerById: jest.fn(() => selectedServer),
};
const apiClientMock = {
health: jest.fn().mockResolvedValue({ version }),
health: jest.fn(),
};
const buildApiClient = jest.fn().mockResolvedValue(apiClientMock);
const dispatch = jest.fn();
beforeEach(() => {
apiClientMock.health.mockClear();
buildApiClient.mockClear();
});
afterEach(jest.clearAllMocks);
afterEach(() => {
ServersServiceMock.findServerById.mockClear();
});
it('dispatches proper actions', async () => {
const dispatch = jest.fn();
each([
[ version, version ],
[ 'latest', MAX_FALLBACK_VERSION ],
[ '%invalid_semver%', MIN_FALLBACK_VERSION ],
]).it('dispatches proper actions', async (serverVersion, expectedVersion) => {
const expectedSelectedServer = {
...selectedServer,
version,
version: expectedVersion,
};
apiClientMock.health.mockResolvedValue({ version: serverVersion });
await selectServer(ServersServiceMock, buildApiClient)(serverId)(dispatch);
expect(dispatch).toHaveBeenCalledTimes(2);
@ -67,5 +69,18 @@ describe('selectedServerReducer', () => {
expect(ServersServiceMock.findServerById).toHaveBeenCalledTimes(1);
expect(buildApiClient).toHaveBeenCalledTimes(1);
});
it('falls back to min version when health endpoint fails', async () => {
const expectedSelectedServer = {
...selectedServer,
version: MIN_FALLBACK_VERSION,
};
apiClientMock.health.mockRejectedValue({});
await selectServer(ServersServiceMock, buildApiClient)(serverId)(dispatch);
expect(dispatch).toHaveBeenNthCalledWith(2, { type: SELECT_SERVER, selectedServer: expectedSelectedServer });
});
});
});