夜间守卫js while循环

时间:2015-03-12 22:45:55

标签: while-loop nightwatch.js

我是节点和夜间表的新手。一直在与Selenium合作多年,但我的公司已经转移到所有的节点。无论如何,在夜间观察我试图点击一个链接,而它的可见和循环,并继续点击它,直到它不是。这是我的代码的样子。任何建议将不胜感激!

"Cart Cleanup": function (browser) {
    browser
        .url(environment + '/ShoppingBag')
        .waitForElementVisible('div.cart-top-message', 190000)
        .pause(3000)
        .element('class name', 'delete-form', function (visible) {
            while (visible.status !== -1) {
                console.log(visible.status);
                browser
                    .useXpath() //NOW USING XPATH
                    .click('/html/body/div[5]/div[2]/div/div[2]/div[1]/div/div[3]/div[4]/div[2]/form[2]/input')
                    .useCss()
                    .pause(3000)
                    .element('class name', 'delete-form', function (visible2) {
                        visible = visible2
                    })
            }
        })
}

3 个答案:

答案 0 :(得分:4)

解决此问题的最佳方法是创建自定义命令。 Nightwatch自定义命令文档:http://nightwatchjs.org/guide#writing-custom-commands

为了更容易解决这些问题,我创建了一个“waitUntil”自定义命令,它作为其他自定义命令的基础:

// WaitUntil.js, in custom commands folder specified in nightwatch.json
var util = require('util');
var events = require('events');
var TIMEOUT_RETRY_INTERVAL = 100;

function waitUntil() {
    events.EventEmitter.call(this);
    this.startTimeInMilliseconds = null;
}

util.inherits(waitUntil, events.EventEmitter);

/**
 * The purpose of this command is to serve as a base for waitUntil_ commands. It will run the getActual function until
 * the predicate funciton returns true or the timeout is reached. At that point, the assertion funciton will be called.
 * @param getActual {Function} - should passe the found value to its callback. The callback will be passed as the only
 *      argument.
 * @param predicate {Function} - the wait will end when this returns true. The actual value is passed as the only
 *      argument.
 * @param assertion {Function} - the assertion to make. The assertion should pass when the predicate returns true. This
 *      function will be passed the actual value and the message.
 * @param timeoutInMilliseconds {number} - the number of milliseconds to wait before timing out and failing.
 * @param message {string} - the message to attach to the assertion. The elapsed time will be appended to this.
 * @returns custom command waitUntil, which can be accessed as browser.waitUntil(args);
 */
waitUntil.prototype.command = function (getActual, predicate, assertion, timeoutInMilliseconds, message) {
    message = message || 'waitUntil';
    this.startTimeInMilliseconds = new Date().getTime();
    var self = this;

    this.check(getActual, predicate, function (actual, loadedTimeInMilliseconds) {
        if (predicate(actual)) {
            message += ': true after '
                + (loadedTimeInMilliseconds - self.startTimeInMilliseconds) + ' ms.';
        } else {
            message += ': timed out after ' + timeoutInMilliseconds + ' ms.';
        }
        assertion(actual, message);
        self.emit('complete');
    }, timeoutInMilliseconds);

    return this;
};

waitUntil.prototype.check = function (getActual, predicate, callback, maxTimeInMilliseconds) {
    var self = this;
    getActual(function (result) {
        // If the argument passed to the callback is an object, it is assumed that the format is of the argument passed
        // to callbacks by the Nightwatch API, in which the object has a "value" attribute with the actual information.
        var resultValue;
        if (typeof result !== 'object') {
            resultValue = result;
        } else if (result.hasOwnProperty('value')) {
            resultValue = result.value;
        } else {
            self.error('Result object does not have a value.');
            return;
        }

        var now = new Date().getTime();
        if (predicate(resultValue)) {
            callback(resultValue, now);
        } else if (now - self.startTimeInMilliseconds < maxTimeInMilliseconds) {
            setTimeout(function () {
                self.check(getActual, predicate, callback, maxTimeInMilliseconds);
            }, TIMEOUT_RETRY_INTERVAL);
        } else {
            callback(resultValue, null);
        }
    });
};

module.exports = waitUntil;

使用这个模块,可以很容易地创建waitUntilTrue,waitUntilEqual等命令。您还可以创建一个“clickUntilNotVisible”命令来解决您的问题(显然,这可以与上述相结合并简化,如果这是您唯一的用例):

// clickUntilNotVisible.js, in custom commands folder specified in nightwatch.json
exports.command = function (clickElementFunction, getVisibilityFunction, assertion, timeout, message) {
    var browser = this;

    function clickAndGetVisiblity (callback) {
        clickElementFunction();
        getVisibilityFunction(callback);
    }

    function isTrue (actual) {
        return !!actual;
    }

    return browser.waitUntil(clickAndGetVisiblity, isTrue, assertion, timeout, message);
};

现在我们已经定义了clickUntilNotVisible命令,我们可以解决您的问题:

function clickMyLink() {
    browser
        .useXpath() //NOW USING XPATH
        .click('/html/body/div[5]/div[2]/div/div[2]/div[1]/div/div[3]/div[4]/div[2]/form[2]/input')
        .useCss();
}

function isDeleteFormVisible(callback) {
    browser
        .pause(3000)
        .elements('class name', 'delete-form', function (result) {
            callback(result.status === 0 && result.value.length);
        });
}

function verifyDeleteFormIsNotVisible (actual, message) {
    browser.verify.ok(!actual, message);
}

module.exports = {
    "Cart Cleanup": function (browser) {
        browser
            .url(environment + '/ShoppingBag')
            .waitForElementVisible('div.cart-top-message', 190000)
            .pause(3000)
            .clickUntilNotVisible(clickMyLink, isDeleteFormVisible, verifyDeleteFormIsNotVisible, 190000);
    }
};

请注意,这使用了我已经完成的工作,并且可能不是解决此问题的最有效方法,但希望它能让您了解如何自行解决问题。此外,除了waitUntil模块之外,所有这些代码都是未经测试的,因此如果没有一点调试,它可能无法工作。

答案 1 :(得分:0)

这可能会对某人有所帮助。我需要一遍又一遍地进行测试,并在此上获得成功:

const doThing = () => {
    browser.pause(20000);
    doThing();
};

doThing();

答案 2 :(得分:0)

在提供解决方案之前,请对您当前的代码提供一些反馈:

  • 您的xpath很长,将来很容易失败。不需要放绝对的头脑。您可以用//input[@class="..."]之类的东西替换它,或在输入标签中添加其他属性,因为您要获取输入标签。
  • 仅在特殊情况下,尽量不要使用pause1000长的时间

现在,关于您的问题,要在元素可见时单击它,可以使用isVisible方法:https://nightwatchjs.org/api/#isVisible

function clickWhileVisible(browser) {
 browser.isVisible('css selector', '#your_element', ({ value }) => {
    if (value === true) {
        browser
            .click('#your_element')
            // you can increase/decrease pause if you want a pause between clicks
            .pause(500);
       clickWhileVisible(browser)
    } 
})

}

您还可以添加重试机制,以确保它不会永远运行:

function clickWhileVisible(browser, retry) {
 browser.isVisible('css selector', '#your_element', ({ value }) => {
    if (value === true && retry <=10) { //retries number can be modified
        browser
            .click('#your_element')
            .pause(500);
       clickWhileVisible(browser, retry+1)
    } 
})