wiki.techinc.nl/tests/selenium/wdio.conf.js
Željko Filipin 0513250c88 Selenium: record video of every test
In addition to two existing modes (headless and visible), this patch
introcues another mode, headless recording.

If DISPLAY environment variable is not set, Chrome will run in it's
built-in headless mode.
If it is set, and the value starts with colon (`:`), Chrome will
run in headless mode using Xvfb and record video of every test using FFmpeg.
If the value does not start with colon, Chrome will be visible.

Bug: T179188
Change-Id: Ic1723c5f2d57a28201caf6ba7056cb73fb74a957
2018-10-16 22:07:22 +00:00

203 lines
6 KiB
JavaScript

const fs = require( 'fs' ),
path = require( 'path' ),
logPath = process.env.LOG_DIR || path.join( __dirname, '/log' );
let ffmpeg;
// get current test title and clean it, to use it as file name
function fileName( title ) {
return encodeURIComponent( title.replace( /\s+/g, '-' ) );
}
// build file path
function filePath( test, screenshotPath, extension ) {
return path.join( screenshotPath, `${fileName( test.parent )}-${fileName( test.title )}.${extension}` );
}
// relative path
function relPath( foo ) {
return path.resolve( __dirname, '../..', foo );
}
exports.config = {
// ======
// Custom WDIO config specific to MediaWiki
// ======
// Use in a test as `browser.options.<key>`.
// Defaults are for convenience with MediaWiki-Vagrant
// Wiki admin
username: process.env.MEDIAWIKI_USER || 'Admin',
password: process.env.MEDIAWIKI_PASSWORD || 'vagrant',
// Base for browser.url() and Page#openTitle()
baseUrl: ( process.env.MW_SERVER || 'http://127.0.0.1:8080' ) + (
process.env.MW_SCRIPT_PATH || '/w'
),
// ======
// Sauce Labs
// ======
// See http://webdriver.io/guide/services/sauce.html
// and https://docs.saucelabs.com/reference/platforms-configurator
services: [ 'sauce' ],
user: process.env.SAUCE_USERNAME,
key: process.env.SAUCE_ACCESS_KEY,
// Default timeout in milliseconds for Selenium Grid requests
connectionRetryTimeout: 90 * 1000,
// Default request retries count
connectionRetryCount: 3,
// ==================
// Test Files
// ==================
specs: [
relPath( './tests/selenium/wdio-mediawiki/specs/*.js' ),
relPath( './tests/selenium/specs/**/*.js' ),
relPath( './extensions/*/tests/selenium/specs/**/*.js' ),
relPath( './extensions/VisualEditor/modules/ve-mw/tests/selenium/specs/**/*.js' ),
relPath( './extensions/Wikibase/repo/tests/selenium/specs/**/*.js' ),
relPath( './skins/*/tests/selenium/specs/**/*.js' )
],
// Patterns to exclude
exclude: [
relPath( './extensions/CirrusSearch/tests/selenium/specs/**/*.js' )
],
// ============
// Capabilities
// ============
// How many instances of the same capability (browser) may be started at the same time.
maxInstances: 1,
capabilities: [ {
// For Chrome/Chromium https://sites.google.com/a/chromium.org/chromedriver/capabilities
browserName: 'chrome',
maxInstances: 1,
chromeOptions: {
// If DISPLAY is set, assume developer asked non-headless or CI with Xvfb.
// Otherwise, use --headless (added in Chrome 59)
// https://chromium.googlesource.com/chromium/src/+/59.0.3030.0/headless/README.md
args: [
...( process.env.DISPLAY ? [] : [ '--headless' ] ),
// Chrome sandbox does not work in Docker
...( fs.existsSync( '/.dockerenv' ) ? [ '--no-sandbox' ] : [] )
]
}
} ],
// ===================
// Test Configurations
// ===================
// Enabling synchronous mode (via the wdio-sync package), means specs don't have to
// use Promise#then() or await for browser commands, such as like `brower.element()`.
// Instead, it will automatically pause JavaScript execution until th command finishes.
//
// For non-browser commands (such as MWBot and other promises), this means you
// have to use `browser.call()` to make sure WDIO waits for it before the next
// browser command.
sync: true,
// Level of logging verbosity: silent | verbose | command | data | result | error
logLevel: 'error',
// Enables colors for log output.
coloredLogs: true,
// Warns when a deprecated command is used
deprecationWarnings: true,
// Stop the tests once a certain number of failed tests have been recorded.
// Default is 0 - don't bail, run all tests.
bail: 0,
// Setting this enables automatic screenshots for when a browser command fails
// It is also used by afterTest for capturig failed assertions.
screenshotPath: logPath,
// Default timeout for each waitFor* command.
waitforTimeout: 10 * 1000,
// Framework you want to run your specs with.
// See also: http://webdriver.io/guide/testrunner/frameworks.html
framework: 'mocha',
// Test reporter for stdout.
// See also: http://webdriver.io/guide/testrunner/reporters.html
reporters: [ 'spec', 'junit' ],
reporterOptions: {
junit: {
outputDir: logPath
}
},
// Options to be passed to Mocha.
// See the full list at http://mochajs.org/
mochaOpts: {
ui: 'bdd',
timeout: 60 * 1000
},
// =====
// Hooks
// =====
// See also: http://webdriver.io/guide/testrunner/configurationfile.html
/**
* Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
* @param {Object} test test details
*/
beforeTest: function ( test ) {
if ( process.env.DISPLAY && process.env.DISPLAY.startsWith( ':' ) ) {
let videoPath = filePath( test, this.screenshotPath, 'mp4' );
const { spawn } = require( 'child_process' );
ffmpeg = spawn( 'ffmpeg', [
'-f', 'x11grab', // grab the X11 display
'-video_size', '1280x1024', // video size
'-i', process.env.DISPLAY, // input file url
'-loglevel', 'error', // log only errors
'-y', // overwrite output files without asking
'-pix_fmt', 'yuv420p', // QuickTime Player support, "Use -pix_fmt yuv420p for compatibility with outdated media players"
videoPath // output file
] );
ffmpeg.stdout.on( 'data', ( data ) => {
console.log( `ffmpeg stdout: ${data}` );
} );
ffmpeg.stderr.on( 'data', ( data ) => {
console.log( `ffmpeg stderr: ${data}` );
} );
ffmpeg.on( 'close', ( code ) => {
console.log( '\n\tVideo location:', videoPath, '\n' );
console.log( `ffmpeg exited with code ${code}` );
} );
}
},
/**
* Save a screenshot when test fails.
*
* @param {Object} test Mocha Test object
*/
afterTest: function ( test ) {
if ( ffmpeg ) {
// stop video recording
ffmpeg.kill( 'SIGINT' );
}
// if test passed, ignore, else take and save screenshot
if ( test.passed ) {
return;
}
// save screenshot
let screenshotPath = filePath( test, this.screenshotPath, 'png' );
browser.saveScreenshot( screenshotPath );
console.log( '\n\tScreenshot location:', screenshotPath, '\n' );
}
};