From: Ċ½eljko Filipin Date: Fri, 30 Mar 2018 16:42:04 +0000 (+0200) Subject: Selenium: record video of every test X-Git-Tag: 1.34.0-rc.0~3755^2 X-Git-Url: http://git.cyclocoop.org/%7D%7Cconcat%7B?a=commitdiff_plain;h=0513250c882457baf3a1e96e1f0b5a7bad5965fe;p=lhc%2Fweb%2Fwiklou.git 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 --- diff --git a/tests/selenium/README.md b/tests/selenium/README.md index a7c9aa6c3c..038b75729e 100644 --- a/tests/selenium/README.md +++ b/tests/selenium/README.md @@ -20,8 +20,26 @@ If using MediaWiki-Vagrant: npm run selenium -By default, Chrome will run in headless mode. If you want to see Chrome, set DISPLAY -environment variable to any value: +There are three supported modes of running the tests: + +- Headless. It's the default. You will not see the browser while tests are + running because it's running in a headless mode. This mode should run fine + on all supported platforms. +- Headless recording. Set DISPLAY environment variable to a value that starts + with colon (`:`) and video of each test will be recorded. Browser will run + headless. Recording videos works only on Linux. +- Visible. If you want to see the browser, set DISPLAY environment variable to + any value that does not start with colon. This mode will not work in a + headless environment like MediaWiki-Vagrant. + +Example recording session: + + sudo apt-get install chromedriver ffmpeg xvfb + export DISPLAY=:94 + Xvfb "$DISPLAY" -screen 0 1280x1024x24 & + npm run selenium + +Example visible session: DISPLAY=1 npm run selenium diff --git a/tests/selenium/wdio.conf.js b/tests/selenium/wdio.conf.js index 8b47dff076..916ee74205 100644 --- a/tests/selenium/wdio.conf.js +++ b/tests/selenium/wdio.conf.js @@ -1,8 +1,20 @@ const fs = require( 'fs' ), path = require( 'path' ), - saveScreenshot = require( 'wdio-mediawiki' ).saveScreenshot, - logPath = process.env.LOG_DIR || __dirname + '/log'; + 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 ); } @@ -135,16 +147,57 @@ exports.config = { // ===== // 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 ) { - var filePath; - if ( !test.passed ) { - filePath = saveScreenshot( test.title ); - console.log( '\n\tScreenshot: ' + filePath + '\n' ); + 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' ); } };