Skip to content

Commit 12f6b94

Browse files
committed
Ensured server version is properly parsed to avoid errors due to invalid semver
1 parent d9a8243 commit 12f6b94

File tree

4 files changed

+67
-13
lines changed

4 files changed

+67
-13
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file.
44

55
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).
66

7+
## 2.2.1 - 2019-10-18
8+
9+
#### Added
10+
11+
* *Nothing*
12+
13+
#### Changed
14+
15+
* *Nothing*
16+
17+
#### Deprecated
18+
19+
* *Nothing*
20+
21+
#### Removed
22+
23+
* *Nothing*
24+
25+
#### Fixed
26+
27+
* [#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).
28+
29+
730
## 2.2.0 - 2019-10-05
831

932
#### Added

src/servers/reducers/selectedServer.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { createAction, handleActions } from 'redux-actions';
22
import { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListParams';
3+
import { versionIsValidSemVer } from '../../utils/utils';
34

45
/* eslint-disable padding-line-between-statements */
56
export const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER';
67
export const RESET_SELECTED_SERVER = 'shlink/selectedServer/RESET_SELECTED_SERVER';
8+
9+
export const MIN_FALLBACK_VERSION = '1.0.0';
10+
export const MAX_FALLBACK_VERSION = '999.999.999';
11+
export const LATEST_VERSION_CONSTRAINT = 'latest';
712
/* eslint-enable padding-line-between-statements */
813

914
const initialState = null;
@@ -15,7 +20,10 @@ export const selectServer = ({ findServerById }, buildShlinkApiClient) => (serve
1520

1621
const selectedServer = findServerById(serverId);
1722
const { health } = await buildShlinkApiClient(selectedServer);
18-
const { version } = await health().catch(() => ({ version: '1.0.0' }));
23+
const version = await health()
24+
.then(({ version }) => version === LATEST_VERSION_CONSTRAINT ? MAX_FALLBACK_VERSION : version)
25+
.then((version) => !versionIsValidSemVer(version) ? MIN_FALLBACK_VERSION : version)
26+
.catch(() => MIN_FALLBACK_VERSION);
1927

2028
dispatch({
2129
type: SELECT_SERVER,

src/utils/utils.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,11 @@ export const compareVersions = (firstVersion, operator, secondVersion) => compar
6060
secondVersion,
6161
operator
6262
);
63+
64+
export const versionIsValidSemVer = (version) => {
65+
try {
66+
return compareVersions(version, '=', version);
67+
} catch (e) {
68+
return false;
69+
}
70+
};

test/servers/reducers/selectedServer.test.js

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import each from 'jest-each';
12
import reducer, {
23
selectServer,
34
resetSelectedServer,
45
RESET_SELECTED_SERVER,
56
SELECT_SERVER,
7+
MAX_FALLBACK_VERSION,
8+
MIN_FALLBACK_VERSION,
69
} from '../../../src/servers/reducers/selectedServer';
710
import { RESET_SHORT_URL_PARAMS } from '../../../src/short-urls/reducers/shortUrlsListParams';
811

@@ -34,26 +37,25 @@ describe('selectedServerReducer', () => {
3437
findServerById: jest.fn(() => selectedServer),
3538
};
3639
const apiClientMock = {
37-
health: jest.fn().mockResolvedValue({ version }),
40+
health: jest.fn(),
3841
};
3942
const buildApiClient = jest.fn().mockResolvedValue(apiClientMock);
43+
const dispatch = jest.fn();
4044

41-
beforeEach(() => {
42-
apiClientMock.health.mockClear();
43-
buildApiClient.mockClear();
44-
});
45-
46-
afterEach(() => {
47-
ServersServiceMock.findServerById.mockClear();
48-
});
45+
afterEach(jest.clearAllMocks);
4946

50-
it('dispatches proper actions', async () => {
51-
const dispatch = jest.fn();
47+
each([
48+
[ version, version ],
49+
[ 'latest', MAX_FALLBACK_VERSION ],
50+
[ '%invalid_semver%', MIN_FALLBACK_VERSION ],
51+
]).it('dispatches proper actions', async (serverVersion, expectedVersion) => {
5252
const expectedSelectedServer = {
5353
...selectedServer,
54-
version,
54+
version: expectedVersion,
5555
};
5656

57+
apiClientMock.health.mockResolvedValue({ version: serverVersion });
58+
5759
await selectServer(ServersServiceMock, buildApiClient)(serverId)(dispatch);
5860

5961
expect(dispatch).toHaveBeenCalledTimes(2);
@@ -67,5 +69,18 @@ describe('selectedServerReducer', () => {
6769
expect(ServersServiceMock.findServerById).toHaveBeenCalledTimes(1);
6870
expect(buildApiClient).toHaveBeenCalledTimes(1);
6971
});
72+
73+
it('falls back to min version when health endpoint fails', async () => {
74+
const expectedSelectedServer = {
75+
...selectedServer,
76+
version: MIN_FALLBACK_VERSION,
77+
};
78+
79+
apiClientMock.health.mockRejectedValue({});
80+
81+
await selectServer(ServersServiceMock, buildApiClient)(serverId)(dispatch);
82+
83+
expect(dispatch).toHaveBeenNthCalledWith(2, { type: SELECT_SERVER, selectedServer: expectedSelectedServer });
84+
});
7085
});
7186
});

0 commit comments

Comments
 (0)