Skip to content

Commit 7e3f809

Browse files
committed
feat(tooling): firefox compatibility for journey tests
1 parent 484d0c5 commit 7e3f809

File tree

14 files changed

+307
-51
lines changed

14 files changed

+307
-51
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ package-lock.json
88
npm-debug*
99
packages/**/es/*
1010
packages/**/cjs/*
11+
.tmp/*

package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@ciscospark/react-ciscospark",
3-
"version": "0.1.209",
3+
"version": "0.1.211",
44
"description": "The Cisco Spark for React library allows developers to easily incorporate Spark functionality into an application.",
55
"scripts": {
66
"build": "./scripts/build/index.js",
@@ -71,6 +71,9 @@
7171
"core-decorators": "^0.20.0",
7272
"custom-event-polyfill": "^0.3.0",
7373
"file-saver": "^1.3.3",
74+
"firefox-profile": "^1.0.0",
75+
"fs-promise": "^2.0.2",
76+
"glob": "^7.1.1",
7477
"highlight.js": "^9.12.0",
7578
"howler": "^2.0.2",
7679
"immutable": "^3.8.1",
@@ -167,10 +170,11 @@
167170
"stylelint-config-standard": "^17.0",
168171
"stylelint-order": "^0.7.0",
169172
"wdio-dot-reporter": "0.0.9",
173+
"wdio-firefox-profile-service": "^0.1.0",
170174
"wdio-junit-reporter": "^0.3.1",
171175
"wdio-mocha-framework": "^0.5.9",
172-
"wdio-sauce-service": "^0.4.0",
173-
"wdio-selenium-standalone-service": "0.0.8",
176+
"wdio-sauce-service": "^0.4.6",
177+
"wdio-selenium-standalone-service": "0.0.9",
174178
"wdio-spec-reporter": "^0.1.0",
175179
"wdio-static-server-service": "^1.0.1",
176180
"webdriverio": "4.9.11",

scripts/tests/async.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const denodeify = require('denodeify');
2+
3+
exports.rimraf = denodeify(require('rimraf'));
4+
exports.glob = denodeify(require('glob'));
5+
exports.mkdirp = denodeify(require('mkdirp'));
6+
exports.transformFile = denodeify(require('babel-core').transformFile);
7+
exports.exec = denodeify(require('child_process').exec);

scripts/tests/openh264.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*!
2+
* Copyright (c) 2015-2017 Cisco Systems, Inc. See LICENSE file.
3+
*/
4+
const path = require('path');
5+
6+
const denodeify = require('denodeify');
7+
const FirefoxProfile = require('firefox-profile');
8+
const {stat} = require('fs-promise');
9+
10+
const spawn = require('../utils/spawn');
11+
12+
const {rimraf} = require('./async');
13+
14+
const PROFILE_DIR = './.tmp/selenium';
15+
16+
const copy = denodeify(FirefoxProfile.copy);
17+
/**
18+
* denodeifies FirefoxProfile.encode
19+
* @param {FirefoxProfile} fp
20+
* @returns {Promise<string>}
21+
*/
22+
function encode(fp) {
23+
return new Promise((resolve, reject) => {
24+
fp.encode((err, encoded) => {
25+
if (err) {
26+
reject(err);
27+
return;
28+
}
29+
resolve(encoded);
30+
});
31+
});
32+
}
33+
34+
/**
35+
* Determines the switchabale platform name from a sauce definition or the
36+
* output of os.platform()
37+
* @param {string} platform
38+
* @returns {string}
39+
*/
40+
function platformToShortName(platform) {
41+
if (platform.toLowerCase().includes('os x') || platform === 'darwin') {
42+
return 'mac';
43+
}
44+
45+
return undefined;
46+
}
47+
48+
/**
49+
* Injects a gzipped, base64-encoded firefox profile directory into a firefox browser definition
50+
* @param {Object} def
51+
* @returns {Promise}
52+
*/
53+
async function injectProfile(def) {
54+
if (def.browserName.toLowerCase().includes('firefox')) {
55+
const platform = platformToShortName(def.platform);
56+
if (platform !== 'mac') {
57+
throw new Error(`No tooling implemented for injecting h264 into ${platform} (${def.platform})`);
58+
}
59+
60+
const dir = path.resolve(process.cwd(), `${PROFILE_DIR}/${platform}`);
61+
const profile = await copy(dir);
62+
const encoded = await encode(profile);
63+
// eslint-disable-next-line
64+
def.firefox_profile = encoded;
65+
}
66+
}
67+
68+
/**
69+
* Determines if a given file/directory already exists
70+
* @param {string} dir
71+
* @returns {Promise<boolean>}
72+
*/
73+
async function exists(dir) {
74+
try {
75+
const s = await stat(dir);
76+
return s.isDirectory();
77+
}
78+
catch (err) {
79+
return false;
80+
}
81+
}
82+
83+
exports.download = async function download() {
84+
await rimraf(`${PROFILE_DIR}/mac`);
85+
await spawn(`${__dirname}/openh264.sh`, []);
86+
};
87+
88+
exports.inject = async function inject(browsers) {
89+
if (!await exists(`${PROFILE_DIR}/mac`)) {
90+
await exports.download();
91+
}
92+
93+
for (const key of Object.keys(browsers)) {
94+
const def = browsers[key];
95+
// eslint-disable-next-line no-await-in-loop
96+
await injectProfile(def);
97+
}
98+
};
99+

