Phantom JS Selenium IDE:如何调整浏览器窗口的大小

时间:2017-03-21 09:28:36

标签: node.js selenium phantomjs selenium-ide

我正在使用Selenium IDE使用我的网络应用程序记录一个简单的测试,我生成的html生成的scènario如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="selenium.base" href="http://pagamac.dev/" />
    <title>addContact</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
    <thead>
    <tr><td rowspan="1" colspan="3">addContact</td></tr>
    </thead><tbody>
<tr>
    <td>open</td>
    <td>/</td>
    <td></td>
</tr>
<tr>
    <td>type</td>
    <td>id=edit-name</td>
    <td>admin</td>
</tr>
<tr>
    <td>click</td>
    <td>id=edit-pass</td>
    <td></td>
</tr>
<tr>
    <td>type</td>
    <td>id=edit-pass</td>
    <td>admin</td>
</tr>
<tr>
    <td>clickAndWait</td>
    <td>id=edit-submit</td>
    <td></td>
</tr>
<tr>
    <td>clickAndWait</td>
    <td>css=li.civicrm &gt; a</td>
    <td></td>
</tr>
<tr>
    <td>click</td>
    <td>//*[@id=&quot;civicrm-menu&quot;]/li[4]</td>
    <td></td>
</tr>
<tr>
    <td>clickAndWait</td>
    <td>//*[@id=&quot;root-menu-div&quot;]/div[5]/ul/li[1]/div/a</td>
    <td>5000</td>
</tr>
<tr>
    <td>select</td>
    <td>//*[@id=&quot;prefix_id&quot;]</td>
    <td>M.</td>
</tr>
<tr>
    <td>click</td>
    <td>id=first_name</td>
    <td></td>
</tr>
<tr>
    <td>type</td>
    <td>id=first_name</td>
    <td>franc</td>
</tr>
<tr>
    <td>click</td>
    <td>id=last_name</td>
    <td></td>
</tr>
<tr>
    <td>type</td>
    <td>id=last_name</td>
    <td>ribery</td>
</tr>
<tr>
    <td>select</td>
    <td>//*[@id=&quot;email_1_location_type_id&quot;]</td>
    <td>Autre</td>
</tr>
<tr>
    <td>click</td>
    <td>id=email_1_email</td>
    <td></td>
</tr>
<tr>
    <td>type</td>
    <td>id=email_1_email</td>
    <td>rib@gmail.com</td>
</tr>
<tr>
    <td>click</td>
    <td>//*[@id=&quot;Email_1_IsBulkmail&quot;]</td>
    <td></td>
</tr>
<tr>
    <td>click</td>
    <td>//*[@id=&quot;email[1][on_hold]&quot;]</td>
    <td></td>
</tr>
<tr>
    <td>type</td>
    <td>id=phone_1_phone</td>
    <td>8888888888</td>
</tr>
<tr>
    <td>clickAndWait</td>
    <td>id=_qf_Contact_upload_view-bottom</td>
    <td></td>
</tr>
</tbody></table>
</body>
</html>

