Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save igorvieira/5faeac62aead68426d844768d7468931 to your computer and use it in GitHub Desktop.
Save igorvieira/5faeac62aead68426d844768d7468931 to your computer and use it in GitHub Desktop.
/**
* Action Type represents that foo is currently being fetched.
* @type {String}
*/
export const FETCHING_FOO = 'FETCHING_FOO';
/**
* Action Type represents that foo has been successfully fetched.
* @type {String}
*/
export const FETCHED_FOO = 'FETCHED_FOO';
/**
* Action Type represents that the fetching of foo failed.
* @type {String}
*/
export const FETCHFAILED_FOO = 'FETCHFAILED_FOO';
import superagent from 'superagent';
import { FETCHING_FOO, FETCHED_FOO, FETCHFAILED_FOO }
from './actionTypes';
export function fetchFoo() {
return (dispatch, getState) => {
const { foo } = getState();
if (foo.isFetched === true) {
// We have already fetched foo, no need to fetch it again.
return;
}
dispatch({ type: FETCHING_FOO });
superagent
.get('/foo')
.accept('application/json')
.end((err, res) => {
if (err) {
dispatch({
type: FETCHFAILED_FOO
});
return;
}
dispatch({
type: FETCHED_FOO,
payload: res.body
});
});
};
}
import { expect } from 'chai';
import sinon from 'sinon';
import superagent from 'superagent';
import { FETCHING_FOO, FETCHED_FOO, FETCHFAILED_FOO } from './actionTypes';
describe('Given a fetchFoo action creator', () => {
const fetchLatestBill = require('./fooActionCreators').fetchFoo;
describe('When successfully fetching foo', () => {
let deferredAction;
let dispatchSpy;
const responseDataStub = {
'bar' : 'bob'
};
before(() => {
sinon.stub(superagent.Request.prototype, 'end', (callback) => {
callback(null, { body: responseDataStub });
});
deferredAction = fetchLatestBill();
/**
* We will be getting a deferred action, so lets call the deferred action
* with some stubs so that we can continue the full test of this
* function.
*/
dispatchSpy = sinon.spy();
const getStateStub = () => {
return { foo: { isFetched: false } };
};
deferredAction(dispatchSpy, getStateStub);
});
after(() => {
superagent.Request.prototype.end.restore();
});
it('Then a deferred action should be returned', () => {
expect(deferredAction).to.exist;
});
it('Then the API should have been requested once only', () => {
expect(superagent.Request.prototype.end.calledOnce).to.be.true;
});
it('Then the action dispatcher should have been called twice', () => {
expect(dispatchSpy.calledTwice).is.true;
});
it('Then the first action dispatched should be FETCHING_FOO action', () => {
expect(dispatchSpy.firstCall.args[0]).to.eql({
type: FETCHING_FOO
});
});
it('Then the second action dispatched should be FETCHED_FOO action', () => {
expect(dispatchSpy.secondCall.args[0]).to.eql({
type: FETCHED_FOO,
payload: responseDataStub
});
});
});
describe('When foo has already been fetched', () => {
let deferredAction;
let dispatchSpy;
before(() => {
sinon.stub(superagent.Request.prototype, 'end', (callback) => {
callback(null, null);
});
deferredAction = fetchFoo();
// stub/mock the deferredAction.
dispatchSpy = sinon.spy();
const getStateStub = () => {
return { foo: { isFetched: true } };
};
deferredAction(dispatchSpy, getStateStub);
});
after(() => {
superagent.Request.prototype.end.restore();
});
it('Then the API should not have been called', () => {
expect(superagent.Request.prototype.end.called).to.be.false;
});
it('Then no actions should have been dispatched', () => {
expect(dispatchSpy.called).to.be.false;
});
});
describe('When there is an error fetching foo', () => {
let deferredAction;
let dispatchSpy;
before(() => {
sinon.stub(superagent.Request.prototype, 'end', (callback) => {
callback(new Error(), null);
});
deferredAction = fetchFoo();
// stub/mock the deferredAction.
dispatchSpy = sinon.spy();
const getStateStub = () => {
return { foo: { isFetched: false } };
};
deferredAction(dispatchSpy, getStateStub);
});
after(() => {
superagent.Request.prototype.end.restore();
});
it('Then the API should have been called once', () => {
expect(superagent.Request.prototype.end.calledOnce).to.be.true;
});
it('Then the first action dispatched should be FETCHING_FOO action', () => {
expect(dispatchSpy.firstCall.args[0]).to.eql({
type: FETCHING_FOO
});
});
it('Then the second action dispatched should be FETCHFAILED_FOO action', () => {
expect(dispatchSpy.secondCall.args[0]).to.eql({
type: FETCHFAILED_FOO
});
});
});
});
import { FETCHING_FOO, FETCHED_FOO, FETCHFAILED_FOO } from './actionTypes';
/**
* The default initial state for the 'foo reducer'.
*/
const initialState = {
// Indicates if foo has been fetched successfully.
isFetched: false,
// Indicates if foo is currently being fetched.
isFetching: false,
// Indicates if the fetching of the foo failed.
isFailed: false,
// The foo data
data: null
};
/**
* The 'foo' reducer.
*
* Accepts the following action types:
* - FETCHING_FOO
* - FETCHED_FOO
* - FETCHFAILED_FOO
*
* @param {Object} state = The current state.
* @param {Object} action = The action.
* @return {Object} the reduced state based on the incoming action.
*/
export default function(state = initialState, action = { type: '__NONE__' }) {
switch (action.type) {
case FETCHING_FOO:
return {
isFetched: false,
isFetching: true,
isFailed: false,
data: null
};
case FETCHED_FOO:
return {
isFetched: true,
isFetching: false,
isFailed: false,
data: action.payload
};
case FETCHFAILED_FOO:
return {
isFetched: false,
isFetching: false,
isFailed: true,
data: null
};
default:
return state;
}
return state;
}
/* This is intentionally blank just and exists to secure a decent gist name */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment