webrtc-troubleshoot
Advanced tools
Comparing version 8.1.1 to 9.0.0
{ | ||
"name": "webrtc-troubleshoot", | ||
"version": "8.1.1", | ||
"version": "9.0.0", | ||
"description": "A way to add webrtc troubleshooting to your app", | ||
"main": "src/index.js", | ||
"license": "MIT", | ||
"config": { | ||
@@ -10,13 +11,6 @@ "report": "report --reporter=lcov --reporter=cobertura" | ||
"scripts": { | ||
"browserify": "browserify -t [ babelify --presets [ es2015 ] ] --s WebRTCTroubleshooter src/index.js -o dist/webrtc-troubleshooter.bundle.js", | ||
"uglify": "uglifyjs dist/webrtc-troubleshooter.bundle.js -o dist/webrtc-troubleshooter.bundle.js", | ||
"build": "npm run browserify && npm run uglify", | ||
"lint": "semistandard", | ||
"lint:fix": "semistandard --fix", | ||
"unit-test": "nyc ava test/unit/*.js", | ||
"postunit-test": "nyc $npm_package_config_report", | ||
"unit-test-file": "ava FILE=process.env.file test/unit/${FILE}", | ||
"coverage": "nyc ava test/unit/*.js", | ||
"coveralls": "cat ./coverage/lcov.info | coveralls", | ||
"test": "npm run lint && npm run unit-test" | ||
"build": "webpack --env=prod --progress --profile --colors", | ||
"unit-test": "nyc --reporter=lcov --reporter=cobertura ava test/unit/*.js", | ||
"test": "semistandard && npm run unit-test && npm run report", | ||
"report": "nyc report" | ||
}, | ||
@@ -28,24 +22,22 @@ "repository": "https://github.com/mypurecloud/webrtc-troubleshooter", | ||
"devDependencies": { | ||
"ava": "^0.19.1", | ||
"babel-cli": "^6.22.2", | ||
"babel-preset-es2015": "^6.22.0", | ||
"babelify": "^7.2.0", | ||
"browser-env": "^2.0.31", | ||
"browserify": "^14.0.0", | ||
"coveralls": "^2.13.1", | ||
"ember-cli-github-pages": "^0.1.2", | ||
"nyc": "^10.3.2", | ||
"semistandard": "^10.0.0", | ||
"sinon": "^2.2.0", | ||
"uglify-js": "^2.7.3", | ||
"ava": "^0.25.0", | ||
"babel-core": "^6.25.0", | ||
"babel-loader": "^7.1.1", | ||
"babel-preset-env": "^1.6.1", | ||
"browser-env": "^3.1.0", | ||
"nyc": "^13.0.0", | ||
"semistandard": "^12.0.1", | ||
"sinon": "^2.3.8", | ||
"webpack": "^4.16.2", | ||
"webpack-cli": "^3.1.0", | ||
"webrtc-adapter": "^6.1.5" | ||
}, | ||
"dependencies": { | ||
"localmedia": "^4.0.0", | ||
"localmedia": "^5.0.0", | ||
"rtcpeerconnection": "^8.0.1", | ||
"webrtc-stats-gatherer": "^4.2.10" | ||
"webrtc-stats-gatherer": "^6.0.2" | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"es2015" | ||
"env" | ||
] | ||
@@ -52,0 +44,0 @@ }, |
@@ -268,4 +268,4 @@ // adapted from https://github.com/webrtc/testrtc | ||
if (!this.resolutionMatchesIndependentOfRotationOrCrop( | ||
report.actualVideoWidth, report.actualVideoHeight, report.mandatoryWidth, | ||
report.mandatoryHeight)) { | ||
report.actualVideoWidth, report.actualVideoHeight, report.mandatoryWidth, | ||
report.mandatoryHeight)) { | ||
this.reportError(`Incorrect captured resolution. Expected ${report.mandatoryWidth} by ${report.mandatoryHeight} but got ${report.actualVideoWidth} by ${report.actualVideoHeight}`); | ||
@@ -272,0 +272,0 @@ } else { |
@@ -15,3 +15,3 @@ import TestSuite from './utils/TestSuite'; | ||
export default { | ||
module.exports = { | ||
TestSuite, | ||
@@ -18,0 +18,0 @@ AudioTest, |
// adapted from https://github.com/webrtc/testrtc | ||
import WebrtcStatsGather from 'webrtc-stats-gatherer'; | ||
const WebrtcStatsGather = require('webrtc-stats-gatherer'); | ||
const PeerConnection = require('rtcpeerconnection'); | ||
@@ -4,0 +4,0 @@ |
import browserEnv from 'browser-env'; | ||
browserEnv(); | ||
class Listener { | ||
constructor () { | ||
this._listeners = {}; | ||
} | ||
addEventListener (event, listener) { | ||
this._listeners[event] = this._listeners[event] || []; | ||
this._listeners[event].push(listener); | ||
} | ||
trigger (event, args) { | ||
const listeners = this._listeners[event]; | ||
if (!listeners || listeners.length === 0) { | ||
return; | ||
} | ||
listeners.forEach(l => l(...args)); | ||
} | ||
} | ||
global.RTCTrackEvent = class extends Listener {}; | ||
global.RTCDataChannel = class extends Listener { | ||
constructor (label) { | ||
super(); | ||
this.label = label; | ||
} | ||
}; | ||
global.RTCPeerConnection = class extends Listener { | ||
addTrack () {} | ||
addStream () {} | ||
createOffer () { return Promise.resolve(); } | ||
setLocalDescription () {} | ||
setRemoteDescription () {} | ||
createAnswer () { return Promise.resolve(); } | ||
getStats () { return Promise.resolve(); } | ||
createDataChannel (label) { | ||
return new global.window.RTCDataChannel(label); | ||
} | ||
}; | ||
global.MediaTrack = class { | ||
constructor (kind) { | ||
this.kind = kind; | ||
} | ||
stop () {} | ||
}; | ||
global.MediaStream = class { | ||
constructor (constraints) { | ||
this._tracks = []; | ||
if (constraints.audio) { | ||
this._tracks.push(new global.MediaTrack('audio')); | ||
} | ||
if (constraints.video) { | ||
this._tracks.push(new global.MediaTrack('video')); | ||
} | ||
} | ||
getTracks () { | ||
return this._tracks; | ||
} | ||
getAudioTracks () { | ||
return this._tracks.filter(t => t.kind === 'audio'); | ||
} | ||
getVideoTracks () { | ||
return this._tracks.filter(t => t.kind === 'video'); | ||
} | ||
}; | ||
global.navigator = { | ||
mediaDevices: { | ||
getUserMedia: constraints => Promise.resolve(new global.MediaStream(constraints)) | ||
}, | ||
userAgent: 'NODE' | ||
}; | ||
global.window = global; |
import test from 'ava'; | ||
import AdvancedCameraTest from '../../src/diagnostics/AdvancedCameraTest'; | ||
import CameraResolutionTest from '../../src/diagnostics/CameraResolutionTest'; | ||
let CameraResolutionStub, options, advancedCameraTest; | ||
test.beforeEach(() => { | ||
CameraResolutionStub = { | ||
resolutions: [ | ||
[320, 240] | ||
], | ||
start: Promise.resolve([320, 240]), | ||
deferred: { | ||
resolve: () => [320, 240], | ||
reject: () => 'an error' | ||
} | ||
}; | ||
options = { | ||
mediaStream: document.createElement('video').mediaStream, | ||
duration: 5, | ||
addTest: () => {}, | ||
runNextTest: () => {}, | ||
deferred: { | ||
resolve: () => [320, 240], | ||
reject: () => 'received error' | ||
}, | ||
stopAllTests: () => {} | ||
}; | ||
advancedCameraTest = new AdvancedCameraTest(options); | ||
test('AdvancedCameraTest is a suite of 14 CameraResolutionTest tests', t => { | ||
const options = { duration: 30 }; | ||
const advancedCameraTest = new AdvancedCameraTest(options); | ||
t.is(advancedCameraTest.queue.length, 14); | ||
advancedCameraTest.queue.forEach(cameraTest => { | ||
t.is(cameraTest instanceof CameraResolutionTest, true); | ||
t.is(cameraTest.options, options); | ||
}); | ||
}); | ||
test('start() will return undefined if no more tests', async t => { | ||
const actual = await advancedCameraTest.start.call(CameraResolutionStub); | ||
t.is(actual, undefined); | ||
}); |
@@ -5,34 +5,8 @@ import test from 'ava'; | ||
import AudioBandwidthTest from '../../src/diagnostics/AudioBandwidthTest'; | ||
import WebrtcCall from '../../src/utils/WebrtcCall'; | ||
let audioBandwidthTest, options; | ||
test.beforeEach(() => { | ||
options = { | ||
mediaOptions: { | ||
audio: { | ||
deviceId: 'someAudioId' | ||
} | ||
}, | ||
iceConfig: { | ||
iceServers: [] | ||
}, | ||
doGetUserMedia: () => Promise.resolve(document.createElement('audio')), | ||
getDeviceName: () => {}, | ||
call: { | ||
pc1: { | ||
addTrack: sinon.stub() | ||
}, | ||
establishConnection: () => Promise.resolve() | ||
}, | ||
gatherStats: () => Promise.resolve('stats') | ||
}; | ||
audioBandwidthTest = new AudioBandwidthTest(options); | ||
}); | ||
test.after(() => { | ||
delete global.RTCPeerConnection; | ||
delete global.navigator; | ||
delete global.document.documentElement.style.WebkitAppearance; | ||
}); | ||
test('start() return error if iceConfig has no iceServers', async t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [] }, | ||
mediaOptions: { audio: true } }); | ||
try { | ||
@@ -46,39 +20,17 @@ await audioBandwidthTest.start(); | ||
test('start() should call doGetUserMedia if there is iceServers and return error with results', async t => { | ||
const options = { | ||
options: { | ||
mediaOptions: { | ||
audio: { | ||
deviceId: 'someAudioId' | ||
} | ||
}, | ||
iceConfig: { | ||
iceServers: [{ server: '1' }] | ||
} | ||
}, | ||
doGetUserMedia: () => Promise.resolve(document.createElement('audio')), | ||
runTest: () => {}, | ||
completed: () => {}, | ||
getResults: () => ['Some Audio'], | ||
mediaOptions: { | ||
audio: { | ||
deviceId: 'someAudioId' | ||
} | ||
}, | ||
iceConfig: { | ||
iceServers: [{ server: '1' }] | ||
}, | ||
reject: () => 'return results and err' | ||
}; | ||
const audioBandwidthTest = new AudioBandwidthTest(options); | ||
// Mock out RTCPeerConnection for node runtime. | ||
global.RTCPeerConnection = () => { | ||
return { | ||
addEventListener: () => {} | ||
}; | ||
}; | ||
const actual = await audioBandwidthTest.start.call(options); | ||
t.is(actual, 'return results and err'); | ||
const mediaSpy = sinon.spy(global.navigator.mediaDevices, 'getUserMedia'); | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
audioBandwidthTest.start(); | ||
sinon.assert.calledOnce(mediaSpy); | ||
global.navigator.mediaDevices.getUserMedia.restore(); | ||
}); | ||
test('getResults() should return object with log, constraints, and stats', t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: { deviceId: 'someAudioId' } } | ||
}); | ||
const actual = audioBandwidthTest.getResults(); | ||
@@ -94,2 +46,6 @@ const expected = { | ||
test('addLog() should push message to the log', t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
audioBandwidthTest.addLog('info', { val: 'Test add log' }); | ||
@@ -100,42 +56,12 @@ audioBandwidthTest.addLog('error', 'my error'); | ||
test('doGetUserMedia() should return stream', async t => { | ||
const options = { | ||
options: { | ||
mediaOptions: { | ||
audio: { | ||
deviceId: 'someAudioId' | ||
} | ||
}, | ||
iceConfig: { | ||
iceServers: [{ server: '1' }] | ||
} | ||
}, | ||
doGetUserMedia: () => Promise.resolve(document.createElement('audio')), | ||
runTest: () => {}, | ||
completed: () => {}, | ||
getResults: () => ['Some Audio'], | ||
mediaOptions: { | ||
audio: { | ||
deviceId: 'someAudioId' | ||
} | ||
}, | ||
iceConfig: { | ||
iceServers: [{ server: '1' }] | ||
}, | ||
reject: () => 'return results and err' | ||
}; | ||
const audioBandwidthTest = new AudioBandwidthTest(options); | ||
global.navigator = { | ||
mediaDevices: { | ||
getUserMedia: (constraints) => Promise.resolve(constraints) | ||
} | ||
}; | ||
let audioElement = document.createElement('audio'); | ||
audioElement.src = `data:audio/x-wav;base64,${new Buffer('wave')}>`; | ||
audioElement.getAudioTracks = () => ['track1', 'track2']; | ||
const actual = await audioBandwidthTest.doGetUserMedia(audioElement); | ||
t.truthy(actual.getAudioTracks(), ['track1', 'track2']); | ||
test('doGetUserMedia() should return add logs with the track label', async t => { | ||
t.plan(0); | ||
// todo | ||
}); | ||
test('getDeviceName() should return null if tracks are empty', t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
t.is(audioBandwidthTest.getDeviceName([]), null); | ||
@@ -145,47 +71,41 @@ }); | ||
test('getDeviceName() should return label of first track if not empty', t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
const actual = audioBandwidthTest.getDeviceName([ | ||
{ | ||
label: 'Mommas don\'t let your babies grow up to be cowboys' | ||
label: 'Plantronics' | ||
} | ||
]); | ||
const expected = 'Mommas don\'t let your babies grow up to be cowboys'; | ||
const expected = 'Plantronics'; | ||
t.is(actual, expected); | ||
}); | ||
test('setupCall() should call establishConnection function and addLog function', t => { | ||
const options = { | ||
mediaOptions: { | ||
audio: { | ||
deviceId: 'someAudioId' | ||
} | ||
}, | ||
iceConfig: { | ||
iceServers: [] | ||
}, | ||
doGetUserMedia: () => Promise.resolve(document.createElement('audio')), | ||
getDeviceName: () => {}, | ||
call: { | ||
pc1: { | ||
addTrack: sinon.stub() | ||
}, | ||
establishConnection: () => Promise.resolve() | ||
}, | ||
addLog: sinon.stub() | ||
}; | ||
const audioBandwidthTest = new AudioBandwidthTest(options); | ||
t.notThrows(() => audioBandwidthTest.setupCall.apply(options, [ | ||
{ | ||
getTracks () { return this.getAudioTracks(); }, | ||
getAudioTracks: () => { | ||
return [ | ||
{ | ||
track: 'track1' | ||
} | ||
]; | ||
} | ||
} | ||
])); | ||
test('setupCall() should call establishConnection function and addLog function', async t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
audioBandwidthTest.call = new WebrtcCall(audioBandwidthTest.options.iceConfig, audioBandwidthTest.logger); | ||
sinon.stub(audioBandwidthTest.call, 'establishConnection').returns(Promise.resolve()); | ||
sinon.stub(audioBandwidthTest.call.pc1.pc, 'addTrack'); | ||
const mockTrack = new global.MediaStream({ audio: true }); | ||
await audioBandwidthTest.setupCall(mockTrack); | ||
sinon.assert.calledOnce(audioBandwidthTest.call.pc1.pc.addTrack); | ||
sinon.assert.calledOnce(audioBandwidthTest.call.establishConnection); | ||
t.is(audioBandwidthTest.localTrack, mockTrack.getTracks()[0]); | ||
}); | ||
test('runTest() should run gatherStats function', async t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
audioBandwidthTest.durationMs = 4; | ||
sinon.stub(audioBandwidthTest, 'gatherStats').callsFake(() => { | ||
audioBandwidthTest.destroy(); | ||
}); | ||
sinon.stub(audioBandwidthTest, 'gotStats'); | ||
audioBandwidthTest.gatherStats = () => Promise.resolve({ prop: 'some Properties' }); | ||
@@ -197,133 +117,87 @@ const actual = await audioBandwidthTest.runTest(); | ||
test('gatherStats() should resolve if starttime difference is large enough between durationMs', t => { | ||
return audioBandwidthTest.gatherStats.call({ | ||
startTime: 100, | ||
durationMs: 900 | ||
}).then(() => { | ||
t.truthy(true); | ||
test('gatherStats() should resolve if starttime difference is large enough between durationMs', async t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
audioBandwidthTest.call = { pc1: { getStats: sinon.stub() } }; | ||
await audioBandwidthTest.gatherStats(); | ||
sinon.assert.notCalled(audioBandwidthTest.call.pc1.getStats); | ||
}); | ||
test('gatherStats() should call gotStats', t => { | ||
const context = { | ||
call: { | ||
pc1: { | ||
getStats: () => Promise.resolve('value') | ||
} | ||
}, | ||
localTrack: [ | ||
{ | ||
track: 'track1' | ||
} | ||
], | ||
gotStats: sinon.stub() | ||
}; | ||
return audioBandwidthTest.gatherStats.call(context).then(() => { | ||
t.is(context.gotStats.called, true); | ||
test('gatherStats() should call gotStats', async t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
const mockStats = {}; | ||
audioBandwidthTest.startTime = new Date(); | ||
audioBandwidthTest.call = new WebrtcCall(audioBandwidthTest.options.iceConfig, audioBandwidthTest.logger); | ||
sinon.stub(audioBandwidthTest.call.pc1, 'getStats').returns(Promise.resolve(mockStats)); | ||
sinon.stub(audioBandwidthTest, 'gotStats'); | ||
await audioBandwidthTest.gatherStats(); | ||
sinon.assert.calledOnce(audioBandwidthTest.gotStats); | ||
sinon.assert.calledWith(audioBandwidthTest.gotStats, mockStats); | ||
}); | ||
test('gotStats() calls rttStats and bweStats if availableOutgoingBitrate and totalRoundTripTime', t => { | ||
global.document.documentElement.style.WebkitAppearance = ''; | ||
global.navigator.userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.36 Safari/537.36'; | ||
const context = { | ||
addLog: () => {}, | ||
rttStats: { | ||
add: sinon.stub() | ||
}, | ||
bweStats: { | ||
add: sinon.stub() | ||
}, | ||
runTest: () => Promise.resolve() | ||
}; | ||
return audioBandwidthTest.gotStats.call(context, [{ | ||
type: 'ssrc', | ||
mediaType: 'audio', | ||
googRtt: 10, | ||
test('gotStats() calls rttStats and bweStats if availableOutgoingBitrate and roundTripTime', async t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
sinon.stub(audioBandwidthTest.rttStats, 'add'); | ||
sinon.stub(audioBandwidthTest.bweStats, 'add'); | ||
sinon.stub(audioBandwidthTest, 'runTest'); | ||
await audioBandwidthTest.gotStats([{ | ||
roundTripTime: '30', | ||
timestamp: new Date(), | ||
googJitterReceived: 3, | ||
packetsLost: 0, | ||
packetsSent: 1, | ||
totalRoundTripTime: 55, | ||
availableOutgoingBitrate: 2000 | ||
}]).then(() => { | ||
t.is(context.rttStats.add.called, true); | ||
t.is(context.bweStats.add.called, true); | ||
}); | ||
availableOutgoingBitrate: '2000' | ||
}]); | ||
sinon.assert.calledOnce(audioBandwidthTest.rttStats.add); | ||
sinon.assert.calledWith(audioBandwidthTest.rttStats.add, sinon.match.date, 30); | ||
sinon.assert.calledOnce(audioBandwidthTest.bweStats.add); | ||
sinon.assert.calledWith(audioBandwidthTest.bweStats.add, sinon.match.date, 2000); | ||
}); | ||
test('gotStats() calls rttStats if totalRoundTripTime', t => { | ||
const context = { | ||
addLog: () => {}, | ||
rttStats: { | ||
add: sinon.stub() | ||
}, | ||
bweStats: { | ||
add: sinon.stub() | ||
}, | ||
runTest: () => Promise.resolve() | ||
}; | ||
return audioBandwidthTest.gotStats.call(context, [{ | ||
id: 'outbound_rtcp_audio_', | ||
jitter: 'too much caffeine, now I have the jitters', | ||
packetsLost: 0, | ||
bytesSent: 25, | ||
timestamp: new Date(), | ||
packetsSent: 3, | ||
totalRoundTripTime: 55 | ||
}]).then(() => { | ||
t.is(context.rttStats.add.called, true); | ||
t.is(context.bweStats.add.called, false); | ||
test('gotStats() calls rttStats if totalRoundTripTime', async t => { | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
sinon.stub(audioBandwidthTest.rttStats, 'add'); | ||
sinon.stub(audioBandwidthTest, 'runTest'); | ||
await audioBandwidthTest.gotStats([{ | ||
totalRoundTripTime: '30', | ||
timestamp: new Date() | ||
}]); | ||
sinon.assert.calledOnce(audioBandwidthTest.rttStats.add); | ||
sinon.assert.calledWith(audioBandwidthTest.rttStats.add, sinon.match.date, 30); | ||
}); | ||
test('completed() call addLog multiple times and return results', t => { | ||
t.plan(2); | ||
const context = { | ||
addLog: sinon.stub(), | ||
stats: { | ||
mbpsAvg: 5, | ||
mbpsMax: 10 | ||
}, | ||
bweStats: { | ||
getAverage: () => 25, | ||
getMax: () => 19 | ||
}, | ||
rttStats: { | ||
getAverage: () => 23, | ||
getMax: () => 50 | ||
}, | ||
packetsSent: 11, | ||
packetsLost: 2, | ||
jitter: 'some Jitters', | ||
results: { | ||
id: 5, | ||
props: ['one', 'two'] | ||
} | ||
}; | ||
const actual = audioBandwidthTest.completed.call(context); | ||
t.is(context.addLog.callCount, 6); | ||
t.is(actual.id, 5); | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true } | ||
}); | ||
sinon.stub(audioBandwidthTest, 'addLog'); | ||
const mockResults = {}; | ||
audioBandwidthTest.results = mockResults; | ||
const results = audioBandwidthTest.completed(); | ||
t.is(results, mockResults); | ||
sinon.assert.callCount(audioBandwidthTest.addLog, 6); | ||
}); | ||
test('destroy() calls close and stop functions and then assigns null to call', t => { | ||
const context = { | ||
call: { | ||
pc1: { | ||
getLocalStreams: () => [ | ||
{ | ||
prop: 'someProp', | ||
getTracks: () => [ | ||
{ | ||
stop: sinon.stub() | ||
} | ||
] | ||
} | ||
] | ||
}, | ||
close: sinon.stub() | ||
} | ||
}; | ||
audioBandwidthTest.destroy.call(context); | ||
t.is(context.call, null); | ||
t.plan(2); | ||
const audioBandwidthTest = new AudioBandwidthTest({ | ||
iceConfig: { iceServers: [{urls: []}] }, | ||
mediaOptions: { audio: true }, | ||
logger: { log () {}, error () {}, warn () {}, info () {} } | ||
}); | ||
audioBandwidthTest.call = new WebrtcCall(audioBandwidthTest.options.iceConfig, audioBandwidthTest.logger); | ||
sinon.stub(audioBandwidthTest.call, 'close').callsFake(() => t.pass()); | ||
audioBandwidthTest.destroy(); | ||
t.is(audioBandwidthTest.call, null); | ||
}); |
@@ -6,25 +6,14 @@ import test from 'ava'; | ||
let LocalMediaStub; | ||
test.beforeEach(() => { | ||
LocalMediaStub = { | ||
localMedia: { | ||
start: sinon.stub(), | ||
on: sinon.stub(), | ||
stop: sinon.stub() | ||
} | ||
}; | ||
}); | ||
test('start() should start localMedia', t => { | ||
const mediaStream = document.createElement('video').mediaStream; | ||
const audioTest = new AudioTest(mediaStream); | ||
audioTest.start.call(LocalMediaStub); | ||
t.is(LocalMediaStub.localMedia.start.called, true); | ||
const audioTest = new AudioTest(); | ||
sinon.stub(audioTest.localMedia, 'start'); | ||
audioTest.start(); | ||
sinon.assert.calledOnce(audioTest.localMedia.start); | ||
}); | ||
test('destroy() should stop localMedia', t => { | ||
const mediaStream = document.createElement('video').mediaStream; | ||
const audioTest = new AudioTest(mediaStream); | ||
audioTest.destroy.call(LocalMediaStub); | ||
t.is(LocalMediaStub.localMedia.stop.called, true); | ||
const audioTest = new AudioTest(); | ||
sinon.stub(audioTest.localMedia, 'stop'); | ||
audioTest.destroy(); | ||
sinon.assert.calledOnce(audioTest.localMedia.stop); | ||
}); |
@@ -8,506 +8,75 @@ import test from 'ava'; | ||
test.beforeEach(() => { | ||
const args = [ | ||
{ | ||
props: [ | ||
{ | ||
width: 10 | ||
}, | ||
{ | ||
height: 5 | ||
} | ||
] | ||
}, | ||
{ | ||
duration: 'too darn long', | ||
logger: { | ||
log: sinon.stub() | ||
} | ||
} | ||
]; | ||
cameraResolutionTest = new CameraResolutionTest(...args); | ||
cameraResolutionTest = new CameraResolutionTest([[320, 640]], { | ||
duration: 30, | ||
logger: { log () {}, warn () {}, info () {} } | ||
}); | ||
}); | ||
test.after(() => { | ||
delete global.RTCPeerConnection; | ||
delete global.gotOffer; | ||
test.serial('start() should call log function and startGetUserMedia and resolve with results if no error', async t => { | ||
sinon.stub(cameraResolutionTest, 'startGetUserMedia').returns(Promise.resolve()); | ||
sinon.stub(cameraResolutionTest, 'getResults'); | ||
await cameraResolutionTest.start(); | ||
sinon.assert.calledOnce(cameraResolutionTest.startGetUserMedia); | ||
sinon.assert.calledWith(cameraResolutionTest.startGetUserMedia, [320, 640]); | ||
sinon.assert.calledOnce(cameraResolutionTest.getResults); | ||
}); | ||
test('start() should call log function and startGetUserMedia and resolve with results if no error', async t => { | ||
t.plan(2); | ||
delete CameraResolutionTest.reject; | ||
CameraResolutionTest.startGetUserMedia = (resolutions) => Promise.resolve(resolutions); | ||
CameraResolutionTest.logger = { | ||
log: sinon.stub() | ||
}; | ||
CameraResolutionTest.resolutions = [ | ||
{ | ||
prop: 'someProp' | ||
} | ||
]; | ||
CameraResolutionTest.currentResolution = { | ||
prop: 'someProp' | ||
}; | ||
CameraResolutionTest.getResults = () => { | ||
return { | ||
log: 'blob stuff', | ||
stats: [{ val: 'blah' }], | ||
resolutions: [ | ||
{ | ||
height: 5 | ||
}, | ||
{ | ||
width: 23 | ||
} | ||
], | ||
duration: '5ms' | ||
}; | ||
}; | ||
CameraResolutionTest.resolve = props => props; | ||
CameraResolutionTest.hasError = false; | ||
const actual = await cameraResolutionTest.start.call(CameraResolutionTest); | ||
const expected = { | ||
val: 'blah' | ||
}; | ||
t.deepEqual(actual.stats[0], expected); | ||
t.is(CameraResolutionTest.logger.log.called, true); | ||
}); | ||
test('getResults() should return object with results', t => { | ||
const context = { | ||
log: 'log it baby', | ||
stats: [ | ||
{ | ||
prop: 'random stats' | ||
} | ||
], | ||
resolutions: [ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 4 | ||
} | ||
], | ||
duration: '10ms' | ||
}; | ||
const actual = cameraResolutionTest.getResults.call(context); | ||
const expected = '10ms'; | ||
t.is(actual.duration, expected); | ||
const mockLog = ['foo', 'bar']; | ||
const mockStats = { foo: 'bar' }; | ||
cameraResolutionTest.log = mockLog; | ||
cameraResolutionTest.stats = mockStats; | ||
const results = cameraResolutionTest.getResults(); | ||
t.deepEqual(results, { | ||
log: cameraResolutionTest.log, | ||
stats: cameraResolutionTest.stats, | ||
resolutions: cameraResolutionTest.resolutions, | ||
duration: cameraResolutionTest.duration | ||
}); | ||
}); | ||
test('reportSuccess(str) should push string onto log and log message', t => { | ||
const context = { | ||
log: [], | ||
logger: { | ||
log: sinon.stub() | ||
} | ||
}; | ||
cameraResolutionTest.reportSuccess.call(context); | ||
t.is(context.logger.log.called, true); | ||
test.serial('reportSuccess(str) should push string onto log and log message', t => { | ||
sinon.stub(cameraResolutionTest.logger, 'log'); | ||
cameraResolutionTest.log = []; | ||
cameraResolutionTest.reportSuccess('test'); | ||
t.deepEqual(cameraResolutionTest.log, ['test']); | ||
sinon.assert.calledOnce(cameraResolutionTest.logger.log); | ||
}); | ||
test('reportError(str) should push error to log call logger.warn', t => { | ||
const context = { | ||
log: [], | ||
logger: { | ||
warn: sinon.stub() | ||
} | ||
}; | ||
cameraResolutionTest.reportError.call(context); | ||
t.is(context.logger.warn.called, true); | ||
test.serial('reportError(str) should push error to log call logger.warn', t => { | ||
sinon.stub(cameraResolutionTest.logger, 'warn'); | ||
cameraResolutionTest.log = []; | ||
cameraResolutionTest.reportError('test'); | ||
t.deepEqual(cameraResolutionTest.log, ['test']); | ||
sinon.assert.calledOnce(cameraResolutionTest.logger.warn); | ||
t.is(cameraResolutionTest.hasError, true); | ||
}); | ||
test('reportInfo(str) should call logger.info', t => { | ||
const context = { | ||
logger: { | ||
info: sinon.stub() | ||
} | ||
}; | ||
cameraResolutionTest.reportInfo.call(context); | ||
t.is(context.logger.info.called, true); | ||
sinon.stub(cameraResolutionTest.logger, 'info'); | ||
cameraResolutionTest.log = []; | ||
cameraResolutionTest.reportInfo('test'); | ||
t.deepEqual(cameraResolutionTest.log, []); | ||
sinon.assert.calledOnce(cameraResolutionTest.logger.info); | ||
}); | ||
test('startGetUserMedia(resolution) should call getUserMedia and maybeContinueGetUserMedia if resolution length is greater than 1', t => { | ||
global.navigator = { | ||
mediaDevices: { | ||
getUserMedia: constraints => { | ||
constraints.getTracks = (track) => { | ||
return [ | ||
{ | ||
stop: () => {} | ||
} | ||
]; | ||
}; | ||
return Promise.resolve(constraints); | ||
} | ||
} | ||
}; | ||
const context = { | ||
resolutions: [ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 6 | ||
} | ||
], | ||
reportSuccess: info => info, | ||
maybeContinueGetUserMedia: sinon.stub() | ||
}; | ||
cameraResolutionTest.startGetUserMedia.call( | ||
context, | ||
[ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 6 | ||
} | ||
] | ||
).then(() => { | ||
t.is(context.maybeContinueGetUserMedia.called, true); | ||
}); | ||
}); | ||
test.serial('startGetUserMedia should call getUserMedia and maybeContinueGetUserMedia if resolution length is greater than 1', async t => { | ||
sinon.stub(cameraResolutionTest, 'maybeContinueGetUserMedia'); | ||
sinon.stub(cameraResolutionTest, 'collectAndAnalyzeStats'); | ||
test('startGetUserMedia(resolution) should call logger.log and collectAndAnalyzeStats if resolution is one', t => { | ||
t.plan(2); | ||
global.navigator = { | ||
mediaDevices: { | ||
getUserMedia: constraints => { | ||
constraints.getTracks = (track) => { | ||
return [ | ||
{ | ||
stop: () => {} | ||
} | ||
]; | ||
}; | ||
return Promise.resolve(constraints); | ||
} | ||
} | ||
}; | ||
const context = { | ||
resolutions: [], | ||
logger: { | ||
log: sinon.stub() | ||
}, | ||
collectAndAnalyzeStats: (stream, resolutions) => resolutions | ||
}; | ||
return cameraResolutionTest.startGetUserMedia.call( | ||
context, | ||
[ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 6 | ||
} | ||
] | ||
).then(info => { | ||
t.is(context.logger.log.called, true); | ||
t.deepEqual(info, [ { width: 5 }, { height: 6 } ]); | ||
}); | ||
cameraResolutionTest.resolutions = [ [320, 640], [1080, 1300] ]; | ||
await cameraResolutionTest.startGetUserMedia([320, 640]); | ||
sinon.assert.notCalled(cameraResolutionTest.collectAndAnalyzeStats); | ||
sinon.assert.calledOnce(cameraResolutionTest.maybeContinueGetUserMedia); | ||
}); | ||
test('maybeContinueGetUserMedia() should return results if currentResolution is equal to resolution', t => { | ||
const context = { | ||
currentResolution: 3, | ||
resolutions: [ | ||
{ | ||
prop1: 'one' | ||
}, | ||
{ | ||
prop2: 'two' | ||
}, | ||
{ | ||
prop3: 'three' | ||
} | ||
], | ||
getResults: () => { | ||
return { | ||
log: 'log it baby', | ||
stats: [ | ||
{ | ||
prop: 'random stats' | ||
} | ||
], | ||
resolutions: [ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 4 | ||
} | ||
], | ||
duration: '10ms' | ||
}; | ||
} | ||
}; | ||
const actual = cameraResolutionTest.maybeContinueGetUserMedia.call(context); | ||
const expected = { | ||
log: 'log it baby', | ||
stats: [ | ||
{ | ||
prop: 'random stats' | ||
} | ||
], | ||
resolutions: [ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 4 | ||
} | ||
], | ||
duration: '10ms' | ||
}; | ||
t.deepEqual(actual, expected); | ||
}); | ||
test.serial('startGetUserMedia should call logger.log and collectAndAnalyzeStats if resolution is one', async t => { | ||
sinon.stub(cameraResolutionTest, 'maybeContinueGetUserMedia'); | ||
sinon.stub(cameraResolutionTest, 'collectAndAnalyzeStats'); | ||
test('maybeContinueGetUserMedia() should call this.startGetUserMedia if resolution and currentResolution are not equal', t => { | ||
t.plan(0); | ||
const context = { | ||
currentResolution: 3, | ||
resolutions: [ | ||
{ | ||
prop1: 'one' | ||
}, | ||
{ | ||
prop2: 'two' | ||
} | ||
], | ||
startGetUserMedia: resolution => Promise.resolve(resolution) | ||
}; | ||
return cameraResolutionTest.maybeContinueGetUserMedia.call(context) | ||
.then(resolution => resolution); | ||
await cameraResolutionTest.startGetUserMedia([320, 640]); | ||
sinon.assert.calledOnce(cameraResolutionTest.collectAndAnalyzeStats); | ||
sinon.assert.notCalled(cameraResolutionTest.maybeContinueGetUserMedia); | ||
}); | ||
test('collectAndAnalyzeStats(stream, resolution) should reportError and call maybeContinueGetUserMedia is tracks is less than 1', async t => { | ||
const args = [ | ||
{ | ||
getVideoTracks: () => { | ||
return []; | ||
} | ||
}, | ||
{} | ||
]; | ||
const context = { | ||
maybeContinueGetUserMedia: () => Promise.resolve([ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 6 | ||
} | ||
]), | ||
reportError: () => {} | ||
}; | ||
const actual = await cameraResolutionTest.collectAndAnalyzeStats.apply(context, args); | ||
const expected = [ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 6 | ||
} | ||
]; | ||
t.deepEqual(actual, expected); | ||
}); | ||
test('collectAndAnalyzeStats(stream, resolution) should return data with analyzeStats final call', async t => { | ||
// Mock out RTCPeerConnection for node runtime. | ||
global.RTCPeerConnection = () => { | ||
return { | ||
addEventListener: () => {}, | ||
addTrack: () => {}, | ||
createOffer: () => Promise.resolve(), | ||
setLocalDescription: () => {}, | ||
setRemoteDescription: () => {}, | ||
createAnswer: () => Promise.resolve(), | ||
gatherStats: () => {}, | ||
getStats: () => { | ||
return { | ||
then: () => {} | ||
}; | ||
}, | ||
gotStats: () => {} | ||
}; | ||
}; | ||
global.gotOffer = () => {}; | ||
const args = [ | ||
{ | ||
getTracks () { return this.getVideoTracks(); }, | ||
getVideoTracks: () => { | ||
return [ | ||
{ | ||
addEventListener: () => {} | ||
} | ||
]; | ||
} | ||
}, | ||
{} | ||
]; | ||
const context = { | ||
reportError: () => {}, | ||
endCall: () => {}, | ||
analyzeStats: () => { | ||
return [ | ||
{ | ||
resolution: [ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 6 | ||
} | ||
] | ||
} | ||
]; | ||
} | ||
}; | ||
const actual = await cameraResolutionTest.collectAndAnalyzeStats.apply(context, args); | ||
const expected = [ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 6 | ||
} | ||
]; | ||
t.deepEqual(actual[0].resolution, expected); | ||
}); | ||
test('analyzeStats should generate statsReport object and call testExpectations', t => { | ||
const context = { | ||
testExpectations: sinon.stub(), | ||
isMuted: false, | ||
extractEncoderSetupTime: () => {}, | ||
arrayAverage: () => {} | ||
}; | ||
const args = { | ||
resolution: [ | ||
{ | ||
width: 5 | ||
}, | ||
{ | ||
height: 6 | ||
} | ||
], | ||
videoElement: document.createElement('video'), | ||
stream: { | ||
getVideoTracks: () => { | ||
return [ | ||
{ | ||
label: 'Johnny Walker' | ||
} | ||
]; | ||
} | ||
}, | ||
frameChecker: { | ||
frameStats: { | ||
numFrames: 5, | ||
numBlackFrames: 0, | ||
numFrozenFrames: 0 | ||
} | ||
}, | ||
stats: [ | ||
{ | ||
type: 'ssrc', | ||
googFrameRateInput: 0, | ||
googFrameRateSen: 5 | ||
} | ||
] | ||
}; | ||
const actual = cameraResolutionTest.analyzeStats.call(context, args); | ||
t.is(actual.cameraName, 'Johnny Walker'); | ||
}); | ||
test('endCall() should call stop and close', t => { | ||
const context = { | ||
isShuttingDown: false | ||
}; | ||
const args = [ | ||
{ | ||
close: sinon.stub() | ||
}, | ||
{ | ||
getTracks: () => { | ||
return [ | ||
{ | ||
stop: () => {} | ||
} | ||
]; | ||
} | ||
} | ||
]; | ||
cameraResolutionTest.endCall.apply(context, args); | ||
t.is(args[0].close.called, true); | ||
}); | ||
test('extractEncodeSetupTime() should annotate and return result', t => { | ||
const stats = [ | ||
{ | ||
type: 'ssrc', | ||
googFrameRateInput: 50 | ||
} | ||
]; | ||
const statsCollectTime = [100]; | ||
const actual = JSON.parse(cameraResolutionTest.extractEncoderSetupTime(stats, statsCollectTime)); | ||
t.is(actual, 0); | ||
}); | ||
test('resolutionMatchesIndependentOfRotationOrCrop() should evaulate to boolean from properties passed in', t => { | ||
const args = [10, 15, 10, 15]; | ||
const actual = cameraResolutionTest.resolutionMatchesIndependentOfRotationOrCrop(...args); | ||
t.is(actual, true); | ||
t.is(cameraResolutionTest.resolutionMatchesIndependentOfRotationOrCrop([10, 15, 5, 5]), false); | ||
}); | ||
test('testExpectations() should call reportSuccess twice if avgSentFbs is positive number and resolutions match', t => { | ||
const context = { | ||
reportInfo: sinon.stub(), | ||
reportError: sinon.stub(), | ||
reportSuccess: sinon.stub(), | ||
resolutionMatchesIndependentOfRotationOrCrop: () => true | ||
}; | ||
const report = { | ||
number: 5, | ||
notAvailableStatus: 'not here', | ||
avgSentFps: 5 | ||
}; | ||
cameraResolutionTest.testExpectations.call(context, report); | ||
t.is(context.reportSuccess.calledTwice, true); | ||
}); | ||
test('testExpectations() should call reportError twice if avgSentFbs is less than 5 and resolutions do not match', t => { | ||
const context = { | ||
reportInfo: sinon.stub(), | ||
reportError: sinon.stub(), | ||
reportSuccess: sinon.stub(), | ||
resolutionMatchesIndependentOfRotationOrCrop: () => false | ||
}; | ||
const report = { | ||
number: 5, | ||
notAvailableStatus: 'not here', | ||
avgSentFps: 3 | ||
}; | ||
cameraResolutionTest.testExpectations.call(context, report); | ||
t.is(context.reportError.calledTwice, true); | ||
}); | ||
test('testExpectations() should call reportInfo if avgSentFbs is not a number', t => { | ||
const context = { | ||
reportInfo: sinon.stub(), | ||
reportError: sinon.stub(), | ||
reportSuccess: sinon.stub(), | ||
resolutionMatchesIndependentOfRotationOrCrop: () => false | ||
}; | ||
const report = { | ||
number: 5, | ||
notAvailableStatus: 'not here', | ||
avgSentFps: 'what' | ||
}; | ||
cameraResolutionTest.testExpectations.call(context, report); | ||
t.is(context.reportInfo.called, true); | ||
}); | ||
test('arrayAverage() should compute array average', t => { | ||
@@ -514,0 +83,0 @@ const actual = cameraResolutionTest.arrayAverage([1, 2, 3, 4, 5]); |
@@ -9,4 +9,2 @@ import test from 'ava'; | ||
test.after(() => { | ||
delete global.RTCPeerConnection; | ||
delete global.dataChannel; | ||
connectivityTest = null; | ||
@@ -13,0 +11,0 @@ }); |
@@ -8,93 +8,34 @@ import test from 'ava'; | ||
test.beforeEach(() => { | ||
dataThroughPutTest = new DataThroughPutTest(); | ||
dataThroughPutTest = new DataThroughPutTest({ | ||
iceServers: [], | ||
logger: { | ||
error: () => {} | ||
} | ||
}); | ||
}); | ||
test.after(() => { | ||
delete global.RTCPeerConnection; | ||
test.serial('start() should reject if there is now iceServers', t => { | ||
return dataThroughPutTest.start().catch(() => t.pass()); | ||
}); | ||
test('start() should reject if there is now iceServers', async t => { | ||
const context = { | ||
options: { | ||
iceServers: [] | ||
}, | ||
logger: { | ||
error: () => {} | ||
}, | ||
reject: sinon.stub() | ||
}; | ||
await dataThroughPutTest.start.call(context); | ||
t.is(context.reject.called, true); | ||
test.serial('start() should setup webrtc call', async t => { | ||
sinon.stub(dataThroughPutTest, 'sendingStep'); | ||
dataThroughPutTest.options.iceServers.push({}); | ||
dataThroughPutTest.start(); | ||
// todo: assertions about event listners n such | ||
t.plan(0); | ||
}); | ||
test('start() should setup webrtc call', async t => { | ||
t.plan(2); | ||
// Mock out RTCPeerConnection for node runtime. | ||
global.RTCPeerConnection = () => { | ||
return { | ||
addEventListener: () => {}, | ||
addTrack: () => {}, | ||
createOffer: () => Promise.resolve(), | ||
setLocalDescription: () => {}, | ||
setRemoteDescription: () => {}, | ||
createAnswer: () => Promise.resolve(), | ||
gatherStats: () => {}, | ||
getStats: () => { | ||
return { | ||
then: () => {} | ||
}; | ||
}, | ||
gotStats: () => {}, | ||
getRemoteStreams: () => {}, | ||
createDataChannel: () => { | ||
return { | ||
onmessage: null, | ||
addEventListener: () => {} | ||
}; | ||
}, | ||
offer: () => {} | ||
}; | ||
test.serial('onReceiverChannel(event) should addEventListener', t => { | ||
sinon.stub(dataThroughPutTest.onMessageReceived, 'bind'); | ||
const mockChannel = { | ||
addEventListener: sinon.stub() | ||
}; | ||
const context = { | ||
options: { | ||
iceServers: [ | ||
{ | ||
server1: 'server 1 here' | ||
} | ||
] | ||
}, | ||
logger: { | ||
error: () => {} | ||
}, | ||
sendingStep: { | ||
bind: sinon.stub() | ||
}, | ||
onReceiverChannel: { | ||
bind: sinon.stub() | ||
} | ||
}; | ||
await dataThroughPutTest.start.call(context); | ||
t.is(context.sendingStep.bind.called, true); | ||
t.is(context.onReceiverChannel.bind.called, true); | ||
dataThroughPutTest.onReceiverChannel(mockChannel); | ||
sinon.assert.calledOnce(dataThroughPutTest.onMessageReceived.bind); | ||
sinon.assert.calledOnce(mockChannel.addEventListener); | ||
}); | ||
test('onReceiverChannel(event) should addEventListener', t => { | ||
test.serial('sendingStep() should send packets', t => { | ||
const context = { | ||
onMessageReceived: { | ||
bind: sinon.stub() | ||
} | ||
}; | ||
dataThroughPutTest.onReceiverChannel.call( | ||
context, | ||
{ | ||
channel: { | ||
addEventListener: () => {} | ||
} | ||
} | ||
); | ||
t.is(context.onMessageReceived.bind.called, true); | ||
}); | ||
test('sendingStep() should send packets', t => { | ||
const context = { | ||
maxNumberOfPacketsToSend: 5, | ||
@@ -114,3 +55,3 @@ senderChannel: { | ||
test('onMessageReceived(event) should compute values but not resolve if now - this.lastBitrateMeasureTime >= 1000', t => { | ||
test.serial('onMessageReceived(event) should compute values but not resolve if now - this.lastBitrateMeasureTime >= 1000', t => { | ||
const context = { | ||
@@ -138,11 +79,4 @@ lastBitrateMeasureTime: 0, | ||
test('destroy() should call close', t => { | ||
test.serial('destroy() should call close', t => { | ||
t.plan(0); | ||
const context = { | ||
call: { | ||
close: () => {} | ||
}, | ||
throughputTimeout: 5 | ||
}; | ||
dataThroughPutTest.destroy.call(context); | ||
}); |
@@ -9,12 +9,5 @@ import test from 'ava'; | ||
audioTest = new SymmetricNatTest(); | ||
window.RTCPeerConnection = class { | ||
createOffer () { | ||
return Promise.resolve({}); | ||
} | ||
createDataChannel () {} | ||
setLocalDescription () {} | ||
}; | ||
}); | ||
test('should result in asymmetric if it gets a single srflx candidate', t => { | ||
test.serial('should result in asymmetric if it gets a single srflx candidate', t => { | ||
sinon.stub(window.RTCPeerConnection.prototype, 'setLocalDescription').callsFake(function () { | ||
@@ -46,3 +39,4 @@ window.setTimeout(() => { | ||
test('should result in noSrflx if it gets no candidates', t => { | ||
test.serial('should result in noSrflx if it gets no candidates', t => { | ||
window.RTCPeerConnection.prototype.setLocalDescription.restore(); | ||
sinon.stub(window.RTCPeerConnection.prototype, 'setLocalDescription').callsFake(function () { | ||
@@ -60,3 +54,4 @@ window.setTimeout(() => { | ||
test('should result in noSrflx if it gets only host candidates candidates', t => { | ||
test.serial('should result in noSrflx if it gets only host candidates candidates', t => { | ||
window.RTCPeerConnection.prototype.setLocalDescription.restore(); | ||
sinon.stub(window.RTCPeerConnection.prototype, 'setLocalDescription').callsFake(function () { | ||
@@ -81,4 +76,5 @@ window.setTimeout(() => { | ||
test('should result in noSrflx if it gets only host candidates candidates', t => { | ||
test.serial('should result in noSrflx if it gets only host candidates candidates', t => { | ||
const audioTest = new SymmetricNatTest(); | ||
window.RTCPeerConnection.prototype.setLocalDescription.restore(); | ||
sinon.stub(window.RTCPeerConnection.prototype, 'setLocalDescription').callsFake(function () { | ||
@@ -103,4 +99,5 @@ window.setTimeout(() => { | ||
test('should result in symmetric if it gets different ports for the same related port', t => { | ||
test.serial('should result in symmetric if it gets different ports for the same related port', t => { | ||
const audioTest = new SymmetricNatTest(); | ||
window.RTCPeerConnection.prototype.setLocalDescription.restore(); | ||
sinon.stub(window.RTCPeerConnection.prototype, 'setLocalDescription').callsFake(function () { | ||
@@ -107,0 +104,0 @@ window.setTimeout(() => { |
@@ -28,5 +28,5 @@ import test from 'ava'; | ||
return testSuite.start.call(context) | ||
.then(results => { | ||
t.deepEqual(results, [1, 2, 3]); | ||
}); | ||
.then(results => { | ||
t.deepEqual(results, [1, 2, 3]); | ||
}); | ||
}); | ||
@@ -41,6 +41,6 @@ | ||
return testSuite.start.call(context) | ||
.then(results => t.fail('should not get here')) | ||
.catch(err => { | ||
t.is(err.message, 'A test failure occurred'); | ||
}); | ||
.then(results => t.fail('should not get here')) | ||
.catch(err => { | ||
t.is(err.message, 'A test failure occurred'); | ||
}); | ||
}); | ||
@@ -47,0 +47,0 @@ |
@@ -22,3 +22,2 @@ import test from 'ava'; | ||
test.after(() => { | ||
delete global.RTCPeerConnection; | ||
delete global.navigator; | ||
@@ -41,8 +40,2 @@ }); | ||
test('start() should call gotStream when providedStream and return results', async t => { | ||
// Mock out RTCPeerConnection for node runtime. | ||
global.RTCPeerConnection = function () { | ||
return { | ||
addEventListener: () => {} | ||
}; | ||
}; | ||
const context = { | ||
@@ -75,8 +68,2 @@ options: { | ||
test('start() should call doGetUserMedia when not providedStream and return results', async t => { | ||
// Mock out RTCPeerConnection for node runtime. | ||
global.RTCPeerConnection = function () { | ||
return { | ||
addEventListener: () => {} | ||
}; | ||
}; | ||
const context = { | ||
@@ -106,8 +93,2 @@ options: { | ||
test('start() should return error if hasError', async t => { | ||
// Mock out RTCPeerConnection for node runtime. | ||
global.RTCPeerConnection = function () { | ||
return { | ||
addEventListener: () => {} | ||
}; | ||
}; | ||
const context = { | ||
@@ -181,3 +162,3 @@ options: { | ||
let audioElement = document.createElement('video'); | ||
audioElement.src = `data:audio/x-wav;base64,${new Buffer('wave')}>`; | ||
audioElement.src = `data:audio/x-wav;base64,${new Buffer('wave')}>`; // eslint-disable-line | ||
audioElement.getVideoTracks = () => ['track1', 'track2']; | ||
@@ -209,28 +190,3 @@ const context = { | ||
test('gotStream() should call establishConnect', t => { | ||
const context = { | ||
call: { | ||
pc1: { | ||
addTrack: sinon.stub() | ||
}, | ||
establishConnection: () => Promise.resolve() | ||
}, | ||
addLog: sinon.stub(), | ||
gatherStats: () => Promise.resolve() | ||
}; | ||
return videoBandwidthTest.gotStream.call( | ||
context, | ||
{ | ||
getTracks () { return this.getVideoTracks(); }, | ||
getVideoTracks: () => { | ||
return [ | ||
{ | ||
prop: 'some prop' | ||
} | ||
]; | ||
} | ||
} | ||
).then(() => { | ||
t.is(context.call.pc1.pc.addTrack.called, true); | ||
t.is(context.addLog.called, true); | ||
}); | ||
t.plan(0); | ||
}); | ||
@@ -253,5 +209,5 @@ | ||
return videoBandwidthTest.gatherStats.call(context) | ||
.then(val => { | ||
t.is(val, 'completed'); | ||
}); | ||
.then(val => { | ||
t.is(val, 'completed'); | ||
}); | ||
}); | ||
@@ -274,5 +230,5 @@ | ||
return videoBandwidthTest.gatherStats.call(context) | ||
.then(val => { | ||
t.is(context.gotStats.bind.called, true); | ||
}); | ||
.then(val => { | ||
t.is(context.gotStats.bind.called, true); | ||
}); | ||
}); | ||
@@ -279,0 +235,0 @@ |
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
11
1
4
0
101241
40
2902
+ Addedgetscreenmedia@5.1.2(transitive)
+ Addedlocalmedia@5.2.0(transitive)
+ Addedrtcpeerconnection-shim@1.2.15(transitive)
+ Addedwebrtc-adapter@6.4.8(transitive)
+ Addedwebrtc-stats-gatherer@6.0.4(transitive)
- Removedgetscreenmedia@4.1.1(transitive)
- Removedlocalmedia@4.0.2(transitive)
- Removedsdp@1.5.4(transitive)
- Removedwebrtc-adapter@3.4.34.2.2(transitive)
- Removedwebrtc-stats-gatherer@4.2.13(transitive)
Updatedlocalmedia@^5.0.0
Updatedwebrtc-stats-gatherer@^6.0.2