3
\$\begingroup\$

I am writing some tests in selenium webdriver (on node.js). and have made a custom function to check the css value of an iFrame Element. I'm a coding beginner.

The script tests an app where the user writes the image width they want (just putting in a number) and the image in an iFrame should change width. This is tricky because one must switch iFrames, wait for elements to become stale (as the new image width is loaded) then grab the new element and check its css value.

Often, the tests are flaky because sometimes it checks before the value has changed etc. I finally wrote a function that passed 120 times out of 120 times.

//function looks for 'el', then switches iframe and extracts the desired cssValur, then compares it to the 'value' we expect
Page.checkCssValue = function (el, cssValue, value){
    //find function, the '0' represents the iframe index
    var newEl = this.find(el, 0);
    return newEl.getCssValue(cssValue).then(function(result){
        if(result !== value){
            console.log(result + " and " + value + " Do not Match.")
            return Page.checkCssValue(el, cssValue, value);
        }
        else{
            console.log(result + " and " + value + " Do Match!")
            return result;
        }
    });
};

But I'm not sure if this is considered bad programming and if a while loop would be better?

\$\endgroup\$
3
\$\begingroup\$

Code structure wise, the recursive pattern in JavaScript/Selenium and Protractor code is a pretty common one. The biggest problem here is that, you don't have a recursive cycle exit condition - if result would never become equal to value, you'll eventually get the recursive call stack size overflow error.

This is a "negative" case for you and would probably mean a test failure, but, in the world end-to-end UI tests, you have to be as specific in your test failures as possible (the "difficulties in finding the root cause for a test failure" is one of the reasons we should generally write more unit tests as opposed to end-to-end tests, according to Google Testing Pyramid).

A better approach to tackle flakiness would be to use Explicit Waits, which are design to continuously execute a function until it evaluates to true, or a timeout is reached:

this.wait( condition, opt_timeout, opt_message ) → Thenable

Schedules a command to wait for a condition to hold. The condition may be specified by a Condition, as a custom function, or as any promise-like thenable.

For a Condition or function, the wait will repeatedly evaluate the condition until it returns a truthy value. If any errors occur while evaluating the condition, they will be allowed to propagate. In the event a condition returns a promise, the polling loop will wait for it to be resolved and use the resolved value for whether the condition has been satisified. Note the resolution time for a promise is factored into whether a wait has timed out.

Here is how you can apply wait() in your case:

// function looks for 'el', then switches iframe and extracts the desired cssValue, then compares it to the 'value' we expect
Page.checkCssValue = function (el, cssValue, value) {
    // find function, the '0' represents the iframe index
    var newEl = this.find(el, 0);

    // wait for the desired CSS value
    var timeout = 5000;  // in milliseconds
    this.driver.wait(function() {
        return newEl.getCssValue(cssValue).then(function (result) {
            return result === value;
        });
    }, timeout, "CSS value '" + cssValue + "' has not become equal to '" + value + "'.");

    return newEl.getCssValue(cssValue);
};

where this.driver is your selenium webdriver instance, 5000 is a timeout value in milliseconds.

\$\endgroup\$
  • \$\begingroup\$ Perfect thank you! I have used explicit wait extensively but never with a custom condition. Thanks for showing me how it's done. \$\endgroup\$ – codemon Jan 28 '17 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.