Sumit
Sumit

Reputation: 3068

Protractor Button Click and open page in new tab

I am fairly new to Protractor. I am trying to automate a scenario where I click on a button and its opens up a page in new tab and then we need to populate form in new page and submit.

Issue: when i click on button to open new page. My tests does not wait for new page to load and say test completed and success message.

I am using simple click event of that button to click the button.

element(by.id("newPlan")).click()

Am I missing something ? Do i need to do something so that my tests wait for new page to load and then I can perform some functions ?

Upvotes: 12

Views: 23071

Answers (5)

Tomasz Libich
Tomasz Libich

Reputation: 31

"Making sure that the new page is also an AngularJS page" doesn't make too much sense to me, if I'm honest :)

The test should be valid regardless of the type of the page/app the browser redirects to, shouldn't it?

If you are facing issues with accessing new tab URL on the non-angular page, try

browser.driver.getCurrentUrl();

instead of

browser.getCurrentUrl();

Upvotes: 2

Andrei Surzhan
Andrei Surzhan

Reputation: 151

Here is implementation without using browser.sleep() method. Function waitForNewWindow() is created using async and underscorejs. Where async.until() method is used for calling getAllWindowHandles() synchronously.

element(by.id("newPlan")).click()
    .then(function () {
        return waitForNewWindow();
    })
    .then(function (newWindowHandle) {
        browser.switchTo().window(newWindowHandle).then(function () {
            expect(browser.getCurrentUrl()).toMatch(/\/url/);
        });
    });

 /**
 * Wait for new window is opened
 *
 * @param {Object} [params]
 * @param {number} [params.runs] - number of tries
 * @param {number} [params.interval] - interval for launching getAllWindowHandles()
 *
 * @returns {webdriver.promise.Promise}
 */
function waitForNewWindow(params) {
    var currentHandles = [];
    var deferred = protractor.promise.defer();
    var finish;
    var newHandle;
    var numberOfRuns = 0;

    params = params ? params : {};
    params.runs = params.runs || 10;
    params.interval = params.interval || 1000;

    browser.driver.getAllWindowHandles()
        .then(function (handles) {
            currentHandles = handles;
        })
        .then(function () {
            async.until(
                // function that tests condition
                function () {
                    return newHandle || finish;
                },
                // function that is executed until test condition is true
                function (callback) {
                    browser.driver.getAllWindowHandles()
                        .then(function (newHandles) {
                            numberOfRuns++;

                            if (numberOfRuns > params.runs) {
                                finish = true;

                                return callback(null, newHandle);
                            }

                            if (currentHandles.length < newHandles.length) {
                                newHandle = _.difference(newHandles, currentHandles);

                                return callback(null, newHandle);
                            }

                            setTimeout(function () {
                                callback(null, newHandle);
                            }, params.interval);
                        });
                },
                // callback when test condition is true
                function (error, result) {
                    if (!result) {
                        return deferred.reject('New browser window hasn\'t been opened');
                    }

                    if (result.length > 1) {
                        return deferred.reject('More than one new browser window were opened');
                    }

                    deferred.fulfill(result.toString());
                }
            );
        });

    return deferred.promise;
};

Upvotes: 0

Omri Bendety
Omri Bendety

Reputation: 73

This is the solution that worked for me, but i've added a browser.sleep(500), to avoid the error mentioned above (UnknownError: unknown error: 'name' must be a nonempty string). The problem was that the new handle was not yet available. Just give it a moment after the click, to open the new tab and have it's handler available. Yes, it's adding an ugly sleep, but it's a short one...

element(by.id("newPlan")).click().then(function () {
        browser.sleep(500);
        browser.getAllWindowHandles().then(function (handles) {
            newWindowHandle = handles[1]; // this is your new window
            browser.switchTo().window(newWindowHandle).then(function () {
                // fill in the form here
                expect(browser.getCurrentUrl()).toMatch(/\/url/);
            });
        });
    });

Upvotes: 3

Blaise
Blaise

Reputation: 22212

There is another more convenient way. Just make use of the functions on the browser object.

element(by.id("newPlan")).click();
browser.sleep(10000);
browser.waitForAngular();
expect(browser.getCurrentUrl()).toMatch(/\/url/)

Upvotes: 2

Michal Lison
Michal Lison

Reputation: 489

You need to wait until the page opens by using callbacks. Try something in this sense:

    element(by.id("newPlan")).click().then(function () {
        browser.getAllWindowHandles().then(function (handles) {
            newWindowHandle = handles[1]; // this is your new window
            browser.switchTo().window(newWindowHandle).then(function () {
                // fill in the form here
                expect(browser.getCurrentUrl()).toMatch(/\/url/);
            });
        });
    });

Upvotes: 32

Related Questions