Reputation: 215
I am trying to use Spectron to test my Electron application. The documentation says when trying to find the nth child, you can use an nth child selector, or get all children that match selector using $$
and then use index operator ie $$ ("foo")[0]
gets first foo. DOCS
With that knowledge, i expect the following code to output: BAR
I can't get this to work, i try the following:
const foo = ".foo";
const fooElements = app.client.$$ (foo);
console.log ("FOOELEMENTS", await TP (app.client.getHTML (foo)));
console.log ("BAR", fooElements[0].getText (".bar"));
And get the following output:
console.log components\pages\analysis\__test__\Analysis.spectron.ts:44
FOOELEMENTS [ '<div class="foo"><div class="bar">BAR</div><div class="baz">BAZ</div></div>',
'<div class="foo"><div class="bar">BAR2</div><div class="baz">BAZ2</div></div>',
'<div class="foo"><div class="bar">BAR3</div><div class="baz">BAZ3</div></div>'
'<div class="foo"><div class="bar">BAR4</div><div class="baz">BAZ4</div></div>' ]
console.log components\pages\analysis\__test__\Analysis.spectron.ts:50
EXCEPTION TypeError: Cannot read property 'getText' of undefined
at components\pages\analysis\__test__\Analysis.spectron.ts:45:44
at Generator.next (<anonymous>)
at fulfilled (components\pages\analysis\__test__\Analysis.spectron.ts:4:58)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
As you can see, the output HTML indeed has several .foo
divs, but when i try to access the first one, it says fooElements[0]
is undefined
sideNote (which should not be relevant): TP
is an alias for a function i wrote called toPromise
which lets me await the webdriver promises, because TypeScript is confused by the way they are implemented:
export async function toPromise<T> (client: Webdriver.Client<T>)
{
return client as any as Promise<T>;
}
// Promise
interface Client<T> {
finally(callback: (...args: any[]) => void): Client<T>;
then<P>(
onFulfilled?: (value: T) => P | Client<P>,
onRejected?: (error: any) => P | Client<P>
): Client<P>;
catch<P>(
onRejected?: (error: any) => P | Client<P>
): Client<P>;
inspect(): {
state: "fulfilled" | "rejected" | "pending";
value?: T;
reason?: any;
};
}
Any idea what i am doing wrong? Or a suggested alternative? I'd prefer to avoid nth-child selectors if possible.
EDIT: changed to class
Upvotes: 3
Views: 3291
Reputation: 1408
Actually webdriver window index and elements refer [1] to be the first element.
This worked fine for me.
var button = ('//*[contains(@class,"popper")]')[1];
return this.app.client.click(button);
Example:
class Clix {
constructor() {
this.clix_search = '(//input[contains(@class,"clix-search")])[1]';
}
clix_input_search(app) {
return help.setValue(app, this.clix_search, "pack");
}
}
In helpers class
setValue(app, element, text) {
return app.client.waitForVisible(element, 60000)
.waitForEnabled(element, 60000)
.clearElement(element)
.setValue(element, text)
.getValue(element)
.should.eventually.equal(text)
}
Upvotes: 1
Reputation: 4112
First off, you're example is intriguing. I don't know how you got that piece of <html>
to be ran. The id
value must be unique:
The id attribute specifies a unique id for an HTML element (the value must be unique within the HTML document).
Your code should work after a small change, just remove the #bar
selector. You were passing the selector to the ELEMENT
object, but it already contains that information via the value of the selector
key.
let locator = 'span[connectqa-device="installed"]'
browser.debug()
Output (blocked test in debug-mode):
> let elems = $$(locator)
[18:10:22] COMMAND POST "/wd/hub/session/775b024e-0b6a-4a60-a5b2-26d4df961d0a/elements"
[18:10:22] DATA {"using":"css selector","value":"span[connectqa-device=\"installed\"]"}
[18:10:22] RESULT [{"element-6066-11e4-a52e-4f735466cecf":"c6719646-30da-43ff-9b17-40c074b4988a"},{"element-6066-11e4-a52e-4f735466cecf":"d5f8acf2-8f4f-4554-9fe6-7f863555f5b5"},{"element-6066-11e4-a52e-4f735466cecf":"53ff9b0a-2a88-4b13-9e54-9c54411c03c5"}]
> elems[0]
{ ELEMENT: 'c6719646-30da-43ff-9b17-40c074b4988a',
'element-6066-11e4-a52e-4f735466cecf': 'c6719646-30da-43ff-9b17-40c074b4988a',
selector: 'span[connectqa-device="installed"]',
value: { ELEMENT: 'c6719646-30da-43ff-9b17-40c074b4988a' },
index: 0 }
>
> elems[0].selector
'span[connectqa-device="installed"]'
>
> elems[0].getText()
[18:10:54] COMMAND GET "/wd/hub/session/775b024e-0b6a-4a60-a5b2-26d4df961d0a/element/c6719646-30da-43ff-9b17-40c074b4988a/text"
[18:10:54] DATA {}
[18:10:54] RESULT "Installed"
'Installed'
Alternatively, you could have done this: let retText2 = browser.getText('span[connectqa-device="installed"]')
> let retText2 = browser.getText(elems[0].selector)
. The second example of course is only for didactic purposes, as you'd probably never want to to it that way.
Hope it helps. Cheers!
Upvotes: 0