UNPKG

webrtc-adapter

Version:

A shim to insulate apps from WebRTC spec changes and browser prefix differences

1,087 lines (1,005 loc) 33.5 kB
/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. */ /* eslint-env node */ 'use strict'; // This is a basic test file for use with testling and webdriver. // The test script language comes from tape. var test = require('tape'); var webdriver = require('selenium-webdriver'); var seleniumHelpers = require('./selenium-lib'); // Start of tests. // Test that adding and removing an eventlistener on navigator.mediaDevices // is possible. The usecase for this is the devicechanged event. // This does not test whether devicechanged is actually called. test('navigator.mediaDevices eventlisteners', function(t) { var driver = seleniumHelpers.buildDriver(); // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.plan(3); t.pass('Page loaded'); return driver.executeScript( 'return typeof(navigator.mediaDevices.addEventListener) === ' + '\'function\''); }) .then(function(isAddEventListenerFunction) { t.ok(isAddEventListenerFunction, 'navigator.mediaDevices.addEventListener is a function'); return driver.executeScript( 'return typeof(navigator.mediaDevices.removeEventListener) === ' + '\'function\''); }) .then(function(isRemoveEventListenerFunction) { t.ok(isRemoveEventListenerFunction, 'navigator.mediaDevices.removeEventListener is a function'); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('createObjectURL shim test', function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; ['audio', 'video'].reduce(function(p, type) { return p.then(function() { var constraints = {fake: true}; constraints[type] = true; return navigator.mediaDevices.getUserMedia(constraints); }) .then(function(stream) { var element = document.createElement(type); window[type] = element; window[type + 'Stream'] = stream; element.id = type; element.autoplay = true; // Test both ways of setting src if (type === 'audio') { element.src = URL.createObjectURL(stream); } else { element.setAttribute('src', URL.createObjectURL(stream)); } return new Promise(function(resolve) { element.addEventListener('loadedmetadata', resolve); }); }); }, Promise.resolve()) .then(function() { document.body.appendChild(window.audio); document.body.appendChild(window.video); callback(null); }) .catch(function(err) { callback(err.name); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.plan(5); t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(error) { var gumResult = error ? 'error: ' + error : 'no errors'; t.ok(!error, 'getUserMedia result: ' + gumResult); // Wait until loadedmetadata event has fired and appended video element. return driver.wait(webdriver.until.elementLocated( webdriver.By.id('video')), 3000); }) .then(function() { return Promise.all([ 'return document.getElementById("audio").srcObject.id', 'return window.audioStream.id', 'return document.getElementById("video").srcObject.id', 'return window.videoStream.id' ].map(function(script) { return driver.executeScript(script); })) .then(function(ids) { t.ok(ids[0] === ids[1], 'audio srcObject getter returns audio stream'); t.ok(ids[2] === ids[3], 'video srcObject getter returns video stream'); t.ok(ids[0] !== ids[2], 'audio and video streams are different'); t.end(); }); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('srcObject set from another object', function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; var constraints = {video: true, fake: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { window.stream = stream; var video = document.createElement('video'); var video2 = document.createElement('video2'); video.setAttribute('id', 'video'); video.setAttribute('autoplay', 'true'); video2.setAttribute('id', 'video2'); video2.setAttribute('autoplay', 'true'); video.srcObject = stream; video2.srcObject = video.srcObject; // If the srcObject shim works, we should get a video // at some point. This will trigger loadedmetadata. video.addEventListener('loadedmetadata', function() { document.body.appendChild(video); document.body.appendChild(video2); callback(null); }); }) .catch(function(err) { callback(err.name); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.plan(3); t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(error) { var gumResult = (error) ? 'error: ' + error : 'no errors'; t.ok(!error, 'getUserMedia result: ' + gumResult); // Wait until loadedmetadata event has fired and appended video element. // 5 second timeout in case the event does not fire for some reason. return driver.wait(webdriver.until.elementLocated( webdriver.By.id('video2')), 3000); }) .then(function() { return driver.executeScript( 'return document.getElementById(\'video\').srcObject.id') .then(function(srcObjectId) { driver.executeScript( 'return document.getElementById(\'video2\').srcObject.id') .then(function(srcObjectId2) { t.ok(srcObjectId === srcObjectId2, 'Stream ids from srcObjects match.'); }); }); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('srcObject null setter', function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; var constraints = {video: true, fake: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { window.stream = stream; var video = document.createElement('video'); video.setAttribute('id', 'video'); video.setAttribute('autoplay', 'true'); document.body.appendChild(video); video.srcObject = stream; video.srcObject = null; callback(null); }) .catch(function(err) { callback(err.name); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.plan(3); t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(error) { var gumResult = (error) ? 'error: ' + error : 'no errors'; t.ok(!error, 'getUserMedia result: ' + gumResult); // Wait until loadedmetadata event has fired and appended video element. // 5 second timeout in case the event does not fire for some reason. return driver.wait(webdriver.until.elementLocated( webdriver.By.id('video')), 3000); }) .then(function() { return driver.executeScript( 'return document.getElementById(\'video\').src'); }) .then(function(src) { t.ok(src === 'file://' + process.cwd() + '/test/testpage.html' || // kind of... it actually is this page. src === '', 'src is the empty string'); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('Attach mediaStream directly', function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; var constraints = {video: true, fake: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { window.stream = stream; var video = document.createElement('video'); video.setAttribute('id', 'video'); video.setAttribute('autoplay', 'true'); // If the srcObject shim works, we should get a video // at some point. This will trigger loadedmetadata. // Firefox < 38 had issues with this, workaround removed // due to 38 being stable now. video.addEventListener('loadedmetadata', function() { document.body.appendChild(video); }); video.srcObject = stream; callback(null); }) .catch(function(err) { callback(err.name); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.plan(4); t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(error) { var gumResult = (error) ? 'error: ' + error : 'no errors'; t.ok(!error, 'getUserMedia result: ' + gumResult); // We need to wait due to the stream can take a while to setup. driver.wait(function() { return driver.executeScript( 'return typeof window.stream !== \'undefined\''); }, 3000); return driver.executeScript( // Firefox and Chrome have different constructor names. 'return window.stream.constructor.name.match(\'MediaStream\') !== null'); }) .then(function(isMediaStream) { t.ok(isMediaStream, 'Stream is a MediaStream'); // Wait until loadedmetadata event has fired and appended video element. // 5 second timeout in case the event does not fire for some reason. return driver.wait(webdriver.until.elementLocated( webdriver.By.id('video')), 3000); }) .then(function() { return driver.wait(function() { return driver.executeScript( 'return document.getElementById("video").readyState === 4'); }, 3000); }) .then(function() { t.pass('Stream attached directly succesfully to a video element'); t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('Re-attaching mediaStream directly', function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; var constraints = {video: true, fake: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { window.stream = stream; var video = document.createElement('video'); var video2 = document.createElement('video'); video.setAttribute('id', 'video'); video.setAttribute('autoplay', 'true'); video2.setAttribute('id', 'video2'); video2.setAttribute('autoplay', 'true'); // If attachMediaStream works, we should get a video // at some point. This will trigger loadedmetadata. // This reattaches to the second video which will trigger // loadedmetadata there. video.addEventListener('loadedmetadata', function() { document.body.appendChild(video); video2.srcObject = video.srcObject; }); video2.addEventListener('loadedmetadata', function() { document.body.appendChild(video2); }); video.srcObject = stream; callback(null); }) .catch(function(err) { callback(err.name); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.plan(5); t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(error) { var gumResult = (error) ? 'error: ' + error : 'no errors'; t.ok(!error, 'getUserMedia result: ' + gumResult); // We need to wait due to the stream can take a while to setup. return driver.wait(function() { return driver.executeScript( 'return typeof window.stream !== \'undefined\''); }, 3000) .then(function() { return driver.executeScript( // Firefox and Chrome have different constructor names. 'return window.stream.constructor.name.match(\'MediaStream\') !== null'); }); }) .then(function(isMediaStream) { t.ok(isMediaStream, 'Stream is a MediaStream'); // Wait until loadedmetadata event has fired and appended video element. // 5 second timeout in case the event does not fire for some reason. return driver.wait(webdriver.until.elementLocated( webdriver.By.id('video')), 3000); }) .then(function(videoElement) { return driver.wait(function() { return driver.executeScript( 'return document.querySelector("video").readyState === 4'); }, 3000); }) .then(function() { t.pass('Stream attached directly succesfully to a video element'); // Wait until loadedmetadata event has fired and appended video element. // 5 second timeout in case the event does not fire for some reason. return driver.wait(webdriver.until.elementLocated( webdriver.By.id('video2')), 3000); }) .then(function() { return driver.wait(function() { return driver.executeScript( 'return document.getElementById("video2").readyState === 4'); }, 3000); }) .then(function() { t.pass('Stream re-attached directly succesfully to a video element'); t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); // deactivated in Chrome due to https://github.com/webrtc/adapter/issues/180 test('Call getUserMedia with impossible constraints', {skip: process.env.BROWSER === 'chrome'}, function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; var impossibleConstraints = { video: { width: 1280, height: {min: 200, ideal: 720, max: 1080}, frameRate: {exact: 0} // to fail } }; // TODO: Remove when firefox 42+ accepts impossible constraints // on fake devices. if (window.adapter.browserDetails.browser === 'firefox') { impossibleConstraints.fake = false; } navigator.mediaDevices.getUserMedia(impossibleConstraints) .then(function(stream) { window.stream = stream; callback(null); }) .catch(function(err) { callback(err.name); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.plan(2); t.pass('Page loaded'); return driver.executeScript( 'return adapter.browserDetails.browser === \'firefox\' ' + '&& adapter.browserDetails.version < 42'); }) .then(function(isFirefoxAndVersionLessThan42) { if (isFirefoxAndVersionLessThan42) { t.skip('getUserMedia(impossibleConstraints) not supported on < 42'); throw 'skip-test'; } return driver.executeAsyncScript(testDefinition); }) .then(function(error) { t.ok(error, 'getUserMedia(impossibleConstraints) must fail'); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('addIceCandidate with null', function(t) { var driver = seleniumHelpers.buildDriver(); var testDefinition = function() { var callback = arguments[arguments.length - 1]; var pc1 = new RTCPeerConnection(null); pc1.addIceCandidate(null) // callback is called with either the empty result // of the .then or the error from .catch. .then(callback) .catch(callback); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(err) { t.ok(err === null, 'addIceCandidate(null) resolves'); t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('addIceCandidate with undefined', function(t) { var driver = seleniumHelpers.buildDriver(); var testDefinition = function() { var callback = arguments[arguments.length - 1]; var pc1 = new RTCPeerConnection(null); pc1.addIceCandidate(undefined) // callback is called with either the empty result // of the .then or the error from .catch. .then(callback) .catch(callback); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(err) { t.ok(err === null, 'addIceCandidate(undefined) resolves'); t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('call enumerateDevices', function(t) { var driver = seleniumHelpers.buildDriver(); var testDefinition = function() { var callback = arguments[arguments.length - 1]; navigator.mediaDevices.enumerateDevices() .then(function(devices) { callback(devices); }) .catch(function(err) { callback(err); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(callback) { // Callback will either return an error object or device array. if (callback.name === 'Error') { t.fail('Enumerate devices failure: ' + callback.toString()); } else { return callback; } }) .then(function(devices) { t.ok(typeof devices.length === 'number', 'Produced a devices array'); devices.forEach(function(device) { t.ok(device.kind === 'videoinput' || device.kind === 'audioinput' || device.kind === 'audiooutput', 'Known device kind'); t.ok(device.deviceId.length !== undefined, 'Device id present'); t.ok(device.label.length !== undefined, 'Device label present'); }); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); // Test polyfill for getStats. test('getStats', {skip: true}, function(t) { var driver = seleniumHelpers.buildDriver(); var testDefinition = function() { var callback = arguments[arguments.length - 1]; window.testsEqualArray = []; var pc1 = new RTCPeerConnection(null); // Test expected new behavior. new Promise(function(resolve, reject) { pc1.getStats(null, resolve, reject); }) .then(function(report) { window.testsEqualArray.push([typeof report, 'object', 'report is an object.']); report.forEach((stat, key) => { window.testsEqualArray.push([stat.id, key, 'report key matches stats id.']); }); return report; }) .then(function(report) { // Test legacy behavior for (var key in report) { // This avoids problems with Firefox if (typeof report[key] === 'function') { continue; } window.testsEqualArray.push([report[key].id, key, 'legacy report key matches stats id.']); } callback(null); }) .catch(function(err) { callback('getStats() should never fail: ' + err); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(error) { var getStatsResult = (error) ? 'error: ' + error.toString() : 'no errors'; t.ok(!error, 'GetStats result: ' + getStatsResult); return driver.wait(function() { return driver.executeScript('return window.testsEqualArray'); }); }) .then(function(testsEqualArray) { testsEqualArray.forEach(function(resultEq) { // resultEq contains an array of test data, // test condition that should be equal and a success message. // resultEq[0] = typeof report. // resultEq[1] = test condition. // resultEq[0] = Success message. t.equal(resultEq[0], resultEq[1], resultEq[2]); }); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); // Test that polyfill for Chrome getStats falls back to builtin functionality // when the old getStats function signature is used; when the callback is passed // as the first argument. // FIXME: Implement callbacks for the results as well. test('originalChromeGetStats', function(t) { var driver = seleniumHelpers.buildDriver(); var testDefinition = function() { var callback = arguments[arguments.length - 1]; window.testsEqualArray = []; window.testsNotEqualArray = []; var pc1 = new RTCPeerConnection(null); new Promise(function(resolve, reject) { // jshint ignore: line pc1.getStats(resolve, null); }) .then(function(response) { var reports = response.result(); // TODO: Figure out a way to get inheritance to work properly in // webdriver. report.names() is just an empty object when returned to // webdriver. reports.forEach(function(report) { window.testsEqualArray.push([typeof report, 'object', 'report is an object']); window.testsEqualArray.push([typeof report.id, 'string', 'report.id is a string']); window.testsEqualArray.push([typeof report.type, 'string', 'report.type is a string']); window.testsEqualArray.push([typeof report.timestamp, 'object', 'report.timestamp is an object']); report.names().forEach(function(name) { window.testsNotEqualArray.push([report.stat(name), null, 'stat ' + name + ' not equal to null']); }); }); callback(null); }) .catch(function(error) { callback('getStats() should never fail: ' + error); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.pass('Page loaded'); return driver.executeScript('return adapter.browserDetails.browser') .then(function(browser) { if (browser !== 'chrome') { t.skip('Non-chrome browser detected.'); throw 'skip-test'; } }); }) .then(function() { return driver.executeAsyncScript(testDefinition); }) .then(function(error) { var getStatsResult = (error) ? 'error: ' + error.toString() : 'no errors'; t.ok(!error, 'GetStats result: ' + getStatsResult); return driver.wait(function() { return driver.executeScript('return window.testsEqualArray'); }); }) .then(function(testsEqualArray) { driver.executeScript('return window.testsNotEqualArray') .then(function(testsNotEqualArray) { testsEqualArray.forEach(function(resultEq) { // resultEq contains an array of test data, // test condition that should be equal and a success message. // resultEq[0] = typeof report. // resultEq[1] = test condition. // resultEq[0] = Success message. t.equal(resultEq[0], resultEq[1], resultEq[2]); }); testsNotEqualArray.forEach(function(resultNoEq) { // resultNoEq contains an array of test data, // test condition that should not be equal and a success message. // resultNoEq[0] = typeof report. // resultNoEq[1] = test condition. // resultNoEq[0] = Success message. t.notEqual(resultNoEq[0], resultNoEq[1], resultNoEq[2]); }); }); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('getStats promise', function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; var testsEqualArray = []; var pc1 = new RTCPeerConnection(null); pc1.getStats(null) .then(function(report) { testsEqualArray.push([typeof report, 'object', 'getStats with no selector returns a Promise']); // Firefox does not like getStats without any arguments, therefore we call // the callback before the next getStats call. // FIXME: Remove this if ever supported by Firefox, also remove the t.skip // section towards the end of the // Run test section. if (window.adapter.browserDetails.browser === 'firefox') { callback(testsEqualArray); return; } pc1.getStats() .then(function(reportWithoutArg) { testsEqualArray.push([typeof reportWithoutArg, 'object', 'getStats with no arguments returns a Promise']); callback(testsEqualArray); }) .catch(function(err) { callback(err); }); }) .catch(function(err) { callback(err); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(callback) { // If the callback contains a stackTrace property it's an error, else an // array of tests results. if (callback.stackTrace) { throw callback.message; } return callback; }) .then(function(testsEqualArray) { testsEqualArray.forEach(function(resultEq) { // resultEq contains an array of test data, // test condition that should be equal and a success message. // resultEq[0] = typeof report. // resultEq[1] = test condition. // resultEq[0] = Success message. t.equal(resultEq[0], resultEq[1], resultEq[2]); }); // FIXME: Remove if supported by firefox. Also remove browser check in // the testDefinition function. return driver.executeScript( 'return adapter.browserDetails.browser === \'firefox\'') .then(function(isFirefox) { if (isFirefox) { t.skip('Firefox does not support getStats without arguments.'); } }); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); // iceTransportPolicy is renamed to iceTransports in Chrome by // adapter, this tests that when not setting any TURN server, // no candidates are generated. test('iceTransportPolicy relay functionality', {skip: process.env.BROWSER !== 'chrome'}, function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; window.candidates = []; var pc1 = new RTCPeerConnection({iceTransportPolicy: 'relay', iceServers: []}); // Since we try to gather only relay candidates without specifying // a TURN server, we should not get any candidates. pc1.onicecandidate = function(event) { if (event.candidate) { window.candidates.push([event.candidate]); callback(new Error('Candidate found'), event.candidate); } else { callback(null); } }; var constraints = {video: true, fake: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { pc1.addStream(stream); pc1.createOffer().then(function(offer) { return pc1.setLocalDescription(offer); }) .catch(function(error) { callback(error); }); }) .catch(function(error) { callback(error); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.pass('Page loaded'); return driver.executeAsyncScript(testDefinition); }) .then(function(error) { var errorMessage = (error) ? 'error: ' + error.toString() : 'no errors'; t.ok(!error, 'Result: ' + errorMessage); // We should not really need this due to using an error callback if a // candidate is found but I'm not sure we will catch due to async nature // of this, hence why this is kept. return driver.executeScript('return window.candidates'); }) .then(function(candidates) { if (candidates.length === 0) { t.pass('No candidates generated'); } else { candidates.forEach(function(candidate) { t.fail('Candidate found: ' + candidate); }); } }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('icegatheringstatechange event', {skip: process.env.BROWSER !== 'MicrosoftEdge'}, function(t) { var driver = seleniumHelpers.buildDriver(); // Define test. var testDefinition = function() { var callback = arguments[arguments.length - 1]; var pc1 = new RTCPeerConnection(); pc1.onicegatheringstatechange = function(event) { if (pc1.iceGatheringState === 'complete') { callback(); } }; var constraints = {video: true, fake: true}; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { pc1.addStream(stream); pc1.createOffer().then(function(offer) { return pc1.setLocalDescription(offer); }); }); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { return driver.executeAsyncScript(testDefinition); }) .then(function() { t.pass('gatheringstatechange fired and is \'complete\''); t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); test('static generateCertificate method', function(t) { var driver = seleniumHelpers.buildDriver(); // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.plan(2); t.pass('Page loaded'); }) .then(function() { return driver.executeScript(function() { return (window.adapter.browserDetails.browser === 'chrome' && window.adapter.browserDetails.version >= 49) || (window.adapter.browserDetails.browser === 'firefox' && window.adapter.browserDetails.version > 38); }); }) .then(function(isSupported) { if (!isSupported) { t.skip('generateCertificate not supported on < Chrome 49'); throw 'skip-test'; } return driver.executeScript( 'return typeof RTCPeerConnection.generateCertificate === \'function\''); }) .then(function(hasGenerateCertificateMethod) { t.ok(hasGenerateCertificateMethod, 'RTCPeerConnection has generateCertificate method'); }) .then(function() { t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); }); // This MUST to be the last test since it loads adapter // again which may result in unintended behaviour. test('Non-module logging to console still works', function(t) { var driver = seleniumHelpers.buildDriver(); var testDefinition = function() { window.testsEqualArray = []; window.logCount = 0; var saveConsole = console.log.bind(console); console.log = function() { window.logCount++; }; console.log('log me'); console.log = saveConsole; // Check for existence of variables and functions from public API. window.testsEqualArray.push([typeof RTCPeerConnection,'function', 'RTCPeerConnection is a function']); window.testsEqualArray.push([typeof navigator.getUserMedia, 'function', 'getUserMedia is a function']); window.testsEqualArray.push([typeof window.adapter.browserDetails.browser, 'string', 'browserDetails.browser browser is a string']); window.testsEqualArray.push([typeof window.adapter.browserDetails.version, 'number', 'browserDetails.version is a number']); }; // Run test. seleniumHelpers.loadTestPage(driver) .then(function() { t.pass('Page loaded'); return driver.executeScript(testDefinition); }) .then(function() { return driver.executeScript('return window.testsEqualArray'); }) .then(function(testsEqualArray) { testsEqualArray.forEach(function(resultEq) { // resultEq contains an array of test data, // test condition that should be equal and a success message. // resultEq[0] = typeof report. // resultEq[1] = test condition. // resultEq[0] = Success message. t.equal(resultEq[0], resultEq[1], resultEq[2]); }); }) .then(function() { return driver.executeScript('return window.logCount'); }) .then(function(logCount) { t.ok(logCount > 0, 'A log message appeared on the console.'); t.end(); }) .then(null, function(err) { if (err !== 'skip-test') { t.fail(err); } t.end(); }); });