Add tests for actions & reducers
This commit is contained in:
parent
46ec853280
commit
300afd6b2f
@ -4,7 +4,8 @@
|
||||
"rules": {
|
||||
"max-len": [2, 80, 4],
|
||||
"jsx-quotes": ["error", "prefer-double"],
|
||||
"padded-blocks": 0
|
||||
"padded-blocks": 0,
|
||||
"import/first": 0
|
||||
},
|
||||
"globals": {
|
||||
"expect": true,
|
||||
|
||||
4
Makefile
4
Makefile
@ -52,7 +52,7 @@ lint-fix:
|
||||
.PHONY: test
|
||||
test:
|
||||
|
||||
jest --verbose
|
||||
jest --forceExit
|
||||
|
||||
.PHONY: testify
|
||||
testify:
|
||||
@ -62,7 +62,7 @@ testify:
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
|
||||
jest --coverage
|
||||
jest --coverage --forceExit
|
||||
|
||||
.PHONY: server
|
||||
server:
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import EventEmitter from 'events'
|
||||
const Peer = jest.genMockFunction().mockImplementation(() => {
|
||||
let peer = new EventEmitter()
|
||||
peer.destroy = jest.genMockFunction()
|
||||
peer.signal = jest.genMockFunction()
|
||||
peer.destroy = jest.fn()
|
||||
peer.signal = jest.fn()
|
||||
peer.send = jest.fn()
|
||||
Peer.instances.push(peer)
|
||||
return peer
|
||||
})
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"start": "node src/index.js",
|
||||
"test": "jest --coverage",
|
||||
"test": "jest --coverage --forceExit",
|
||||
"testify": "jest --watch",
|
||||
"lint": "eslint ./index.js ./src/js"
|
||||
},
|
||||
|
||||
2
src/client/__mocks__/socket.js
Normal file
2
src/client/__mocks__/socket.js
Normal file
@ -0,0 +1,2 @@
|
||||
import EventEmitter from 'events'
|
||||
export default new EventEmitter()
|
||||
@ -6,21 +6,23 @@ import getUserMedia from '../window/getUserMedia.js'
|
||||
import handshake from '../peer/handshake.js'
|
||||
import socket from '../socket.js'
|
||||
|
||||
export const init = () => dispatch => ({
|
||||
type: constants.INIT,
|
||||
payload: Promise.all([
|
||||
connect()(dispatch),
|
||||
getCameraStream()(dispatch)
|
||||
])
|
||||
.spread((socket, stream) => {
|
||||
handshake.init({ socket, callId, stream })
|
||||
export const init = () => dispatch => {
|
||||
return dispatch({
|
||||
type: constants.INIT,
|
||||
payload: Promise.all([
|
||||
connect()(dispatch),
|
||||
getCameraStream()(dispatch)
|
||||
])
|
||||
.spread((socket, stream) => {
|
||||
handshake({ socket, callId, stream })
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const connect = () => dispatch => {
|
||||
return new Promise(resolve => {
|
||||
socket.once('connect', () => {
|
||||
dispatch(NotifyActions.warn('Connected to server socket'))
|
||||
dispatch(NotifyActions.warning('Connected to server socket'))
|
||||
resolve(socket)
|
||||
})
|
||||
socket.on('disconnect', () => {
|
||||
@ -35,9 +37,9 @@ export const getCameraStream = () => dispatch => {
|
||||
dispatch(addStream({ stream, userId: constants.ME }))
|
||||
return stream
|
||||
})
|
||||
.catch(() => {
|
||||
.catch(err => {
|
||||
dispatch(NotifyActions.alert('Could not get access to microphone & camera'))
|
||||
return null
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import * as constants from '../constants.js'
|
||||
import Immutable from 'seamless-immutable'
|
||||
|
||||
const TIMEOUT = 5000
|
||||
|
||||
@ -11,7 +12,7 @@ function format (string, args) {
|
||||
const _notify = (type, args) => dispatch => {
|
||||
let string = args[0] || ''
|
||||
let message = format(string, Array.prototype.slice.call(args, 1))
|
||||
const payload = { type, message }
|
||||
const payload = Immutable({ type, message })
|
||||
dispatch({
|
||||
type: constants.NOTIFY,
|
||||
payload
|
||||
@ -24,18 +25,22 @@ const _notify = (type, args) => dispatch => {
|
||||
}, TIMEOUT)
|
||||
}
|
||||
|
||||
export const info = function() {
|
||||
export const info = function () {
|
||||
return dispatch => _notify('info', arguments)(dispatch)
|
||||
}
|
||||
|
||||
export const warn = function() {
|
||||
export const warning = function () {
|
||||
return dispatch => _notify('warning', arguments)(dispatch)
|
||||
}
|
||||
|
||||
export const error = function() {
|
||||
export const error = function () {
|
||||
return dispatch => _notify('error', arguments)(dispatch)
|
||||
}
|
||||
|
||||
export const clear = () => ({
|
||||
type: constants.NOTIFY_CLEAR
|
||||
})
|
||||
|
||||
export function alert (message, dismissable) {
|
||||
return {
|
||||
type: constants.ALERT,
|
||||
@ -48,9 +53,15 @@ export function alert (message, dismissable) {
|
||||
}
|
||||
}
|
||||
|
||||
export const dismiss = alert => {
|
||||
export const dismissAlert = alert => {
|
||||
return {
|
||||
type: constants.ALERT_DISMISS,
|
||||
payload: alert
|
||||
}
|
||||
}
|
||||
|
||||
export const clearAlerts = () => {
|
||||
return {
|
||||
type: constants.ALERT_CLEAR
|
||||
}
|
||||
}
|
||||
|
||||
93
src/client/actions/__tests__/CallActions-test.js
Normal file
93
src/client/actions/__tests__/CallActions-test.js
Normal file
@ -0,0 +1,93 @@
|
||||
jest.mock('../../callId.js')
|
||||
jest.mock('../../iceServers.js')
|
||||
jest.mock('../../peer/handshake.js')
|
||||
jest.mock('../../socket.js')
|
||||
jest.mock('../../window/getUserMedia.js')
|
||||
jest.mock('../../store.js')
|
||||
|
||||
import * as CallActions from '../CallActions.js'
|
||||
import * as constants from '../../constants.js'
|
||||
import * as getUserMediaMock from '../../window/getUserMedia.js'
|
||||
import callId from '../../callId.js'
|
||||
import handshake from '../../peer/handshake.js'
|
||||
import socket from '../../socket.js'
|
||||
import store from '../../store.js'
|
||||
|
||||
jest.useFakeTimers()
|
||||
|
||||
describe('reducers/alerts', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
store.clearActions()
|
||||
getUserMediaMock.fail(false)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.runAllTimers()
|
||||
socket.removeAllListeners('connect')
|
||||
socket.removeAllListeners('disconnect')
|
||||
})
|
||||
|
||||
describe('init', () => {
|
||||
|
||||
it('calls handshake.init when connected & got camera stream', done => {
|
||||
const promise = store.dispatch(CallActions.init())
|
||||
socket.emit('connect')
|
||||
expect(store.getActions()).toEqual([{
|
||||
type: constants.INIT_PENDING
|
||||
}, {
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
message: 'Connected to server socket',
|
||||
type: 'warning'
|
||||
}
|
||||
}])
|
||||
promise.then(() => {
|
||||
expect(handshake.mock.calls).toEqual([[{
|
||||
socket,
|
||||
callId,
|
||||
stream: getUserMediaMock.stream
|
||||
}]])
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail)
|
||||
})
|
||||
|
||||
it('calls dispatches disconnect message on disconnect', done => {
|
||||
const promise = store.dispatch(CallActions.init())
|
||||
socket.emit('connect')
|
||||
socket.emit('disconnect')
|
||||
expect(store.getActions()).toEqual([{
|
||||
type: constants.INIT_PENDING
|
||||
}, {
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
message: 'Connected to server socket',
|
||||
type: 'warning'
|
||||
}
|
||||
}, {
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
message: 'Server socket disconnected',
|
||||
type: 'error'
|
||||
}
|
||||
}])
|
||||
promise.then(done).catch(done.fail)
|
||||
})
|
||||
|
||||
it('dispatches alert when failed to get media stream', done => {
|
||||
getUserMediaMock.fail(true)
|
||||
const promise = store.dispatch(CallActions.init())
|
||||
socket.emit('connect')
|
||||
promise
|
||||
.then(done.fail)
|
||||
.catch(err => {
|
||||
expect(err.message).toEqual('test')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -8,6 +8,7 @@ import _ from 'underscore'
|
||||
|
||||
export default class App extends React.Component {
|
||||
static propTypes = {
|
||||
dismissAlert: PropTypes.func.isRequired,
|
||||
streams: PropTypes.objectOf(StreamPropType).isRequired,
|
||||
alerts: PropTypes.arrayOf(AlertPropType).isRequired,
|
||||
activate: PropTypes.func.isRequired,
|
||||
@ -21,11 +22,11 @@ export default class App extends React.Component {
|
||||
}
|
||||
render () {
|
||||
const {
|
||||
active, activate, alerts, dismiss, notify, notifications, streams
|
||||
active, activate, alerts, dismissAlert, notify, notifications, streams
|
||||
} = this.props
|
||||
|
||||
return (<div className="app">
|
||||
<Alerts alerts={alerts} dismiss={dismiss} />
|
||||
<Alerts alerts={alerts} dismiss={dismissAlert} />
|
||||
<Notifications notifications={notifications} />
|
||||
<Input notify={notify} />
|
||||
<div className="videos">
|
||||
|
||||
@ -2,9 +2,9 @@ import { PENDING, FULFILLED, REJECTED } from 'redux-promise-middleware'
|
||||
export const ME = '_me_'
|
||||
|
||||
export const INIT = 'INIT'
|
||||
export const INIT_PENDING = `${INIT}${PENDING}`
|
||||
export const INIT_FULFILLED = `${INIT}${FULFILLED}`
|
||||
export const INIT_REJECTED = `${INIT}${REJECTED}`
|
||||
export const INIT_PENDING = `${INIT}_${PENDING}`
|
||||
export const INIT_FULFILLED = `${INIT}_${FULFILLED}`
|
||||
export const INIT_REJECTED = `${INIT}_${REJECTED}`
|
||||
|
||||
export const ALERT = 'ALERT'
|
||||
export const ALERT_DISMISS = 'ALERT_DISMISS'
|
||||
|
||||
@ -18,7 +18,7 @@ function mapStateToProps(state) {
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
activate: bindActionCreators(CallActions.activateStream, dispatch),
|
||||
dismiss: bindActionCreators(NotifyActions.dismiss, dispatch),
|
||||
dismissAlert: bindActionCreators(NotifyActions.dismissAlert, dispatch),
|
||||
init: bindActionCreators(CallActions.init, dispatch),
|
||||
notify: bindActionCreators(NotifyActions.info, dispatch)
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ jest.mock('../../callId.js')
|
||||
jest.mock('../../iceServers.js')
|
||||
|
||||
import * as constants from '../../constants.js'
|
||||
import * as handshake from '../handshake.js'
|
||||
import handshake from '../handshake.js'
|
||||
import Peer from 'simple-peer'
|
||||
import peers from '../peers.js'
|
||||
import store from '../../store.js'
|
||||
@ -25,7 +25,7 @@ describe('handshake', () => {
|
||||
describe('socket events', () => {
|
||||
describe('users', () => {
|
||||
it('add a peer for each new user and destroy peers for missing', () => {
|
||||
handshake.init(socket, 'bla')
|
||||
handshake(socket, 'bla')
|
||||
|
||||
// given
|
||||
let payload = {
|
||||
@ -53,7 +53,7 @@ describe('handshake', () => {
|
||||
let data
|
||||
beforeEach(() => {
|
||||
data = {}
|
||||
handshake.init(socket, 'bla')
|
||||
handshake(socket, 'bla')
|
||||
socket.emit('users', {
|
||||
initiator: 'a',
|
||||
users: [{ id: 'a' }, { id: 'b' }]
|
||||
@ -88,7 +88,7 @@ describe('handshake', () => {
|
||||
let ready = false
|
||||
socket.once('ready', () => { ready = true })
|
||||
|
||||
handshake.init(socket, 'bla')
|
||||
handshake(socket, 'bla')
|
||||
|
||||
socket.emit('users', {
|
||||
initiator: 'a',
|
||||
|
||||
@ -26,8 +26,6 @@ import store from '../../store.js'
|
||||
import { EventEmitter } from 'events'
|
||||
import { play } from '../../window/video.js'
|
||||
|
||||
const { dispatch } = store
|
||||
|
||||
describe('peers', () => {
|
||||
function createSocket () {
|
||||
const socket = new EventEmitter()
|
||||
@ -71,7 +69,6 @@ describe('peers', () => {
|
||||
peers.create({ socket, user, initiator: 'user2', stream })
|
||||
|
||||
expect(store.getActions()).toEqual([actions.connecting])
|
||||
// expect(notify.warn.mock.calls).toEqual([[ 'Connecting to peer...' ]])
|
||||
|
||||
expect(Peer.instances.length).toBe(1)
|
||||
expect(Peer.mock.calls.length).toBe(1)
|
||||
@ -121,6 +118,34 @@ describe('peers', () => {
|
||||
expect(play.mock.calls.length).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('data', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
window.TextDecoder = class TextDecoder {
|
||||
constructor(encoding) {
|
||||
this.encoding = encoding
|
||||
}
|
||||
decode(object) {
|
||||
return object.toString(this.encoding)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('decodes a message', () => {
|
||||
store.clearActions()
|
||||
const message = 'test'
|
||||
const object = JSON.stringify({ message })
|
||||
peer.emit('data', Buffer.from(object, 'utf-8'))
|
||||
expect(store.getActions()).toEqual([{
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
type: 'info',
|
||||
message: `${user.id}: ${message}`
|
||||
}
|
||||
}])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('get', () => {
|
||||
@ -138,10 +163,10 @@ describe('peers', () => {
|
||||
describe('getIds', () => {
|
||||
it('returns ids of all peers', () => {
|
||||
peers.create({
|
||||
socket, user: {id: 'user2' }, initiator: 'user2', stream
|
||||
socket, user: { id: 'user2' }, initiator: 'user2', stream
|
||||
})
|
||||
peers.create({
|
||||
socket, user: {id: 'user3' }, initiator: 'user3', stream
|
||||
socket, user: { id: 'user3' }, initiator: 'user3', stream
|
||||
})
|
||||
|
||||
expect(peers.getIds()).toEqual([ 'user2', 'user3' ])
|
||||
@ -165,10 +190,10 @@ describe('peers', () => {
|
||||
describe('clear', () => {
|
||||
it('destroys all peers and removes them', () => {
|
||||
peers.create({
|
||||
socket, user: {id: 'user2' }, initiator: 'user2', stream
|
||||
socket, user: { id: 'user2' }, initiator: 'user2', stream
|
||||
})
|
||||
peers.create({
|
||||
socket, user: {id: 'user3' }, initiator: 'user3', stream
|
||||
socket, user: { id: 'user3' }, initiator: 'user3', stream
|
||||
})
|
||||
|
||||
peers.clear()
|
||||
@ -179,4 +204,22 @@ describe('peers', () => {
|
||||
expect(peers.getIds()).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('message', () => {
|
||||
|
||||
it('sends a message to all peers', () => {
|
||||
peers.create({
|
||||
socket, user: { id: 'user2' }, initiator: 'user2', stream
|
||||
})
|
||||
peers.create({
|
||||
socket, user: { id: 'user3' }, initiator: 'user3', stream
|
||||
})
|
||||
peers.message('test')
|
||||
expect(peers.get('user2').send.mock.calls)
|
||||
.toEqual([[ '{"message":"test"}' ]])
|
||||
expect(peers.get('user3').send.mock.calls)
|
||||
.toEqual([[ '{"message":"test"}' ]])
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
@ -7,7 +7,7 @@ import store from '../store.js'
|
||||
const debug = _debug('peercalls')
|
||||
const { dispatch } = store
|
||||
|
||||
export function init (socket, roomName, stream) {
|
||||
export default function init (socket, roomName, stream) {
|
||||
function createPeer (user, initiator) {
|
||||
return peers.create({ socket, user, initiator, stream })
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ let peers = {}
|
||||
function create ({ socket, user, initiator, stream }) {
|
||||
debug('create peer: %s, stream:', user.id, stream)
|
||||
dispatch(
|
||||
NotifyActions.warn('Connecting to peer...')
|
||||
NotifyActions.warning('Connecting to peer...')
|
||||
)
|
||||
|
||||
if (peers[user.id]) {
|
||||
@ -56,7 +56,7 @@ function create ({ socket, user, initiator, stream }) {
|
||||
peer.once('connect', () => {
|
||||
debug('peer: %s, connect', user.id)
|
||||
dispatch(
|
||||
NotifyActions.warn('Peer connection established')
|
||||
NotifyActions.warning('Peer connection established')
|
||||
)
|
||||
play()
|
||||
})
|
||||
@ -86,9 +86,7 @@ function create ({ socket, user, initiator, stream }) {
|
||||
CallActions.removeStream(user.id)
|
||||
)
|
||||
|
||||
// make sure some other peer with same id didn't take place between calling
|
||||
// `destroy()` and `close` event
|
||||
if (peers[user.id] === peer) delete peers[user.id]
|
||||
delete peers[user.id]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
95
src/client/reducers/__tests__/alerts-test.js
Normal file
95
src/client/reducers/__tests__/alerts-test.js
Normal file
@ -0,0 +1,95 @@
|
||||
import * as NotifyActions from '../../actions/NotifyActions.js'
|
||||
import { applyMiddleware, createStore } from 'redux'
|
||||
import { create } from '../../middlewares.js'
|
||||
import reducers from '../index.js'
|
||||
|
||||
jest.useFakeTimers()
|
||||
|
||||
describe('reducers/alerts', () => {
|
||||
|
||||
let store
|
||||
beforeEach(() => {
|
||||
store = createStore(
|
||||
reducers,
|
||||
applyMiddleware.apply(null, create())
|
||||
)
|
||||
})
|
||||
|
||||
describe('clearAlert', () => {
|
||||
|
||||
const actions = {
|
||||
true: 'Dismiss',
|
||||
false: ''
|
||||
}
|
||||
;[true, false].forEach(dismissable => {
|
||||
beforeEach(() => {
|
||||
store.dispatch(NotifyActions.clearAlerts())
|
||||
})
|
||||
it('adds alert to store', () => {
|
||||
store.dispatch(NotifyActions.alert('test', dismissable))
|
||||
expect(store.getState().alerts).toEqual([{
|
||||
action: actions[dismissable],
|
||||
dismissable,
|
||||
message: 'test',
|
||||
type: 'warning'
|
||||
}])
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('dismissAlert', () => {
|
||||
|
||||
it('removes an alert', () => {
|
||||
store.dispatch(NotifyActions.alert('test', true))
|
||||
expect(store.getState().alerts.length).toBe(1)
|
||||
store.dispatch(NotifyActions.dismissAlert(store.getState().alerts[0]))
|
||||
expect(store.getState().alerts.length).toBe(0)
|
||||
})
|
||||
|
||||
it('does not remove an alert when not found', () => {
|
||||
store.dispatch(NotifyActions.alert('test', true))
|
||||
expect(store.getState().alerts.length).toBe(1)
|
||||
store.dispatch(NotifyActions.dismissAlert({}))
|
||||
expect(store.getState().alerts.length).toBe(1)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
;['info', 'warning', 'error'].forEach(type => {
|
||||
|
||||
describe(type, () => {
|
||||
|
||||
beforeEach(() => {
|
||||
store.dispatch(NotifyActions[type]('Hi {0}!', 'John'))
|
||||
})
|
||||
|
||||
it('adds a notification', () => {
|
||||
expect(store.getState().notifications).toEqual([{
|
||||
message: 'Hi John!',
|
||||
type
|
||||
}])
|
||||
})
|
||||
|
||||
it('dismisses notification after a timeout', () => {
|
||||
jest.runAllTimers()
|
||||
expect(store.getState().notifications).toEqual([])
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('clear', () => {
|
||||
|
||||
it('clears all alerts', () => {
|
||||
store.dispatch(NotifyActions.info('Hi {0}!', 'John'))
|
||||
store.dispatch(NotifyActions.warning('Hi {0}!', 'John'))
|
||||
store.dispatch(NotifyActions.error('Hi {0}!', 'John'))
|
||||
store.dispatch(NotifyActions.clear())
|
||||
expect(store.getState().notifications).toEqual([])
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
70
src/client/reducers/__tests__/streams-test.js
Normal file
70
src/client/reducers/__tests__/streams-test.js
Normal file
@ -0,0 +1,70 @@
|
||||
jest.mock('../../callId.js')
|
||||
jest.mock('../../iceServers.js')
|
||||
jest.mock('../../window/createObjectURL.js')
|
||||
|
||||
import * as CallActions from '../../actions/CallActions.js'
|
||||
import { applyMiddleware, createStore } from 'redux'
|
||||
import { create } from '../../middlewares.js'
|
||||
import reducers from '../index.js'
|
||||
|
||||
describe('reducers/alerts', () => {
|
||||
|
||||
class MediaStream {}
|
||||
let store, stream, userId
|
||||
beforeEach(() => {
|
||||
store = createStore(
|
||||
reducers,
|
||||
applyMiddleware.apply(null, create())
|
||||
)
|
||||
userId = 'test id'
|
||||
stream = new MediaStream()
|
||||
})
|
||||
|
||||
describe('defaultState', () => {
|
||||
it('should have default state set', () => {
|
||||
expect(store.getState().streams).toEqual({
|
||||
active: null,
|
||||
all: {}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('addStream', () => {
|
||||
it('adds a stream', () => {
|
||||
store.dispatch(CallActions.addStream({ userId, stream }))
|
||||
expect(store.getState().streams).toEqual({
|
||||
active: userId,
|
||||
all: {
|
||||
[userId]: {
|
||||
userId,
|
||||
stream,
|
||||
url: jasmine.any(String)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('removeStream', () => {
|
||||
it('removes a stream', () => {
|
||||
store.dispatch(CallActions.addStream({ userId, stream }))
|
||||
store.dispatch(CallActions.removeStream(userId))
|
||||
expect(store.getState().streams).toEqual({
|
||||
active: userId,
|
||||
all: {}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('activateStream', () => {
|
||||
it('activates a stream', () => {
|
||||
store.dispatch(CallActions.activateStream(userId))
|
||||
expect(store.getState().streams).toEqual({
|
||||
active: userId,
|
||||
all: {}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -6,7 +6,9 @@ const defaultState = Immutable([])
|
||||
export default function alerts (state = defaultState, action) {
|
||||
switch (action && action.type) {
|
||||
case constants.ALERT:
|
||||
return Immutable(state.asMutable().push(action.payload))
|
||||
const alerts = state.asMutable()
|
||||
alerts.push(action.payload)
|
||||
return Immutable(alerts)
|
||||
case constants.ALERT_DISMISS:
|
||||
return state.filter(a => a !== action.payload)
|
||||
case constants.ALERT_CLEAR:
|
||||
|
||||
@ -9,19 +9,19 @@ const defaultState = Immutable({
|
||||
|
||||
function addStream (state, action) {
|
||||
const { userId, stream } = action.payload
|
||||
const streams = state.all.merge({
|
||||
const all = state.all.merge({
|
||||
[userId]: {
|
||||
userId,
|
||||
stream,
|
||||
url: createObjectURL(stream)
|
||||
}
|
||||
})
|
||||
return { active: userId, streams }
|
||||
return state.merge({ active: userId, all })
|
||||
}
|
||||
|
||||
function removeStream (state, action) {
|
||||
const streams = state.all.without(action.payload.userId)
|
||||
return state.merge({ streams })
|
||||
const all = state.all.without(action.payload.userId)
|
||||
return state.merge({ all })
|
||||
}
|
||||
|
||||
export default function streams (state = defaultState, action) {
|
||||
|
||||
1
src/client/window/__mocks__/createObjectURL.js
Normal file
1
src/client/window/__mocks__/createObjectURL.js
Normal file
@ -0,0 +1 @@
|
||||
export default object => 'blob://' + String(object)
|
||||
13
src/client/window/__mocks__/getUserMedia.js
Normal file
13
src/client/window/__mocks__/getUserMedia.js
Normal file
@ -0,0 +1,13 @@
|
||||
import Promise from 'bluebird'
|
||||
|
||||
class MediaStream {}
|
||||
|
||||
let shouldFail
|
||||
export const fail = _fail => shouldFail = !!_fail
|
||||
export const stream = new MediaStream()
|
||||
export default function getUserMedia () {
|
||||
return !shouldFail
|
||||
? Promise.resolve(stream)
|
||||
: Promise.reject(new Error('test'))
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user