Protractor: Can't locate web element using Protractor API

Created on 26 Jul 2018  路  31Comments  路  Source: angular/protractor

Hi,

I am using chrome headless browser in protractor for testing of Angular WebApp. But, the problem is headless browser is not locating the web element and giving below error,
- Failed: No element found using locator: By(css selector, *[id="login_form_login"])

obviously because it doesn't wait to load browser, css elements etc.

How it can be resolved to locate web element for headless browser?

Most helpful comment

@IgorSasovets, Thanks for the additional pointer. I'll surely try this and will update you.

All 31 comments

Hi, @bharukaRupesh ! Please provide your config file and test example.

Hi @IgorSasovets ,
Thanks for quick response..!

I have attached 3 files i.e.,
1)config.js file
2)LoginPage.ts - As I am using page object model in this example
3)login_spec.ts

Config_File.txt
LoginPage.txt
login_spec.txt

Please check it and let me know if I am going wrong anywhere.

Thanks) I'll check it and provide feedback.

@bharukaRupesh , I modified it a bit. Please try and provide feedback. Also, if it's Angular app I would recommend you to comment line browser.waitForAngularEnabled(false); in your config file. Which version of Angular used in your application?

Config_File.txt
login_spec.txt
LoginPage.txt

@IgorSasovets , I tried with the latest code modified by you, still I am getting the same error as below,
- Failed: No element found using locator: By(css selector, *[id="login_form_login"])

Basically, the application which I am working on is hybrid i.e. the login page is in "Angular Js" and post login it is in "Angular 5" that's why I have kept browser.waitForAngularEnabled(false); line in my config.js file.

I need to take a look at application. Could you share link to app if it's possible?

@IgorSasovets The application is still under development and not hosted anywhere.

Ok, but I still need example app to help you with this issue. Do you know some app with similar logic?

I can't share the application since it's under development. I just want to understand, what you need to see in the app. so that I can check it for you and update you.

It would be better if you give me any other pointers to look into.

I want to see integration of Angular5 into AngularJS because I had a lot of issues with Angular5 and synchronization. I used before hooks and worked with synchronization settings using browser.ignoreSynchronization = (false - if I want to work with angularjs | true - angular5).

As I said, the "Login" page is in "AngularJs" so for that I have kept browser.waitForAngularEnabled(false); in my config.js file and once I login to the application it's working fine for Angular 5 as well.

In other way, if I set browser.waitForAngularEnabled(true) to true, I get an error on login page itself that's why I kept it false so that it'll not wait for Angular to load since the login page is not in "Angular"

Apart from this, I don't have any other integration in my application.

@bharukaRupesh have you tried to use explicit waiter?

@CrispusDH, Yes I have one util package inside which I have written 2 methods with explicit wait( ) code as below,

util.txt

Please have a look at this utility methods and let me know if I am going wrong anywhere. This code is working perfectly with UI browser.

Waiting for your response!

@bharukaRupesh I did not find element with *[id="login_form_login"] locator in the LoginPage. Could you provide class with this element?

@CrispusDH I am providing you 3 different files as below,
1) Config.js file
2) LoginPage.ts
3) login_spec.ts

Config_File.txt
login_spec.txt
LoginPage.txt

This files are already checked by @IgorSasovets and suggested few changes but that also didn't work.

@bharukaRupesh yep, I took a look at those files. But I don't see the element, that's why I don't see how you implement action with this element. Maybe you didn't use explicit waiter.
You should wait element and only then do something.

Hey @CrispusDH , I am using Page Object Model and I have given you the "LoginPage" file in which I have used "element( )" to locate the UI Elements as below,

private userName = element(by.id('f_user'));
private password = element(by.id('f_pass'));
private loginButton = element(by.id('login_form_submit'));

Yesterday also I had provided you one "util" file in which I have implemented explicit wait. Still, I getting an issue.

@bharukaRupesh I see element with locator *[id="login_form_login"] that was root of issue in the your error message - Failed: No element found using locator: By(css selector, *[id="login_form_login"]).

  • 'f_user' does not equal to "login_form_login"
  • 'f_pass' does not equal to "login_form_login"
  • 'login_form_submit' does not equal to "login_form_login"

So, I ask you where I can take a look on your class where element with this locator "login_form_login" is located?

@CrispusDH Ohhh, yes it's my mistake. I had made some changes in a file that's the reason you can not see the "login_form_login"

But, yes I got the errors as below,
Failed: No element found using locator: By(css selector, *[id="f_user"])
Failed: No element found using locator: By(css selector, *[id="f_pass"])
Failed: No element found using locator: By(css selector, *[id="login_form_submit"])

Firstly, let's try to find the root of problem.
this it:

    it('should login to the application', function(){
        console.log("Login to application");

        loginPage.enterUsername(browser.params.userName);
        loginPage.enterPassword(browser.params.password);
        loginPage.clickLoginButton();
    });

change to:

    it('should login to the application', function(){
        console.log("Login to application");
        browser.sleep(10000);

        loginPage.enterUsername(browser.params.userName);
        loginPage.enterPassword(browser.params.password);
        loginPage.clickLoginButton();
    });

It will wait 10 sec until further actions will start. In this way we will understand wether the problem with wait or with something else.

I have tried by using browser.sleep(10000); but still getting the same error message.

So, what I think is problem is not with wait but it's with something else.

could you provide HTML of this page (DOM)?

I can't share the application since it's under development.

It would be better if I get to know what you want to check in it, so that I can check it for you and let you know.

I want to check the error. Maybe you don't have these ids in your DOM. Or you use iframe?

The first thing is, we have id's in the DOM that is for sure. The reason being confident is, I am using these ids to run my UI Automation on chrome and firefox. There it's working perfectly.

Secondly we are not using iframe.

So, the issue in the headless chrome. I'm sure will be better to create a question on stack overflow :). I'm not familiar with specific issues that could appear on headless chrome.

Hey,

I have tried using headless firefox and it has worked perfectly. Just did the following configurations,

multiCapabilities:[ { browserName: 'firefox', firefoxOptions: { args: ['--headless'] }, 'moz:firefoxOptions': { args: [ '--headless' ] } } ]

That means, now we can say there might be an issue in headless chrome.

@bharukaRupesh , you can do another one PoC. Just add custom wait that would be enough on your mind for this element to appear and execute next command:
const res = await browser.executeScript('return document.querySelector(<elementSelector>).offsetParent;', <selector>);.
If res not equal to null and you don't get any errors then element is visible on page.

@IgorSasovets, Thanks for the additional pointer. I'll surely try this and will update you.

While we may feel tempted to wait/sleep for certain amount of seconds what we are actually doing is increasing the time it takes to run all the E2E tests. This isn't a good practice, E2E UI automanted tests are already slow and we really want is to achieve faster feedback.

A way I got to avoid using wait/sleep was to use protractor's waitForAngular(): Promise
I have a Page Object where I defined:

Page.js

const __candyOption = element(by.id("ca-option-0"));
/**
     * Clicks on the dropdown selector box
     * @returns Promise<void>
     */
    function openDropdown() {
        return _dropdownSelector.click();
    }

    /**
     * Clicks on the the first candy displayed in the dropdown
     * @returns Promise<void>
     */
    function selectCandy() {
        return browser.waitForAngular()
            .then(() => _candyOption.click());
    }

Then I have my test:

it("Then the user can chooses the candy", (done) => {
            Page.openDropdown()
                .then(Page.selectCandy)
                .then(()=> {
                    expect(true).toBeTruthy();
                    done();
                });
});

@IgorSasovets, Thanks for the additional pointer. I'll surely try this and will update you.

Did you get a solution to this problem. We are getting a similar issue, but it is behaving differently in different machines, which is even stranger.

Was this page helpful?
0 / 5 - 0 ratings