Add documentation
This commit is contained in:
parent
380732d28a
commit
6ee5077c88
@ -6,6 +6,19 @@ function isPromise(value: any): value is Promise<any> {
|
||||
typeof (value as any).then === 'function'
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles promises returned from Actions.
|
||||
*
|
||||
* If `action.payload` is a `Promise`, it will be handled by this class. It
|
||||
* differs from other promise middlewares for redux because by default it does
|
||||
* not add an extension to action dispatched after a promise is fulfilled. This
|
||||
* makes it easier to infer types from the API endpoints so they can be used in
|
||||
* both Action creators and Reducers.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* const middleware = applyMiddleware(new PromiseMiddleware().handle)
|
||||
*/
|
||||
export class PromiseMiddleware {
|
||||
constructor(
|
||||
readonly pendingExtension = '_PENDING',
|
||||
|
||||
@ -3,11 +3,34 @@ import {connect, Omit} from 'react-redux'
|
||||
import {Dispatch} from 'redux'
|
||||
import {ComponentType} from 'react'
|
||||
|
||||
// https://stackoverflow.com/questions/54277411
|
||||
/**
|
||||
* Helps isolate the component along with actions and reducer from the global
|
||||
* application state.
|
||||
*
|
||||
* The connect() function requires a state selector, which can be used to
|
||||
* select a slice of the current state to the component, which will be passed
|
||||
* on to `mapStateToProps()`.
|
||||
*
|
||||
* Classes that extend Connector can provide dependencies in the constructor
|
||||
* and then bind them to dispatch in mapDispatchToProps. This is useful to
|
||||
* build components which do not depend on a "global" singletons. For example,
|
||||
* the Actions class might depend on the HTTPClient class, and then it becomes
|
||||
* easy to mock it during tests, or swap out different dependencies for
|
||||
* different applications.
|
||||
*/
|
||||
export abstract class Connector {
|
||||
|
||||
/**
|
||||
* Connects a component using redux. The `selectState` method is used to
|
||||
* select a subset of state to map to the component.
|
||||
*
|
||||
* It returns a component with `any` props. Ideally this could be changed to
|
||||
* required props.
|
||||
*
|
||||
* https://stackoverflow.com/questions/54277411
|
||||
*/
|
||||
abstract connect<State, LocalState>(
|
||||
getLocalState: IStateSelector<State, LocalState>,
|
||||
selectState: IStateSelector<State, LocalState>,
|
||||
): ComponentType<any>
|
||||
|
||||
protected wrap<
|
||||
|
||||
@ -1,2 +1,5 @@
|
||||
/*
|
||||
* Select and return a part of the state
|
||||
*/
|
||||
export type IStateSelector<GlobalState, StateSlice>
|
||||
= (state: GlobalState) => StateSlice
|
||||
|
||||
@ -28,6 +28,9 @@ export class HTTPClientMock<T extends IRoutes> extends HTTPClient<T> {
|
||||
super()
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock the http client.
|
||||
*/
|
||||
createRequestor() {
|
||||
return {
|
||||
request: (req: IRequest): Promise<IResponse> => {
|
||||
@ -62,11 +65,19 @@ export class HTTPClientMock<T extends IRoutes> extends HTTPClient<T> {
|
||||
return JSON.stringify(req, null, ' ')
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new mock. If a mock with the same signature exists, it will be
|
||||
* replaced. The signature is calculated using the `serialize()` method,
|
||||
* which just does a `JSON.stringify(req)`.
|
||||
*/
|
||||
mockAdd(req: IRequest, data: any, status = 200): this {
|
||||
this.mocks[this.serialize(req)] = {data, status}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all mocks and recorded requests
|
||||
*/
|
||||
mockClear(): this {
|
||||
this.requests = []
|
||||
this.mocks = {}
|
||||
@ -86,6 +97,17 @@ export class HTTPClientMock<T extends IRoutes> extends HTTPClient<T> {
|
||||
waitPromise.resolve(r)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new promise which will be resolve/rejected as soon as the next
|
||||
* HTTP promise is resolved or rejected. Useful during testing, when the
|
||||
* actual request promise is inaccessible.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* TestUtils.Simulate.submit(node) // This triggers a HTTP request
|
||||
* const {req, res} = await httpMock.wait()
|
||||
* expect(req).toEqual({method:'get', url:'/auth/post', data: {...}})
|
||||
*/
|
||||
async wait(): Promise<IReqRes> {
|
||||
expect(this.waitPromise).toBe(undefined)
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@ -44,6 +44,9 @@ export class TestUtils {
|
||||
return combineReducers(reducers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a redux store
|
||||
*/
|
||||
createStore<State, A extends Action<any> = AnyAction>(
|
||||
params: IStoreParams<State, A>,
|
||||
): Store<State, A> {
|
||||
@ -55,6 +58,10 @@ export class TestUtils {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a redux store, connects a component, and provides the `render`
|
||||
* method to render the connected component with a `Provider`.
|
||||
*/
|
||||
withProvider<State, A extends Action<any> = AnyAction>(
|
||||
params: IRenderParams<State>,
|
||||
) {
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Waits for a promise be rejected and return the error. If a promise resolves
|
||||
* it will throw an error. To be used during testing since
|
||||
* `expect(...).toThrowError()` only works with synchronous calls
|
||||
*/
|
||||
export async function getError(promise: Promise<any>): Promise<Error> {
|
||||
let error: Error
|
||||
try {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user