scripts/tests/openh264.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
3+
MOZ_GMP_PATH=./.tmp/selenium/mac/gmp-gmpopenh264/1.6
4+
5+
curl -O http://ciscobinary.openh264.org/libopenh264-1.6.0-osx64.dylib.bz2
6+
bzip2 -d libopenh264-1.6.0-osx64.dylib.bz2
7+
mkdir -p "${MOZ_GMP_PATH}"
8+
mv libopenh264-1.6.0-osx64.dylib "${MOZ_GMP_PATH}/libgmpopenh264.dylib"
9+
echo 'Name: gmpopenh264' > "${MOZ_GMP_PATH}/gmpopenh264.info"
10+
echo 'Description: GMP Plugin for OpenH264.' >> "${MOZ_GMP_PATH}/gmpopenh264.info"
11+
echo 'Version: 1.6' >> "${MOZ_GMP_PATH}/gmpopenh264.info"
12+
echo 'APIs: encode-video[h264], decode-video[h264]' >> "${MOZ_GMP_PATH}/gmpopenh264.info"
13+
echo 'user_pref("media.gmp-gmpopenh264.abi", "x86_64-gcc3");' >> "./.tmp/selenium/mac/user.js"
14+
echo 'user_pref("media.gmp-gmpopenh264.lastUpdate", 1494528046);' >> "./.tmp/selenium/mac/user.js"
15+
echo 'user_pref("media.gmp-gmpopenh264.version", "1.6");' >> "./.tmp/selenium/mac/user.js"
16+
echo 'user_pref("media.gmp-manager.buildID", "20170504105526");' >> "./.tmp/selenium/mac/user.js"
17+
echo 'user_pref("media.gmp-manager.lastCheck", 1494528044);' >> "./.tmp/selenium/mac/user.js"
18+
echo 'user_pref("media.gmp-provider.enabled", true);' >> "./.tmp/selenium/mac/user.js"
19+
echo 'user_pref("media.gmp-widevinecdm.abi", "x86_64-gcc3");' >> "./.tmp/selenium/mac/user.js"
20+
echo 'user_pref("media.gmp-widevinecdm.lastUpdate", 1494528048);' >> "./.tmp/selenium/mac/user.js"
21+
echo 'user_pref("media.gmp-widevinecdm.version", "1.4.8.903");' >> "./.tmp/selenium/mac/user.js"
22+
echo 'user_pref("media.gmp.storage.version.observed", 1);' >> "./.tmp/selenium/mac/user.js"
23+
echo 'user_pref("media.peerconnection.video.h264_enabled", true);' >> "./.tmp/selenium/mac/user.js"
24+
echo 'user_pref("dom.webnotifications.enabled", false);' >> "./.tmp/selenium/mac/user.js"
25+
echo 'user_pref("media.navigator.streams.fake", true);' >> "./.tmp/selenium/mac/user.js"

