Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(core): Add better error message for client-side redirects #2643

Closed
sjelin opened this issue Oct 28, 2015 · 49 comments
Closed

chore(core): Add better error message for client-side redirects #2643

sjelin opened this issue Oct 28, 2015 · 49 comments
Assignees

Comments

@sjelin
Copy link
Contributor

sjelin commented Oct 28, 2015

If the test clicks a link or something which causes a redirect outside of browser.get or browser.refresh, then the next time waitForAngular is called the user will probably run into this error message (since we didn't wait for Angular to load), which is not very helpful.

Users should be told what's going wrong and about potential work-arounds (e.g. using browser.get or browser.refresh to fix the bootstrapping).

@Awk34
Copy link
Contributor

Awk34 commented Nov 19, 2015

@sjelin would you please explain a bit more on what can be done to mitigate this problem?

My use case: I have a test that enters username/password and hits a log in button, that redirects to another page on successful log in.

@sjelin
Copy link
Contributor Author

sjelin commented Nov 19, 2015

If both pages are angular pages, you should just add a browser.refresh after the new page loads to fix the problem

@sjelin
Copy link
Contributor Author

sjelin commented Nov 19, 2015

We're working on a feature to make this better in the future

@phillee
Copy link

phillee commented Dec 7, 2015

I've been struggling with this issue for a week now. browser.refresh() doesn't work if I'm doing a POST.

@sjelin
Copy link
Contributor Author

sjelin commented Dec 8, 2015

That's good to keep in mind, thanks. For now, you could probably mitigate the problem by just having your test wait a few hundred milliseconds after the client side redirect occurs. This will stop Protractor from throwing the error message, though it wouldn't allow Protractor to bootstrap properly so it may cause some other unexpected problems (especially if you're using plugins or mock modules).

@tassoevan
Copy link

Actually, I'm using something like this as workaround where I know there will be a redirection:

(function (expectedUrl, timeout) {
    var loaded = false;

    browser.wait(function () {
        browser.executeScript(function () {
            return {
                url: window.location.href,
                haveAngular: !!window.angular
            };
        }).then(function (obj) {
            loaded = (obj.url == expectedUrl && obj.haveAngular);
        });

        return loaded;
    }, timeout);
})(expectedUrl, timeout);

@phillee
Copy link

phillee commented Jan 8, 2016

@tassoevan, that's perfect! It's what I'd expect waitForAngular to do - wait for angular to be available.

@patrickliechty
Copy link

When protractor starts, it always goes to the baseUrl then my test page. Is that considered the redirect you are talking about?

@phillee
Copy link

phillee commented Feb 14, 2016

Not quite @patrickliechty, I mean when you click on a link (like <a href='google.com'>) and it directs the browser to google.cm

@sjelin
Copy link
Contributor Author

sjelin commented Feb 16, 2016

@juliemr with @hankduan gone is there anyone working on the longer term fix for this anymore?

@vivekbrahmadandi
Copy link

@sjelin , is this issue still exists in protractor 3.1.1.I can see that one

@bobbyg603
Copy link

+1 for a better fix. Ran into this today with no idea how to reliably work-around it. Thanks!

@T3KT4K
Copy link

T3KT4K commented Feb 23, 2016

Having the same Issue!!! thanks @tassoevan for a reliable fix

@tchaffee
Copy link

+1 for a fix.

@keithdtyler
Copy link

I got this error by doing element().getText() outside of the specs (without a browser.get() having occurred) -- was trying to create a shortcut for the output of a particular div outside the specs. Turned it into a function and all was well.

@jamestrotter
Copy link

I get this error when running against \node_modules\protractor\example\conf.js, surely the example conf.js should always work regardless??

@Overdrivr
Copy link

For people using Protractor without Angular, is there a workaround ?

@deltadanger
Copy link

@Overdrivr You can set browser.ignoreSynchronization = true; to tell Protractor to not wait for Angular.

@adnanghaffar07
Copy link

browser.ignoreSynchronization = true works for me when i switch windows.

@jrgleason
Copy link

I am getting this without ignoreSynchronization with something like this....

afterAll(function(){
    adminPage.header.logout();
    // FIXME: WTF why isn't even this working 100% of the time
    setTimeout(function(){
      expect(loginPage.isVisible()).toBeTruthy();
    }, 1000 )
  })

loginPage seems to take a sec to load and this setTimeout doesn't help. browser.wait seems to help a little bit but still fails.

@xGreylee
Copy link

xGreylee commented Apr 1, 2017

@tassoevan hi dude, could you tell me how to config that browser.wait() like your description and where to config it

(function (expectedUrl, timeout) {
    var loaded = false;

    browser.wait(function () {
        browser.executeScript(function () {
            return {
                url: window.location.href,
                haveAngular: !!window.angular
            };
        }).then(function (obj) {
            loaded = (obj.url == expectedUrl && obj.haveAngular);
        });

        return loaded;
    }, timeout);
})(expectedUrl, timeout);

@danielduhh
Copy link

in angular (2) - Make sure your spec begins w/ browser.get('/');

import { browser, element, by } from 'protractor';

it('should display message saying app works', () => {
    browser.get('/');

    let title = element(by.id('title')).getText();
    expect<any>(title).toEqual('cool');
});

@elliotaplant
Copy link

elliotaplant commented May 25, 2017

After looking at @tassoevan's great workaround and getting my redirect tests working, I figured I'd share my TypeScript and Angular2 solution. I put this function on my abstract page class, but I think it might fit better on the browser object.

/**
  Wait for the page to make it to the next URL before continuing.
  A supplement to browser.waitForAngular() because protractor will continue control
  flow before navigation starts.

  Inputs:
    necessaryUrlFragment: a portion of the url that signifies you have successfully navigated
    timeout: the number of ms to wait before throwing an error. Defaults to the browsers default
      page timeout.
 */
waitForRedirect(necessaryUrlFragment: string, timeout: number = browser.getPageTimeout) {
  // Before we tell the browser to wait, assume it has not navigated
  let hasRedirected = false;

  // Passing a function to browser.wait() tells protractor to call that function repeatedly.
  // This function returns the closure variable hasRedirected, which will be set to true once the
  // necessaryUrlFragment has been found in the url
  browser.wait(() => {
    browser.getCurrentUrl()
      // Check to see if necessaryUrlFragment is in the current url
      .then(url => url.includes(necessaryUrlFragment))
      // Update our navigation status
      .then(hasNavigated => {
        hasRedirected = hasNavigated;
      });

    // Return our navigation status every time protractor asks for it - even if navigation is
    // not complete
    return hasRedirected;
  }, timeout);
}

Here's an example of how I used it in a test:

it('Should be able load the preferences page', () => {
  page.navigateToMarketing();
  page.clickButton('Manage Preferences');
  page.waitForRedirect('preferences/preferences');
  expect(page.getPageTitle()).toBe('MY PREFERENCES');
});

@Hokrani
Copy link

Hokrani commented Jun 16, 2017

My login page is non-Angular js page. Once i login to the application Angular js page is created. So I created spec file as given below:

describe('Login to Application', function() {
var userID = element(by.name('username'));
var password = element(by.name('password'));
var logInButton = element(by.id('Submit'));

function loginToApplication(stringSSOID, stringPassword) {
userID.sendKeys(stringSSOID);
password.sendKeys(stringPassword);
logInButton.click();

}

beforeEach(function() {
browser.ignoreSynchronisation = true;
browser.get(''); // which will navigate to login page of the application
});

it('have login to application', function() {
loginToApplication('77777','test')
browser.ignoreSynchronisation=false
expect(browser.getTitle()).toEqual('Software');
});
});

Getting below error message:
Failed: Error while waiting for Protractor to sync with the page: "window.an
gular is undefined. This could be either because this is a non-angular page or
because your test involves client-side navigation, which can interfere with Prot
ractor's bootstrapping. See http://git.io/v4gXM for details"

@maciejkamela
Copy link

Hi take a look at http://www.protractortest.org/#/timeouts#how-to-disable-waiting-for-angular
Besically there are couple of ways to login using non-Angular page but firstly try this one show in the docs.
Best Regards
Camel

@ArnaudPel
Copy link

I realize it's a lengthy discussion already, but this might help someone.

Such an error message can also happen when the page is reloading unexpectedly because of an unhandled error happening in an Angular component. The fact that browser console may not be persisted, together with how fast the tests execute made it quite not-straightforward for me to understand what was going on.

So maybe something could be done as far as the error message is concerned, since the aforementioned case is not 'client side navigation' per se :)

@wswebcreation
Copy link
Contributor

Hi @ArnaudPel

Tnx for your extra info. Maybe you can add a PR to explain this in the docs if you want?

@benjaminapetersen
Copy link

I currently get this error when doing the trip to our login page (a common problem):

Failed: Error while waiting for Protractor to sync with the page: "window.angular is undefined.  This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping.  See http://git.io/v4gXM for details"

Doing the ignoreSync trick doesn't seem to help:

browser.ignoreSynchronization = true;
// do work here with browser.driver 
browser.ignoreSynchronization = false;

The link lands here at this thread, but what to do next is not exactly clear.

Tested with Protractor versions: 5.2.1, 5.1.1, 5.1.0, 5.0.0

@thompsnm
Copy link

@benjaminapetersen - You could try using waitForAngularEnabled instead of ignoreSynchronization. I'm looking at the API reference page for Protractor v5.1.2 and it no longer includes ignoreSynchronization, but looking through the CHANGELOG I don't see when, if ever, that property was officially deprecated...

@seel93
Copy link

seel93 commented Nov 27, 2017

I tried waitForAngularEnabled but i still get the same error as @benjaminapetersen gets. Here is my current config:

exports.config = {
    rootElement: 'app',
    baseUrl: 'http://localhost:1384/#/',
    framework: 'jasmine',
    seleniumAddress: 'http://localhost:4444/wd/hub',
    specs: ['./tests/e2e/*.js'],
    multiCapabilities: [{
      'browserName': 'firefox',
      //'browserName': 'chrome',
    }, 
  ],
  jasmineNodeOpts: {
    showColors: true
  },
}

//example test: 

describe('Overall navigation', function () {
  it('test link', function () {
     browser.get('http://localhost:1384/#/registrerprodukt');
  });
});

@benjaminapetersen
Copy link

@thompsnm thanks! Though it looks like waitForAngularEnabled is also deprecated....

@mikehaas763
Copy link

@benjaminapetersen that deprecated doc tag is on the ignoreSynchronization property, not waitForAngularEnabled

@olga-nov
Copy link

olga-nov commented Jan 3, 2018

waitForAngularEnabled doesn't work for me either. It worked with IgnoreSynchronization before upgrading to Protractor 5. I need to switch into non-Angular iframe, and now I can't. Please advise. Thanks

@raduciobanu22
Copy link

raduciobanu22 commented Jan 5, 2018

@seel93 Try commenting rootElement: 'app', or try replacing it with rootElement: '*[ng-app]'.
I just installed protractor latest version and wrote a few specs for an Angular 1.6.1 app and seems to be working ok so far. I encountered that error message when I was trying to login in my app but I'm now using this approach:

onPrepare: function () {
    browser.driver.manage().timeouts().setScriptTimeout(60000);

    browser.driver.get('http://app.local.dev'+ '/login');
    browser.driver.findElement(by.id('user_login')).sendKeys('d','e','m', 'o');
    browser.driver.findElement(by.id('user_pass')).sendKeys('d','e','m', 'o');
    browser.driver.findElement(by.id('submit')).click();

    // Login takes some time, so wait until it's done.
    return browser.driver.wait(function() {
        return browser.driver.getCurrentUrl().then(function(url) {
            return /students\/agenda/.test(url);
        });
    }, 30000);
}

Note: I have ng-app set on the html tag

@benjaminapetersen
Copy link

rootElement: '*[ng-app]'? works to just search the page for whatever node? Haven't seen this before.

@bushev
Copy link

bushev commented Feb 1, 2018

I just solved my issue. 🥇 Root cause: Developer console side effect

@lkgarrison
Copy link

I was having this problem and the fix for me ended up being to change to protractor "^5.3.2" in my package.json

@rain01
Copy link

rain01 commented Jul 2, 2018

I have a regular login page and then I redirect to angular page.

So I don't exactly know how or why it works, because I'm really new to angular and angular e2e, but I got it working once I used the browser.waitForAngularEnabled(false); twice.

logIn() {
    const email = 'test';
    const password = 'test';

    browser.waitForAngularEnabled(false);
    browser.get('/login');

    element(by.id('username')).sendKeys(email);
    element(by.id('password')).sendKeys(password);
    element(by.css('[type="submit"]')).click();

    return browser.wait(function() {
        browser.waitForAngularEnabled(false);
        return browser.getCurrentUrl().then(function(url) {
            browser.waitForAngularEnabled(true);
            return /dashboard/.test(url);
        });
    }, 5000);
}

Hope it helps.

@svassr
Copy link

svassr commented May 27, 2019

That last solution almost work for me unless I got an error after the test passes :
Error: ECONNREFUSED connect ECONNREFUSED 127.0.0.1:4444 From: Task: WebDriver.getCurrentUrl()

rduthel added a commit to Iteatime/Acrabadabra that referenced this issue Jun 13, 2019
Yes, it's irrelevant for us, but it works at least (exit code 0), avoiding the so frustrating error described here : angular/protractor#2643.

Maybe some refactoring is possible, but first we need to modify tests to make them reflect our needs. Stay tuned.
rduthel added a commit to Iteatime/Acrabadabra that referenced this issue Jun 13, 2019
Yes, it's irrelevant for us, but it works at least (exit code 0), avoiding the so frustrating error described here : angular/protractor#2643.

Maybe some refactoring is possible, but first we need to modify tests to make them reflect our needs. Stay tuned.
@barddoo
Copy link

barddoo commented Aug 5, 2019

I got this error by doing element().getText() outside of the specs (without a browser.get() having occurred) -- was trying to create a shortcut for the output of a particular div outside the specs. Turned it into a function and all was well.

It works for anything, you can't use more than one 'element().anyfunction()' outside an ' it '.
Found it out the hard way...

@Hello-dl
Copy link

Hello-dl commented Nov 5, 2019

Got error when switch from one web page to another in Protractor:

Failed: Error while waiting for Protractor to sync with the page: "both angularJS testability and angular testability are undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See http://git.io/v4gXM for details"

the code is :
var url = browser.params.login.Url;
browser.get(url+'/#!/app/manage-users');

@phalgunv
Copy link

I started getting this error suddenly my CT builds. I noticed that this error occurs only with Firefox headless and worked fine with Chrome headless on Linux. I upgraded from Firefox v69 to the latest one (v72.0.2 at the moment) which fixed this issue.

@AlexanderTang
Copy link

browser.ignoreSynchronization has been deprecated and should not be used. As hinted from the original post, using browser.get seems to solve the issue.

If you want to use it in a way that you can disable and enable waitForAngularEnabled at will, you need to use browser.get after setting waitForAngularEnabled(true). For example:

// do things on your Angular application

waitForAngularEnabled(false)

// do things on non-angular page

waitForAngularEnabled(true)
browser.get('/home') // this is a page from your Angular application

browser.get blocks until the Angular page is loaded.

@188599
Copy link

188599 commented Nov 6, 2020

I'm currently hitting this error:

Exception has occurred: Error: Error while waiting for Protractor to sync with the page: "both angularJS testability and angular testability are undefined. This could be either because this is a non-angular page or because your test involves client-side navigation, which can interfere with Protractor's bootstrapping. See http://git.io/v4gXM for details"

But only when trying to debug through either VS Code debugger or chrome inspector debug (followed the instructions here for both cases https://www.protractortest.org/#/debugging).

Here's my launch.json config in VSCode.

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "E2E Test",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "program": "${workspaceFolder}\\node_modules\\protractor\\bin\\protractor",
            "args": ["${workspaceFolder}\\e2e\\protractor.conf.js"],
            "outFiles": [
                "${workspaceFolder}/e2e/**/*.js",
                "${workspaceFolder}/src/**/*.js"
            ]
        }
    ]
}

Maybe it's something I have set up wrong. Any help is appreciated, trying to write these without being able to properly debug is insanely difficult.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests