Simple test but invalid locator :-(

11,179

Solution 1

To extend @Gunderson's answer a little bit more. The main problem is that you are using an ElementFinder (the result of element() call) instead of a by locator. See how the buttonOnward is defined:

let buttonOnward = element(by.linkText('Continue'));

Now, you are using the buttonOnward, which is now an ElementFinder in place of a locator:

expect(element.all(buttonOnward).count()).toBe(1);

which, understandably, results into an "invalid locator" error.


What you meant is using the "by" locator instead:

expect(element.all(by.linkText('Continue')).count()).toBe(1);

Solution 2

I don't think your error has to do with the linkText locator at all, your problem is with expect(element.all(buttonOnward).count()).toBe(1);, that is an invalid locator. If you want to count the total buttons, you should just declare your locator like that:

let buttonOnward = element.all(by.linkText('Continue'));
expect(buttonOnward.count()).toBe(1);

Solution 3

In my case I was using browser.driver.findElement. This means I was using the Selenium API. However, the Selenium API apparently doesn't support by.model locators. However, the Protractor API does include support for the by.model locator, and to use the Protractor API I use the element function instead:

Doesn't Work:

//This would not work: 
//error  E/launcher - Error: TypeError: Invalid locator
browser.driver.findElement(by.model('login_form.email'))

Works:

//But this works; note it uses the `element` function 
//instead of `browser.driver.findElement`
element(by.model('login_form.email'))

Also Works:

//And this also works; note it uses `browser.driver.findElement`
//But it passes a different locator; not `by.model`, but `by.id`
browser.driver.findElement(by.id('#login_form_email'))

Note:

The Protractor by.model locator will ultimately call a CSS querySelectorAll by prefixing with 'ng-model'. It makes sense that Protractor adds by.model locator functionality because Protractor is more Angular-focused.

I am assuming Selenium doesn't support by.model natively because the "Model" locator is not listed among Selenium (Java) locators on this page

  • Id
  • Name
  • ClassName
  • CSS
  • Xpath
  • How to op

Nor in this Python list of Selenium methods.

Share:
11,179
Patrick
Author by

Patrick

Updated on July 30, 2022

Comments

  • Patrick
    Patrick almost 2 years

    I have this test:

    // import {by, element, browser} from "protractor";
    describe('intro', () => {
      beforeEach(() => {
        browser.get('');
      });
    
    it('should have multiple pages', () => {
        let buttonOnward = element(by.linkText('Continue'));
        expect(element.all(buttonOnward).count()).toBe(1);
      });
    });
    

    And get this result.

    1) intro should have multiple pages
      Message:
        Failed: Invalid locator
      Stack:
        TypeError: Invalid locator
            at Object.check [as checkedLocator] (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\by.js:267:9)
            at WebDriver.findElements (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\webdriver.js:919:18)
            at C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\built\element.js:161:44
            at ManagedPromise.invokeCallback_ (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:1379:14)
            at TaskQueue.execute_ (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2913:14)
            at TaskQueue.executeNext_ (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2896:21)
            at asyncRun (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2775:27)
            at C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:639:7
            at process._tickCallback (internal/process/next_tick.js:103:7)
        From: Task: Run it("should have multiple pages") in control flow
            at Object.<anonymous> (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:79:14)
            at C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\jasminewd2\index.js:16:5
            at ManagedPromise.invokeCallback_ (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:1379:14)
            at TaskQueue.execute_ (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2913:14)
            at TaskQueue.executeNext_ (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2896:21)
            at asyncRun (C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2775:27)
        From asynchronous test:
        Error
            at Suite.describe (C:\xampp\htdocs\test\intro_spec.ts:11:3)
            at Object.<anonymous> (C:\xampp\htdocs\test\intro_spec.ts:2:1)
            at Module._compile (module.js:556:32)
            at Object.Module._extensions..js (module.js:565:10)
            at Module.load (module.js:473:32)
            at tryModuleLoad (module.js:432:12)
    
    1 spec, 1 failure
    

    And I don't know why. Its really simple. I downloaded the typings for Jasmine and checked this file C:\Users\Patrick\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\by.js.

    There is a function defined for it:

    The defined function in by.js

    And the documentation says the function exists, too.

    http://www.protractortest.org/#/api?view=ProtractorBy.prototype.buttonText

    $ protractor --version
    Version 4.0.9
    $ npm -v
    3.10.8
    $ node -v
    v6.7.0
    

    Thanks in Advance for your ideas!