Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple test but invalid locator :-(

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!

like image 749
Patrick Avatar asked Oct 01 '16 18:10

Patrick


3 Answers

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);
like image 109
alecxe Avatar answered Oct 06 '22 01:10

alecxe


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);
like image 36
Gunderson Avatar answered Oct 06 '22 00:10

Gunderson


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.

like image 38
The Red Pea Avatar answered Oct 05 '22 23:10

The Red Pea