-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Tests for the two ducks' reducers and the patreon epic.
- Loading branch information
Showing
8 changed files
with
177 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,12 @@ | ||
{ | ||
"extends": "airbnb", | ||
"env": { | ||
"jest": true | ||
}, | ||
"rules": { | ||
// Apprently react-native doesn't like .jsx files | ||
"react/jsx-filename-extension": ["error", { "extensions": [".js"] }], | ||
"import/prefer-default-export": "off" | ||
"import/prefer-default-export": "off", | ||
"import/no-extraneous-dependencies": ["error", { devDependencies: true }] | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export function isAuthenticated(state) { | ||
return state.auth.authenticated; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import configureStore from '../../store'; | ||
import * as actions from './actions'; | ||
import * as selectors from './selectors'; | ||
|
||
let store; | ||
|
||
beforeEach(() => { | ||
store = configureStore({ noEpic: true }); | ||
}); | ||
|
||
test('user is initially not logged in', () => { | ||
expect(selectors.isAuthenticated(store.getState())).toBe(false); | ||
}); | ||
|
||
test('login() logs the user in', () => { | ||
store.dispatch(actions.login()); | ||
expect(selectors.isAuthenticated(store.getState())).toBe(true); | ||
}); | ||
|
||
test('logout() logs the user out', () => { | ||
store.dispatch(actions.login()); | ||
expect(selectors.isAuthenticated(store.getState())).toBe(true); | ||
|
||
store.dispatch(actions.logout()); | ||
expect(selectors.isAuthenticated(store.getState())).toBe(false); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { ActionsObservable } from 'redux-observable'; | ||
import axios from 'axios'; | ||
import MockAdapter from 'axios-mock-adapter'; | ||
|
||
import configureStore from '../../store'; | ||
import * as types from './types'; | ||
import * as actions from './actions'; | ||
import * as selectors from './selectors'; | ||
import epic from './epic'; | ||
|
||
/* | ||
* Reducers are tested by stubbing out the epic with one that does nothing, | ||
* and then asserting things about the synchronous actions only. Later, | ||
* we test that the epics emit those synchronous actions in response | ||
* to the async stuff they do, which closes the loop and effectively | ||
* tests that dispatching the async action that the epic handled | ||
* eventually caused the expected state change. | ||
* | ||
* This is a lot simpler than trying to test the entire store | ||
* with the redux-observable middleware installed, and it gives us | ||
* the same coverage. | ||
*/ | ||
|
||
describe('patreon reducer', () => { | ||
let store; | ||
|
||
beforeEach(() => { | ||
store = configureStore({ noEpic: true }); | ||
}); | ||
|
||
test('patreon is initially not enabled', () => { | ||
expect(selectors.isPatron(store.getState())).toBe(false); | ||
}); | ||
|
||
test('patreonEnabled() enables patreon', () => { | ||
store.dispatch(actions.patreonEnabled()); | ||
expect(selectors.isPatron(store.getState())).toBe(true); | ||
}); | ||
|
||
test('patreonDisabled() disables patreon', () => { | ||
store.dispatch(actions.patreonEnabled()); | ||
expect(selectors.isPatron(store.getState())).toBe(true); | ||
|
||
store.dispatch(actions.patreonDisabled()); | ||
expect(selectors.isPatron(store.getState())).toBe(false); | ||
}); | ||
}); | ||
|
||
|
||
/* | ||
* Direct epic tests are very simple. An epic is just a function | ||
* that accepts an ActionsObservable and returns an Observable. | ||
* A test for an epic therefore just has to: | ||
* 1) Create an ActionObservable that emits the action(s) you want to test | ||
* 2) Assert that the Observable the epic returns emits the expected action(s) | ||
*/ | ||
|
||
describe('patreon epic', () => { | ||
const baseUrl = 'https://httpbin.org'; | ||
let mock; | ||
|
||
beforeEach(() => { | ||
mock = new MockAdapter(axios); | ||
}); | ||
|
||
// These tests are very simple; one action leads to a single other. | ||
// Other tests that result in multiple actions from the epic | ||
// will have to be a little more complicated. | ||
|
||
describe('when Patreon API call succeeds', () => { | ||
beforeEach(() => { | ||
mock.onPost(new RegExp(`${baseUrl}/.*`)).reply(200, {}); | ||
}); | ||
|
||
test('enable() leads to patreonEnabled()', () => { | ||
const action$ = ActionsObservable.of(actions.enable()); | ||
return expect(epic(action$).toPromise()).resolves.toEqual(actions.patreonEnabled()); | ||
}); | ||
|
||
test('disable() leads to patreonDisabled()', () => { | ||
const action$ = ActionsObservable.of(actions.disable()); | ||
return expect(epic(action$).toPromise()).resolves.toEqual(actions.patreonDisabled()); | ||
}); | ||
}); | ||
|
||
describe('when Patreon API call fails', () => { | ||
const status = 429; | ||
|
||
beforeEach(() => { | ||
mock.onPost(new RegExp(`${baseUrl}/.*`)).reply(status, {}); | ||
}); | ||
|
||
function expectErrorActionWithStatus(action, statusCode) { | ||
expect(action.type).toEqual(types.PATREON_ERROR); | ||
expect(action.error).toBe(true); | ||
expect(action.payload).toBeInstanceOf(Error); | ||
expect(action.payload.response.status).toEqual(statusCode); | ||
} | ||
|
||
test('enable() leads to patreonError()', async () => { | ||
const action$ = ActionsObservable.of(actions.enable()); | ||
const errorAction = await epic(action$).toPromise(); | ||
expectErrorActionWithStatus(errorAction, status); | ||
}); | ||
|
||
test('disable() leads to patreonError()', async () => { | ||
const action$ = ActionsObservable.of(actions.disable()); | ||
const errorAction = await epic(action$).toPromise(); | ||
expectErrorActionWithStatus(errorAction, status); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters