如何为 SpectronClient 实现 Typescript webdriverio?

How do I implement Typescript webdriverio for the SpectronClient?

Spectron is a node.js framework for automating Electron apps. I'm using Spectron along with AVA and Typescript to do automated Integration Testing. I'm using AVA's suggest method for making the test's context typesafe but I'm not able to figure out how to get typesafety on the Spectron's client property which is a webdriverio 客户。我只能看到 Spectron 打字稿定义文件提供的一些属性,这会导致打字稿转译错误。

这些是我遇到的错误:

src/pages/drive-shell.ts(7,34): error TS2339: Property 'waitForVisible' does not exist on type 'SpectronClient'.
src/pages/login.ts(7,34): error TS2339: Property 'waitForVisible' does not exist on type 'SpectronClient'.
src/pages/login.ts(11,21): error TS2339: Property 'setValue' does not exist on type 'SpectronClient'.
src/pages/login.ts(12,21): error TS2339: Property 'setValue' does not exist on type 'SpectronClient'.
src/pages/login.ts(13,21): error TS2339: Property 'click' does not exist on type 'SpectronClient'.

我在输入问题时实际上解决了这个问题,但我想既然我做了一些搜索但找不到任何解决方案,我想我可以回答我自己的问题以帮助其他人。

我需要获取 webdriver io 的类型

npm i -S @types/webdriverio

然后我将该类型导入我的 login.ts 脚本并将其用作 SpectronClient

import * as WebdriverIO from 'webdriverio';
export class Login {
    constructor(private client: WebdriverIO.Client<void>) { }

    public async waitForPageToLoad() {
        return await this.client.waitForVisible('#username');
    }

    public login(username: string, password: string) {
        this.client.setValue('#username', username);
        this.client.setValue('#Password', password);
        this.client.click('#login');
    }
}

这是我的完整 test.ts 测试脚本

import * as ava from 'ava';
import { Application } from 'spectron';
import { Login } from './pages/login';
import { Settings } from './settings';

function contextualize<T>(getContext: () => Promise<T>): ava.RegisterContextual<T> {
    ava.test.beforeEach(async (t) => {
        Object.assign(t.context, await getContext());
    });
    return ava.test;
}
const test = contextualize(async () => {
    const app = new Application({
        path: '../electron.exe',
        args: ['../app/index.html'],
    });
    await app.start();
    return { app };
});

test.afterEach.always(async (t) => await t.context.app.stop());

test('can login', async (t) => {
    const login = new Login(t.context.app.client);
    await login.waitForPageToLoad();
    login.login(Settings.username, Settings.password);
});

截至目前(2019 年 7 月),WebdriverIO 已移至版本 5.0,但 Spectron 仍在使用 WebdriverIO 4。确保在安装 WebdriverIO 类型时指定 Spectron 中使用的版本以解决此问题:

npm i -S @types/webdriverio@^4.8.0

在花了将近一整天的时间深入研究源代码后,我发现 Spectron 文档是错误的。

上面写的很清楚,

Spectron uses WebdriverIO and exposes the managed client property on the created Application instances. The client API is WebdriverIO's browser object.

但是在WebdriverIO documentation the functions like click, setValue, etc are not part of the browser object. They are available under the element object中可以看出。这就是我所做的,

const inputText = await app.client.$('user_name'); // get hold of the element
inputText.click(); // get access to the WebdriverIO functions