Skip to content

Commit

Permalink
Throw exceptions instead of using magical key
Browse files Browse the repository at this point in the history
  • Loading branch information
dpikt committed Jun 20, 2019
1 parent 8bf6653 commit 880c8af
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 16 deletions.
6 changes: 4 additions & 2 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ A function that creates action creators for making stubbed API requests.
Unlike [createRequest][21], these action creators do not make real API calls but rather
resolve immediately with the provided data.

If an `error` key is provided in the stub data object, the "request" will reject with the value of that key instead of resolving.
If an exception is thrown from the data creator function, the "request" will reject with that exception instead of resolving.

### Parameters

Expand All @@ -375,7 +375,9 @@ handleActions({

// ** Stubbing a failed request: **

export const fetchUser = createStubRequest('FETCH_USER', (id) => ({ error: new Error('My mock error.') }))
export const fetchUser = createStubRequest('FETCH_USER', (id) => {
throw new Error('My mock error.')
})

fetchUsers(5)
// -> won't make any api request, but will reject with the given error.
Expand Down
22 changes: 15 additions & 7 deletions src/create-stub-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { isObject, isFunction, identity } from 'lodash'
* Unlike {@link createRequest}, these action creators do not make real API calls but rather
* resolve immediately with the provided data.
*
* If an `error` key is provided in the stub data object, the "request" will reject with the value of that key instead of resolving.
* If an exception is thrown from the data creator function, the "request" will reject with that exception instead of resolving.
*
* @name createStubRequest
* @param {String} type - A unique key that will be used to identify the request internally in redux
Expand All @@ -31,27 +31,35 @@ import { isObject, isFunction, identity } from 'lodash'
*
* // ** Stubbing a failed request: **
*
* export const fetchUser = createStubRequest('FETCH_USER', (id) => ({ error: new Error('My mock error.') }))
* export const fetchUser = createStubRequest('FETCH_USER', (id) => {
* throw new Error('My mock error.')
* })
*
* fetchUsers(5)
* // -> won't make any api request, but will reject with the given error.
*
**/

function createActionOptions (definition, args) {
return isFunction(definition)
? definition(...args) || {}
: definition
function getStubData (definition, args) {
if (!isFunction(definition)) return { stubData: definition }
try {
const stubData = definition(...args) || {}
return { stubData }
} catch (e) {
return { stubData: e, isError: true }
}
}

function createStubRequest (type, definition=identity) {
if (!type) throw new Error('Must include a type for your request.')
if (!(isObject(definition) || isFunction(definition))) throw new Error('Request definition must be an object or a function.')
function actionCreator (...args) {
const { stubData, isError } = getStubData(definition, args)
return {
[LP_API]: {
isStub: true,
stubData: createActionOptions(definition, args),
isStubError: isError,
stubData,
type,
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/middleware/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ import { isFunction } from 'lodash'
*/

// custom HTTP method for stub requests- makes no call, but resolves/rejects with provided data
function createStubRequest (data) {
function createStubRequest (data, isError) {
return function request () {
return new Promise((resolve, reject) => {
return data.error ? reject(data.error) : resolve(data)
return isError ? reject(data) : resolve(data)
})
}
}
Expand Down Expand Up @@ -69,6 +69,7 @@ function middleware (mainAdapter, options={}) {
successAction,
failureAction,
isStub,
isStubError,
stubData,
adapter=mainAdapter,
} = mergedConfigOptions
Expand All @@ -82,7 +83,7 @@ function middleware (mainAdapter, options={}) {
// Send built-in request action
next(actions.setStatusLoading(type))
// Make the request
const request = isStub ? createStubRequest(stubData) : adapter
const request = isStub ? createStubRequest(stubData, isStubError) : adapter
return request(mergedRequestOptions)
.then(
// Success handler
Expand Down
2 changes: 2 additions & 0 deletions src/middleware/parse-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ function parseOptions ({
successAction,
failureAction,
isStub,
isStubError,
stubData,
adapter,
...requestOptions
Expand All @@ -25,6 +26,7 @@ function parseOptions ({
successAction,
failureAction,
isStub,
isStubError,
stubData,
adapter,
}),
Expand Down
9 changes: 9 additions & 0 deletions test/create-stub-request.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ test('createStubRequest accepts function data creator', () => {
expect(action[LP_API]).toEqual({ type: REQUEST_TYPE, isStub: true, stubData: { foo: 'bar' } })
})

test('createStubRequest function sets data and error flag from thrown exception', () => {
const myException = new Error('oops')
const actionCreator = createStubRequest(REQUEST_TYPE, () => {
throw myException
})
const action = actionCreator('bar')
expect(action[LP_API]).toEqual({ type: REQUEST_TYPE, isStub: true, isStubError: true, stubData: myException })
})

test('createStubRequest defaults to identity for data creator', () => {
const actionCreator = createStubRequest(REQUEST_TYPE)
const action = actionCreator('bar')
Expand Down
9 changes: 5 additions & 4 deletions test/middleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,18 +149,19 @@ test('middleware resolves stubbed requests with provided data', () => {
})
})

test('middleware rejects stubbed requests with error key', () => {
test('middleware rejects stubbed requests with error flag', () => {
expect.assertions(1)
const ERROR = new Error('mock error')
const stubData = { foo: 'bar' }
const store = mockStore({})
const stubAction = {
[LP_API]: {
isStub: true,
stubData: { error: ERROR }
isStubError: true,
stubData
}
}
return store.dispatch(stubAction).catch((res) => {
expect(res).toEqual(ERROR)
expect(res).toEqual(stubData)
})
})

Expand Down

0 comments on commit 880c8af

Please sign in to comment.