diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..932115e --- /dev/null +++ b/.eslintrc @@ -0,0 +1,46 @@ +{ + "rules": { + "array-bracket-spacing": 2, + "block-spacing": [2, "never"], + "brace-style": [2, "1tbs", { "allowSingleLine": false }], + "camelcase": [2, {"properties": "always"}], + "curly": 2, + "default-case": 2, + "dot-notation": 2, + "eqeqeq": 2, + "indent": [ + 2, + 2, + {"SwitchCase": 1} + ], + "key-spacing": [2, {"beforeColon": false, "afterColon": true}], + "max-len": [2, 80, 2, {"ignoreUrls": true}], + "new-cap": 2, + "no-console": 0, + "no-else-return": 2, + "no-eval": 2, + "no-multi-spaces": 2, + "no-multiple-empty-lines": [2, {"max": 2}], + "no-shadow": 2, + "no-trailing-spaces": 2, + "no-unused-expressions": 2, + "no-unused-vars": [2, {"args": "none"}], + "object-curly-spacing": [2, "never"], + "padded-blocks": [2, "never"], + "quotes": [ + 2, + "single" + ], + "semi": [ + 2, + "always" + ], + "space-after-keywords": 2, + "space-before-blocks": 2, + "space-before-function-paren": [2, "never"], + "spaced-comment": 2, + "valid-typeof": 2 + }, + "extends": "eslint:recommended", + "globals": {} +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f63d68 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +node_modules/ +*~ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b2be627 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +sudo: false +language: node_js +node_js: +- 4.1 + +script: + - npm install + - grunt diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..9f4c3fe --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,28 @@ +'use strict'; + +/* globals module */ + +module.exports = function(grunt) { + // configure project + grunt.initConfig({ + // make node configurations available + pkg: grunt.file.readJSON('package.json'), + eslint: { + options: { + configFile: '.eslintrc' + }, + target: ['src/**/*.js', 'main.js'] + }, + githooks: { + all: { + 'pre-commit': 'eslint' + } + } + }); + // enable plugins + grunt.loadNpmTasks('grunt-eslint'); + grunt.loadNpmTasks('grunt-githooks'); + + // set default tasks to run when grunt is called without parameters + grunt.registerTask('default', ['eslint']); +}; diff --git a/README.md b/README.md index 6442703..0b3b439 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,19 @@ -# utilities +# WebRTC utilities # Contains shared utilities, support tools and frameworks for the other WebRTC sub repositories. + +## Install using npm ## +´´´ +npm install webrtc-utilities --save-dev +´´´ + +## SeleniumLib ## +src/selenium-lib.js contains all that is needed to build a selenium webdriver driver for Chrome and Firefox (whatever is set in the env $BROWSER variable). +It is used using require() in node. + +## run-tests ## +A bash shell script that helps travis-multirunner to download and install Chrome and Firefox browser from stable, beta and unstable channels. + +## Development ## +Add new utilities under the src folder and add them to the main.js file in the project root with the appropriate module.export set. + +Detailed information on developing in the [webrtc](https://github.com/webrtc) github repositories can be found in the [WebRTC GitHub repo developer's guide](https://docs.google.com/document/d/1tn1t6LW2ffzGuYTK3366w1fhTkkzsSvHsBnOHoDfRzY/edit?pli=1#heading=h.e3366rrgmkdk). diff --git a/main.js b/main.js new file mode 100644 index 0000000..a6b9e54 --- /dev/null +++ b/main.js @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2016 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'; + +// Add all modules to be exported here. +var seleniumLib = require('./src/selenium/selenium-lib.js'); + +module.export = { + seleniumLib: seleniumLib +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..f849479 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "webrtc-utilities", + "version": "0.0.1", + "author": "The WebRTC project authors (https://www.webrtc.org/)", + "description": "WebRTC test framework utilities.", + "license": "BSD-3-Clause", + "main": "main.js", + "repository": { + "type": "git", + "url": "https://github.com/webrtc/utilities.git" + }, + "dependencies": { + "chromedriver": "^2.16.0", + "selenium-webdriver": "^2.48.0", + "tape": "^4.0.0", + "testling": "^1.7.1", + "travis-multirunner": "^3.0.0" + }, + "scripts": { + "postinstall": "grunt githooks" + }, + "devDependencies": { + "grunt": "^0.4.5", + "grunt-cli": ">=0.1.9", + "grunt-eslint": "^17.2.0", + "grunt-githooks": "^0.3.1" + } +} diff --git a/src/selenium/run-tests b/src/selenium/run-tests new file mode 100755 index 0000000..ebfce09 --- /dev/null +++ b/src/selenium/run-tests @@ -0,0 +1,16 @@ +#!/bin/sh +# +# Run testling with a default set of parameters +# +BINDIR=./browsers/bin +export BROWSER=${BROWSER-chrome} +export BVER=${BVER-stable} +BROWSERBIN=$BINDIR/$BROWSER-$BVER +if [ ! -x $BROWSERBIN ]; then + echo "Installing browser" + ./node_modules/travis-multirunner/setup.sh +fi +echo "Starting browser" +PATH=$PATH:./node_modules/.bin + +node test/run-tests.js diff --git a/src/selenium/selenium-lib.js b/src/selenium/selenium-lib.js new file mode 100644 index 0000000..cd131ad --- /dev/null +++ b/src/selenium/selenium-lib.js @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016 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'; + +// https://code.google.com/p/selenium/wiki/WebDriverJs +var webdriver = require('selenium-webdriver'); +var chrome = require('selenium-webdriver/chrome'); +var firefox = require('selenium-webdriver/firefox'); +var fs = require('fs'); + +var sharedDriver = null; + +function getBrowserVersion() { + var browser = process.env.BROWSER; + var browserChannel = process.env.BVER; + var symlink = './browsers/bin/' + browser + '-' + browserChannel + '/'; + var symPath = fs.readlink(symlink); + + // Browser reg expressions and position to look for the milestone version. + var chromeExp = '/Chrom(e|ium)\/([0-9]+)\./'; + var firefoxExp = '/Firefox\/([0-9]+)\./'; + var chromePos = 2; + var firefoxPos = 1; + + var browserVersion = function(path, expr, pos) { + var match = path.match(expr); + return match && match.length >= pos && parseInt(match[pos], 10); + }; + + switch (browser) { + case 'chrome': + return browserVersion(symPath, chromeExp, chromePos); + case 'firefox': + return browserVersion(symPath, firefoxExp, firefoxPos); + default: + return 'non supported browser.'; + } +} + +function buildDriver() { + if (sharedDriver) { + return sharedDriver; + } + // Firefox options. + // http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_firefox.html + var profile = new firefox.Profile(); + profile.setPreference('media.navigator.streams.fake', true); + // This enables device labels for enumerateDevices when using fake devices. + profile.setPreference('media.navigator.permission.disabled', true); + // Currently the FF webdriver extension is not signed and FF 41 no longer + // allows unsigned extensions by default. + // TODO: Remove this once FF no longer allow turning this off and the + // selenium team starts making a signed FF webdriver extension. + // https://github.com/SeleniumHQ/selenium/issues/901. + profile.setPreference('xpinstall.signatures.required', false); + + var firefoxOptions = new firefox.Options() + .setProfile(profile) + .setBinary('node_modules/.bin/start-firefox'); + + // Chrome options. + // http://selenium.googlecode.com/git/docs/api/javascript/module_selenium-webdriver_chrome_class_Options.html#addArguments + var chromeOptions = new chrome.Options() + .setChromeBinaryPath('node_modules/.bin/start-chrome') + .addArguments('allow-file-access-from-files') + .addArguments('use-fake-device-for-media-stream') + .addArguments('use-fake-ui-for-media-stream'); + + // Only enable this for Chrome >= 49. + if (process.env.BROWSER === 'chrome' && getBrowserVersion >= '49') { + chromeOptions.addArguments('--enable-experimental-web-platform-features'); + } + + sharedDriver = new webdriver.Builder() + .forBrowser(process.env.BROWSER) + .setFirefoxOptions(firefoxOptions) + .setChromeOptions(chromeOptions) + .build(); + + // Set global executeAsyncScript() timeout (default is 0) to allow async + // callbacks to be caught in tests. + sharedDriver.manage().timeouts().setScriptTimeout(2000); + + return sharedDriver; +} + +// A helper function to query stats from a PeerConnection. +function getStats(driver, peerConnection) { + // Execute getStats on peerconnection named `peerConnection`. + driver.manage().timeouts().setScriptTimeout(1000); + return driver.executeAsyncScript( + 'var callback = arguments[arguments.length - 1];' + + peerConnection + '.getStats(null).then(function(report) {' + + ' callback(report);' + + '});'); +} + +module.exports = { + buildDriver: buildDriver, + getStats: getStats +};