diff --git a/.github/ISSUE_TEMPLATE/Bug.md b/.github/ISSUE_TEMPLATE/Bug.md index 182df2be..93e61ad4 100644 --- a/.github/ISSUE_TEMPLATE/Bug.md +++ b/.github/ISSUE_TEMPLATE/Bug.md @@ -16,6 +16,7 @@ With that said, please fill in the information requested next. More information #### Shlink web client version * Version: x.y.z +* How do you use shlink-web-client: app.shlink.io|Docker image|self-hosted #### Summary diff --git a/.github/ISSUE_TEMPLATE/Question_Support.md b/.github/ISSUE_TEMPLATE/Question_Support.md index 8e75a1c1..4fdd085c 100644 --- a/.github/ISSUE_TEMPLATE/Question_Support.md +++ b/.github/ISSUE_TEMPLATE/Question_Support.md @@ -16,6 +16,7 @@ With that said, please fill in the information requested next. More information #### Shlink web client version * Version: x.y.z +* How do you use shlink-web-client: app.shlink.io|Docker image|self-hosted #### Summary diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c99e2e9..38f6dddf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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.2 - 2019-10-21 + +#### Added + +* *Nothing* + +#### Changed + +* *Nothing* + +#### Deprecated + +* *Nothing* + +#### Removed + +* *Nothing* + +#### Fixed + +* [#167](https://github.com/shlinkio/shlink-web-client/issues/167) Fixed `/servers.json` path not being ignored when returning something other than an array. + + ## 2.2.1 - 2019-10-18 #### Added diff --git a/config/docker/nginx.conf b/config/docker/nginx.conf index f9b2b816..ddc24af8 100644 --- a/config/docker/nginx.conf +++ b/config/docker/nginx.conf @@ -5,7 +5,7 @@ server { index index.html; # When requesting static paths with extension, try them, and return a 404 if not found - location ~ .+\.(css|js|html|png|jpg|jpeg|gif|bmp|ico|csv|otf|eot|svg|svgz|ttf|woff|woff2|ijmap|pdf|tif|map) { + location ~ .+\.(css|js|html|png|jpg|jpeg|gif|bmp|ico|json|csv|otf|eot|svg|svgz|ttf|woff|woff2|ijmap|pdf|tif|map) { try_files $uri $uri/ =404; } diff --git a/src/servers/reducers/server.js b/src/servers/reducers/server.js index f1624027..576eca14 100644 --- a/src/servers/reducers/server.js +++ b/src/servers/reducers/server.js @@ -30,10 +30,20 @@ export const listServers = ({ listServers, createServers }, { get }) => () => as return; } - // If local list is empty, try to fetch it remotely and calculate IDs for every server + // If local list is empty, try to fetch it remotely (making sure it's an array) and calculate IDs for every server + const getDataAsArrayWithIds = pipe( + prop('data'), + (value) => { + if (!Array.isArray(value)) { + throw new Error('Value is not an array'); + } + + return value; + }, + map(assocId), + ); const remoteList = await get(`${homepage}/servers.json`) - .then(prop('data')) - .then(map(assocId)) + .then(getDataAsArrayWithIds) .catch(() => []); createServers(remoteList); diff --git a/test/servers/reducers/server.test.js b/test/servers/reducers/server.test.js index 14d204bb..278e3e92 100644 --- a/test/servers/reducers/server.test.js +++ b/test/servers/reducers/server.test.js @@ -1,4 +1,5 @@ import { values } from 'ramda'; +import each from 'jest-each'; import reducer, { createServer, deleteServer, @@ -20,27 +21,18 @@ describe('serverReducer', () => { createServers: jest.fn(), }; + afterEach(jest.clearAllMocks); + describe('reducer', () => { it('returns servers when action is FETCH_SERVERS', () => expect(reducer({}, { type: FETCH_SERVERS, list })).toEqual({ loading: false, list })); }); describe('action creators', () => { - beforeEach(() => { - ServersServiceMock.listServers.mockClear(); - ServersServiceMock.createServer.mockReset(); - ServersServiceMock.deleteServer.mockReset(); - ServersServiceMock.createServers.mockReset(); - }); - describe('listServers', () => { - const axios = { get: jest.fn().mockResolvedValue({ data: [] }) }; + const axios = { get: jest.fn() }; const dispatch = jest.fn(); - - beforeEach(() => { - axios.get.mockClear(); - dispatch.mockReset(); - }); + const NoListServersServiceMock = { ...ServersServiceMock, listServers: jest.fn(() => ({})) }; it('fetches servers from local storage when found', async () => { await listServers(ServersServiceMock, axios)()(dispatch); @@ -55,14 +47,49 @@ describe('serverReducer', () => { expect(axios.get).not.toHaveBeenCalled(); }); - it('tries to fetch servers from remote when not found locally', async () => { - const NoListServersServiceMock = { ...ServersServiceMock, listServers: jest.fn(() => ({})) }; + each([ + [ + Promise.resolve({ + data: [ + { + id: '111', + name: 'acel.me from servers.json', + url: 'https://acel.me', + apiKey: '07fb8a96-8059-4094-a24c-80a7d5e7e9b0', + }, + { + id: '222', + name: 'Local from servers.json', + url: 'http://localhost:8000', + apiKey: '7a531c75-134e-4d5c-86e0-a71b7167b57a', + }, + ], + }), + { + 111: { + id: '111', + name: 'acel.me from servers.json', + url: 'https://acel.me', + apiKey: '07fb8a96-8059-4094-a24c-80a7d5e7e9b0', + }, + 222: { + id: '222', + name: 'Local from servers.json', + url: 'http://localhost:8000', + apiKey: '7a531c75-134e-4d5c-86e0-a71b7167b57a', + }, + }, + ], + [ Promise.resolve(''), {}], + [ Promise.reject({}), {}], + ]).it('tries to fetch servers from remote when not found locally', async (mockedValue, expectedList) => { + axios.get.mockReturnValue(mockedValue); await listServers(NoListServersServiceMock, axios)()(dispatch); expect(dispatch).toHaveBeenCalledTimes(2); expect(dispatch).toHaveBeenNthCalledWith(1, { type: FETCH_SERVERS_START }); - expect(dispatch).toHaveBeenNthCalledWith(2, { type: FETCH_SERVERS, list: {} }); + expect(dispatch).toHaveBeenNthCalledWith(2, { type: FETCH_SERVERS, list: expectedList }); expect(NoListServersServiceMock.listServers).toHaveBeenCalledTimes(1); expect(NoListServersServiceMock.createServer).not.toHaveBeenCalled(); expect(NoListServersServiceMock.deleteServer).not.toHaveBeenCalled();