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:
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!
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);
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);
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
Nor in this Python list of Selenium methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With