我正在使用一个特定的插件: selenium-html-js-converter (你在这里找到它: https://www.npmjs.com/package/selenium-html-js-converter

此插件将我的html测试转换为js,如下所示:

"use strict";
/* jslint node: true */

var assert = require('assert');

var browser, element, currentCommand = '',
    options = {
        timeout: 30000,
        retries: 0,
        screenshotFolder: 'screenshots/test_add_SimpleContact',
        baseUrl: 'http://pagamac.dev/'
    };

module.exports = function testAddSimpleContact(_browser, _options) {

    browser = _browser;
    var acceptNextAlert = true;
    getRuntimeOptions(_options);
    try {
        currentCommand = 'open("/", "")';
        browser.get(addBaseUrl("/"));

        currentCommand = 'type("id=edit-name", "admin")';
        browser.elementById("edit-name").clear();
        browser.elementById("edit-name").sendKeys("admin");

        currentCommand = 'click("id=edit-pass", "")';
        browser.elementById("edit-pass").click();

        currentCommand = 'type("id=edit-pass", "admin")';
        browser.elementById("edit-pass").clear();
        browser.elementById("edit-pass").sendKeys("admin");

        currentCommand = 'clickAndWait("id=edit-submit", "")';
        doAndWait(function() {
            browser.elementById("edit-submit").click();
        });

        currentCommand = 'clickAndWait("css=li.civicrm > a", "")';
        doAndWait(function() {
            browser.elementByCssSelector("li.civicrm > a").click();
        });

        currentCommand = 'click("//*[@id="civicrm-menu"]/li[4]", "")';
        browser.elementByXPath("//*[@id=\"civicrm-menu\"]/li[4]").click();

        currentCommand = 'clickAndWait("//*[@id="root-menu-div"]/div[5]/ul/li[1]/div/a", "5000")';
        doAndWait(function() {
            browser.elementByXPath("//*[@id=\"root-menu-div\"]/div[5]/ul/li[1]/div/a").click();
        });

        currentCommand = 'select("//*[@id="prefix_id"]", "M.")';
        browser.elementByXPath("//*[@id=\"prefix_id\"]").elementByXPath('option[text()="M."][1]').click();

        currentCommand = 'click("id=first_name", "")';
        browser.elementById("first_name").click();

        currentCommand = 'type("id=first_name", "franc")';
        browser.elementById("first_name").clear();
        browser.elementById("first_name").sendKeys("franc");

        currentCommand = 'click("id=last_name", "")';
        browser.elementById("last_name").click();

        currentCommand = 'type("id=last_name", "ribery")';
        browser.elementById("last_name").clear();
        browser.elementById("last_name").sendKeys("ribery");

        currentCommand = 'select("//*[@id="email_1_location_type_id"]", "Autre")';
        browser.elementByXPath("//*[@id=\"email_1_location_type_id\"]").elementByXPath('option[text()="Autre"][1]').click();

        currentCommand = 'click("id=email_1_email", "")';
        browser.elementById("email_1_email").click();

        currentCommand = 'type("id=email_1_email", "rib@gmail.com")';
        browser.elementById("email_1_email").clear();
        browser.elementById("email_1_email").sendKeys("rib@gmail.com");

        currentCommand = 'click("//*[@id="Email_1_IsBulkmail"]", "")';
        browser.elementByXPath("//*[@id=\"Email_1_IsBulkmail\"]").click();

        currentCommand = 'click("//*[@id="email[1][on_hold]"]", "")';
        browser.elementByXPath("//*[@id=\"email[1][on_hold]\"]").click();

        currentCommand = 'type("id=phone_1_phone", "8888888888")';
        browser.elementById("phone_1_phone").clear();
        browser.elementById("phone_1_phone").sendKeys("8888888888");

        currentCommand = 'clickAndWait("id=_qf_Contact_upload_view-bottom", "")';
        doAndWait(function() {
            browser.elementById("_qf_Contact_upload_view-bottom").click();
        });

    } catch (e) {
        var failedScreenShot = options.screenshotFolder + '/Exception@' + currentCommand.replace(/\(.+/, '') + '.png';
        try {
            createFolderPath(options.screenshotFolder);
            browser.saveScreenshot(failedScreenShot);
        } catch (e) {
            e.message = 'Failure in Selenium command "' + currentCommand + '": ' + e.message + ' (Could not save screenshot after failure occured)';
            throw e;
        }
        e.message = 'Failure in Selenium command "' + currentCommand + '": ' + e.message + ' (Screenshot was saved to ' + failedScreenShot + ')';
        throw e;
    }

};

/**
 * A hacky way to implement *AndWait Selenese commands. Native wd doesn't offer
 * commands equivalent to e.g. clickAndWait or dragAndDropAndWait (actually
 * neither dragAndDrop nor AndWait exist in wd) or clickAndWait. We work around
 * it wrapping all *AndWait commands in code that first taints the document body
 * with a class, then runs the base command, and waits for a new document ready
 * state without the tainted body.
 *
 * @param  {function}             code      The code to execute
 * @param  {WdSyncClient.browser} wdBrowser (optional) Browser instance
 * @return {void}
 */
function doAndWait(code, wdBrowser) {
    if (typeof wdBrowser !== 'object') {
        wdBrowser = browser;
    }
    wdBrowser.execute('document.body.className += " SHTML2JSC"');
    code();
    withRetry(function() {
        if (wdBrowser.execute("return document.readyState") !== 'complete' || wdBrowser.hasElementByCssSelector('body.SHTML2JSC'))
            throw new Error('Page did not load in time');
    }, wdBrowser);
}

/**
 * Implements waitForPageToLoad selenese command. As opposed to the Selenium
 * IDE implementation, this one actually waits for all resources to have been
 * loaded.
 *
 * @param  {WdSyncClient.browser} wdBrowser (optional) Browser instance.
 * @return {void}
 */
function waitForPageToLoad(wdBrowser) {
    if (typeof wdBrowser !== 'object') {
        wdBrowser = browser;
    }
    withRetry(function() {
        if (wdBrowser.execute("return document.readyState") !== 'complete')
            throw new Error('Page did not load in time');
    });
}

function getRuntimeOptions(opts) {
    if (!opts) return;

    if (typeof opts.lbParam === 'object') {
        options.lbParam = opts.lbParam;
    }

    if (opts.baseUrl && typeof opts.baseUrl === 'string') {
        options.baseUrl = opts.baseUrl;
        if (opts.forceBaseUrl && typeof opts.forceBaseUrl === 'boolean') {
            options.forceBaseUrl = opts.forceBaseUrl;
        }
    }

    if (opts.screenshotFolder && typeof opts.screenshotFolder === 'string') {
        options.screenshotFolder = opts.screenshotFolder;
    }

    if (opts.timeout && isNumber(opts.timeout)) {
        options.timeout = opts.timeout;
    }

    if (opts.retries && isNumber(opts.retries)) {
        options.retries = opts.retries;
    }
}

function isNumber(val) {
    return typeof val === 'number' && !isNaN(val);
}

function isAlertPresent(wdBrowser) {
    if (typeof wdBrowser !== 'object') {
        wdBrowser = browser;
    }

    try {
        wdBrowser.alertText();
        return true;
    } catch (e) {
        return false;
    }
}

function closeAlertAndGetItsText(acceptNextAlert, wdBrowser) {
    if (typeof wdBrowser !== 'object') {
        wdBrowser = browser;
    }

    try {
        var alertText = wdBrowser.alertText();
        if (acceptNextAlert) {
            wdBrowser.acceptAlert();
        } else {
            wdBrowser.dismissAlert();
        }
        return alertText;
    } catch (ignore) {}
}

function isEmptyArray(arr) {
    return arr instanceof Array && arr.length === 0;
}

function waitFor(checkFunc, expression, timeout, pollFreq, wdBrowser) {

    if (typeof wdBrowser !== 'object') {
        wdBrowser = browser;
    }
    if (!isNumber(timeout)) {
        timeout = options.timeout;
    }
    if (!isNumber(pollFreq)) {
        pollFreq = 200;
    }

    var val;
    var timeLeft = timeout;

    while (!val) {
        val = checkFunc();

        if (val)
            break;

        if (timeLeft < 0) {
            throw new Error('Timed out after ' + timeout + ' msecs waiting for expression: ' + expression);
        }

        wdBrowser.sleep(pollFreq);
        timeLeft -= pollFreq;
    }

    return val;
}

function createFolderPath(path) {
    var fs = require('fs');
    var folders = path.split(/[/\\]+/);
    path = '';

    while (folders.length) {
        /* This works for both absolute and relative paths, as split on an absolute path will have resulted in an array with the first bit empty. Safe for absolute Windows paths as well: */
        path += folders.shift() + '/';

        if (!fs.existsSync(path)) {
            fs.mkdirSync(path);
        } else if (!fs.statSync(path).isDirectory()) {
            throw new Error("Cannot create directory '" + path + "'. File of same name already exists.");
        }
    }
}

/**
 * Prefix a (relative) path with a base url.
 *
 * If the path itself is an absolute one including a domain, it'll be returned as-is, unless force is set to true, in
 * which case the existing domain is replaced with the base.
 *
 * When optional arguments are when omitted, values from glocal options object are used.
 *
 * @param  {string} path  The path to prefix with the base url
 * @param  {string} base  (optional) The base url
 * @param  {bool}   force (optional) If true, force prefixing even if path is an absolute url
 * @return {string}       The prefixed url
 */
function addBaseUrl(path, base, force) {
    if (typeof base !== 'string') {
        base = options.baseUrl;
    }

    if (typeof force !== 'boolean') {
        force = options.forceBaseUrl;
    }

    if (path.match(/^http/)) {
        if (force) {
            return path.replace(/^http(s?):\/\/[^/]+/, base).replace(/([^:])\/\/+/g, '$1/');
        }
        return path;
    }
    return (base + '/' + path).replace(/([^:])\/\/+/g, '$1/');
}

/**
 * Focuses the topmost window on the stack of handles in the browser.
 *
 * After a WdSyncClient.browser.close() wd does not automatically restore focus
 * to the previous window on the stack, so you may execute this function to
 * ensure that subsequent tests won't be targeting a defunct window handle.
 *
 * @param  {WdSyncClient.browser} wdBrowser (optional) Browser instance.
 * @return {void}
 */
function refocusWindow(wdBrowser) {
    if (typeof wdBrowser !== 'object') {
        wdBrowser = browser;
    }
    var handles = wdBrowser.windowHandles();
    if (handles.length) {
        try {
            wdBrowser.window(handles[handles.length - 1]);
        } catch (e) {
            console.warn('Failed to automatically restore focus to topmost window on browser stack. Error:', e);
        }
    }
}

/**
 * Tries to execute an Error throwing function, and if an error is thrown, one
 * or more retries are attempted until <timeout> msecs have passed.
 *
 * Pauses between retries are increasing in length. The pause before the final
 * retry will be half the total timeout. The pause before the second-to-last
 * will be half of the last one's, and so forth. The first attempt will have the
 * same pause as that of the first retry.
 *
 * Optional arguments use glocal values when omitted
 *
 * @param  {function}             code      The code to execute
 * @param  {WdSyncClient.browser} wdBrowser (optional) Browser instance
 * @param  {number}               retries   (optional) The max number of retries
 * @param  {number}               timeout   (optional) The max number of msecs to keep trying
 * @return {mixed}                Whatever the code block returns
 */
function withRetry(code, wdBrowser, retries, timeout) {
    if (typeof wdBrowser !== 'object') {
        wdBrowser = browser;
    }

    if (!isNumber(retries)) {
        retries = options.retries;
    }

    if (!isNumber(timeout)) {
        timeout = options.timeout;
    }

    var durations = [timeout];
    var err;

    while (retries) {
        durations[0] = Math.ceil(durations[0] / 2);
        durations.unshift(durations[0]);
        --retries;
    }

    for (var i = 0; i < durations.length; ++i) {
        try {
            return code();
        } catch (e) {
            err = e;
            wdBrowser.sleep(durations[i]);
        }
    }

    throw (err);
}

/**
 * Triggers a keyboard event on the provided wd browser element.
 *
 * @param    {WD Element} element Target DOM element to trigger the event on
 * @param    {string}     event   Keyboard event (keyup|keydown|keypress)
 * @param    {keyCode}    key     Charcode to use
 * @return   {void}
 */
function keyEvent(element, event, keyCode) {
    browser.execute(functionBody(function() {
        var element = arguments[0];
        var event = arguments[1];
        var keyCode = arguments[2];
        var ev = window.document.createEvent('KeyboardEvent');
        if (ev.initKeyEvent)
            ev.initKeyEvent(event, true, true, window, 0, 0, 0, 0, 0, keyCode);
        else
            ev.initKeyboardEvent(event, true, true, window, 0, 0, 0, 0, 0, keyCode);
        return element.dispatchEvent(ev);
    }), [element.rawElement, event, keyCode]);
}

function functionBody(func) {
    return func.toString().replace(/^function[^{]+{/, '').replace(/}[^}]*$/, '');
}

/* User extensions */

function typeRedactor(target, value, element) {
    /* .execute takes just a function body as a string to be eval'ed: */
    var className = browser.execute(functionBody(function() {
        var element = arguments[0];
        var text = arguments[1];
        var callback = arguments[2];
        /* Once done, we tag redactor with a class, so we know when we finished: */
        var className = "seleniumDoTypeRedactor-" + (new Date()).getTime();
        var keyEvent = function(element, event, keyCode) {
            var ev = window.document.createEvent('KeyboardEvent');
            if (ev.initKeyEvent)
                ev.initKeyEvent(event, true, true, window, 0, 0, 0, 0, 0, keyCode);
            else
                ev.initKeyboardEvent(event, true, true, window, 0, 0, 0, 0, 0, keyCode);
            return element.dispatchEvent(ev);
        };
        keyEvent(element, 'keydown', 0);
        keyEvent(element, 'keyup', 0);
        element.textContent = 'redactor';
        setTimeout(function() {
            keyEvent(element, 'keydown', 0);
            keyEvent(element, 'keyup', 0);
            element.textContent = text;
            setTimeout(function() {
                keyEvent(element, 'keydown', 0);
                keyEvent(element, 'keyup', 0);
                element.className += ' ' + className;
            }, 50);
        }, 50);
        return className;
    }), [element.rawElement /* Important! element is mangled by wd-sync; we need the raw wd element */ , value]);
    waitFor(function() {
        return browser.hasElementByCssSelector('.' + className);
    }, 'browser.hasElementByCssSelector(".' + className + '") [to mark completion of typeRedactor execution]');
}

最后运行此测试我正在使用节点&amp; phantom.js :首先我运行phantom.js;然后我执行我的测试。

我的问题是当我这样做的时候;我的测试,在selenium IDE(html格式)中运行良好,在phantom.js中不能正常工作

经过一些调试后,我发现phatom.js在错误的窗口大小(弱和高度)下运行 - &gt;顺便说一句,我的网页在调整为较小时会丢失一些元素。

我正在寻找如何控制phantom.js浏览器窗口大小:宽度和放大器heignt

注意:我注意使用经典的webdriver(你可以注意到它是我的js测试文件)

建议?

1 个答案:

答案 0 :(得分:1)

几天前面对类似的情况。浏览了很多讨论论坛/讨论。我得到的关于窗口大小调整的一个建议是this,你必须

$voteIds = Auth::user()->votes()->get()->pluck('id')->toArray();

话虽如此,这个解决方案并没有达到我的目的。我不得不采取一些棘手的措施。

让我知道如果它有效,我会建议你更多的选择。