123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- jest.setTimeout(30000); // eslint-disable-line no-undef
- import bindAll from 'lodash.bindall';
- import 'chromedriver'; // register path
- import webdriver from 'selenium-webdriver';
- const {By, until, Button} = webdriver;
- const USE_HEADLESS = process.env.USE_HEADLESS !== 'no';
- // The main reason for this timeout is so that we can control the timeout message and report details;
- // if we hit the Jasmine default timeout then we get a terse message that we can't control.
- // The Jasmine default timeout is 30 seconds so make sure this is lower.
- const DEFAULT_TIMEOUT_MILLISECONDS = 20 * 1000;
- class SeleniumHelper {
- constructor () {
- bindAll(this, [
- 'clickText',
- 'clickButton',
- 'clickXpath',
- 'elementIsVisible',
- 'findByText',
- 'findByXpath',
- 'getDriver',
- 'getSauceDriver',
- 'getLogs',
- 'loadUri',
- 'rightClickText'
- ]);
- this.Key = webdriver.Key; // map Key constants, for sending special keys
- }
- elementIsVisible (element, timeoutMessage = 'elementIsVisible timed out') {
- return this.driver.wait(until.elementIsVisible(element), DEFAULT_TIMEOUT_MILLISECONDS, timeoutMessage);
- }
- get scope () {
- // List of useful xpath scopes for finding elements
- return {
- blocksTab: "*[@id='react-tabs-1']",
- costumesTab: "*[@id='react-tabs-3']",
- modal: '*[@class="ReactModalPortal"]',
- reportedValue: '*[@class="blocklyDropDownContent"]',
- soundsTab: "*[@id='react-tabs-5']",
- spriteTile: '*[starts-with(@class,"react-contextmenu-wrapper")]',
- monitors: '*[starts-with(@class,"stage_monitor-wrapper")]'
- };
- }
- getDriver () {
- const chromeCapabilities = webdriver.Capabilities.chrome();
- const args = [];
- if (USE_HEADLESS) {
- args.push('--headless');
- }
- // Stub getUserMedia to always not allow access
- args.push('--use-fake-ui-for-media-stream=deny');
- // Suppress complaints about AudioContext starting before a user gesture
- // This is especially important on Windows, where Selenium directs JS console messages to stdout
- args.push('--autoplay-policy=no-user-gesture-required');
- chromeCapabilities.set('chromeOptions', {args});
- chromeCapabilities.setLoggingPrefs({
- performance: 'ALL'
- });
- this.driver = new webdriver.Builder()
- .forBrowser('chrome')
- .withCapabilities(chromeCapabilities)
- .build();
- return this.driver;
- }
- getSauceDriver (username, accessKey, configs) {
- this.driver = new webdriver.Builder()
- .withCapabilities({
- browserName: configs.browserName,
- platform: configs.platform,
- version: configs.version,
- username: username,
- accessKey: accessKey
- })
- .usingServer(`http://${username}:${accessKey
- }@ondemand.saucelabs.com:80/wd/hub`)
- .build();
- return this.driver;
- }
- findByXpath (xpath, timeoutMessage = `findByXpath timed out for path: ${xpath}`) {
- return this.driver.wait(until.elementLocated(By.xpath(xpath)), DEFAULT_TIMEOUT_MILLISECONDS, timeoutMessage)
- .then(el => (
- this.driver.wait(el.isDisplayed(), DEFAULT_TIMEOUT_MILLISECONDS, `${xpath} is not visible`)
- .then(() => el)
- ));
- }
- findByText (text, scope) {
- return this.findByXpath(`//body//${scope || '*'}//*[contains(text(), '${text}')]`);
- }
- loadUri (uri) {
- const WINDOW_WIDTH = 1024;
- const WINDOW_HEIGHT = 768;
- return this.driver
- .get(`file://${uri}`)
- .then(() => (
- this.driver.executeScript('window.onbeforeunload = undefined;')
- ))
- .then(() => (
- this.driver.manage()
- .window()
- .setSize(WINDOW_WIDTH, WINDOW_HEIGHT)
- ));
- }
- clickXpath (xpath) {
- return this.findByXpath(xpath).then(el => el.click());
- }
- clickText (text, scope) {
- return this.findByText(text, scope).then(el => el.click());
- }
- rightClickText (text, scope) {
- return this.findByText(text, scope).then(el => this.driver.actions()
- .click(el, Button.RIGHT)
- .perform());
- }
- clickButton (text) {
- return this.clickXpath(`//button//*[contains(text(), '${text}')]`);
- }
- getLogs (whitelist) {
- if (!whitelist) {
- // Default whitelist
- whitelist = [
- 'The play() request was interrupted by a call to pause()'
- ];
- }
- return this.driver.manage()
- .logs()
- .get('browser')
- .then(entries => entries.filter(entry => {
- const message = entry.message;
- for (let i = 0; i < whitelist.length; i++) {
- if (message.indexOf(whitelist[i]) !== -1) {
- return false;
- } else if (entry.level !== 'SEVERE') {
- return false;
- }
- }
- return true;
- }));
- }
- }
- export default SeleniumHelper;
|