Fix CallActions.test.ts

This commit is contained in:
Jerko Steiner 2019-11-13 21:28:43 -03:00
parent 7009e53037
commit 4bdd2e4cae
8 changed files with 63 additions and 61 deletions

View File

@ -1,26 +1,38 @@
jest.mock('../socket')
jest.mock('../window')
jest.mock('../store')
jest.mock('./SocketActions')
import * as CallActions from './CallActions'
import * as SocketActions from './SocketActions'
import * as constants from '../constants'
import socket from '../socket'
import storeMock from '../store'
import { callId, getUserMedia } from '../window'
import { MockStore } from 'redux-mock-store'
import { bindActionCreators } from 'redux'
import { bindActionCreators, createStore, AnyAction, combineReducers, applyMiddleware } from 'redux'
import reducers from '../reducers'
import { middlewares } from '../middlewares'
jest.useFakeTimers()
describe('reducers/alerts', () => {
describe('CallActions', () => {
const store: MockStore = storeMock as any
const callActions = bindActionCreators(CallActions, store.dispatch)
let callActions: typeof CallActions
function allActions(state: AnyAction[] = [], action: AnyAction) {
return [...state, action]
}
const configureStore = () => createStore(
combineReducers({...reducers, allActions }),
applyMiddleware(...middlewares),
)
let store: ReturnType<typeof configureStore>
beforeEach(() => {
store.clearActions();
store = createStore(
combineReducers({ allActions }),
applyMiddleware(...middlewares),
)
callActions = bindActionCreators(CallActions, store.dispatch);
(getUserMedia as any).fail(false);
(SocketActions.handshake as jest.Mock).mockReturnValue(jest.fn())
})
@ -35,9 +47,8 @@ describe('reducers/alerts', () => {
it('calls handshake.init when connected & got camera stream', async () => {
const promise = callActions.init()
socket.emit('connect')
expect(store.getActions()).toEqual([{
type: constants.INIT_PENDING,
}, {
await promise
expect(store.getState().allActions.slice(1)).toEqual([{
type: constants.NOTIFY,
payload: {
id: jasmine.any(String),
@ -45,15 +56,14 @@ describe('reducers/alerts', () => {
type: 'warning',
},
}, {
type: constants.MESSAGE_ADD,
type: constants.STREAM_ADD,
payload: {
image: null,
message: 'Connected to server socket',
timestamp: jasmine.any(String),
userId: '[PeerCalls]',
stream: jasmine.anything(),
userId: constants.ME,
},
}, {
type: constants.INIT,
}])
await promise
expect((SocketActions.handshake as jest.Mock).mock.calls).toEqual([[{
socket,
roomName: callId,
@ -65,23 +75,13 @@ describe('reducers/alerts', () => {
const promise = callActions.init()
socket.emit('connect')
socket.emit('disconnect')
expect(store.getActions()).toEqual([{
type: constants.INIT_PENDING,
}, {
expect(store.getState().allActions.slice(1)).toEqual([{
type: constants.NOTIFY,
payload: {
id: jasmine.any(String),
message: 'Connected to server socket',
type: 'warning',
},
}, {
type: constants.MESSAGE_ADD,
payload: {
image: null,
message: 'Connected to server socket',
timestamp: jasmine.any(String),
userId: '[PeerCalls]',
},
}, {
type: constants.NOTIFY,
payload: {
@ -89,14 +89,6 @@ describe('reducers/alerts', () => {
message: 'Server socket disconnected',
type: 'error',
},
}, {
type: constants.MESSAGE_ADD,
payload: {
image: null,
message: 'Server socket disconnected',
timestamp: jasmine.any(String),
userId: '[PeerCalls]',
},
}])
await promise
})

View File

@ -4,7 +4,8 @@ import * as StreamActions from './StreamActions'
import * as constants from '../constants'
import socket from '../socket'
import { callId, getUserMedia } from '../window'
import { Dispatch, GetState } from '../store'
import { Dispatch, GetState, ThunkResult } from '../store'
import { makeAction } from '../async'
export interface InitAction {
type: 'INIT'
@ -19,20 +20,21 @@ const initialize = (): InitializeAction => ({
type: 'INIT',
})
export const init = () => async (dispatch: Dispatch, getState: GetState) => {
dispatch(initialize())
export const init = (): ThunkResult<Promise<void>> =>
async (dispatch, getState) => {
const socket = await dispatch(connect())
const stream = await dispatch(getCameraStream())
const socket = await connect(dispatch)
const stream = await getCameraStream(dispatch)
SocketActions.handshake({
dispatch(SocketActions.handshake({
socket,
roomName: callId,
stream,
})(dispatch, getState)
}))
dispatch(initialize())
}
export async function connect (dispatch: Dispatch) {
export const connect = () => (dispatch: Dispatch) => {
return new Promise<SocketIOClient.Socket>(resolve => {
socket.once('connect', () => {
resolve(socket)
@ -46,7 +48,7 @@ export async function connect (dispatch: Dispatch) {
})
}
export async function getCameraStream (dispatch: Dispatch) {
export const getCameraStream = () => async (dispatch: Dispatch) => {
try {
const stream = await getUserMedia({
video: { facingMode: 'user' },

View File

@ -27,15 +27,15 @@ function notify(dispatch: Dispatch, type: NotifyType, args: string[]) {
}
export const info = (...args: any[]): ThunkResult<NotificationAddAction> => {
return dispatch => notify(dispatch, 'info', args)
return dispatch => dispatch(notify(dispatch, 'info', args))
}
export const warning = (...args: any[]): ThunkResult<NotificationAddAction> => {
return dispatch => notify(dispatch, 'warning', args)
return dispatch => dispatch(notify(dispatch, 'warning', args))
}
export const error = (...args: any[]): ThunkResult<NotificationAddAction> => {
return dispatch => notify(dispatch, 'error', args)
return dispatch => dispatch(notify(dispatch, 'error', args))
}
function addNotification(payload: Notification): NotificationAddAction {

View File

@ -1,4 +1,4 @@
import { Action } from 'redux'
import { Action, Dispatch } from 'redux'
export type PendingAction<T extends string, P> = Action<T> & Promise<P> & {
status: 'pending'
@ -49,9 +49,9 @@ export function isPendingAction(
export function makeAction<A extends unknown[], T extends string, P>(
type: T,
impl: (...args: A) => Promise<P>,
): (...args: A) => PendingAction<T, P>{
): (...args: A) => PendingAction<T, P> {
return (...args: A) => {
const pendingAction= impl(...args) as PendingAction<T, P>
const pendingAction = impl(...args) as PendingAction<T, P>
pendingAction.type = type
pendingAction.status = 'pending'
return pendingAction

View File

@ -1,13 +1,20 @@
import { AnyAction, Middleware } from 'redux'
import { isPendingAction, ResolvedAction, PendingAction, RejectedAction } from './action'
import { isPendingAction, ResolvedAction, RejectedAction } from './action'
import _debug from 'debug'
const debug = _debug('peercalls:async')
export const middleware: Middleware = store => next => (action: AnyAction) => {
if (!isPendingAction(action)) {
debug('NOT pending %o', action)
return next(action)
}
debug('Pending: %s %s', action.type, action.status)
const promise = action
.then(payload => {
debug('Resolved: %s resolved', action.type)
const resolvedAction: ResolvedAction<string, unknown> = {
payload,
type: action.type,
@ -17,6 +24,7 @@ export const middleware: Middleware = store => next => (action: AnyAction) => {
})
// Propagate this action. Only attach listeners to the promise.
debug('Calling next for %s %s', action.type, action.status)
next({
type: action.type,
status: 'pending',
@ -24,6 +32,7 @@ export const middleware: Middleware = store => next => (action: AnyAction) => {
const promise2 = promise
.catch((err: Error) => {
debug('Rejected: %s rejected %s', action.type, err.stack)
const rejectedAction: RejectedAction<string> = {
payload: err,
type: action.type,
@ -32,5 +41,7 @@ export const middleware: Middleware = store => next => (action: AnyAction) => {
store.dispatch(rejectedAction)
})
return promise2.then(() => action)
return promise2.then(() => {
return action
})
}

View File

@ -6,9 +6,6 @@ export const ALERT_DISMISS = 'ALERT_DISMISS'
export const ALERT_CLEAR = 'ALERT_CLEAR'
export const INIT = 'INIT'
export const INIT_PENDING = `${INIT}_PENDING`
export const INIT_FULFILLED = `${INIT}_FULFILLED`
export const INIT_REJECTED = `${INIT}_REJECTED`
export const ME = '_me_'

View File

@ -1,8 +1,9 @@
import { Middleware } from 'redux'
import logger from 'redux-logger'
import promiseMiddleware from 'redux-promise-middleware'
import thunk from 'redux-thunk'
import { middleware as asyncMiddleware } from './async'
export const middlewares = [thunk, promiseMiddleware()]
export const middlewares: Middleware[] = [thunk, asyncMiddleware]
export const create = (log = false) => {
const m = middlewares.slice()
log && m.push(logger)

View File

@ -1,7 +1,6 @@
import { Action, applyMiddleware, createStore as _createStore, Store as ReduxStore } from 'redux'
import { ThunkAction, ThunkDispatch } from 'redux-thunk'
import { create } from './middlewares'
import { middleware as asyncMiddleware }from './async'
import reducers from './reducers'
export const middlewares = create(
@ -10,7 +9,7 @@ export const middlewares = create(
export const createStore = () => _createStore(
reducers,
applyMiddleware(...middlewares, asyncMiddleware),
applyMiddleware(...middlewares),
)
export default createStore()