src/system/__tests__/SystemConfiguration.spec.js

Summary

Maintainability
C
1 day
Test Coverage
import MockApi from '../../api/Api'
import SystemConfiguration from '../SystemConfiguration'

jest.mock('../../api/Api')

describe('System.configuration', () => {
    let configuration
    let mockApi

    const mockConfiguration = {
        systemId: 'eed3d451-4ff5-4193-b951-ffcc68954299',
        feedbackRecipients: {
            name: 'Feedback Message Recipients',
            created: '2011-12-25T16:52:04.409+0000',
            lastUpdated: '2015-10-19T10:27:27.636+0000',
            externalAccess: false,
            user: {
                name: 'John Traore',
                created: '2013-04-18T17:15:08.407+0000',
                lastUpdated: '2015-09-14T20:18:28.355+0000',
                externalAccess: false,
                id: 'xE7jOejl9FI',
            },
            id: 'QYrzIjSfI8z',
        },
        offlineOrganisationUnitLevel: {
            name: 'Chiefdom',
            created: '2011-12-24T12:24:22.935+0000',
            lastUpdated: '2015-08-09T12:58:05.001+0000',
            externalAccess: false,
            id: 'tTUf91fCytl',
        },
        infrastructuralIndicators: {
            name: 'Staffing',
            created: '2013-04-18T14:36:27.000+0000',
            lastUpdated: '2013-04-18T14:36:27.000+0000',
            externalAccess: false,
            publicAccess: 'rw------',
            id: 'EdDc97EJUdd',
        },
        infrastructuralDataElements: {
            name: 'Population Estimates',
            created: '2011-12-24T12:24:24.298+0000',
            lastUpdated: '2013-03-15T16:08:56.135+0000',
            externalAccess: false,
            publicAccess: 'rw------',
            id: 'sP7jTt3YGBb',
        },
        infrastructuralPeriodType: 'Yearly',
        selfRegistrationRole: {
            name: 'Guest',
            created: '2012-11-13T15:56:23.510+0000',
            lastUpdated: '2015-01-20T11:32:40.188+0000',
            externalAccess: false,
            id: 'XS0dNzuZmfH',
        },
        selfRegistrationOrgUnit: {
            code: 'OU_525',
            name: 'Sierra Leone',
            created: '2012-11-13T12:20:53.028+0000',
            lastUpdated: '2015-04-24T11:21:00.090+0000',
            externalAccess: false,
            user: {
                name: 'Tom Wakiki',
                created: '2012-11-21T12:02:04.303+0000',
                lastUpdated: '2015-10-19T10:27:27.567+0000',
                externalAccess: false,
                id: 'GOLswS44mh8',
            },
            id: 'ImspTQPwCqd',
        },
        corsWhitelist: [
            'http://cors1.example.com',
            'https://cors2.example.com',
        ],
        remoteServerUrl: 'https://apps.dhis2.org/demo',
        remoteServerUsername: 'admin',
    }

    const mockCorsWhitelistText =
        'http://cors1.example.com\nhttps://cors2.example.com'

    beforeEach(() => {
        mockApi = MockApi.getApi()
        MockApi.mockClear()
        configuration = new SystemConfiguration()
    })

    it('should not be allowed to be called without new', () => {
        expect(() => SystemConfiguration()).toThrowErrorMatchingSnapshot()
    })

    it('should add the mockApi onto the SystemConfiguration instance', () => {
        expect(configuration.api).toBe(mockApi)
    })

    it('all() should be a function', () => {
        expect(configuration.all).toBeInstanceOf(Function)
    })

    it('get() should be a function', () => {
        expect(configuration.get).toBeInstanceOf(Function)
    })

    it('should use the api object when it is passed', () => {
        const apiMockObject = {}

        configuration = new SystemConfiguration(apiMockObject)

        expect(configuration.api).toBe(apiMockObject)
    })

    describe('API call', () => {
        beforeEach(() => {
            mockApi.get.mockImplementation((url) => {
                if (url === 'configuration') {
                    return Promise.resolve(mockConfiguration)
                }
                return Promise.reject()
            })
            mockApi.post.mockReturnValue(Promise.resolve())
            mockApi.delete.mockReturnValue(Promise.resolve())
        })

        afterEach(() => {
            configuration = new SystemConfiguration()
        })

        describe('.all()', () => {
            it('should return the entire config', () => {
                expect.assertions(1)

                return configuration.all().then((res) => {
                    expect(res).toEqual(mockConfiguration)
                })
            })

            it('should query the API for all configuration endpoints', () => {
                configuration.all()

                expect(mockApi.get).toHaveBeenCalledTimes(1)
                expect(mockApi.get.mock.calls[0][0]).toBe('configuration')
            })

            it('should only call the API once', () => {
                expect.assertions(4)

                return configuration.all().then(() => {
                    configuration.all().then(() => {
                        expect(mockApi.get).toHaveBeenCalledTimes(1)
                        expect(mockApi.get.mock.calls[0][0]).toBe(
                            'configuration'
                        )
                    })
                    expect(mockApi.get).toHaveBeenCalledTimes(1)
                    expect(mockApi.get.mock.calls[0][0]).toBe('configuration')
                })
            })

            it('should call the API again if ignoreCache is true', () => {
                expect.assertions(5)

                return configuration.all(true).then(() => {
                    expect(mockApi.get).toHaveBeenCalledTimes(1)
                    expect(mockApi.get.mock.calls[0][0]).toBe('configuration')

                    return configuration.all(true).then(() => {
                        expect(mockApi.get).toHaveBeenCalledTimes(2)
                        expect(mockApi.get.mock.calls[0][0]).toBe(
                            'configuration'
                        )
                        expect(mockApi.get.mock.calls[1][0]).toBe(
                            'configuration'
                        )
                    })
                })
            })
        })

        describe('.get()', () => {
            it('should return the correct systemId', () => {
                expect.assertions(1)

                return configuration.get('systemId').then((res) => {
                    expect(res).toBe(mockConfiguration.systemId)
                })
            })

            it('should return the correct feedback recipient user group', () => {
                expect.assertions(1)

                return configuration.get('feedbackRecipients').then((res) => {
                    expect(res).toBe(mockConfiguration.feedbackRecipients)
                })
            })

            it('should only query the API once', () => {
                expect.assertions(4)

                return configuration.get('systemId').then((res1) => {
                    expect(res1).toBe(mockConfiguration.systemId)
                    expect(mockApi.get.mock.calls[0][0]).toBe('configuration')

                    configuration.get('systemId').then((res2) => {
                        expect(res2).toBe(mockConfiguration.systemId)
                        expect(mockApi.get.mock.calls[0][0]).toBe(
                            'configuration'
                        )
                    })
                })
            })

            it('should query the API twice if ignoreCache is true', () => {
                expect.assertions(4)

                return configuration.get('systemId', true).then((res1) => {
                    expect(res1).toBe(mockConfiguration.systemId)
                    expect(mockApi.get.mock.calls[0][0]).toBe('configuration')

                    configuration.get('systemId', true).then((res2) => {
                        expect(res2).toBe(mockConfiguration.systemId)
                        expect(mockApi.get.mock.calls[1][0]).toBe(
                            'configuration'
                        )
                    })
                })
            })

            it('should throw an error when asked for an unknown config option', () => {
                expect.assertions(1)

                return configuration
                    .get('someRandomOptionThatDoesntExist')
                    .catch((err) => {
                        expect(err).toMatchSnapshot()
                    })
            })
        })

        describe('.set()', () => {
            it('should not be able to change the systemId', () => {
                expect.assertions(1)

                return configuration
                    .set('systemId', 'my-random-system-id')
                    .catch((err) => {
                        expect(err).toMatchSnapshot()
                    })
            })

            it('should not attempt to change unknown settings', () => {
                expect.assertions(1)

                return configuration
                    .set(
                        'completelyCrazyConfigurationOption',
                        'totally rediculous value'
                    )
                    .then(() => {
                        // TODO: useless assertion
                        expect(true).toBe(true)
                    })
            })

            it('should call DELETE to remove feedback recipients', () => {
                expect.assertions(3)

                return configuration
                    .set('feedbackRecipients', 'null')
                    .then(() => {
                        expect(mockApi.post).toHaveBeenCalledTimes(0)
                        expect(mockApi.delete).toHaveBeenCalledTimes(1)
                        expect(mockApi.delete.mock.calls[0][0]).toBe(
                            'configuration/feedbackRecipients'
                        )
                    })
            })

            it('should call DELETE to remove self registration role', () => {
                expect.assertions(2)

                return configuration
                    .set('selfRegistrationRole', null)
                    .then(() => {
                        expect(mockApi.post).toHaveBeenCalledTimes(0)
                        expect(mockApi.delete.mock.calls[0][0]).toBe(
                            'configuration/selfRegistrationRole'
                        )
                    })
            })

            it('should call DELETE to remove self registration organisation unit', () => {
                expect.assertions(2)

                return configuration
                    .set('selfRegistrationOrgUnit', 'null')
                    .then(() => {
                        expect(mockApi.post).toHaveBeenCalledTimes(0)
                        expect(mockApi.delete.mock.calls[0][0]).toBe(
                            'configuration/selfRegistrationOrgUnit'
                        )
                    })
            })

            it('should convert CORS string to an array', () =>
                configuration
                    .set('corsWhitelist', mockCorsWhitelistText)
                    .then(() => {
                        expect(mockApi.post.mock.calls[0][0]).toBe(
                            'configuration/corsWhitelist'
                        )
                        expect(mockApi.post.mock.calls[0][1]).toEqual(
                            mockConfiguration.corsWhitelist
                        )
                    }))

            it('should post new settings to the API', () => {
                mockApi.post.mockClear()

                return configuration
                    .set('infrastructuralPeriodType', 'Monthly')
                    .then(() => {
                        expect(mockApi.post.mock.calls[0][0]).toBe(
                            'configuration/infrastructuralPeriodType'
                        )
                        expect(mockApi.post.mock.calls[0][1]).toBe('Monthly')
                    })
            })

            it('should reject a promise when no configuration can be found for the key', () => {
                mockApi.post.mockReset()
                mockApi.post.mockReturnValue(Promise.reject('StackTrace!'))

                return configuration
                    .set('thisKeyDoesNotExist', 'Some value')
                    .catch((message) => message)
                    .then((message) => {
                        expect(message).toBe(
                            'No configuration found for thisKeyDoesNotExist'
                        )
                    })
            })
        })
    })
})