Skip to content

Commit

Permalink
typescript promise commands (#3577)
Browse files Browse the repository at this point in the history
## Proposed changes

webdriverio types are async by default.
webdriverio sync types are in @wdio/sync package

## Types of changes

- [x] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing functionality to not work as expected)

## Checklist

- [x] I have read the [CONTRIBUTING](https://github.com/webdriverio/webdriverio/blob/master/CONTRIBUTING.md) doc
- [ ] I have added tests that prove my fix is effective or that my feature works
- [x] I have added necessary documentation (if appropriate)

## Further comments

- In order to make this PR work webdriverio, webdriver and @wdio/sync packages have to be released
- Please note that it is a braking change for existing TypeScript users that work in sync mode

### Reviewers: @webdriverio/technical-committee

@CrispusDH
  • Loading branch information
mgrybyk authored and christian-bromann committed Feb 21, 2019
1 parent 792f089 commit c36d1f7
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -67,6 +67,7 @@ typings/
!/packages/wdio-mocha-framework/mocha-framework.d.ts
!/packages/wdio-jasmine-framework/jasmine-framework.d.ts
!/packages/wdio-selenium-standalone-service/selenium-standalone-service.d.ts
!/packages/**/webdriverio.d.ts
!babel.config.js
!.eslintrc.js
package-lock.json
Expand Down
10 changes: 10 additions & 0 deletions docs/TypeScript.md
Expand Up @@ -42,6 +42,16 @@ and your `tsconfig.json` needs to look like:
}
```

For sync mode (@wdio/sync) `webdriverio` types have to be replaced with `@wdio/sync`:

```json
{
"compilerOptions": {
"types": ["node", "@wdio/sync"]
}
}
```

You can even use a typed configuration if you desire.
All you have to do is create a plain js config file that registers typescript and requires the typed config:

Expand Down
1 change: 1 addition & 0 deletions packages/wdio-sync/package.json
Expand Up @@ -17,6 +17,7 @@
"test:eslint": "eslint src test",
"test:unit": "jest"
},
"types": "./webdriverio.d.ts",
"repository": {
"type": "git",
"url": "git://github.com/webdriverio/webdriverio.git"
Expand Down
22 changes: 22 additions & 0 deletions packages/wdio-sync/webdriverio.d.ts
@@ -0,0 +1,22 @@
/// <reference types="./webdriverio-core"/>

type BrowserObject = WebDriver.ClientOptions & WebDriver.Client & WebdriverIO.Browser;

declare namespace WebdriverIO {
function remote(
options?: WebDriver.Options,
modifier?: (...args: any[]) => any
): BrowserObject;

function multiremote(
options: WebdriverIO.MultiRemoteOptions
): WebDriver.Client;
}

declare var browser: BrowserObject;
declare function $(selector: string | Function): WebdriverIO.Element;
declare function $$(selector: string | Function): WebdriverIO.Element[];

declare module "@wdio/sync" {
export = WebdriverIO
}
45 changes: 45 additions & 0 deletions packages/webdriverio/webdriverio.d.ts
@@ -0,0 +1,45 @@
/// <reference types="./webdriverio-core"/>

type BrowserObject = WebDriver.ClientOptions & WebDriver.ClientAsync & WebdriverIOAsync.Browser;

// Element commands that should be wrapper with Promise
type ElementPromise = Omit<WebdriverIO.Element, 'addCommand'>;

// Element commands wrapper with Promise
type ElementAsync = {
[K in keyof ElementPromise]: WrapWithPromise<WebdriverIO.Element[K]>
}
// Element commands that should not be wrapper with promise
type ElementStatic = Pick<WebdriverIO.Element, 'addCommand'>

// Browser commands that should be wrapper with Promise
type BrowserPromise = Omit<WebdriverIO.Browser, 'addCommand' | 'options'>;

// Browser commands wrapper with Promise
type BrowserAsync = {
[K in keyof BrowserPromise]: WrapWithPromise<WebdriverIO.Browser[K]>
}

// Browser commands that should not be wrapper with promise
type BrowserStatic = Pick<WebdriverIO.Browser, 'addCommand' | 'options'>;
declare namespace WebdriverIOAsync {
function remote(
options?: WebDriver.Options,
modifier?: (...args: any[]) => any
): BrowserObject;

function multiremote(
options: WebdriverIO.MultiRemoteOptions
): WebDriver.ClientAsync;

interface Browser extends BrowserAsync, BrowserStatic { }
interface Element extends ElementAsync, ElementStatic { }
}

declare var browser: BrowserObject;
declare function $(selector: string | Function): Promise<WebdriverIOAsync.Element>;
declare function $$(selector: string | Function): Promise<WebdriverIOAsync.Element[]>;

declare module "webdriverio" {
export = WebdriverIOAsync
}
15 changes: 13 additions & 2 deletions scripts/templates/webdriver.tpl.d.ts
Expand Up @@ -4,6 +4,11 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
/// <reference types="node"/>

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

type ArgumentTypes<T> = T extends (...args: infer U) => infer R ? U : never;
type WrapWithPromise<T> = (...args: ArgumentTypes<T>) => Promise<[T]>;

declare namespace WebDriver {
type PageLoadingStrategy = 'none' | 'eager' | 'normal';
type ProxyTypes = 'pac' | 'noproxy' | 'autodetect' | 'system' | 'manual';
Expand Down Expand Up @@ -231,9 +236,9 @@ declare namespace WebDriver {
modifier?: (...args: any[]) => any,
proto?: object,
commandWrapper?: (commandName: string, fn: (...args: any[]) => any) => any
): Client;
): Promise<Client>;

interface Client {
interface ClientOptions {
capabilities: DesiredCapabilities;
isW3C: boolean;
isAndroid: boolean;
Expand All @@ -244,6 +249,12 @@ declare namespace WebDriver {

// generated typings
// ... insert here ...

interface ClientAsync extends AsyncClient {}
}

type AsyncClient = {
[K in keyof WebDriver.Client]: WrapWithPromise<WebDriver.Client[K]>
}

declare module "webdriver" {
Expand Down
24 changes: 4 additions & 20 deletions scripts/templates/webdriverio.tpl.d.ts
Expand Up @@ -2,15 +2,6 @@
/// <reference types="webdriver"/>

declare namespace WebdriverIO {
function remote(
options?: WebDriver.Options,
modifier?: (...args: any[]) => any
): WebDriver.Client & WebdriverIO.Browser;

function multiremote(
options: any
): WebDriver.Client;

type LocationParam = 'x' | 'y';

interface LocationReturn {
Expand Down Expand Up @@ -73,6 +64,10 @@ declare namespace WebdriverIO {
execArgv?: string[]
}

interface MultiRemoteOptions {
[capabilityName: string]: Options;
}

interface Suite {}
interface Test {}

Expand All @@ -83,7 +78,6 @@ declare namespace WebdriverIO {
}

interface Hooks {

onPrepare?(
config: Config,
capabilities: WebDriver.DesiredCapabilities
Expand Down Expand Up @@ -191,15 +185,5 @@ declare namespace WebdriverIO {
// ... browser commands ...
}

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

interface Config extends Options, Omit<WebDriver.Options, "capabilities">, Hooks {}
}

declare var browser: WebDriver.Client & WebdriverIO.Browser;
declare function $(selector: string | Function): WebdriverIO.Element;
declare function $$(selector: string | Function): WebdriverIO.Element[];

declare module "webdriverio" {
export = WebdriverIO
}
12 changes: 9 additions & 3 deletions scripts/type-generation/webdriverio-generate-typings.js
Expand Up @@ -66,8 +66,14 @@ const templateContents = fs.readFileSync(templatePath, 'utf8')
let typingsContents = templateContents.replace('// ... element commands ...', allElementCommands)
typingsContents = typingsContents.replace('// ... browser commands ...', allBrowserCommands)

const outputFile = path.join(__dirname, '..', '..', 'packages/webdriverio', 'webdriverio.d.ts')
fs.writeFileSync(outputFile, typingsContents, { encoding: 'utf-8' })
const outputFileWebdriverio = path.join(__dirname, '..', '..', 'packages/webdriverio', 'webdriverio-core.d.ts')
fs.writeFileSync(outputFileWebdriverio, typingsContents, { encoding: 'utf-8' })

const outputFileSync = path.join(__dirname, '..', '..', 'packages/wdio-sync', 'webdriverio-core.d.ts')
fs.writeFileSync(outputFileSync, typingsContents, { encoding: 'utf-8' })

// eslint-disable-next-line no-console
console.log(`Generated typings file at ${outputFileWebdriverio}`)

// eslint-disable-next-line no-console
console.log(`Generated typings file at ${outputFile}`)
console.log(`Generated typings file at ${outputFileSync}`)

0 comments on commit c36d1f7

Please sign in to comment.