Skip to content

Commit

Permalink
fix(webdriverio): fix types between v8 and <v8 (#962)
Browse files Browse the repository at this point in the history
* fix(webdriverio): fix types between v8 and <v8

* fix tests and pin to same version

* latest wdio

* drop cli to use chromedriver 119 to fix 120 problem

* Update packages/webdriverio/src/utils.ts

Co-authored-by: Gabe <41127686+Zidious@users.noreply.github.com>

* suggestions

---------

Co-authored-by: Gabe <41127686+Zidious@users.noreply.github.com>
  • Loading branch information
straker and Zidious committed Dec 21, 2023
1 parent 4eec517 commit 0511338
Show file tree
Hide file tree
Showing 9 changed files with 522 additions and 1,425 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- run: npm ci
# HACK: Force a TTY to enable browser-driver-manager to manipulate stdout.
- shell: 'script -q -e -c "bash {0}"'
run: npx browser-driver-manager install chromedriver --verbose
run: npx browser-driver-manager install chromedriver=119 --verbose
working-directory: packages/cli
- run: npm run coverage --workspace=packages/cli

Expand Down
1,825 changes: 441 additions & 1,384 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion packages/webdriverio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@
"@types/chromedriver": "^81.0.1",
"@types/cssesc": "^3.0.0",
"@types/express": "^4.17.14",
"@types/mocha": "^10.0.0",
"@types/mocha": "^10.0.6",
"@types/node": "^20.8.10",
"@wdio/globals": "^8.27.0",
"async-listen": "^3.0.1",
"axe-test-fixtures": "github:dequelabs/axe-test-fixtures#v1",
"chai": "^4.3.6",
Expand Down
25 changes: 16 additions & 9 deletions packages/webdriverio/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,20 @@ import {
import { getFilename } from 'cross-dirname';
import { pathToFileURL } from 'url';

import type { Browser, Element } from 'webdriverio';
import type {
RunOptions,
AxeResults,
SerialContextObject,
SerialSelectorList,
SerialFrameSelector
} from 'axe-core';
import type { Options, CallbackFunction, PartialResults } from './types';
import type {
Options,
CallbackFunction,
PartialResults,
WdioBrowser,
WdioElement
} from './types';

let axeCorePath = '';
async function loadAxePath() {
Expand All @@ -43,7 +48,7 @@ async function loadAxePath() {
loadAxePath();

export default class AxeBuilder {
private client: Browser;
private client: WdioBrowser;
private axeSource: string;
private includes: SerialSelectorList = [];
private excludes: SerialSelectorList = [];
Expand Down Expand Up @@ -199,7 +204,9 @@ export default class AxeBuilder {
/**
* Injects `axe-core` into all frames.
*/
private async inject(browsingContext: Element | null = null): Promise<void> {
private async inject(
browsingContext: WdioElement | null = null
): Promise<void> {
await this.setBrowsingContext(browsingContext);
const runPartialSupported = await axeSourceInject(
this.client,
Expand Down Expand Up @@ -246,15 +253,15 @@ export default class AxeBuilder {
// ensure we fail quickly if an iframe cannot be loaded (instead of waiting
// the default length of 30 seconds)
const { pageLoad } = await this.client.getTimeouts();
this.client.setTimeout({
(this.client as WebdriverIO.Browser).setTimeout({
pageLoad: FRAME_LOAD_TIMEOUT
});

let partials: PartialResults | null;
try {
partials = await this.runPartialRecursive(context);
} finally {
this.client.setTimeout({
(this.client as WebdriverIO.Browser).setTimeout({
pageLoad
});
}
Expand Down Expand Up @@ -301,7 +308,7 @@ export default class AxeBuilder {
* - https://webdriver.io/docs/api/webdriver.html#switchtoframe
*/
private async setBrowsingContext(
id: null | Element | Browser = null
id: null | WdioElement | WdioBrowser = null
): Promise<void> {
if (id) {
await this.client.switchToFrame(id);
Expand All @@ -317,7 +324,7 @@ export default class AxeBuilder {

private async runPartialRecursive(
context: SerialContextObject,
frameStack: Element[] = []
frameStack: WdioElement[] = []
): Promise<PartialResults> {
const frameContexts = await axeGetFrameContext(this.client, context);
const partials: PartialResults = [
Expand Down Expand Up @@ -362,7 +369,7 @@ export default class AxeBuilder {

try {
await client.switchToWindow(newWindow.handle);
await client.url('about:blank');
await (client as WebdriverIO.Browser).url('about:blank');
} catch (error) {
throw new Error(
`switchToWindow failed. Are you using updated browser drivers? \nDriver reported:\n${
Expand Down
33 changes: 31 additions & 2 deletions packages/webdriverio/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
import type { Browser } from 'webdriverio';
import type { AxeResults, BaseSelector } from 'axe-core';
import * as axe from 'axe-core';
import { type Browser, type Element } from 'webdriverio';

/*
This type allows both webdriverio v8 and <=v7 Browser types
to work in the same codebase. The types are incompatible with
each other, but are compatible with the functions that we use.
Every new feature that we use from the Browser type will need
to be added to the Pick list
*/
export type WdioBrowser =
| Browser
| Pick<
WebdriverIO.Browser,
| '$$'
| '$'
| 'switchToFrame'
| 'switchToParentFrame'
| 'getWindowHandles'
| 'getWindowHandle'
| 'switchToWindow'
| 'createWindow'
| 'url'
| 'getTimeouts'
| 'setTimeout'
| 'closeWindow'
| 'executeAsync'
| 'execute'
>;

export type WdioElement = Element | WebdriverIO.Element;

export type CallbackFunction = (
error: string | null,
results: AxeResults | null
) => void;

export interface Options {
client: Browser;
client: WdioBrowser;
axeSource?: string;
}

Expand Down
44 changes: 22 additions & 22 deletions packages/webdriverio/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import assert from 'assert';
import type { Browser } from 'webdriverio';
import type {
AxeResults,
PartialResult,
Expand All @@ -9,13 +8,14 @@ import type {
SerialSelectorList,
SerialContextObject
} from 'axe-core';
import type { WdioBrowser } from './types';

export const FRAME_LOAD_TIMEOUT = 1000;

/**
* Validates that the client provided is WebdriverIO v5+.
*/
export const isWebdriverClient = (client: Browser): boolean => {
export const isWebdriverClient = (client: WdioBrowser): boolean => {
if (!client) {
return false;
}
Expand Down Expand Up @@ -82,14 +82,14 @@ const promisify = <T>(thenable: Promise<T>): Promise<T> => {
};

export const axeSourceInject = async (
client: Browser,
client: WdioBrowser,
axeSource: string
): Promise<{ runPartialSupported: boolean }> => {
await assertFrameReady(client);
return promisify(
// Had to use executeAsync() because we could not use multiline statements in client.execute()
// we were able to return a single boolean in a line but not when assigned to a variable.
client.executeAsync(`
(client as WebdriverIO.Browser).executeAsync(`
var callback = arguments[arguments.length - 1];
${axeSource};
window.axe.configure({
Expand All @@ -101,7 +101,7 @@ export const axeSourceInject = async (
);
};

async function assertFrameReady(client: Browser): Promise<void> {
async function assertFrameReady(client: WdioBrowser): Promise<void> {
// Wait so that we know there is an execution context.
// Assume that if we have an html node we have an execution context.
try {
Expand All @@ -119,7 +119,7 @@ async function assertFrameReady(client: Browser): Promise<void> {
reject();
}, FRAME_LOAD_TIMEOUT);
});
const executePromise = client.execute(() => {
const executePromise = (client as WebdriverIO.Browser).execute(() => {
return document.readyState === 'complete';
});
const readyState = await Promise.race([timeoutPromise, executePromise]);
Expand All @@ -130,13 +130,13 @@ async function assertFrameReady(client: Browser): Promise<void> {
}

export const axeRunPartial = (
client: Browser,
client: WdioBrowser,
context?: SerialContextObject,
options?: RunOptions
): Promise<PartialResult> => {
return promisify(
client
.executeAsync<string, []>(
(client as WebdriverIO.Browser)
.executeAsync(
`
var callback = arguments[arguments.length - 1];
var context = ${JSON.stringify(context)} || document;
Expand All @@ -145,20 +145,20 @@ export const axeRunPartial = (
callback(JSON.stringify(partials))
});`
)
.then((r: string) => deserialize<PartialResult>(r))
.then(r => deserialize<PartialResult>(r as string))
);
};

export const axeGetFrameContext = (
client: Browser,
client: WdioBrowser,
context: SerialContextObject
// TODO: add proper types
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any[]> => {
return promisify(
// Had to use executeAsync() because we could not use multiline statements in client.execute()
// we were able to return a single boolean in a line but not when assigned to a variable.
client.executeAsync(`
(client as WebdriverIO.Browser).executeAsync(`
var callback = arguments[arguments.length - 1];
var context = ${JSON.stringify(context)};
var frameContexts = window.axe.utils.getFrameContexts(context);
Expand All @@ -168,14 +168,14 @@ export const axeGetFrameContext = (
};

export const axeRunLegacy = (
client: Browser,
client: WdioBrowser,
context: SerialContextObject,
options: RunOptions,
config?: Spec
): Promise<AxeResults> => {
return promisify(
client
.executeAsync<string, []>(
(client as WebdriverIO.Browser)
.executeAsync(
`var callback = arguments[arguments.length - 1];
var context = ${JSON.stringify(context)} || document;
var options = ${JSON.stringify(options)} || {};
Expand All @@ -187,12 +187,12 @@ export const axeRunLegacy = (
callback(JSON.stringify(axeResults))
});`
)
.then((r: string) => deserialize<AxeResults>(r))
.then(r => deserialize<AxeResults>(r as string))
);
};

export const axeFinishRun = (
client: Browser,
client: WdioBrowser,
axeSource: string,
partialResults: PartialResults,
options: RunOptions
Expand All @@ -207,7 +207,7 @@ export const axeFinishRun = (
function chunkResults(result: string): Promise<void> {
const chunk = JSON.stringify(result.substring(0, sizeLimit));
return promisify(
client.execute(
(client as WebdriverIO.Browser).execute(
`
window.partialResults ??= '';
window.partialResults += ${chunk};
Expand All @@ -223,7 +223,7 @@ export const axeFinishRun = (
return chunkResults(partialString)
.then(() => {
return promisify(
client.executeAsync<string, []>(
(client as WebdriverIO.Browser).executeAsync(
`var callback = arguments[arguments.length - 1];
${axeSource};
window.axe.configure({
Expand All @@ -238,12 +238,12 @@ export const axeFinishRun = (
)
);
})
.then((r: string) => deserialize<AxeResults>(r));
.then(r => deserialize<AxeResults>(r as string));
};

export const configureAllowedOrigins = (client: Browser): Promise<void> => {
export const configureAllowedOrigins = (client: WdioBrowser): Promise<void> => {
return promisify(
client.execute(`
(client as WebdriverIO.Browser).execute(`
window.axe.configure({ allowedOrigins: ['<unsafe_all_origins>'] })
`)
);
Expand Down
2 changes: 1 addition & 1 deletion packages/webdriverio/test/axe-webdriverio.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('@axe-core/webdriverio', () => {
describe(`WebdriverIO Async (${protocol} protocol)`, () => {
let server: Server;
let addr: string;
let client: webdriverio.Browser;
let client: WebdriverIO.Browser;
const axePath = require.resolve('axe-core');
const axeSource = fs.readFileSync(axePath, 'utf8');
const axeLegacySource = fs.readFileSync(
Expand Down
3 changes: 3 additions & 0 deletions packages/webdriverio/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": ["node", "mocha", "@wdio/globals/types"]
},
"include": ["src"],
"exclude": ["test"]
}
10 changes: 5 additions & 5 deletions test/wdio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
"@axe-core/webdriverio": "^4.8.2",
"@types/chai": "^4.3.9",
"@types/mocha": "^10.0.3",
"@wdio/cli": "^8.20.2",
"@wdio/globals": "^8.20.0",
"@wdio/local-runner": "^8.20.0",
"@wdio/mocha-framework": "^8.20.0",
"@wdio/spec-reporter": "^8.20.0",
"@wdio/cli": "^8.27.0",
"@wdio/globals": "^8.27.0",
"@wdio/local-runner": "^8.27.0",
"@wdio/mocha-framework": "^8.27.0",
"@wdio/spec-reporter": "^8.27.0",
"async-listen": "^3.0.1",
"axe-test-fixtures": "github:dequelabs/axe-test-fixtures#v1",
"chai": "^4.3.10",
Expand Down

0 comments on commit 0511338

Please sign in to comment.