jasmine.DEFAULT_TIMEOUT_INTERVAL = 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',
            'waitUntilGone'
        ]);
    }

    elementIsVisible (element, {
        message = 'elementIsVisible timed out',
        timeout = DEFAULT_TIMEOUT_MILLISECONDS
    } = {}) {
        return this.driver.wait(until.elementIsVisible(element), timeout, message);
    }

    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');

        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, {
        message = `findByXpath timed out for path: ${xpath}`,
        timeout = DEFAULT_TIMEOUT_MILLISECONDS
    } = {}) {
        return this.driver.wait(until.elementLocated(By.xpath(xpath)), timeout, message);
    }

    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}')]`);
    }

    waitUntilGone (element, {
        message = 'waitUntilGone timed out',
        timeout = DEFAULT_TIMEOUT_MILLISECONDS
    } = {}) {
        return this.driver.wait(until.stalenessOf(element), timeout, message);
    }

    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;

@@ -1040,35 +1040,32 @@
 e (element, 
-%7B%0A        m
+timeoutM
 essage = 'el
@@ -1093,67 +1093,8 @@
 out'
-,%0A        timeout = DEFAULT_TIMEOUT_MILLISECONDS%0A    %7D = %7B%7D
 ) %7B%0A
@@ -1153,32 +1153,62 @@
 le(element),
+ DEFAULT_TIMEOUT_MILLISECONDS,
  timeout
 , message);%0A
@@ -1187,35 +1187,33 @@
 SECONDS, timeout
-, m
+M
 essage);%0A    %7D%0A%0A
@@ -2913,27 +2913,24 @@
 (xpath, 
-%7B%0A        m
+timeoutM
 essage =
@@ -2976,67 +2976,8 @@
 th%7D%60
-,%0A        timeout = DEFAULT_TIMEOUT_MILLISECONDS%0A    %7D = %7B%7D
 ) %7B%0A
@@ -3046,24 +3046,54 @@
 xpath)),
+ DEFAULT_TIMEOUT_MILLISECONDS,
  timeout
 , messag
@@ -3076,35 +3076,33 @@
 SECONDS, timeout
-, m
+M
 essage);%0A    %7D%0A%0A
@@ -4198,19 +4198,16 @@
 nt, 
-%7B%0A        m
+timeoutM
 essa
@@ -4240,67 +4240,8 @@
 out'
-,%0A        timeout = DEFAULT_TIMEOUT_MILLISECONDS%0A    %7D = %7B%7D
 ) %7B%0A
@@ -4299,24 +4299,54 @@
 lement),
+ DEFAULT_TIMEOUT_MILLISECONDS,
  timeout
 , messag
@@ -4341,11 +4341,9 @@
 eout
-, m
+M
 essa

simplify SeleniumHelper timeout options