Skip to content

Commit

Permalink
fix(webdriverJS): include/exclude chaining and iframe selectors (#404)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zidious authored Nov 30, 2021
1 parent 0372686 commit c7c50fb
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 43 deletions.
17 changes: 12 additions & 5 deletions packages/webdriverjs/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { WebDriver } from 'selenium-webdriver';
import { RunOptions, Spec, AxeResults, ContextObject } from 'axe-core';
import { source } from 'axe-core';
import { CallbackFunction, BuilderOptions, PartialResults } from './types';
import {
CallbackFunction,
BuilderOptions,
PartialResults,
Selector
} from './types';
import { normalizeContext } from './utils/index';
import AxeInjector from './axe-injector';
import {
Expand All @@ -16,8 +21,8 @@ import * as assert from 'assert';
class AxeBuilder {
private driver: WebDriver;
private axeSource: string;
private includes: string[];
private excludes: string[];
private includes: Selector[];
private excludes: Selector[];
private option: RunOptions;
private config: Spec | null;
private builderOptions: BuilderOptions;
Expand All @@ -41,7 +46,8 @@ class AxeBuilder {
* Selector to include in analysis.
* This may be called any number of times.
*/
public include(selector: string): this {
public include(selector: Selector): this {
selector = Array.isArray(selector) ? selector : [selector];
this.includes.push(selector);
return this;
}
Expand All @@ -50,7 +56,8 @@ class AxeBuilder {
* Selector to exclude in analysis.
* This may be called any number of times.
*/
public exclude(selector: string): this {
public exclude(selector: Selector): this {
selector = Array.isArray(selector) ? selector : [selector];
this.excludes.push(selector);
return this;
}
Expand Down
4 changes: 3 additions & 1 deletion packages/webdriverjs/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { WebDriver } from 'selenium-webdriver';
import type { Spec, AxeResults } from 'axe-core';
import type { Spec, AxeResults, BaseSelector } from 'axe-core';
import * as axe from 'axe-core';

export interface Options {
Expand All @@ -25,3 +25,5 @@ export type CallbackFunction = (
export type InjectCallback = (err?: Error) => void;

export type PartialResults = Parameters<typeof axe.finishRun>[0];

export type Selector = BaseSelector | BaseSelector[];
24 changes: 11 additions & 13 deletions packages/webdriverjs/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import type { ContextObject } from 'axe-core';
import { Selector } from '../types';

/**
* Get running context
*/
export const normalizeContext = (
include: string[],
exclude: string[]
include: Selector[],
exclude: Selector[]
): ContextObject => {
if (!exclude.length) {
if (!include.length) {
return { exclude: [] };
}
return { include };
const base: ContextObject = {
exclude: []
};
if (exclude.length && Array.isArray(base.exclude)) {
base.exclude.push(...exclude);
}
if (!include.length) {
return { exclude };
if (include.length) {
base.include = include;
}
return {
include,
exclude
};
return base;
};
101 changes: 77 additions & 24 deletions packages/webdriverjs/tests/axe-webdriverjs.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'mocha';
import { Spec } from 'axe-core';
import { AxeResults, Spec } from 'axe-core';
import { WebDriver } from 'selenium-webdriver';
import * as express from 'express';
import * as chromedriver from 'chromedriver';
Expand Down Expand Up @@ -404,48 +404,101 @@ describe('@axe-core/webdriverjs', () => {
});

describe('include/exclude', () => {
const flatPassesTargets = (results: AxeResults): string[] => {
return results.passes
.reduce((acc, pass) => {
return acc.concat(pass.nodes as any);
}, [])
.reduce((acc, node: any) => {
return acc.concat(node.target);
}, []);
};
it('with include and exclude', async () => {
let error: Error | null = null;
await driver.get(`${addr}/context.html`);
const builder = new AxeBuilder(driver)
.include('.include')
.exclude('.exclude');
const results = await builder.analyze();

try {
await builder.analyze();
} catch (e) {
error = e as Error;
}

assert.strictEqual(error, null);
assert.isTrue(flatPassesTargets(results).includes('.include'));
assert.isFalse(flatPassesTargets(results).includes('.exclude'));
});

it('with only include', async () => {
let error: Error | null = null;
await driver.get(`${addr}/context.html`);
const builder = new AxeBuilder(driver).include('.include');
const results = await builder.analyze();

try {
await builder.analyze();
} catch (e) {
error = e as Error;
}

assert.strictEqual(error, null);
assert.isTrue(flatPassesTargets(results).includes('.include'));
});

it('with only exclude', async () => {
let error: Error | null = null;
await driver.get(`${addr}/context.html`);
const builder = new AxeBuilder(driver).exclude('.exclude');
const results = await builder.analyze();

try {
await builder.analyze();
} catch (e) {
error = e as Error;
}
assert.isFalse(flatPassesTargets(results).includes('.exclude'));
});

it('with chaining only include', async () => {
await driver.get(`${addr}/context.html`);
const builder = new AxeBuilder(driver)
.include('.include')
.include('.include2');
const results = await builder.analyze();

assert.isTrue(flatPassesTargets(results).includes('.include'));
assert.isTrue(flatPassesTargets(results).includes('.include2'));
});

it('with chaining only exclude', async () => {
await driver.get(`${addr}/context.html`);
const builder = new AxeBuilder(driver)
.exclude('.exclude')
.exclude('.exclude2');
const results = await builder.analyze();

assert.isFalse(flatPassesTargets(results).includes('.exclude'));
assert.isFalse(flatPassesTargets(results).includes('.exclude2'));
});

it('with chaining include and exclude', async () => {
await driver.get(`${addr}/context.html`);
const builder = new AxeBuilder(driver)
.include('.include')
.include('.include2')
.exclude('.exclude')
.exclude('.exclude2');
const results = await builder.analyze();

assert.isTrue(flatPassesTargets(results).includes('.include'));
assert.isTrue(flatPassesTargets(results).includes('.include2'));
assert.isFalse(flatPassesTargets(results).includes('.exclude'));
assert.isFalse(flatPassesTargets(results).includes('.exclude2'));
});

it('with include and exclude iframe selectors with no violations', async () => {
await driver.get(`${addr}/context.html`);
const builder = new AxeBuilder(driver)
.include(['#ifr-one', 'html'])
.exclude(['#ifr-one', 'main'])
.exclude(['#ifr-one', 'img']);

const results = await builder.analyze();

assert.lengthOf(results.violations, 0);
});

it('with include and exclude iframe selectors with violations', async () => {
await driver.get(`${addr}/context.html`);
const builder = new AxeBuilder(driver)
.include(['#ifr-one', 'html'])
.exclude(['#ifr-one', 'main']);
const results = await builder.analyze();

assert.strictEqual(error, null);
assert.lengthOf(results.violations, 2);
assert.strictEqual(results.violations[0].id, 'image-alt');
assert.strictEqual(results.violations[1].id, 'region');
});
});

Expand Down
4 changes: 4 additions & 0 deletions packages/webdriverjs/tests/fixtures/context.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<body>
<h1>Context Test</h1>
<div class="include">include me</div>
<div class="include2">include me two</div>
<div class="exclude">exclude me</div>
<div class="exclude2">exclude me two</div>

<iframe src="iframe-one.html" id="ifr-one"></iframe>
</body>
</html>
14 changes: 14 additions & 0 deletions packages/webdriverjs/tests/fixtures/iframe-one.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>iframe one</title>
</head>
<body>
<main>
<h1>iframe context test</h1>
<input />
</main>
<!-- to produce 1 violations -->
<img />
</body>
</html>

0 comments on commit c7c50fb

Please sign in to comment.