nightwatch
nightwatch copied to clipboard
element found by `element.findAll(selector).nth()` cannot be used in old command like `setValue(ele, text)`
Description of the bug/issue
When I use element.findAll(selector).nth()
to find an element, I expect to put this element into the old command like setValue(ele, text)
, but throw error. It works with element.find(selector)
Steps to reproduce
No response
Sample test
import { NightwatchTests } from "nightwatch";
const home: NightwatchTests = {
"Google search test": async() => {
browser.url("https://google.com/ncr").assert.titleEquals("Google");
const ele1 = browser.element.findAll(by.css("textarea[name=q]")).nth(0);
await browser.setValue(ele1, "nightwatchjs"); //Fail
const ele2 = browser.element.find(by.css("textarea[name=q]"));
await browser.setValue(ele2, "nightwatchjs"); //Success
},
};
export default home;
Command to run
npx nightwatch nightwatch/google.ts
Verbose Output
- OTHER ERRORS:
Error
NoSuchElementError
An element could not be located on the page using the given search parameters.
{"error":{},"status":-1,"value":null}
Try fixing by :
1. Please inspect the html before the step
2. Verify if an element with the mentioned selector is present in the DOM tree
Error location:
/Users/wenguang.tian/nightwatch-test/nightwatch/google.ts:
–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
5 | browser.url("https://google.com/ncr").assert.titleEquals("Google");
6 | const ele = browser.element.findAll(by.css("textarea[name=q]")).nth(0);
7 | await browser.setValue(ele, "nightwatchjs");
8 | browser.debug();
9 | },
–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
Nightwatch Configuration
No response
Nightwatch.js Version
3.1.0
Node Version
19.9.0
Browser
No response
Operating System
No response
Additional Information
No response
@Terence625 That is not the correct way of using it. Instead of using browser.setValue()
and passing the element to it, you can directly do:
import { NightwatchTests } from "nightwatch";
const home: NightwatchTests = {
"Google search test": async () => {
browser.url("https://google.com/ncr").assert.titleEquals("Google");
const ele1 = browser.element.findAll(by.css("textarea[name=q]")).nth(0);
await ele1.setValue("nightwatchjs");
const ele2 = browser.element.find(by.css("textarea[name=q]"));
await ele2.setValue("nightwatchjs");
},
};
export default home;
@Terence625 That is not the correct way of using it. Instead of using
browser.setValue()
and passing the element to it, you can directly do:import { NightwatchTests } from "nightwatch"; const home: NightwatchTests = { "Google search test": async () => { browser.url("https://google.com/ncr").assert.titleEquals("Google"); const ele1 = browser.element.findAll(by.css("textarea[name=q]")).nth(0); await ele1.setValue("nightwatchjs"); const ele2 = browser.element.find(by.css("textarea[name=q]")); await ele2.setValue("nightwatchjs"); }, }; export default home;
@garg3133 yeah, I know that way, just our project used to use V2, and has a lot of old commands like setValue(ele, text)
, I'm just refactoring the element definition without changing the commands. browser.element.find()
works with the old command and the element type matches the command argument type requirement. I assume these new element command will work with the old commands too
@Terence625 In that case, you could use await
with element.find
and element.findAll
commands. Awaiting these commands returns a WebElement
which can be directly used with other commands.
import { NightwatchTests } from "nightwatch";
const home: NightwatchTests = {
"Google search test": async() => {
browser.url("https://google.com/ncr").assert.titleEquals("Google");
const ele1 = await browser.element.findAll(by.css("textarea[name=q]")).nth(0);
await browser.setValue(ele1, "nightwatchjs");
const ele2 = await browser.element.find(by.css("textarea[name=q]"));
await browser.setValue(ele2, "nightwatchjs");
},
};
export default home;
While passing the object returned by browser.element.find()
to other commands works right now, it is not entirely correct. It will only work with one layer, and if you nest element.find()
with other find commands, it won't work.
@Terence625 In that case, you could use
await
withelement.find
andelement.findAll
commands. Awaiting these commands returns aWebElement
which can be directly used with other commands.import { NightwatchTests } from "nightwatch"; const home: NightwatchTests = { "Google search test": async() => { browser.url("https://google.com/ncr").assert.titleEquals("Google"); const ele1 = await browser.element.findAll(by.css("textarea[name=q]")).nth(0); await browser.setValue(ele1, "nightwatchjs"); const ele2 = await browser.element.find(by.css("textarea[name=q]")); await browser.setValue(ele2, "nightwatchjs"); }, }; export default home;
While passing the object returned by
browser.element.find()
to other commands works right now, it is not entirely correct. It will only work with one layer, and if you nestelement.find()
with other find commands, it won't work.
@garg3133 then is this a typescript related bug? Because you can see if passing ScopedElement
as the command argument, there is not typescript error
But passing the
WebElement
as the command argument, it shows typescript error
You're right. I think we should be doing both of these things:
- Allow to pass
ScopedElement
to older commands (this could be done by checking if a.webElement
property exists onScopedElement
instance and if that is an instance ofWebElementPromise
). - Add a fix in TypeScript to allow the use of
WebElement
in older commands (but first we would need to check ifWebElement
is actually accepted in all the older commands).
For now, could you try passing the WebElement
instance to the older commands and use // @ts-ignore
to ignore the TS error on that line for temporary basis, till this is fixed in TS?
@garg3133 yes, I'll use @ts-ignore
to workaround for now, thanks