使用$$[n]代替选择器来获取Spectron/WebdriverIO中的第n个子元素

3
我正在尝试使用Spectron测试我的Electron应用程序。文档中提到,当尝试查找第n个子元素时,可以使用nth child选择器,或者使用$$获取与选择器匹配的所有子元素,然后使用索引运算符,例如$$("foo")[0]获取第一个foo。文档 有了这个知识,我期望以下代码输出:BAR。但是我无法让它工作,我尝试了以下内容:
const foo = ".foo";
const fooElements = app.client.$$ (foo);
console.log ("FOOELEMENTS", await TP (app.client.getHTML (foo)));
console.log ("BAR", fooElements[0].getText (".bar"));

并获取以下输出结果:
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)

你可以看到,输出的HTML确实有几个.foo div,但是当我尝试访问第一个时,它说fooElements[0]undefined
顺便提一下(这不应该与主题相关):TP是我写的一个名为toPromise的函数的别名,它让我等待webdriver的promise,因为TypeScript对它们的实现方式感到困惑。
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;
        };
    }

有没有想法我做错了什么?或者有什么建议的替代方案?如果可能的话,我更愿意避免使用nth-child选择器。

编辑:更改为类

2个回答

1
实际上,webdriver窗口索引和元素[1]指的是第一个元素。

这对我来说很有效。

var button = ('//*[contains(@class,"popper")]')[1];

返回 this.app.client.click(button);

例子:

class Clix {

    constructor() {

        this.clix_search = '(//input[contains(@class,"clix-search")])[1]';

    }

    clix_input_search(app) {
        return help.setValue(app, this.clix_search, "pack");
    }

}

在辅助类中。
setValue(app, element, text) {

        return app.client.waitForVisible(element, 60000)
            .waitForEnabled(element, 60000)
            .clearElement(element)
            .setValue(element, text)
            .getValue(element)
            .should.eventually.equal(text)

    }

你是用Spectron还是webdriverio?我总是无法让它与Spectron一起工作。 - cham
哦,它只能使用xpath工作!如果不是我的一周,你已经让我开心了。非常感谢!!!! - cham

0

首先,你的例子很有趣。我不知道你是如何运行那段<html>代码的。 id值必须是唯一的:

id属性为HTML元素指定唯一的ID(在HTML文档中该值必须是唯一的)。

只需删除#bar选择器,你的代码就可以正常工作了。你已经通过selector键的值将选择器传递给了ELEMENT对象,因此不需要再次传递。

let locator = 'span[connectqa-device="installed"]'

browser.debug()

输出(在调试模式下被阻止的测试):

> 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'

或者,您可以这样做:let retText2 = browser.getText('span[connectqa-device="installed"]') > let retText2 = browser.getText(elems[0].selector)。当然,第二个例子只是为了教学目的,因为您可能永远不想以这种方式进行操作。

希望对您有所帮助。干杯!


我意识到ID不太对,这是我最终要修复的问题,但有趣的是这不是一个强制规则,更像是一个建议,但对于某些DOM函数,行为变得未定义。另外,虽然你的答案很有道理,但它并没有解决我的问题,因为选择器不是问题所在。问题在于getText未定义。参见“EXCEPTION TypeError: Cannot read property 'getText' of undefined”。 - austinrulezd00d
@austinrulezd00d,我会首先使用 .debug() 锁定测试用例的调试模式,并查看 fooElements 在初始化后返回了什么内容:const fooElements = app.client.$$(foo);。正如我在上面的回答中所演示的那样,它适用于常规设置,但不幸的是,在我作为新手出现的 TypeScript 方面,我的手被绑住了。 - iamdanchiv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接