scripts/utils/spawn.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
const cp = require('child_process');
2+
3+
module.exports = function spawn(cmd, args, options) {
4+
return new Promise((resolve, reject) => {
5+
if (!cmd) {
6+
return reject(new Error('`cmd` is required'));
7+
}
8+
9+
options = Object.assign({detached: false}, options);
10+
11+
const child = cp.spawn(cmd, args, Object.assign({stdio: 'inherit'}, options));
12+
13+
let data = '';
14+
if (child.stderr) {
15+
child.stderr.on('data', (d) => {
16+
data += d;
17+
});
18+
}
19+
20+
child.on('close', (code) => {
21+
if (code) {
22+
const e = new Error(code);
23+
e.data = data;
24+
return reject(e);
25+
}
26+
return resolve();
27+
});
28+
29+
if (options && options.detached) {
30+
child.unref();
31+
/* eslint no-param-reassign: [0] */
32+
options.child = child;
33+
}
34+
35+
return null;
36+
});
37+
};
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import uuid from 'uuid';
2+
3+
/**
4+
* Move mouse a specified amount of pixels
5+
* Origin is set to the element that matches the selector passed
6+
* Mouse is then moved from the origin by the x and y offset
7+
* @param {Object} aBrowser
8+
* @param {string} selector
9+
* @param {integer} [x=100]
10+
* @param {integer} [y=100]
11+
* @returns {void}
12+
*/
13+
// eslint-disable-next-line import/prefer-default-export
14+
export function moveMouse(aBrowser, selector, x = 100, y = 100) {
15+
const element = aBrowser.element(selector);
16+
if (aBrowser.desiredCapabilities.browserName.toLowerCase().includes('firefox')) {
17+
aBrowser.actions([{
18+
type: 'pointer',
19+
id: `mouse-${uuid.v4()}`,
20+
parameters: {pointerType: 'mouse'},
21+
actions: [
22+
{
23+
type: 'pointerMove', element: element.value, duration: 0, x, y
24+
}
25+
]
26+
}]);
27+
}
28+
else {
29+
aBrowser.moveToObject(selector);
30+
}
31+
}

test/journeys/lib/test-helpers/space-widget/meet.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,13 @@ export const elements = {
1818
callControls: '.call-controls',
1919
remoteVideo: '.remote-video video'
2020
};
21-
22-
2321
/**
2422
* @typedef {object} TestObject
2523
* @param {object} browser - browser for test
2624
* @param {object} user - user object for test
2725
* @param {object} displayName - name used to identify test object
2826
*/
2927

30-
3128
/**
3229
* Answers call on specified browser
3330
* @param {Object} aBrowser
@@ -48,7 +45,6 @@ export function answer(aBrowser) {
4845
* @returns {void}
4946
*/
5047
export function call(caller, reciever) {
51-
caller.moveToObject(elements.meetWidget);
5248
caller.element(elements.meetWidget).element(elements.callButton).waitForVisible();
5349
caller.element(elements.meetWidget).element(elements.callButton).click();
5450
// wait for call to establish
@@ -72,8 +68,8 @@ export function decline(aBrowser) {
7268
*/
7369
export function hangup(aBrowser) {
7470
// Call controls currently has a hover state
75-
aBrowser.moveToObject(elements.meetWidget);
7671
aBrowser.waitForVisible(elements.callControls);
72+
aBrowser.element(elements.meetWidget).element(elements.hangupButton).waitForVisible();
7773
aBrowser.element(elements.meetWidget).element(elements.hangupButton).click();
7874
}
7975

test/journeys/specs/multiple/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import CiscoSpark from '@ciscospark/spark-core';
77
import testUsers from '@ciscospark/test-helper-test-users';
88

99
import waitForPromise from '../../lib/wait-for-promise';
10+
import {moveMouse} from '../../lib/test-helpers/index';
1011
import {elements as spaceElements} from '../../lib/test-helpers/space-widget/main';
1112
import {sendMessage, verifyMessageReceipt} from '../../lib/test-helpers/space-widget/messaging';
1213

@@ -189,7 +190,7 @@ describe('Multiple widgets on a page', () => {
189190

190191
it('displays a call button on hover', () => {
191192
displayIncomingMessage(browserLocal, lorraine, oneOnOneConversation, 'Can you call me?', true);
192-
browserLocal.moveToObject(recentsElements.firstSpace);
193+
moveMouse(browserLocal, recentsElements.firstSpace, 10, 10);
193194
browserLocal.waitUntil(() =>
194195
browserLocal.element(`${recentsElements.callButton}`).isVisible(),
195196
1500,

test/journeys/specs/oneOnOne/dataApi/startup-settings.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import testUsers from '@ciscospark/test-helper-test-users';
22

3+
import {moveMouse} from '../../../lib/test-helpers/index.js';
34
import {elements} from '../../../lib/test-helpers/space-widget/main.js';
4-
import {answer, hangup} from '../../../lib/test-helpers/space-widget/meet.js';
5+
import {answer, hangup, elements as meetElements} from '../../../lib/test-helpers/space-widget/meet.js';
56

67
describe('Widget Space: One on One', () => {
78
describe('Data API Settings', () => {
@@ -122,6 +123,7 @@ describe('Widget Space: One on One', () => {
122123

123124
it('starts call when set to true', () => {
124125
answer(browserRemote);
126+
moveMouse(browserLocal, meetElements.callContainer);
125127
hangup(browserLocal);
126128
});
127129

0 commit comments

Comments
 (0)