From 46ec853280384c505a2f6db4666a05dc702d3a01 Mon Sep 17 00:00:00 2001 From: Jerko Steiner Date: Thu, 15 Jun 2017 23:00:17 -0400 Subject: [PATCH] Fix old unit tests --- .eslintrc | 3 +- __mocks__/simple-peer.js | 10 ++ src/client/__mocks__/store.js | 3 + src/client/__tests__/App-test.js | 4 - src/client/actions/NotifyActions.js | 12 +- src/client/middlewares.js | 10 ++ src/client/peer/Peer.js | 8 -- src/client/peer/__tests__/handshake-test.js | 87 ++++++++------- src/client/peer/__tests__/peers-test.js | 117 +++++++++++++------- src/client/peer/handshake.js | 5 +- src/client/peer/peers.js | 11 +- src/client/store.js | 8 +- src/client/window/__tests__/window-test.js | 100 +++++++++++++++++ 13 files changed, 263 insertions(+), 115 deletions(-) create mode 100644 __mocks__/simple-peer.js create mode 100644 src/client/__mocks__/store.js create mode 100644 src/client/middlewares.js delete mode 100644 src/client/peer/Peer.js create mode 100644 src/client/window/__tests__/window-test.js diff --git a/.eslintrc b/.eslintrc index 5058461..1928063 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,7 +3,8 @@ "extends": ["standard", "standard-react"], "rules": { "max-len": [2, 80, 4], - "jsx-quotes": ["error", "prefer-double"] + "jsx-quotes": ["error", "prefer-double"], + "padded-blocks": 0 }, "globals": { "expect": true, diff --git a/__mocks__/simple-peer.js b/__mocks__/simple-peer.js new file mode 100644 index 0000000..2d4e2b9 --- /dev/null +++ b/__mocks__/simple-peer.js @@ -0,0 +1,10 @@ +import EventEmitter from 'events' +const Peer = jest.genMockFunction().mockImplementation(() => { + let peer = new EventEmitter() + peer.destroy = jest.genMockFunction() + peer.signal = jest.genMockFunction() + Peer.instances.push(peer) + return peer +}) +Peer.instances = [] +export default Peer diff --git a/src/client/__mocks__/store.js b/src/client/__mocks__/store.js new file mode 100644 index 0000000..4bf55af --- /dev/null +++ b/src/client/__mocks__/store.js @@ -0,0 +1,3 @@ +import configureStore from 'redux-mock-store' +import { middlewares } from '../middlewares.js' +export default configureStore(middlewares)({}) diff --git a/src/client/__tests__/App-test.js b/src/client/__tests__/App-test.js index e7435cd..a6d5592 100644 --- a/src/client/__tests__/App-test.js +++ b/src/client/__tests__/App-test.js @@ -12,8 +12,6 @@ import { Provider } from 'react-redux' import { init } from '../actions/CallActions.js' import { middlewares } from '../store.js' -// jest.useFakeTimers() - describe('App', () => { let state @@ -25,7 +23,6 @@ describe('App', () => { let component, node, store function render() { store = configureStore(middlewares)(state) - console.log(store.getState()) component = TestUtils.renderIntoDocument( @@ -37,7 +34,6 @@ describe('App', () => { describe('render', () => { it('renders without issues', () => { render() - // jest.runAllTimers() expect(node).toBeTruthy() expect(init.mock.calls.length).toBe(1) }) diff --git a/src/client/actions/NotifyActions.js b/src/client/actions/NotifyActions.js index 433297f..531cd5c 100644 --- a/src/client/actions/NotifyActions.js +++ b/src/client/actions/NotifyActions.js @@ -24,16 +24,16 @@ const _notify = (type, args) => dispatch => { }, TIMEOUT) } -export const info = () => dispatch => { - _notify('info', arguments) +export const info = function() { + return dispatch => _notify('info', arguments)(dispatch) } -export const warn = () => dispatch => { - _notify('warning', arguments) +export const warn = function() { + return dispatch => _notify('warning', arguments)(dispatch) } -export const error = () => dispatch => { - _notify('error', arguments) +export const error = function() { + return dispatch => _notify('error', arguments)(dispatch) } export function alert (message, dismissable) { diff --git a/src/client/middlewares.js b/src/client/middlewares.js new file mode 100644 index 0000000..d0e109a --- /dev/null +++ b/src/client/middlewares.js @@ -0,0 +1,10 @@ +import logger from 'redux-logger' +import promiseMiddleware from 'redux-promise-middleware' +import thunk from 'redux-thunk' + +export const middlewares = [thunk, promiseMiddleware()] +export const create = log => { + const m = middlewares.slice() + log && m.push(logger) + return m +} diff --git a/src/client/peer/Peer.js b/src/client/peer/Peer.js deleted file mode 100644 index eb4e3b6..0000000 --- a/src/client/peer/Peer.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict' -const Peer = require('simple-peer') - -function init (opts) { - return Peer(opts) -} - -module.exports = { init } diff --git a/src/client/peer/__tests__/handshake-test.js b/src/client/peer/__tests__/handshake-test.js index 72c8dcc..40971c1 100644 --- a/src/client/peer/__tests__/handshake-test.js +++ b/src/client/peer/__tests__/handshake-test.js @@ -1,30 +1,23 @@ -jest.unmock('../handshake.js') -jest.unmock('../peers.js') -jest.unmock('events') -jest.unmock('underscore') +jest.mock('simple-peer') +jest.mock('../../store.js') +jest.mock('../../callId.js') +jest.mock('../../iceServers.js') -const EventEmitter = require('events').EventEmitter -const Peer = require('../Peer.js') -const dispatcher = require('../../dispatcher/dispatcher.js') -const handshake = require('../handshake.js') -const peers = require('../peers.js') +import * as constants from '../../constants.js' +import * as handshake from '../handshake.js' +import Peer from 'simple-peer' +import peers from '../peers.js' +import store from '../../store.js' +import { EventEmitter } from 'events' describe('handshake', () => { - let socket, peerInstances + let socket beforeEach(() => { socket = new EventEmitter() socket.id = 'a' - peerInstances = [] - Peer.init = jest.genMockFunction().mockImplementation(() => { - let peer = new EventEmitter() - peer.destroy = jest.genMockFunction() - peer.signal = jest.genMockFunction() - peerInstances.push(peer) - return peer - }) - - dispatcher.dispatch.mockClear() + Peer.instances = [] + store.clearActions() }) afterEach(() => peers.clear()) @@ -40,7 +33,7 @@ describe('handshake', () => { initiator: 'a' } socket.emit('users', payload) - expect(peerInstances.length).toBe(1) + expect(Peer.instances.length).toBe(1) // when payload = { @@ -50,9 +43,9 @@ describe('handshake', () => { socket.emit('users', payload) // then - expect(peerInstances.length).toBe(2) - expect(peerInstances[0].destroy.mock.calls.length).toBe(1) - expect(peerInstances[1].destroy.mock.calls.length).toBe(0) + expect(Peer.instances.length).toBe(2) + expect(Peer.instances[0].destroy.mock.calls.length).toBe(1) + expect(Peer.instances[1].destroy.mock.calls.length).toBe(0) }) }) @@ -73,8 +66,8 @@ describe('handshake', () => { data }) - expect(peerInstances.length).toBe(1) - expect(peerInstances[0].signal.mock.calls.length).toBe(1) + expect(Peer.instances.length).toBe(1) + expect(Peer.instances[0].signal.mock.calls.length).toBe(1) }) it('does nothing if no peer', () => { @@ -83,8 +76,8 @@ describe('handshake', () => { data }) - expect(peerInstances.length).toBe(1) - expect(peerInstances[0].signal.mock.calls.length).toBe(0) + expect(Peer.instances.length).toBe(1) + expect(Peer.instances[0].signal.mock.calls.length).toBe(0) }) }) }) @@ -101,8 +94,8 @@ describe('handshake', () => { initiator: 'a', users: [{ id: 'a' }, { id: 'b'}] }) - expect(peerInstances.length).toBe(1) - peer = peerInstances[0] + expect(Peer.instances.length).toBe(1) + peer = Peer.instances[0] expect(ready).toBeDefined() }) @@ -130,29 +123,37 @@ describe('handshake', () => { describe('stream', () => { it('adds a stream to streamStore', () => { - expect(dispatcher.dispatch.mock.calls.length).toBe(0) - + store.clearActions() let stream = {} peer.emit('stream', stream) - expect(dispatcher.dispatch.mock.calls.length).toBe(1) - expect(dispatcher.dispatch.mock.calls).toEqual([[{ - type: 'add-stream', - userId: 'b', - stream - }]]) + expect(store.getActions()).toEqual([{ + type: constants.STREAM_ADD, + payload: { + stream, + userId: 'b' + } + }]) }) }) describe('close', () => { it('removes stream from streamStore', () => { + store.clearActions() peer.emit('close') - expect(dispatcher.dispatch.mock.calls.length).toBe(1) - expect(dispatcher.dispatch.mock.calls).toEqual([[{ - type: 'remove-stream', - userId: 'b' - }]]) + expect(store.getActions()).toEqual([{ + type: constants.NOTIFY, + payload: { + message: 'Peer connection closed', + type: 'error' + } + }, { + type: constants.STREAM_REMOVE, + payload: { + userId: 'b' + } + }]) }) }) }) diff --git a/src/client/peer/__tests__/peers-test.js b/src/client/peer/__tests__/peers-test.js index b6c52a3..4b61029 100644 --- a/src/client/peer/__tests__/peers-test.js +++ b/src/client/peer/__tests__/peers-test.js @@ -1,68 +1,101 @@ -jest.unmock('../peers.js') +jest.mock('../../window/video.js') +jest.mock('../../callId.js') +jest.mock('../../iceServers.js') +jest.mock('../../store.js') + // const configureStore = require('redux-mock-store').default + // const { middlewares } = require('../../middlewares.js') + // return configureStore(middlewares)({}) +// }) +jest.mock('simple-peer') + // const EventEmitter = require('events').EventEmitter + // const Peer = jest.genMockFunction().mockImplementation(() => { + // let peer = new EventEmitter() + // peer.destroy = jest.genMockFunction() + // peer.signal = jest.genMockFunction() + // Peer.instances.push(peer) + // return peer + // }) + // Peer.instances = [] + // return Peer +// }) -const EventEmitter = require('events').EventEmitter -const Peer = require('../Peer.js') -const dispatcher = require('../../dispatcher/dispatcher.js') -const notify = require('../../action/notify.js') -const peers = require('../peers.js') +import * as constants from '../../constants.js' +import Peer from 'simple-peer' +import peers from '../peers.js' +import store from '../../store.js' +import { EventEmitter } from 'events' +import { play } from '../../window/video.js' + +const { dispatch } = store describe('peers', () => { function createSocket () { - let socket = new EventEmitter() + const socket = new EventEmitter() socket.id = 'user1' return socket } - let socket, stream, peerInstances, user + let socket, stream, user beforeEach(() => { - dispatcher.dispatch.mockClear() - notify.warn.mockClear() + store.clearActions() user = { id: 'user2' } socket = createSocket() - peerInstances = [] + Peer.instances = [] + Peer.mockClear() + play.mockClear() stream = { stream: true } - - Peer.init = jest.genMockFunction().mockImplementation(() => { - let peer = new EventEmitter() - peer.destroy = jest.genMockFunction() - peer.signal = jest.genMockFunction() - peerInstances.push(peer) - return peer - }) }) + const actions = { + connecting: { + type: constants.NOTIFY, + payload: { + message: 'Connecting to peer...', + type: 'warning' + } + }, + established: { + type: constants.NOTIFY, + payload: { + message: 'Peer connection established', + type: 'warning' + } + } + } + afterEach(() => peers.clear()) describe('create', () => { it('creates a new peer', () => { peers.create({ socket, user, initiator: 'user2', stream }) - expect(notify.warn.mock.calls).toEqual([[ 'Connecting to peer...' ]]) + expect(store.getActions()).toEqual([actions.connecting]) + // expect(notify.warn.mock.calls).toEqual([[ 'Connecting to peer...' ]]) - expect(peerInstances.length).toBe(1) - expect(Peer.init.mock.calls.length).toBe(1) - expect(Peer.init.mock.calls[0][0].initiator).toBe(false) - expect(Peer.init.mock.calls[0][0].stream).toBe(stream) + expect(Peer.instances.length).toBe(1) + expect(Peer.mock.calls.length).toBe(1) + expect(Peer.mock.calls[0][0].initiator).toBe(false) + expect(Peer.mock.calls[0][0].stream).toBe(stream) }) it('sets initiator correctly', () => { peers.create({ socket, user, initiator: 'user1', stream }) - expect(peerInstances.length).toBe(1) - expect(Peer.init.mock.calls.length).toBe(1) - expect(Peer.init.mock.calls[0][0].initiator).toBe(true) - expect(Peer.init.mock.calls[0][0].stream).toBe(stream) + expect(Peer.instances.length).toBe(1) + expect(Peer.mock.calls.length).toBe(1) + expect(Peer.mock.calls[0][0].initiator).toBe(true) + expect(Peer.mock.calls[0][0].stream).toBe(stream) }) it('destroys old peer before creating new one', () => { peers.create({ socket, user, initiator: 'user2', stream }) peers.create({ socket, user, initiator: 'user2', stream }) - expect(peerInstances.length).toBe(2) - expect(Peer.init.mock.calls.length).toBe(2) - expect(peerInstances[0].destroy.mock.calls.length).toBe(1) - expect(peerInstances[1].destroy.mock.calls.length).toBe(0) + expect(Peer.instances.length).toBe(2) + expect(Peer.mock.calls.length).toBe(2) + expect(Peer.instances[0].destroy.mock.calls.length).toBe(1) + expect(Peer.instances[1].destroy.mock.calls.length).toBe(0) }) }) @@ -71,21 +104,21 @@ describe('peers', () => { beforeEach(() => { peers.create({ socket, user, initiator: 'user1', stream }) - notify.warn.mockClear() - peer = peerInstances[0] + peer = Peer.instances[0] }) describe('connect', () => { beforeEach(() => peer.emit('connect')) it('sends a notification', () => { - expect(notify.warn.mock.calls).toEqual([[ - 'Peer connection established' - ]]) + expect(store.getActions()).toEqual([ + actions.connecting, + actions.established + ]) }) it('dispatches "play" action', () => { - expect(dispatcher.dispatch.mock.calls).toEqual([[{ type: 'play' }]]) + expect(play.mock.calls.length).toBe(1) }) }) }) @@ -98,7 +131,7 @@ describe('peers', () => { it('returns Peer instance when found', () => { peers.create({ socket, user, initiator: 'user2', stream }) - expect(peers.get(user.id)).toBe(peerInstances[0]) + expect(peers.get(user.id)).toBe(Peer.instances[0]) }) }) @@ -121,7 +154,7 @@ describe('peers', () => { peers.destroy(user.id) - expect(peerInstances[0].destroy.mock.calls.length).toEqual(1) + expect(Peer.instances[0].destroy.mock.calls.length).toEqual(1) }) it('throws no error when peer missing', () => { @@ -140,8 +173,8 @@ describe('peers', () => { peers.clear() - expect(peerInstances[0].destroy.mock.calls.length).toEqual(1) - expect(peerInstances[1].destroy.mock.calls.length).toEqual(1) + expect(Peer.instances[0].destroy.mock.calls.length).toEqual(1) + expect(Peer.instances[1].destroy.mock.calls.length).toEqual(1) expect(peers.getIds()).toEqual([]) }) diff --git a/src/client/peer/handshake.js b/src/client/peer/handshake.js index 30ae070..4490553 100644 --- a/src/client/peer/handshake.js +++ b/src/client/peer/handshake.js @@ -1,10 +1,11 @@ -import NotifyActions from '../actions/NotifyActions.js' +import * as NotifyActions from '../actions/NotifyActions.js' import _ from 'underscore' import _debug from 'debug' import peers from './peers.js' -import { dispatch } from '../store.js' +import store from '../store.js' const debug = _debug('peercalls') +const { dispatch } = store export function init (socket, roomName, stream) { function createPeer (user, initiator) { diff --git a/src/client/peer/peers.js b/src/client/peer/peers.js index 427e6c2..98e42df 100644 --- a/src/client/peer/peers.js +++ b/src/client/peer/peers.js @@ -1,13 +1,14 @@ -import CallActions from '../actions/CallActions.js' -import NotifyActions from '../actions/NotifyActions.js' -import Peer from './Peer.js' +import * as CallActions from '../actions/CallActions.js' +import * as NotifyActions from '../actions/NotifyActions.js' +import Peer from 'simple-peer' import _ from 'underscore' import _debug from 'debug' import iceServers from '../iceServers.js' -import { dispatch } from '../store.js' +import store from '../store.js' import { play } from '../window/video.js' const debug = _debug('peercalls') +const { dispatch } = store let peers = {} @@ -31,7 +32,7 @@ function create ({ socket, user, initiator, stream }) { destroy(user.id) } - const peer = peers[user.id] = Peer.init({ + const peer = peers[user.id] = new Peer({ initiator: socket.id === initiator, stream, config: { iceServers } diff --git a/src/client/store.js b/src/client/store.js index 40f7912..e5a4b21 100644 --- a/src/client/store.js +++ b/src/client/store.js @@ -1,10 +1,10 @@ -import logger from 'redux-logger' -import promiseMiddleware from 'redux-promise-middleware' +import { create } from './middlewares.js' import reducers from './reducers' -import thunk from 'redux-thunk' import { applyMiddleware, createStore } from 'redux' -export const middlewares = [thunk, promiseMiddleware(), logger] +export const middlewares = create( + window.localStorage && window.localStorage.debug +) export default createStore( reducers, diff --git a/src/client/window/__tests__/window-test.js b/src/client/window/__tests__/window-test.js new file mode 100644 index 0000000..1243089 --- /dev/null +++ b/src/client/window/__tests__/window-test.js @@ -0,0 +1,100 @@ +import Promise from 'bluebird' +import createObjectURL from '../createObjectURL.js' +import getUserMedia from '../getUserMedia.js' +import navigator from '../navigator.js' +import { play } from '../video.js' + +describe('window', () => { + + describe('getUserMedia', () => { + + class MediaStream {} + const stream = new MediaStream() + const constraints = { video: true } + + afterEach(() => { + delete navigator.mediaDevices + delete navigator.getUserMedia + delete navigator.webkitGetUserMedia + }) + + it('calls navigator.mediaDevices.getUserMedia', () => { + const promise = Promise.resolve(stream) + navigator.mediaDevices = { + getUserMedia: jest.fn().mockReturnValue(promise) + } + expect(getUserMedia(constraints)).toBe(promise) + }) + + ;['getUserMedia', 'webkitGetUserMedia'].forEach((method) => { + it(`it calls navigator.${method} as a fallback`, () => { + navigator[method] = jest.fn() + .mockImplementation( + (constraints, onSuccess, onError) => onSuccess(stream) + ) + return getUserMedia(constraints) + .then(s => expect(s).toBe(stream)) + }) + }) + + it('throws error when no supported method', done => { + getUserMedia(constraints) + .asCallback(err => { + expect(err).toBeTruthy() + expect(err.message).toBe('Browser unsupported') + done() + }) + }) + + }) + + describe('play', () => { + + let v1, v2 + beforeEach(() => { + v1 = window.document.createElement('video') + v2 = window.document.createElement('video') + window.document.body.appendChild(v1) + window.document.body.appendChild(v2) + v1.play = jest.fn() + v2.play = jest.fn() + }) + + afterEach(() => { + window.document.body.removeChild(v1) + window.document.body.removeChild(v2) + }) + + it('gets all videos and plays them', () => { + play() + expect(v1.play.mock.calls.length).toBe(1) + expect(v2.play.mock.calls.length).toBe(1) + }) + + it('does not fail on error', () => { + v1.play.mockImplementation(() => { throw new Error('test') }) + play() + expect(v1.play.mock.calls.length).toBe(1) + expect(v2.play.mock.calls.length).toBe(1) + }) + + }) + + describe('navigator', () => { + + it('exposes window.navigator', () => { + expect(navigator).toBe(window.navigator) + }) + + }) + + describe('createObjectURL', () => { + + it('calls window.URL.createObjectURL', () => { + window.URL.createObjectURL = jest.fn().mockReturnValue('test') + expect(createObjectURL()).toBe('test') + }) + + }) + +})