Increase test coverage
This commit is contained in:
parent
300afd6b2f
commit
06821e1fce
@ -2,6 +2,7 @@ jest.mock('../actions/CallActions.js')
|
||||
jest.mock('../callId.js')
|
||||
jest.mock('../iceServers.js')
|
||||
|
||||
import * as constants from '../constants.js'
|
||||
import App from '../containers/App.js'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
@ -14,9 +15,11 @@ import { middlewares } from '../store.js'
|
||||
|
||||
describe('App', () => {
|
||||
|
||||
const initAction = { type: 'INIT' }
|
||||
|
||||
let state
|
||||
beforeEach(() => {
|
||||
init.mockReturnValue({ type: 'INIT' })
|
||||
init.mockReturnValue(initAction)
|
||||
state = reducers()
|
||||
})
|
||||
|
||||
@ -39,4 +42,56 @@ describe('App', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('state', () => {
|
||||
let alert
|
||||
beforeEach(() => {
|
||||
state.streams = state.streams.setIn(['all'], {
|
||||
'test': {
|
||||
userId: 'test',
|
||||
url: 'blob://'
|
||||
}
|
||||
})
|
||||
state.notifications = state.notifications.merge({
|
||||
'notification1': {
|
||||
id: 'notification1',
|
||||
message: 'test',
|
||||
type: 'warning'
|
||||
}
|
||||
})
|
||||
const alerts = state.alerts.asMutable()
|
||||
alert = {
|
||||
dismissable: true,
|
||||
action: 'Dismiss',
|
||||
message: 'test alert'
|
||||
}
|
||||
alerts.push(alert)
|
||||
state.alerts = alerts
|
||||
render()
|
||||
store.clearActions()
|
||||
})
|
||||
|
||||
describe('alerts', () => {
|
||||
it('can be dismissed', () => {
|
||||
const dismiss = node.querySelector('.action-alert-dismiss')
|
||||
TestUtils.Simulate.click(dismiss)
|
||||
expect(store.getActions()).toEqual([{
|
||||
type: constants.ALERT_DISMISS,
|
||||
payload: alert
|
||||
}])
|
||||
})
|
||||
})
|
||||
|
||||
describe('video', () => {
|
||||
it('can be activated', () => {
|
||||
const video = node.querySelector('video')
|
||||
TestUtils.Simulate.click(video)
|
||||
expect(store.getActions()).toEqual([{
|
||||
type: constants.STREAM_ACTIVATE,
|
||||
payload: { userId: 'test' }
|
||||
}])
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
11
src/client/__tests__/store-test.js
Normal file
11
src/client/__tests__/store-test.js
Normal file
@ -0,0 +1,11 @@
|
||||
window.localStorage = { debug: true }
|
||||
import logger from 'redux-logger'
|
||||
const store = require('../store.js')
|
||||
|
||||
describe('store', () => {
|
||||
|
||||
it('should load logger middleware', () => {
|
||||
expect(store.middlewares.some(m => m === logger)).toBeTruthy()
|
||||
})
|
||||
|
||||
})
|
||||
@ -1,3 +1,4 @@
|
||||
import * as StreamActions from './StreamActions.js'
|
||||
import * as NotifyActions from './NotifyActions.js'
|
||||
import * as constants from '../constants.js'
|
||||
import Promise from 'bluebird'
|
||||
@ -34,7 +35,7 @@ export const connect = () => dispatch => {
|
||||
export const getCameraStream = () => dispatch => {
|
||||
return getUserMedia({ video: true, audio: true })
|
||||
.then(stream => {
|
||||
dispatch(addStream({ stream, userId: constants.ME }))
|
||||
dispatch(StreamActions.addStream({ stream, userId: constants.ME }))
|
||||
return stream
|
||||
})
|
||||
.catch(err => {
|
||||
@ -42,21 +43,3 @@ export const getCameraStream = () => dispatch => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
export const addStream = ({ stream, userId }) => ({
|
||||
type: constants.STREAM_ADD,
|
||||
payload: {
|
||||
userId,
|
||||
stream
|
||||
}
|
||||
})
|
||||
|
||||
export const removeStream = userId => ({
|
||||
type: constants.STREAM_REMOVE,
|
||||
payload: { userId }
|
||||
})
|
||||
|
||||
export const activateStream = userId => ({
|
||||
type: constants.STREAM_ACTIVATE,
|
||||
payload: { userId }
|
||||
})
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as constants from '../constants.js'
|
||||
import Immutable from 'seamless-immutable'
|
||||
import _ from 'underscore'
|
||||
|
||||
const TIMEOUT = 5000
|
||||
|
||||
@ -12,7 +12,8 @@ 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 = Immutable({ type, message })
|
||||
const id = _.uniqueId('notification')
|
||||
const payload = { id, type, message }
|
||||
dispatch({
|
||||
type: constants.NOTIFY,
|
||||
payload
|
||||
@ -20,7 +21,7 @@ const _notify = (type, args) => dispatch => {
|
||||
setTimeout(() => {
|
||||
dispatch({
|
||||
type: constants.NOTIFY_DISMISS,
|
||||
payload
|
||||
payload: { id }
|
||||
})
|
||||
}, TIMEOUT)
|
||||
}
|
||||
|
||||
19
src/client/actions/StreamActions.js
Normal file
19
src/client/actions/StreamActions.js
Normal file
@ -0,0 +1,19 @@
|
||||
import * as constants from '../constants.js'
|
||||
|
||||
export const addStream = ({ stream, userId }) => ({
|
||||
type: constants.STREAM_ADD,
|
||||
payload: {
|
||||
userId,
|
||||
stream
|
||||
}
|
||||
})
|
||||
|
||||
export const removeStream = userId => ({
|
||||
type: constants.STREAM_REMOVE,
|
||||
payload: { userId }
|
||||
})
|
||||
|
||||
export const activateStream = userId => ({
|
||||
type: constants.STREAM_ACTIVATE,
|
||||
payload: { userId }
|
||||
})
|
||||
@ -38,6 +38,7 @@ describe('reducers/alerts', () => {
|
||||
}, {
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
id: jasmine.any(String),
|
||||
message: 'Connected to server socket',
|
||||
type: 'warning'
|
||||
}
|
||||
@ -62,12 +63,14 @@ describe('reducers/alerts', () => {
|
||||
}, {
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
id: jasmine.any(String),
|
||||
message: 'Connected to server socket',
|
||||
type: 'warning'
|
||||
}
|
||||
}, {
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
id: jasmine.any(String),
|
||||
message: 'Server socket disconnected',
|
||||
type: 'error'
|
||||
}
|
||||
|
||||
@ -18,13 +18,16 @@ export class Alert extends React.Component {
|
||||
dismiss(alert)
|
||||
}
|
||||
render () {
|
||||
const { alert, dismiss } = this.props
|
||||
const { alert } = this.props
|
||||
|
||||
return (
|
||||
<div className={classnames('alert', alert.type)}>
|
||||
<span>{alert.message}</span>
|
||||
{alert.dismissable && (
|
||||
<button onClick={dismiss}>{alert.action}</button>
|
||||
<button
|
||||
className="action-alert-dismiss"
|
||||
onClick={this.dismiss}
|
||||
>{alert.action}</button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -34,6 +34,7 @@ export default class App extends React.Component {
|
||||
<Video
|
||||
activate={activate}
|
||||
active={userId === active}
|
||||
key={userId}
|
||||
stream={stream}
|
||||
/>
|
||||
))}
|
||||
|
||||
@ -11,7 +11,7 @@ export const NotificationPropTypes = PropTypes.shape({
|
||||
|
||||
export default class Notifications extends React.Component {
|
||||
static propTypes = {
|
||||
notifications: PropTypes.arrayOf(NotificationPropTypes).isRequired,
|
||||
notifications: PropTypes.objectOf(NotificationPropTypes).isRequired,
|
||||
max: PropTypes.number.isRequired
|
||||
}
|
||||
static defaultProps = {
|
||||
@ -26,12 +26,12 @@ export default class Notifications extends React.Component {
|
||||
transitionLeaveTimeout={100}
|
||||
transitionName="fade"
|
||||
>
|
||||
{notifications.slice(max).map(notification => (
|
||||
{Object.keys(notifications).slice(-max).map(id => (
|
||||
<div
|
||||
className={classnames(notification.type, 'notification')}
|
||||
key={notification.id}
|
||||
className={classnames(notifications[id].type, 'notification')}
|
||||
key={id}
|
||||
>
|
||||
{notification.message}
|
||||
{notifications[id].message}
|
||||
</div>
|
||||
))}
|
||||
</CSSTransitionGroup>
|
||||
|
||||
@ -5,14 +5,13 @@ import { ME } from '../constants.js'
|
||||
|
||||
export const StreamPropType = PropTypes.shape({
|
||||
userId: PropTypes.string.isRequired,
|
||||
stream: PropTypes.instanceOf(ArrayBuffer).isRequired,
|
||||
url: PropTypes.string.isRequired
|
||||
})
|
||||
|
||||
export default class Video extends React.Component {
|
||||
static propTypes = {
|
||||
activate: PropTypes.func.isRequired,
|
||||
active: PropTypes.string.required,
|
||||
active: PropTypes.bool.isRequired,
|
||||
stream: StreamPropType.isRequired
|
||||
}
|
||||
activate = e => {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import * as NotifyActions from '../actions/NotifyActions.js'
|
||||
import * as CallActions from '../actions/CallActions.js'
|
||||
import * as NotifyActions from '../actions/NotifyActions.js'
|
||||
import * as StreamActions from '../actions/StreamActions.js'
|
||||
import App from '../components/App.js'
|
||||
import React from 'react'
|
||||
import { bindActionCreators } from 'redux'
|
||||
@ -17,7 +18,7 @@ function mapStateToProps(state) {
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
activate: bindActionCreators(CallActions.activateStream, dispatch),
|
||||
activate: bindActionCreators(StreamActions.activateStream, dispatch),
|
||||
dismissAlert: bindActionCreators(NotifyActions.dismissAlert, dispatch),
|
||||
init: bindActionCreators(CallActions.init, dispatch),
|
||||
notify: bindActionCreators(NotifyActions.info, dispatch)
|
||||
|
||||
@ -145,6 +145,7 @@ describe('handshake', () => {
|
||||
expect(store.getActions()).toEqual([{
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
id: jasmine.any(String),
|
||||
message: 'Peer connection closed',
|
||||
type: 'error'
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ describe('peers', () => {
|
||||
connecting: {
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
id: jasmine.any(String),
|
||||
message: 'Connecting to peer...',
|
||||
type: 'warning'
|
||||
}
|
||||
@ -56,6 +57,7 @@ describe('peers', () => {
|
||||
established: {
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
id: jasmine.any(String),
|
||||
message: 'Peer connection established',
|
||||
type: 'warning'
|
||||
}
|
||||
@ -140,6 +142,7 @@ describe('peers', () => {
|
||||
expect(store.getActions()).toEqual([{
|
||||
type: constants.NOTIFY,
|
||||
payload: {
|
||||
id: jasmine.any(String),
|
||||
type: 'info',
|
||||
message: `${user.id}: ${message}`
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import * as CallActions from '../actions/CallActions.js'
|
||||
import * as NotifyActions from '../actions/NotifyActions.js'
|
||||
import * as StreamActions from '../actions/StreamActions.js'
|
||||
import Peer from 'simple-peer'
|
||||
import _ from 'underscore'
|
||||
import _debug from 'debug'
|
||||
@ -63,7 +64,7 @@ function create ({ socket, user, initiator, stream }) {
|
||||
|
||||
peer.on('stream', stream => {
|
||||
debug('peer: %s, stream', user.id)
|
||||
dispatch(CallActions.addStream({
|
||||
dispatch(StreamActions.addStream({
|
||||
userId: user.id,
|
||||
stream
|
||||
}))
|
||||
@ -83,7 +84,7 @@ function create ({ socket, user, initiator, stream }) {
|
||||
NotifyActions.error('Peer connection closed')
|
||||
)
|
||||
dispatch(
|
||||
CallActions.removeStream(user.id)
|
||||
StreamActions.removeStream(user.id)
|
||||
)
|
||||
|
||||
delete peers[user.id]
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import * as NotifyActions from '../../actions/NotifyActions.js'
|
||||
import _ from 'underscore'
|
||||
import { applyMiddleware, createStore } from 'redux'
|
||||
import { create } from '../../middlewares.js'
|
||||
import reducers from '../index.js'
|
||||
@ -65,7 +66,8 @@ describe('reducers/alerts', () => {
|
||||
})
|
||||
|
||||
it('adds a notification', () => {
|
||||
expect(store.getState().notifications).toEqual([{
|
||||
expect(_.values(store.getState().notifications)).toEqual([{
|
||||
id: jasmine.any(String),
|
||||
message: 'Hi John!',
|
||||
type
|
||||
}])
|
||||
@ -73,9 +75,14 @@ describe('reducers/alerts', () => {
|
||||
|
||||
it('dismisses notification after a timeout', () => {
|
||||
jest.runAllTimers()
|
||||
expect(store.getState().notifications).toEqual([])
|
||||
expect(store.getState().notifications).toEqual({})
|
||||
})
|
||||
|
||||
it('does not fail when no arguments', () => {
|
||||
store.dispatch(NotifyActions[type]())
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
@ -87,7 +94,7 @@ describe('reducers/alerts', () => {
|
||||
store.dispatch(NotifyActions.warning('Hi {0}!', 'John'))
|
||||
store.dispatch(NotifyActions.error('Hi {0}!', 'John'))
|
||||
store.dispatch(NotifyActions.clear())
|
||||
expect(store.getState().notifications).toEqual([])
|
||||
expect(store.getState().notifications).toEqual({})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -2,7 +2,7 @@ jest.mock('../../callId.js')
|
||||
jest.mock('../../iceServers.js')
|
||||
jest.mock('../../window/createObjectURL.js')
|
||||
|
||||
import * as CallActions from '../../actions/CallActions.js'
|
||||
import * as StreamActions from '../../actions/StreamActions.js'
|
||||
import { applyMiddleware, createStore } from 'redux'
|
||||
import { create } from '../../middlewares.js'
|
||||
import reducers from '../index.js'
|
||||
@ -31,13 +31,12 @@ describe('reducers/alerts', () => {
|
||||
|
||||
describe('addStream', () => {
|
||||
it('adds a stream', () => {
|
||||
store.dispatch(CallActions.addStream({ userId, stream }))
|
||||
store.dispatch(StreamActions.addStream({ userId, stream }))
|
||||
expect(store.getState().streams).toEqual({
|
||||
active: userId,
|
||||
all: {
|
||||
[userId]: {
|
||||
userId,
|
||||
stream,
|
||||
url: jasmine.any(String)
|
||||
}
|
||||
}
|
||||
@ -47,8 +46,8 @@ describe('reducers/alerts', () => {
|
||||
|
||||
describe('removeStream', () => {
|
||||
it('removes a stream', () => {
|
||||
store.dispatch(CallActions.addStream({ userId, stream }))
|
||||
store.dispatch(CallActions.removeStream(userId))
|
||||
store.dispatch(StreamActions.addStream({ userId, stream }))
|
||||
store.dispatch(StreamActions.removeStream(userId))
|
||||
expect(store.getState().streams).toEqual({
|
||||
active: userId,
|
||||
all: {}
|
||||
@ -58,7 +57,7 @@ describe('reducers/alerts', () => {
|
||||
|
||||
describe('activateStream', () => {
|
||||
it('activates a stream', () => {
|
||||
store.dispatch(CallActions.activateStream(userId))
|
||||
store.dispatch(StreamActions.activateStream(userId))
|
||||
expect(store.getState().streams).toEqual({
|
||||
active: userId,
|
||||
all: {}
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import * as constants from '../constants.js'
|
||||
import Immutable from 'seamless-immutable'
|
||||
|
||||
const defaultState = Immutable([])
|
||||
const defaultState = Immutable({})
|
||||
|
||||
export default function notifications (state = defaultState, action) {
|
||||
switch (action && action.type) {
|
||||
case constants.NOTIFY:
|
||||
const notifications = state.asMutable()
|
||||
notifications.push(action.payload)
|
||||
return Immutable(notifications)
|
||||
return state.merge({
|
||||
[action.payload.id]: action.payload
|
||||
})
|
||||
case constants.NOTIFY_DISMISS:
|
||||
return state.filter(n => n !== action.payload)
|
||||
return state.without(action.payload.id)
|
||||
case constants.NOTIFY_CLEAR:
|
||||
return defaultState
|
||||
default:
|
||||
|
||||
@ -12,7 +12,6 @@ function addStream (state, action) {
|
||||
const all = state.all.merge({
|
||||
[userId]: {
|
||||
userId,
|
||||
stream,
|
||||
url: createObjectURL(stream)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { create } from './middlewares.js'
|
||||
import reducers from './reducers'
|
||||
import { applyMiddleware, createStore } from 'redux'
|
||||
|
||||
export const middlewares = create(
|
||||
window.localStorage && window.localStorage.debug
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user