diff options
| author | Erik Larkö <erik@mullvad.net> | 2017-07-04 16:50:46 +0200 |
|---|---|---|
| committer | Erik Larkö <erik@mullvad.net> | 2017-07-04 16:50:46 +0200 |
| commit | b0d7ea1ae5b4555ad0aa90451480bf7ae83b3be4 (patch) | |
| tree | 396f3eae4ef55621836dca8f3f1a6bfb4c0602d9 | |
| parent | c714a1cb4ea2cdb0a21e3c71684e7047a77da10e (diff) | |
| parent | db63fd56226d97243aa7c5858ecc0ebd7099d5c9 (diff) | |
| download | mullvadvpn-b0d7ea1ae5b4555ad0aa90451480bf7ae83b3be4.tar.xz mullvadvpn-b0d7ea1ae5b4555ad0aa90451480bf7ae83b3be4.zip | |
Merge branch 'testing-login-flow'
| -rw-r--r-- | app/lib/backend.js | 7 | ||||
| -rw-r--r-- | test/helpers/ipc-helpers.js | 35 | ||||
| -rw-r--r-- | test/login.spec.js | 64 |
3 files changed, 102 insertions, 4 deletions
diff --git a/app/lib/backend.js b/app/lib/backend.js index 4cd2cf49e9..2923baf34d 100644 --- a/app/lib/backend.js +++ b/app/lib/backend.js @@ -1,4 +1,5 @@ // @flow + import log from 'electron-log'; import EventEmitter from 'events'; import { servers } from '../config'; @@ -169,7 +170,11 @@ export class Backend { error: null, })); - this._store.dispatch(push('/connect')); + // Redirect the user after some time to allow for + // the 'Login Successful' screen to be visible + setTimeout(() => { + this._store.dispatch(push('/connect')); + }, 1000); }).catch(e => { log.error('Failed to log in', e); diff --git a/test/helpers/ipc-helpers.js b/test/helpers/ipc-helpers.js index 39fc9fba06..bffc6b1540 100644 --- a/test/helpers/ipc-helpers.js +++ b/test/helpers/ipc-helpers.js @@ -4,6 +4,7 @@ import { Backend } from '../../app/lib/backend'; import { newMockIpc } from '../mocks/ipc'; import configureStore from '../../app/redux/store'; import { createMemoryHistory } from 'history'; +import { mockState, mockStore } from '../mocks/redux'; type DoneCallback = (?mixed) => void; type Check = () => void; @@ -17,7 +18,7 @@ export function setupBackendAndStore() { const memoryHistory = createMemoryHistory(); const store = configureStore(null, memoryHistory); - + const mockIpc = newMockIpc(); const backend = new Backend(store, mockIpc); @@ -25,6 +26,13 @@ export function setupBackendAndStore() { return { store, mockIpc, backend }; } +export function setupBackendAndMockStore() { + const store = mockStore(mockState()); + const mockIpc = newMockIpc(); + const backend = new Backend(store, mockIpc); + return { store, mockIpc, backend }; +} + // chai and async aren't the best of friends. To allow us // to get the assertion error in the output of failed async // tests we need to do this try-catch thing. @@ -37,6 +45,16 @@ export function check(fn: Check, done: DoneCallback) { } } +// Sometimes with redux we cannot know when all reducers have +// finished running. This function puts the check at the end +// of the execution queue, hopefully resulting in the check being +// run after the reducers are finished +export function checkNextTick(fn: Check, done: DoneCallback) { + setTimeout(() => { + check(fn, done); + }, 1); +} + // In async tests where we want to test a chain of IPC messages // we can only invoke `done` for the last message. This function @@ -49,3 +67,18 @@ export function failFast(fn: Check, done: DoneCallback) { } } +type MockStore = { + getActions: () => Array<{type: string, payload: Object}>, +} +// Parses the action log to find out which URL we most recently navigated to +// Note that this cannot be done with the real redux store, but rather must be +// done with the mock store. +export function getLocation(store: MockStore): ?string { + const navigations = store.getActions().filter(action => action.type === '@@router/CALL_HISTORY_METHOD'); + if (navigations.length === 0) { + return null; + } + + return navigations[navigations.length - 1].payload.args[0]; +} + diff --git a/test/login.spec.js b/test/login.spec.js index 84ca0f431a..3d7a1ed0d1 100644 --- a/test/login.spec.js +++ b/test/login.spec.js @@ -1,7 +1,7 @@ // @flow import { expect } from 'chai'; -import { setupBackendAndStore } from './helpers/ipc-helpers'; +import { setupBackendAndStore, setupBackendAndMockStore, checkNextTick, getLocation, failFast, check } from './helpers/ipc-helpers'; import { IpcChain } from './helpers/IpcChain'; import accountActions from '../app/redux/account/actions'; @@ -26,5 +26,65 @@ describe('Logging in', () => { const action: any = accountActions.login(backend, '123'); store.dispatch(action); }); -}); + it('should put the account data in the state', (done) => { + const { store, backend, mockIpc } = setupBackendAndStore(); + mockIpc.getAccountData = () => new Promise(r => r({ + paid_until: '2001-01-01T00:00:00', + })); + + const action: any = accountActions.login(backend, '123'); + store.dispatch(action); + + checkNextTick( () => { + const state = store.getState().account; + expect(state.status).to.equal('ok'); + expect(state.accountNumber).to.equal('123'); + expect(state.paidUntil).to.equal('2001-01-01T00:00:00'); + }, done); + }); + + it('should indicate failure for non-existing accounts', (done) => { + const { store, mockIpc, backend } = setupBackendAndStore(); + + mockIpc.getAccountData = (_num) => new Promise((_,reject) => { + reject('NO SUCH ACCOUNT'); + }); + + + const action: any = accountActions.login(backend, '123'); + store.dispatch(action); + + + checkNextTick(() => { + const state = store.getState().account; + expect(state.status).to.equal('failed'); + expect(state.error).to.not.be.null; + }, done); + }); + + it('should redirect to /connect after 1s after successful login', (done) => { + const { store, backend } = setupBackendAndMockStore(); + + const action: any = accountActions.login(backend, '123'); + store.dispatch(action); + + + setTimeout(() => { + + failFast(() => { + expect(getLocation(store)).not.to.equal('/connect'); + }, done); + + }, 100); + + + setTimeout(() => { + + check(() => { + expect(getLocation(store)).to.equal('/connect'); + }, done); + + }, 1100); + }); +}); |
