量角器 - StaleElementReferenceException偶尔发生

时间:2015-10-09 11:00:19

标签: javascript exception testing selenium-webdriver protractor

我使用量角器/ jasmine2时遇到了Stale Element Reference Exception的问题。

我的规格:

var LoginPage = require('../pages/login_page.js');
var WelcomePage = require('../pages/welcome_page.js');

describe('Test -> testing something', function () {

    var loginPage;
    var EC = protractor.ExpectedConditions;
    var waitTimeout = 10000;

    function logIn() {
        loginPage.setUser('user');
        loginPage.setPassword('password');
        loginPage.login();
    }

    beforeEach(function () {
        browser.ignoreSynchronization = true;
        loginPage = new LoginPage();
        browser.wait(EC.presenceOf(loginPage.userLogin), waitTimeout);
        logIn();
        var welcomePage = new WelcomePage();
        browser.wait(EC.visibilityOf(welcomePage.usersButton), waitTimeout);
        welcomePage.usersButton.click();
    });

问题是当我想点击usersButton时,在lastEach函数的最后一行上随机出现StaleElementReferenceException。 不知道为什么ExpectedCondition不起作用(尝试了不同的EC,如presenceOf,elementToBeClickable等,但没有解决问题)。

请参阅定义了usersButton以供参考的页面:

'use strict';
var WelcomePage = function () {
};

WelcomePage.prototype = Object.create({}, {
    usersButton: {
        get: function () {
            return element(by.css('#users a'));
        }
    }
});

module.exports = WelcomePage;

我认为需要一些通用的retry_mechanism来处理它,任何人都有类似的问题吗?

最后写了这样的函数

var clickOn = function (element) {
    browser.wait(EC.visibilityOf(element), waitTimeout).then(function() {
        element.click();
    });}

这样调用:

    clickOn(welcomePage.usersButton);

更新: 已经多次测试过了,当我在selenium网格上运行测试时,我仍然在这个确切的元素上得到Stale Element异常。所以提供的解决方案不起作用......

Failed: stale element reference: element is not attached to the page document (Session info: chrome=45.0.2454.93) (Driver info: chromedriver=2.19.346078 (6f1f0cde889532d48ce8242342d0b84f94b114a1),platform=Windows NT 6.1 SP1 x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 15 milliseconds For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html Build info: version: '2.47.1', revision: '411b314', time: '2015-07-30 03:03:16' System info: host: 'ITHFPC17', ip: '10.98.0.48', os.name: 'Windows 7', os.arch: 'x86', os.version: '6.1', java.version: '1.8.0_40' Driver info: org.openqa.selenium.chrome.ChromeDriver Capabilities [{applicationCacheEnabled=false, rotatable=false, mobileEmulationEnabled=false, chrome={userDataDir=C:\Users\SELENI~1\AppData\Local\Temp\scoped_dir2384_11396}, takesHeapSnapshot=true, databaseEnabled=false, handlesAlerts=true, hasTouchScreen=false, version=45.0.2454.93, platform=XP, browserConnectionEnabled=false, nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true, webStorageEnabled=true, browserName=chrome, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true}] Session ID: 3244710644015ee170986333564ab806
Failed: Wait timed out after 10032ms

接下来的方法是等到元素存在,之后如果它是可见的,之后如果它是可点击的......但它也不起作用。奇怪的是,在selenium网格上一切正常,但是当我尝试在本地运行测试然后获得之前提到的异常时。

exports.clickOn = function (element) {
    browser.wait(EC.presenceOf(element), waitTimeout).then(function () {
        browser.wait(EC.visibilityOf(element), waitTimeout)
    }).then(function () {
        browser.wait(EC.elementToBeClickable(element), waitTimeout)
    }).then(function () {
        element.click();
    });
};

任何人都知道如何处理它? ......我被困住了。

2 个答案:

答案 0 :(得分:1)

通过解析等待elementToBeClickable()函数返回的承诺,等待元素有资格被点击。还要确保完成click()之前的操作,以便量角器可以按预期找到元素。可能将所有操作链接到彼此可能是一个很好的解决方案。这样可以避免StaleElementReferenceException错误。这是怎样的 -

browser.wait(EC.presenceOf(loginPage.userLogin), waitTimeout).then(function(){
    logIn();
}).then(function(){
    var welcomePage = new WelcomePage();
}).then(function(){
    browser.wait(EC.elementToBeClickable(welcomePage.usersButton), waitTimeout).then(function(){
        welcomePage.usersButton.click();
    });
});

希望它有所帮助。

答案 1 :(得分:1)

最后,我通过添加“不太好”来解决这个问题'简单的重试机制。

exports.clickOnElementWithWait = function (element, attempts) {
    if (attempts == null) {
        attempts = 10;
    }
    return element.click().then(function (found) {
    }, function (err) {
        if (attempts > 0) {
            browser.sleep(100);
            return exports.clickOnElementWithWait(element, attempts - 1);
        } else {
            throw err;
        }
    });
};

更新:不幸的是它随机工作。异常数量减少但仍然......

我有Java代码,当我在纯selenium / junit中体验它并想知道它是否有任何免费工具将其转换为javascript时帮助了我? 有人可以帮帮我吗?

public class RetryMechanism {

    private static final int DEFAULT_RETRY_NR = 20;
    private static final long DEFAULT_WAIT_TIME_IN_MILLI = 1000;
    private int numberOfRetries;
    private int numberOfTriesLeft;
    private static long timeToWait;

    public RetryMechanism() {
        this(DEFAULT_RETRY_NR, DEFAULT_WAIT_TIME_IN_MILLI);
    }

    public RetryMechanism(int numberOfRetries, long timeToWait) {
        this.numberOfRetries = numberOfRetries;
        numberOfTriesLeft = numberOfRetries;
        this.timeToWait = timeToWait;
    }

    public boolean shouldRetry() {
        return numberOfTriesLeft > 0;
    }

    public void errorOccurred(Throwable throwable) throws Exception {
        numberOfTriesLeft--;
        if (!shouldRetry()) {
            throw new Exception("Retry Failed: Total " + numberOfRetries
                    + " attempts made at interval " + getTimeToWait()
                    + "ms.\n"
                    + "Error message is : " + throwable.getMessage()
                    + "\n"
                    + "Caused by : " + throwable.getCause());
        }
        waitUntilNextTry();
    }

    public static long getTimeToWait() {
        return timeToWait;
    }

    public static void waitUntilNextTry() {
        try {
            Thread.sleep(getTimeToWait());
        } catch (InterruptedException ignored) {
        }
    }

    public interface Action {
        void doJob();
    }

    public static void retry(Action action) throws Exception {
        RetryMechanism retry = new RetryMechanism();
        while (retry.shouldRetry()) try {
            action.doJob();
            break;
        } catch (Exception e) {
            retry.errorOccurred(e);
        }
    }
}