Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use axe run options from accessibility-insights-web (disables empty-table-header rule) #2402

Merged
merged 4 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { AxePuppeteer } from '@axe-core/puppeteer';
import * as Puppeteer from 'puppeteer';
import { IMock, Mock, MockBehavior, Times } from 'typemoq';
import { AxePuppeteerFactory } from './axe-puppeteer-factory';
import { RuleExclusion } from './rule-exclusion';
import { AxeConfiguration } from './axe-configuration';
import { AxeRunOptions } from './axe-run-options';

/* eslint-disable @typescript-eslint/no-explicit-any */

Expand All @@ -18,26 +18,30 @@ describe('AxePuppeteerFactory', () => {
let page: IMock<Puppeteer.Page>;
let fsMock: IMock<typeof fs>;
let axeConfiguration: AxeConfiguration;
let axeRunOptions: AxeRunOptions;

beforeEach(() => {
page = Mock.ofType<Puppeteer.Page>();
fsMock = Mock.ofInstance(fs, MockBehavior.Strict);
axeConfiguration = { allowedOrigins: ['test origin'] };
testSubject = new AxePuppeteerFactory(axeConfiguration, new RuleExclusion(), fsMock.object);
axeRunOptions = { runOnly: ['test-rule'] };
testSubject = new AxePuppeteerFactory(axeConfiguration, axeRunOptions, fsMock.object);
});

it('create axe puppeteer instance', async () => {
const axePuppeteer = await testSubject.createAxePuppeteer(page.object);
expect(axePuppeteer).toBeDefined();
expect(axePuppeteer).toBeInstanceOf(AxePuppeteer);
expect((axePuppeteer as any).config).toStrictEqual(axeConfiguration);
expect((axePuppeteer as any).axeOptions).toStrictEqual(axeRunOptions);
});

it('create axe puppeteer instance, sourcePath is empty', async () => {
const axePuppeteer = await testSubject.createAxePuppeteer(page.object, '');
expect(axePuppeteer).toBeDefined();
expect(axePuppeteer).toBeInstanceOf(AxePuppeteer);
expect((axePuppeteer as any).config).toStrictEqual(axeConfiguration);
expect((axePuppeteer as any).axeOptions).toStrictEqual(axeRunOptions);
});

it('create axe puppeteer instance, sourcePath is not empty', async () => {
Expand All @@ -52,12 +56,14 @@ describe('AxePuppeteerFactory', () => {
expect(axePuppeteer).toBeDefined();
expect(axePuppeteer).toBeInstanceOf(AxePuppeteer);
expect((axePuppeteer as any).config).toStrictEqual(axeConfiguration);
expect((axePuppeteer as any).axeOptions).toStrictEqual(axeRunOptions);
});

it('create axe puppeteer instance, legacyMode is true', async () => {
const axePuppeteer = await testSubject.createAxePuppeteer(page.object, '', true);
expect(axePuppeteer).toBeDefined();
expect(axePuppeteer).toBeInstanceOf(AxePuppeteer);
expect((axePuppeteer as any).config).toStrictEqual(axeConfiguration);
expect((axePuppeteer as any).axeOptions).toStrictEqual(axeRunOptions);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,21 @@ import { inject, injectable } from 'inversify';
import { isEmpty } from 'lodash';
import * as Puppeteer from 'puppeteer';
import { iocTypes } from '../ioc-types';
import { RuleExclusion } from './rule-exclusion';
import { AxeConfiguration } from './axe-configuration';
import { AxeRunOptions } from './axe-run-options';

@injectable()
export class AxePuppeteerFactory {
constructor(
@inject(iocTypes.AxeConfiguration) private readonly axeConfiguration: AxeConfiguration,
private readonly ruleExclusion: RuleExclusion = new RuleExclusion(),
@inject(iocTypes.AxeRunOptions) private readonly axeRunOptions: AxeRunOptions,
private readonly fileSystemObj: typeof fs = fs,
) {}

public async createAxePuppeteer(page: Puppeteer.Page, contentSourcePath?: string, legacyMode: boolean = false): Promise<AxePuppeteer> {
const axeSource = await this.getAxeSource(contentSourcePath);

return new AxePuppeteer(page, axeSource)
.configure(this.axeConfiguration)
.disableRules(this.ruleExclusion.accessibilityRuleExclusionList)
.setLegacyMode(legacyMode);
return new AxePuppeteer(page, axeSource).configure(this.axeConfiguration).options(this.axeRunOptions).setLegacyMode(legacyMode);
}

private async getAxeSource(contentSourcePath?: string): Promise<string> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import type { RunOptions } from 'axe-core';

export type AxeRunOptions = RunOptions;

// This is copied verbatim from the built version of the @accessibility-insights/axe-config
// package in microsoft/accessibility-insights-web. It must be updated with each axe-core update
// and also to pick up any out-of-band rule customizations.
//
// In the future, it would be nice to publish that package and pick it up via NPM instead of
// copying it here. See https://github.com/microsoft/accessibility-insights-service/issues/571
export const webAxeRunOptions: AxeRunOptions = {
runOnly: {
type: 'rule',
values: [
'area-alt',
'aria-allowed-attr',
'aria-allowed-role',
'aria-command-name',
'aria-hidden-body',
'aria-hidden-focus',
'aria-input-field-name',
'aria-meter-name',
'aria-progressbar-name',
'aria-required-attr',
'aria-required-children',
'aria-required-parent',
'aria-roledescription',
'aria-roles',
'aria-toggle-field-name',
'aria-tooltip-name',
'aria-valid-attr-value',
'aria-valid-attr',
'audio-caption',
'autocomplete-valid',
'avoid-inline-spacing',
'blink',
'button-name',
'color-contrast',
'definition-list',
'dlitem',
'document-title',
'duplicate-id-active',
'duplicate-id-aria',
'frame-focusable-content',
'frame-title',
'html-has-lang',
'html-lang-valid',
'html-xml-lang-mismatch',
'image-alt',
'input-button-name',
'input-image-alt',
'label',
'link-in-text-block',
'link-name',
'list',
'listitem',
'marquee',
'meta-refresh',
'meta-viewport',
'nested-interactive',
'object-alt',
'presentation-role-conflict',
'role-img-alt',
'select-name',
'server-side-image-map',
'svg-img-alt',
'td-headers-attr',
'th-has-data-cells',
'valid-lang',
'video-caption',
],
},
pingWaitTime: 1000,
};

This file was deleted.

1 change: 1 addition & 0 deletions packages/scanner-global-library/src/ioc-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@

export const iocTypes = {
AxeConfiguration: 'AxeConfiguration',
AxeRunOptions: 'AxeRunOptions',
AzureAuthClientCredentialProvider: 'azureAuthClientCredentialProvider',
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Container } from 'inversify';
import { AxePuppeteerFactory } from './axe-scanner/axe-puppeteer-factory';
import { setupCloudScannerContainer, setupLocalScannerContainer } from './setup-scanner-container';
import { cloudAxeConfiguration, localAxeConfiguration } from './axe-scanner/axe-configuration';
import { webAxeRunOptions } from './axe-scanner/axe-run-options';
import { iocTypes } from './ioc-types';

/* eslint-disable @typescript-eslint/no-explicit-any */
Expand All @@ -27,6 +28,10 @@ describe(setupCloudScannerContainer, () => {
expect(container.get(iocTypes.AxeConfiguration)).toBe(cloudAxeConfiguration);
});

it('should use webAxeRunOptions', () => {
expect(container.get(iocTypes.AxeRunOptions)).toBe(webAxeRunOptions);
});

function verifySingletonResolution(key: any): void {
expect(container.get(key)).toBeDefined();
expect(container.get(key)).toBe(container.get(key));
Expand All @@ -44,4 +49,8 @@ describe(setupLocalScannerContainer, () => {
it('should use localAxeConfiguration', () => {
expect(container.get(iocTypes.AxeConfiguration)).toBe(localAxeConfiguration);
});

it('should use webAxeRunOptions', () => {
expect(container.get(iocTypes.AxeRunOptions)).toBe(webAxeRunOptions);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@

import * as inversify from 'inversify';
import { cloudAxeConfiguration, localAxeConfiguration } from './axe-scanner/axe-configuration';
import { webAxeRunOptions } from './axe-scanner/axe-run-options';
import { AxePuppeteerFactory } from './axe-scanner/axe-puppeteer-factory';
import { iocTypes } from './ioc-types';

export function setupCloudScannerContainer(container: inversify.Container): inversify.Container {
container.bind(iocTypes.AxeConfiguration).toConstantValue(cloudAxeConfiguration);
container.bind(iocTypes.AxeRunOptions).toConstantValue(webAxeRunOptions);
container.bind(AxePuppeteerFactory).toSelf().inSingletonScope();

return container;
}

export function setupLocalScannerContainer(container: inversify.Container): inversify.Container {
container.bind(iocTypes.AxeConfiguration).toConstantValue(localAxeConfiguration);
container.bind(iocTypes.AxeRunOptions).toConstantValue(webAxeRunOptions);

return container;
}