diff --git a/build/.eslintrc.json b/build/.eslintrc.json index 9f2c0a79f0..e5e4859af8 100644 --- a/build/.eslintrc.json +++ b/build/.eslintrc.json @@ -1,9 +1,11 @@ { "root": true, "extends": [ - "../.eslintrc.json", "wikimedia/server" ], + "globals": { + "langs": "readonly" + }, "rules": { "max-len": "off", "mediawiki/valid-package-file-require": "off" diff --git a/build/screenshots-client/.eslintrc.json b/build/screenshots-client/.eslintrc.json new file mode 100644 index 0000000000..e027c09d61 --- /dev/null +++ b/build/screenshots-client/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "root": true, + "extends": [ + "../../.eslintrc.json" + ], + "globals": { + "seleniumUtils": "readonly" + } +} diff --git a/build/screenshots-client/diffs.js b/build/screenshots-client/diffs.js new file mode 100644 index 0000000000..775f672caa --- /dev/null +++ b/build/screenshots-client/diffs.js @@ -0,0 +1,46 @@ +module.exports = { + simple: function () { + var done = arguments[ arguments.length - 1 ]; + + seleniumUtils.runDiffTest( + '

Lorem ipsum

' + + '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

', + '

Lorem ipsum

' + + '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

', + done + ); + }, + moveAndChange: function () { + var done = arguments[ arguments.length - 1 ]; + + seleniumUtils.runDiffTest( + '

Lorem ipsum

' + + '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

' + + '

Maecenas fringilla turpis et nunc bibendum mattis.

', + '

Lorem ipsum

' + + '

Maecenas fringilla turpis et nunc bibendum mattis.

' + + '

Lorem ipsum dolor sit amat, consectetur adipiscing elit.

', + done + ); + }, + linkChange: function () { + var done = arguments[ arguments.length - 1 ]; + + seleniumUtils.runDiffTest( + '

Lorem ipsum

' + + '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

', + '

Lorem ipsum

' + + '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

', + done + ); + }, + listChange: function () { + var done = arguments[ arguments.length - 1 ]; + + seleniumUtils.runDiffTest( + '', + '', + done + ); + } +}; diff --git a/build/screenshots-client/userGuide.js b/build/screenshots-client/userGuide.js new file mode 100644 index 0000000000..0b1bffb5a7 --- /dev/null +++ b/build/screenshots-client/userGuide.js @@ -0,0 +1,205 @@ +/* eslint-disable no-jquery/no-global-selector */ + +module.exports = { + toolbar: function () { + var done = arguments[ arguments.length - 1 ]; + // HACK: The test page is on the help namespace, so overwrite the + // read tab with the nstab-main message. + new mw.Api().loadMessagesIfMissing( [ 'nstab-main' ], { amenableparser: true } ).then( function () { + $( '#ca-nstab-help a' ).text( mw.msg( 'nstab-main' ) ); + done( + seleniumUtils.getBoundingRect( [ + ve.init.target.toolbar.$element[ 0 ], + $( '#p-namespaces' )[ 0 ] + ] ) + ); + } ); + }, + toolbarActions: function () { + var done = arguments[ arguments.length - 1 ]; + done( + seleniumUtils.getBoundingRect( [ + ve.init.target.toolbar.$actions[ 0 ] + ] ) + ); + }, + citoidInspector: function () { + var done = arguments[ arguments.length - 1 ], + surface = ve.init.target.surface; + ve.init.target.toolbar.tools.citoid.onSelect(); + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + surface.$element.find( '.ve-ce-mwReferenceNode' )[ 0 ], + surface.context.inspectors.currentWindow.$element[ 0 ] + ] ) + ); + }, 500 ); + }, + citoidInspectorManual: function () { + var done = arguments[ arguments.length - 1 ], + surface = ve.init.target.surface; + ve.init.target.surface.context.inspectors.currentWindow.setModePanel( 'manual' ); + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + surface.$element.find( '.ve-ce-mwReferenceNode' )[ 0 ], + surface.context.inspectors.currentWindow.$element[ 0 ] + ] ) + ); + } ); + }, + citoidInspectorReuse: function () { + var done = arguments[ arguments.length - 1 ], + surface = ve.init.target.surface; + ve.init.target.surface.context.inspectors.currentWindow.setModePanel( 'reuse' ); + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + surface.$element.find( '.ve-ce-mwReferenceNode' )[ 0 ], + surface.context.inspectors.currentWindow.$element[ 0 ] + ] ) + ); + } ); + }, + toolbarHeadings: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.paragraph ); + }, + toolbarFormatting: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.bold, true ); + }, + toolbarLists: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.bullet ); + }, + toolbarInsert: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.media, true ); + }, + toolbarMedia: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.media, false, true ); + }, + toolbarTemplate: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.transclusion, false, true ); + }, + toolbarTable: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.insertTable, false, true ); + }, + toolbarFormula: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.math, true, true ); + }, + toolbarReferences: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.referencesList, true, true ); + }, + toolbarSettings: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.actionsToolbar.tools.advancedSettings, false, false, + [ ve.init.target.toolbarSaveButton.$element[ 0 ] ] + ); + }, + toolbarPageSettings: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.actionsToolbar.tools.settings, false, true ); + }, + toolbarCategory: function () { + seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.actionsToolbar.tools.categories, false, true ); + }, + save: function () { + var done = arguments[ arguments.length - 1 ]; + ve.init.target.toolbarSaveButton.onSelect(); + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + ve.init.target.surface.dialogs.currentWindow.$frame[ 0 ] + ] ) + ); + }, 500 ); + }, + specialCharacters: function () { + var done = arguments[ arguments.length - 1 ]; + ve.init.target.toolbar.tools.specialCharacter.onSelect(); + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + ve.init.target.toolbar.tools.specialCharacter.$element[ 0 ], + ve.init.target.surface.toolbarDialogs.$element[ 0 ] + ] ) + ); + }, 1000 ); + }, + formula: function () { + var done = arguments[ arguments.length - 1 ], + surface = ve.init.target.surface; + + surface.dialogs.once( 'opening', function ( win, opening ) { + opening.then( function () { + win.previewElement.once( 'render', function () { + win.previewElement.$element.find( 'img' ).on( 'load', function () { + done( + seleniumUtils.getBoundingRect( [ + win.$frame[ 0 ] + ] ) + ); + } ); + } ); + win.input.setValue( 'E = mc^2' ).moveCursorToEnd(); + } ); + } ); + surface.executeCommand( 'mathDialog' ); + }, + referenceList: function () { + var done = arguments[ arguments.length - 1 ], + surface = ve.init.target.surface; + + surface.dialogs.once( 'opening', function ( win, opening ) { + opening.then( function () { + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + win.$frame[ 0 ] + ] ) + ); + }, 500 ); + } ); + } ); + surface.executeCommand( 'referencesList' ); + // The first command inserts a reference list instantly, so run again to open the window + surface.executeCommand( 'referencesList' ); + }, + toolbarCite: function () { + var done = arguments[ arguments.length - 1 ]; + + ve.init.target.$element.css( 'font-size', '250%' ); + // Wait for re-paint + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + ve.init.target.toolbar.tools.citoid.$element[ 0 ] + ] ) + ); + }, 100 ); + }, + linkSearchResults: function () { + var done = arguments[ arguments.length - 1 ], + surface = ve.init.target.surface; + + surface.getModel().getFragment() + // TODO: i18n this message, the linked word, and the API endpoint of the link inspector + .insertContent( 'World literature is literature that is read by many people all over' ) + .collapseToStart().select(); + + surface.context.inspectors.once( 'opening', function ( win, opening ) { + opening.then( function () { + surface.context.inspectors.windows.link.annotationInput.input.requestRequest.then( function () { + // Wait a while for the images to load using a time guesstimate - as they're background + // images it's quite tricky to get load events. + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + surface.$element.find( '.ve-ce-linkAnnotation' )[ 0 ], + surface.context.inspectors.currentWindow.$element[ 0 ] + ] ) + ); + }, 2500 ); + } ); + } ); + } ); + ve.init.target.surface.executeCommand( 'link' ); + } +}; diff --git a/build/screenshots-client/utils.js b/build/screenshots-client/utils.js new file mode 100644 index 0000000000..31a83f67ba --- /dev/null +++ b/build/screenshots-client/utils.js @@ -0,0 +1,122 @@ +module.exports = function () { + var done = arguments[ arguments.length - 1 ]; + + window.seleniumUtils = { + getBoundingRect: function ( elements ) { + var i, l, rect, boundingRect; + for ( i = 0, l = elements.length; i < l; i++ ) { + rect = elements[ i ].getBoundingClientRect(); + if ( !boundingRect ) { + boundingRect = { + left: rect.left, + top: rect.top, + right: rect.right, + bottom: rect.bottom + }; + } else { + boundingRect.left = Math.min( boundingRect.left, rect.left ); + boundingRect.top = Math.min( boundingRect.top, rect.top ); + boundingRect.right = Math.max( boundingRect.right, rect.right ); + boundingRect.bottom = Math.max( boundingRect.bottom, rect.bottom ); + } + } + if ( boundingRect ) { + boundingRect.width = boundingRect.right - boundingRect.left; + boundingRect.height = boundingRect.bottom - boundingRect.top; + } + return boundingRect; + }, + collapseToolbar: function () { + ve.init.target.toolbar.items.forEach( function ( group ) { + if ( group.setActive ) { + group.setActive( false ); + } + } ); + ve.init.target.actionsToolbar.items.forEach( function ( group ) { + if ( group.setActive ) { + group.setActive( false ); + } + } ); + }, + runMenuTask: function ( done, tool, expanded, highlight, extraElements ) { + var toolGroup = tool.toolGroup; + + seleniumUtils.collapseToolbar(); + toolGroup.setActive( true ); + if ( toolGroup.updateCollapsibleState ) { + toolGroup.expanded = !!expanded; + toolGroup.updateCollapsibleState(); + } + + if ( highlight ) { + tool.$link[ 0 ].focus(); + } + + setTimeout( function () { + done( + seleniumUtils.getBoundingRect( [ + toolGroup.$element[ 0 ], + toolGroup.$group[ 0 ] + ].concat( extraElements || [] ) ) + ); + } ); + }, + runDiffTest: function ( oldHtml, newHtml, done ) { + var target = ve.init.target, + surface = target.surface; + + if ( target.saveDialog ) { + target.saveDialog.clearDiff(); + target.saveDialog.close(); + while ( surface.getModel().canUndo() ) { + surface.getModel().undo(); + } + } + + target.originalDmDoc = target.constructor.static.createModelFromDom( target.constructor.static.parseDocument( oldHtml ), 'visual' ); + + surface.getModel().getDocument().getStore().merge( target.originalDmDoc.getStore() ); + + surface.getModel().getLinearFragment( new ve.Range( 0 ) ).insertDocument( + target.constructor.static.createModelFromDom( target.constructor.static.parseDocument( newHtml ), 'visual' ) + ).collapseToEnd().adjustLinearSelection( 0, 3 ).removeContent(); + + target.once( 'saveReview', function () { + setTimeout( function () { + var dialog = surface.dialogs.currentWindow; + dialog.reviewModeButtonSelect.selectItemByData( 'visual' ); + + // Fake parsed edit summary + dialog.$previewEditSummary.text( '(Lorem ipsum)' ); + + done( + seleniumUtils.getBoundingRect( [ + dialog.$frame[ 0 ] + ] ) + ); + }, 500 ); + } ); + surface.execute( 'mwSaveDialog', 'review' ); + } + }; + + // Suppress welcome dialog + mw.storage.set( 've-beta-welcome-dialog', 1 ); + // Suppress user education indicators + mw.storage.set( 've-hideusered', 1 ); + mw.hook( 've.activationComplete' ).add( function () { + var target = ve.init.target, + surfaceView = target.getSurface().getView(); + // Modify the document to make the save button blue + // Wait for focus + surfaceView.once( 'focus', function () { + target.surface.getModel().getFragment().insertContent( ' ' ).collapseToStart().select(); + // Hide edit notices + target.actionsToolbar.tools.notices.getPopup().toggle( false ); + // Wait for save button fade + setTimeout( function () { + done( { width: window.innerWidth, height: window.innerHeight } ); + }, 100 ); + } ); + } ); +}; diff --git a/build/screenshots.diffs.js b/build/screenshots.diffs.js index 2aac6fc2d6..f568ab64c9 100644 --- a/build/screenshots.diffs.js +++ b/build/screenshots.diffs.js @@ -1,121 +1,28 @@ -/* global seleniumUtils, langs */ +const createScreenshotEnvironment = require( './screenshots.js' ).createScreenshotEnvironment, + test = require( 'selenium-webdriver/testing' ), + runScreenshotTest = createScreenshotEnvironment( test ); -( function () { - 'use strict'; - var runScreenshotTest, - createScreenshotEnvironment = require( './screenshots.js' ).createScreenshotEnvironment, - test = require( 'selenium-webdriver/testing' ); +function runTests( lang ) { - runScreenshotTest = createScreenshotEnvironment( test, function () { - var done = arguments[ arguments.length - 1 ]; - - window.seleniumUtils.runDiffTest = function ( oldHtml, newHtml, done ) { - var target = ve.init.target, - surface = target.surface; - - if ( target.saveDialog ) { - target.saveDialog.clearDiff(); - target.saveDialog.close(); - while ( surface.getModel().canUndo() ) { - surface.getModel().undo(); - } - } - - target.originalDmDoc = target.constructor.static.createModelFromDom( target.constructor.static.parseDocument( oldHtml ), 'visual' ); - - surface.getModel().getDocument().getStore().merge( target.originalDmDoc.getStore() ); - - surface.getModel().getLinearFragment( new ve.Range( 0 ) ).insertDocument( - target.constructor.static.createModelFromDom( target.constructor.static.parseDocument( newHtml ), 'visual' ) - ).collapseToEnd().adjustLinearSelection( 0, 3 ).removeContent(); - - target.once( 'saveReview', function () { - setTimeout( function () { - var dialog = surface.dialogs.currentWindow; - dialog.reviewModeButtonSelect.selectItemByData( 'visual' ); - - // Fake parsed edit summary - dialog.$reviewEditSummary.text( '(Lorem ipsum)' ); - - done( - seleniumUtils.getBoundingRect( [ - dialog.$frame[ 0 ] - ] ) - ); - }, 500 ); - } ); - surface.execute( 'mwSaveDialog', 'review' ); - }; - - done(); - } ); - - function runTests( lang ) { - - test.describe( 'Screenshots: ' + lang, function () { - this.lang = lang; - test.it( 'Simple diff', function () { - runScreenshotTest( 'VisualEditor_diff_simple', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - - seleniumUtils.runDiffTest( - '

Lorem ipsum

' + - '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

', - '

Lorem ipsum

' + - '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

', - done - ); - } - ); - runScreenshotTest( 'VisualEditor_diff_move_and_change', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - - seleniumUtils.runDiffTest( - '

Lorem ipsum

' + - '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

' + - '

Maecenas fringilla turpis et nunc bibendum mattis.

', - '

Lorem ipsum

' + - '

Maecenas fringilla turpis et nunc bibendum mattis.

' + - '

Lorem ipsum dolor sit amat, consectetur adipiscing elit.

', - done - ); - } - ); - runScreenshotTest( 'VisualEditor_diff_link_change', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - - seleniumUtils.runDiffTest( - '

Lorem ipsum

' + - '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

', - '

Lorem ipsum

' + - '

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

', - done - ); - } - ); - runScreenshotTest( 'VisualEditor_diff_list_change', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - - seleniumUtils.runDiffTest( - '', - '', - done - ); - } - ); - } ); + test.describe( 'Screenshots: ' + lang, function () { + this.lang = lang; + test.it( 'Simple diff', function () { + runScreenshotTest( 'VisualEditor_diff_simple', lang, + require( './screenshots-client/diffs.js' ).simple + ); + runScreenshotTest( 'VisualEditor_diff_move_and_change', lang, + require( './screenshots-client/diffs.js' ).moveAndChange + ); + runScreenshotTest( 'VisualEditor_diff_link_change', lang, + require( './screenshots-client/diffs.js' ).linkChange + ); + runScreenshotTest( 'VisualEditor_diff_list_change', lang, + require( './screenshots-client/diffs.js' ).listChange + ); } ); - } + } ); +} - for ( let i = 0, l = langs.length; i < l; i++ ) { - runTests( langs[ i ] ); - } -}() ); +for ( let i = 0, l = langs.length; i < l; i++ ) { + runTests( langs[ i ] ); +} diff --git a/build/screenshots.js b/build/screenshots.js index 539fce7fa9..7b8e25e3f4 100644 --- a/build/screenshots.js +++ b/build/screenshots.js @@ -1,197 +1,102 @@ -/* global seleniumUtils */ +const accessKey = process.env.SAUCE_ONDEMAND_ACCESS_KEY, + Builder = require( 'selenium-webdriver' ).Builder, + fs = require( 'fs' ), + Jimp = require( 'jimp' ), + username = process.env.SAUCE_ONDEMAND_USERNAME, + webdriver = require( 'selenium-webdriver' ), + TIMEOUT = 40 * 1000; -/* eslint-disable no-console */ +function createScreenshotEnvironment( test, beforeEach ) { + let clientSize, driver; -( function () { - 'use strict'; - var accessKey = process.env.SAUCE_ONDEMAND_ACCESS_KEY, - Builder = require( 'selenium-webdriver' ).Builder, - fs = require( 'fs' ), - Jimp = require( 'jimp' ), - username = process.env.SAUCE_ONDEMAND_USERNAME, - webdriver = require( 'selenium-webdriver' ), - TIMEOUT = 40 * 1000; + test.beforeEach( function () { + const lang = this.currentTest.parent.lang || 'en'; - function createScreenshotEnvironment( test, beforeEach ) { - var clientSize, driver; + // Use Sauce Labs when running on Jenins + if ( process.env.JENKINS_URL ) { + driver = new webdriver.Builder().withCapabilities( { + browserName: process.env.BROWSER, + platform: process.env.PLATFORM, + username: username, + accessKey: accessKey + } ).usingServer( 'http://' + username + ':' + accessKey + + '@ondemand.saucelabs.com:80/wd/hub' ).build(); + } else { + // If not running on Jenkins, use local browser + driver = new Builder().forBrowser( 'chrome' ).build(); + } - test.beforeEach( function () { - var lang = this.currentTest.parent.lang || 'en'; - - // Use Sauce Labs when running on Jenins - if ( process.env.JENKINS_URL ) { - driver = new webdriver.Builder().withCapabilities( { - browserName: process.env.BROWSER, - platform: process.env.PLATFORM, - username: username, - accessKey: accessKey - } ).usingServer( 'http://' + username + ':' + accessKey + - '@ondemand.saucelabs.com:80/wd/hub' ).build(); - } else { - // If not running on Jenkins, use local browser - driver = new Builder().forBrowser( 'chrome' ).build(); - } + driver.manage().timeouts().setScriptTimeout( TIMEOUT ); + driver.manage().window().setSize( 1200, 1000 ); + driver.get( 'https://en.wikipedia.org/wiki/Help:Sample_page?veaction=edit&uselang=' + lang ); + driver.wait( + driver.executeAsyncScript( + require( './screenshots-client/utils.js' ) + ).then( function ( cs ) { + clientSize = cs; + }, function ( e ) { + // Log error (timeout) + console.error( e.message ); + } ) + ); + if ( beforeEach ) { driver.manage().timeouts().setScriptTimeout( TIMEOUT ); - driver.manage().window().setSize( 1200, 1000 ); - - driver.get( 'https://en.wikipedia.org/wiki/Help:Sample_page?veaction=edit&uselang=' + lang ); driver.wait( - driver.executeAsyncScript( - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - - window.seleniumUtils = { - getBoundingRect: function ( elements ) { - var i, l, rect, boundingRect; - for ( i = 0, l = elements.length; i < l; i++ ) { - rect = elements[ i ].getBoundingClientRect(); - if ( !boundingRect ) { - boundingRect = { - left: rect.left, - top: rect.top, - right: rect.right, - bottom: rect.bottom - }; - } else { - boundingRect.left = Math.min( boundingRect.left, rect.left ); - boundingRect.top = Math.min( boundingRect.top, rect.top ); - boundingRect.right = Math.max( boundingRect.right, rect.right ); - boundingRect.bottom = Math.max( boundingRect.bottom, rect.bottom ); - } - } - if ( boundingRect ) { - boundingRect.width = boundingRect.right - boundingRect.left; - boundingRect.height = boundingRect.bottom - boundingRect.top; - } - return boundingRect; - }, - collapseToolbar: function () { - ve.init.target.toolbar.items.forEach( function ( group ) { - if ( group.setActive ) { - group.setActive( false ); - } - } ); - ve.init.target.actionsToolbar.items.forEach( function ( group ) { - if ( group.setActive ) { - group.setActive( false ); - } - } ); - }, - runMenuTask: function ( done, tool, expanded, highlight, extraElements ) { - var toolGroup = tool.toolGroup; - - seleniumUtils.collapseToolbar(); - toolGroup.setActive( true ); - if ( toolGroup.updateCollapsibleState ) { - toolGroup.expanded = !!expanded; - toolGroup.updateCollapsibleState(); - } - - if ( highlight ) { - tool.$link[ 0 ].focus(); - } - - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - toolGroup.$element[ 0 ], - toolGroup.$group[ 0 ] - ].concat( extraElements || [] ) ) - ); - } ); - } - }; - - // Suppress welcome dialog - mw.storage.set( 've-beta-welcome-dialog', 1 ); - // Suppress user education indicators - mw.storage.set( 've-hideusered', 1 ); - mw.hook( 've.activationComplete' ).add( function () { - var target = ve.init.target, - surfaceView = target.getSurface().getView(); - // Modify the document to make the save button blue - // Wait for focus - surfaceView.once( 'focus', function () { - target.surface.getModel().getFragment().insertContent( ' ' ).collapseToStart().select(); - // Hide edit notices - target.actionsToolbar.tools.notices.getPopup().toggle( false ); - // Wait for save button fade - setTimeout( function () { - done( { width: window.innerWidth, height: window.innerHeight } ); - }, 100 ); - } ); - } ); + driver.executeAsyncScript( beforeEach ).then( + function () {}, + function ( e ) { + // Log error (timeout) + console.error( e.message ); } - ).then( function ( cs ) { - clientSize = cs; - }, function ( e ) { - // Log error (timeout) - console.error( e.message ); - } ) - ); - if ( beforeEach ) { - driver.manage().timeouts().setScriptTimeout( TIMEOUT ); - driver.wait( - driver.executeAsyncScript( beforeEach ).then( - function () {}, - function ( e ) { - // Log error (timeout) - console.error( e.message ); - } - ) - ); - } - } ); - - test.afterEach( function () { - driver.quit(); - } ); - - function cropScreenshot( filename, imageBuffer, rect, padding ) { - var left, top, right, bottom; - - if ( padding === undefined ) { - padding = 5; - } - - left = Math.max( 0, rect.left - padding ); - top = Math.max( 0, rect.top - padding ); - right = Math.min( clientSize.width, rect.left + rect.width + padding ); - bottom = Math.min( clientSize.height, rect.top + rect.height + padding ); - - return Jimp.read( imageBuffer ).then( function ( jimpImage ) { - jimpImage - .crop( left, top, right - left, bottom - top ) - .write( filename ); - } ); - } - - function runScreenshotTest( name, lang, clientScript, padding ) { - var filename = './screenshots/' + name + '-' + lang + '.png'; - - driver.manage().timeouts().setScriptTimeout( TIMEOUT ); - driver.wait( - driver.executeAsyncScript( clientScript ).then( function ( rect ) { - return driver.takeScreenshot().then( function ( base64Image ) { - var imageBuffer; - if ( rect ) { - imageBuffer = Buffer.from( base64Image, 'base64' ); - return cropScreenshot( filename, imageBuffer, rect, padding ); - } else { - fs.writeFile( filename, base64Image, 'base64' ); - } - } ); - }, function ( e ) { - // Log error (timeout) - console.error( e ); - } ) + ) ); } + } ); - return runScreenshotTest; + test.afterEach( function () { + driver.quit(); + } ); + + function cropScreenshot( filename, imageBuffer, rect, padding ) { + if ( padding === undefined ) { + padding = 5; + } + + const left = Math.max( 0, rect.left - padding ); + const top = Math.max( 0, rect.top - padding ); + const right = Math.min( clientSize.width, rect.left + rect.width + padding ); + const bottom = Math.min( clientSize.height, rect.top + rect.height + padding ); + + return Jimp.read( imageBuffer ).then( function ( jimpImage ) { + jimpImage + .crop( left, top, right - left, bottom - top ) + .write( filename ); + } ); } - module.exports.createScreenshotEnvironment = createScreenshotEnvironment; -}() ); + function runScreenshotTest( name, lang, clientScript, padding ) { + const filename = './screenshots/' + name + '-' + lang + '.png'; + + driver.manage().timeouts().setScriptTimeout( TIMEOUT ); + driver.wait( + driver.executeAsyncScript( clientScript ).then( function ( rect ) { + return driver.takeScreenshot().then( function ( base64Image ) { + if ( rect ) { + const imageBuffer = Buffer.from( base64Image, 'base64' ); + return cropScreenshot( filename, imageBuffer, rect, padding ); + } else { + fs.writeFile( filename, base64Image, 'base64' ); + } + } ); + }, function ( e ) { + // Log error (timeout) + console.error( e ); + } ) + ); + } + + return runScreenshotTest; +} + +module.exports.createScreenshotEnvironment = createScreenshotEnvironment; diff --git a/build/screenshots.userGuide.js b/build/screenshots.userGuide.js index ac5185c984..76a79a0a0a 100644 --- a/build/screenshots.userGuide.js +++ b/build/screenshots.userGuide.js @@ -1,311 +1,104 @@ -/* global seleniumUtils, langs */ -/* eslint-disable no-jquery/no-global-selector */ +const createScreenshotEnvironment = require( './screenshots.js' ).createScreenshotEnvironment, + test = require( 'selenium-webdriver/testing' ), + runScreenshotTest = createScreenshotEnvironment( test ); -( function () { - 'use strict'; - var createScreenshotEnvironment = require( './screenshots.js' ).createScreenshotEnvironment, - test = require( 'selenium-webdriver/testing' ), - runScreenshotTest = createScreenshotEnvironment( test ); +function runTests( lang ) { - function runTests( lang ) { - - test.describe( 'Screenshots: ' + lang, function () { - this.lang = lang; - test.it( 'Toolbar & action tools', function () { - runScreenshotTest( 'VisualEditor_toolbar', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - // HACK: The test page is on the help namespace, so overwrite the - // read tab with the nstab-main message. - new mw.Api().loadMessagesIfMissing( [ 'nstab-main' ], { amenableparser: true } ).then( function () { - $( '#ca-nstab-help a' ).text( mw.msg( 'nstab-main' ) ); - done( - seleniumUtils.getBoundingRect( [ - ve.init.target.toolbar.$element[ 0 ], - $( '#p-namespaces' )[ 0 ] - ] ) - ); - } ); - }, - 0 - ); - runScreenshotTest( 'VisualEditor_toolbar_actions', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - done( - seleniumUtils.getBoundingRect( [ - ve.init.target.toolbar.$actions[ 0 ] - ] ) - ); - }, - 0 - ); - } ); - test.it( 'Citoid inspector', function () { - runScreenshotTest( 'VisualEditor_Citoid_Inspector', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ], - surface = ve.init.target.surface; - ve.init.target.toolbar.tools.citoid.onSelect(); - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - surface.$element.find( '.ve-ce-mwReferenceNode' )[ 0 ], - surface.context.inspectors.currentWindow.$element[ 0 ] - ] ) - ); - }, 500 ); - } - ); - runScreenshotTest( 'VisualEditor_Citoid_Inspector_Manual', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ], - surface = ve.init.target.surface; - ve.init.target.surface.context.inspectors.currentWindow.setModePanel( 'manual' ); - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - surface.$element.find( '.ve-ce-mwReferenceNode' )[ 0 ], - surface.context.inspectors.currentWindow.$element[ 0 ] - ] ) - ); - } ); - } - ); - runScreenshotTest( 'VisualEditor_Citoid_Inspector_Reuse', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ], - surface = ve.init.target.surface; - ve.init.target.surface.context.inspectors.currentWindow.setModePanel( 'reuse' ); - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - surface.$element.find( '.ve-ce-mwReferenceNode' )[ 0 ], - surface.context.inspectors.currentWindow.$element[ 0 ] - ] ) - ); - } ); - } - ); - } ); - test.it( 'Tool groups (headings/text style/indentation/insert/page settings)', function () { - runScreenshotTest( 'VisualEditor_Toolbar_Headings', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.paragraph ); - } - ); - runScreenshotTest( 'VisualEditor_Toolbar_Formatting', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.bold, true ); - } - ); - runScreenshotTest( 'VisualEditor_Toolbar_Lists_and_indentation', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.bullet ); - } - ); - runScreenshotTest( 'VisualEditor_Insert_Menu', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.media, true ); - } - ); - runScreenshotTest( 'VisualEditor_Media_Insert_Menu', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.media, false, true ); - } - ); - runScreenshotTest( 'VisualEditor_Template_Insert_Menu', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.transclusion, false, true ); - } - ); - runScreenshotTest( 'VisualEditor_insert_table', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.insertTable, false, true ); - } - ); - runScreenshotTest( 'VisualEditor_Formula_Insert_Menu', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.math, true, true ); - } - ); - runScreenshotTest( 'VisualEditor_References_List_Insert_Menu', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.toolbar.tools.referencesList, true, true ); - } - ); - runScreenshotTest( 'VisualEditor_More_Settings', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.actionsToolbar.tools.advancedSettings, false, false, - [ ve.init.target.toolbarSaveButton.$element[ 0 ] ] - ); - } - ); - runScreenshotTest( 'VisualEditor_page_settings_item', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.actionsToolbar.tools.settings, false, true ); - } - ); - runScreenshotTest( 'VisualEditor_category_item', lang, - // This function is converted to a string and executed in the browser - function () { - seleniumUtils.runMenuTask( arguments[ arguments.length - 1 ], ve.init.target.actionsToolbar.tools.categories, false, true ); - } - ); - } ); - test.it( 'Save dialog', function () { - runScreenshotTest( 'VisualEditor_save_dialog', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - ve.init.target.toolbarSaveButton.onSelect(); - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - ve.init.target.surface.dialogs.currentWindow.$frame[ 0 ] - ] ) - ); - }, 500 ); - } - ); - } ); - test.it( 'Special character inserter', function () { - runScreenshotTest( 'VisualEditor_Toolbar_SpecialCharacters', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - ve.init.target.toolbar.tools.specialCharacter.onSelect(); - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - ve.init.target.toolbar.tools.specialCharacter.$element[ 0 ], - ve.init.target.surface.toolbarDialogs.$element[ 0 ] - ] ) - ); - }, 1000 ); - } - ); - } ); - test.it( 'Math dialog', function () { - runScreenshotTest( 'VisualEditor_formula', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ], - surface = ve.init.target.surface; - - surface.dialogs.once( 'opening', function ( win, opening ) { - opening.then( function () { - win.previewElement.once( 'render', function () { - win.previewElement.$element.find( 'img' ).on( 'load', function () { - done( - seleniumUtils.getBoundingRect( [ - win.$frame[ 0 ] - ] ) - ); - } ); - } ); - win.input.setValue( 'E = mc^2' ).moveCursorToEnd(); - } ); - } ); - surface.executeCommand( 'mathDialog' ); - } - ); - } ); - test.it( 'Reference list dialog', function () { - runScreenshotTest( 'VisualEditor_references_list', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ], - surface = ve.init.target.surface; - - surface.dialogs.once( 'opening', function ( win, opening ) { - opening.then( function () { - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - win.$frame[ 0 ] - ] ) - ); - }, 500 ); - } ); - } ); - surface.executeCommand( 'referencesList' ); - // The first command inserts a reference list instantly, so run again to open the window - surface.executeCommand( 'referencesList' ); - } - ); - } ); - test.it( 'Cite button', function () { - runScreenshotTest( 'VisualEditor_citoid_Cite_button', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ]; - - ve.init.target.$element.css( 'font-size', '250%' ); - // Wait for re-paint - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - ve.init.target.toolbar.tools.citoid.$element[ 0 ] - ] ) - ); - }, 100 ); - }, - 0 - ); - } ); - test.it( 'Link inspector', function () { - runScreenshotTest( 'VisualEditor-link_tool-search_results', lang, - // This function is converted to a string and executed in the browser - function () { - var done = arguments[ arguments.length - 1 ], - surface = ve.init.target.surface; - - surface.getModel().getFragment() - // TODO: i18n this message, the linked word, and the API endpoint of the link inspector - .insertContent( 'World literature is literature that is read by many people all over' ) - .collapseToStart().select(); - - surface.context.inspectors.once( 'opening', function ( win, opening ) { - opening.then( function () { - surface.context.inspectors.windows.link.annotationInput.input.requestRequest.then( function () { - // Wait a while for the images to load using a time guesstimate - as they're background - // images it's quite tricky to get load events. - setTimeout( function () { - done( - seleniumUtils.getBoundingRect( [ - surface.$element.find( '.ve-ce-linkAnnotation' )[ 0 ], - surface.context.inspectors.currentWindow.$element[ 0 ] - ] ) - ); - }, 2500 ); - } ); - } ); - } ); - ve.init.target.surface.executeCommand( 'link' ); - } - ); - } ); + test.describe( 'Screenshots: ' + lang, function () { + this.lang = lang; + test.it( 'Toolbar & action tools', function () { + runScreenshotTest( 'VisualEditor_toolbar', lang, + require( './screenshots-client/userGuide.js' ).toolbar, + 0 + ); + runScreenshotTest( 'VisualEditor_toolbar_actions', lang, + require( './screenshots-client/userGuide.js' ).toolbarActions, + 0 + ); } ); - } + test.it( 'Citoid inspector', function () { + runScreenshotTest( 'VisualEditor_Citoid_Inspector', lang, + require( './screenshots-client/userGuide.js' ).citoidInspector + ); + runScreenshotTest( 'VisualEditor_Citoid_Inspector_Manual', lang, + require( './screenshots-client/userGuide.js' ).citoidInspectorManual + ); + runScreenshotTest( 'VisualEditor_Citoid_Inspector_Reuse', lang, + require( './screenshots-client/userGuide.js' ).citoidInspectorReuse + ); + } ); + test.it( 'Tool groups (headings/text style/indentation/insert/page settings)', function () { + runScreenshotTest( 'VisualEditor_Toolbar_Headings', lang, + require( './screenshots-client/userGuide.js' ).toolbarHeadings + ); + runScreenshotTest( 'VisualEditor_Toolbar_Formatting', lang, + require( './screenshots-client/userGuide.js' ).toolbarFormatting + ); + runScreenshotTest( 'VisualEditor_Toolbar_Lists_and_indentation', lang, + require( './screenshots-client/userGuide.js' ).toolbarLists + ); + runScreenshotTest( 'VisualEditor_Insert_Menu', lang, + require( './screenshots-client/userGuide.js' ).toolbarInsert + ); + runScreenshotTest( 'VisualEditor_Media_Insert_Menu', lang, + require( './screenshots-client/userGuide.js' ).toolbarMedia + ); + runScreenshotTest( 'VisualEditor_Template_Insert_Menu', lang, + require( './screenshots-client/userGuide.js' ).toolbarTemplate + ); + runScreenshotTest( 'VisualEditor_insert_table', lang, + require( './screenshots-client/userGuide.js' ).toolbarTable + ); + runScreenshotTest( 'VisualEditor_Formula_Insert_Menu', lang, + require( './screenshots-client/userGuide.js' ).toolbarFormula + ); + runScreenshotTest( 'VisualEditor_References_List_Insert_Menu', lang, + require( './screenshots-client/userGuide.js' ).toolbarReferences + ); + runScreenshotTest( 'VisualEditor_More_Settings', lang, + require( './screenshots-client/userGuide.js' ).toolbarSettings + ); + runScreenshotTest( 'VisualEditor_page_settings_item', lang, + require( './screenshots-client/userGuide.js' ).toolbarPageSettings + ); + runScreenshotTest( 'VisualEditor_category_item', lang, + require( './screenshots-client/userGuide.js' ).toolbarCategory + ); + } ); + test.it( 'Save dialog', function () { + runScreenshotTest( 'VisualEditor_save_dialog', lang, + require( './screenshots-client/userGuide.js' ).save + ); + } ); + test.it( 'Special character inserter', function () { + runScreenshotTest( 'VisualEditor_Toolbar_SpecialCharacters', lang, + require( './screenshots-client/userGuide.js' ).specialCharacters + ); + } ); + test.it( 'Math dialog', function () { + runScreenshotTest( 'VisualEditor_formula', lang, + require( './screenshots-client/userGuide.js' ).formula + ); + } ); + test.it( 'Reference list dialog', function () { + runScreenshotTest( 'VisualEditor_references_list', lang, + require( './screenshots-client/userGuide.js' ).referenceList + ); + } ); + test.it( 'Cite button', function () { + runScreenshotTest( 'VisualEditor_citoid_Cite_button', lang, + require( './screenshots-client/userGuide.js' ).toolbarCite, + 0 + ); + } ); + test.it( 'Link inspector', function () { + runScreenshotTest( 'VisualEditor-link_tool-search_results', lang, + require( './screenshots-client/userGuide.js' ).linkSearchResults + ); + } ); + } ); +} - for ( let i = 0, l = langs.length; i < l; i++ ) { - runTests( langs[ i ] ); - } -}() ); +for ( let i = 0, l = langs.length; i < l; i++ ) { + runTests( langs[ i ] ); +}