Skip to content

Commit

Permalink
test(storefront): refactored axe-core test and added test for dark sc…
Browse files Browse the repository at this point in the history
…heme | oh | #3099
  • Loading branch information
o-hook committed Jun 18, 2024
1 parent abf883b commit f6c6e84
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 82 deletions.
77 changes: 16 additions & 61 deletions packages/storefront/tests/a11y/helpers/axe-helper.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,19 @@
import { AxeBuilder } from '@axe-core/playwright';
import { type Page, expect } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';
import { test as base } from '@playwright/test';

const console = require('console'); // workaround for nicer logs

const AXE_RESULTS_DIR = path.resolve(__dirname, '../results');
fs.mkdirSync(AXE_RESULTS_DIR, { recursive: true });
fs.readdirSync(AXE_RESULTS_DIR)
.filter((file) => file.match(/^a11y-[a-z\d-]+\.json$/))
.forEach((file) => fs.rmSync(path.resolve(AXE_RESULTS_DIR, file)));

export const a11yAnalyze = async (
page: Page,
opts?: { suffix?: string; excludeSelector?: string; includeSelector?: string }
) => {
const pageUrl = page.url();
const { suffix, includeSelector, excludeSelector } = opts || {};

// docs: https://github.com/dequelabs/axe-core-npm/tree/develop/packages/playwright
const axe = new AxeBuilder({ page })
// defaults aren't good enough: https://github.com/dequelabs/axe-core/blob/master/doc/API.md#axe-core-tags
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa']);

if (includeSelector) {
axe.include(includeSelector);
}
if (excludeSelector) {
axe.exclude(excludeSelector);
}

const result = await axe.analyze();

const { length: amountOfViolations } = result.violations.filter((violation) => {
// TODO: needs to be re-enabled with issue #1919
return violation.id !== 'target-size';
});

if (amountOfViolations > 0) {
const testId = (pageUrl.replace(/\//g, '-') || 'root') + (suffix ? `-${suffix}` : '');
fs.writeFileSync(path.resolve(AXE_RESULTS_DIR, 'a11y-' + testId + '.json'), JSON.stringify(result, null, 2));

// map strangely nested and unreadable violations to readable and usable element selectors
const output = result.violations
.map((item) => {
const title = `${item.id} (${item.impact})` + (suffix ? ` on ${suffix}` : '');

const selectors = item.nodes
.map(
(node) =>
'– ' +
(Array.isArray(node.target)[0] ? (node.target[0] as unknown as string[]) : node.target).join(' >>> ')
)
.join('\n');
return `${title}:\n${selectors}`;
})
.join('\n');

console.log(output);
}

expect(amountOfViolations).toBe(0);
type AxeFixture = {
makeAxeBuilder: () => AxeBuilder;
};

// Extend base test by providing "makeAxeBuilder"
//
// This new "test" can be used in multiple test files, and each of them will get
// a consistently configured AxeBuilder instance.
export const test = base.extend<AxeFixture>({
makeAxeBuilder: async ({ page }, use) => {
const makeAxeBuilder = () =>
new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'wcag22aa']);
await use(makeAxeBuilder);
},
});
export { expect } from '@playwright/test';
85 changes: 64 additions & 21 deletions packages/storefront/tests/a11y/specs/accessibility.a11y.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { type Page, test, expect } from '@playwright/test';
import { a11yAnalyze } from '../helpers';
import { type Page } from '@playwright/test';
import { test, expect } from '../helpers';
import * as fs from 'fs';
import * as path from 'path';
import { schemes } from '@porsche-design-system/shared/testing/playwright.vrt';

const console = require('console'); // workaround for nicer logs

const getInternalUrls = (): string[] => {
const sitemapPath = path.resolve(__dirname, '../../e2e/fixtures/sitemap.json');
const sitemap = JSON.parse(fs.readFileSync(sitemapPath, 'utf8'));
Expand Down Expand Up @@ -58,21 +60,49 @@ test('should have successfully extracted :root styles', () => {

test.describe('outside main element', () => {
const excludeSelector = 'main';
schemes.forEach((scheme) => {
const enableDarkModeScheme = (page: Page) => {
if (scheme === 'dark') {
return enableDarkMode(page);
}
};

test('should have no accessibility issues on front page', async ({ page }) => {
await gotoUrl(page, '/');
await a11yAnalyze(page, { suffix: 'light', excludeSelector });
test(`should have no accessibility issues on front page for scheme ${scheme}`, async ({
page,
makeAxeBuilder,
}, testInfo) => {
await gotoUrl(page, '/');

await enableDarkMode(page);
await a11yAnalyze(page, { suffix: 'dark', excludeSelector });
});
await enableDarkModeScheme(page);

const accessibilityScanResults = await makeAxeBuilder().exclude(excludeSelector).analyze();

await testInfo.attach(`a11y-scan-results-changelog-${scheme}`, {
body: JSON.stringify(accessibilityScanResults.violations, null, 2),
contentType: 'application/json',
});

expect(accessibilityScanResults.violations.length).toBe(0);
});

test('should have no accessibility issues on changelog page', async ({ page }) => {
await gotoUrl(page, '/news/changelog'); // to have open accordion in sidebar
await a11yAnalyze(page, { suffix: 'light', excludeSelector });
// NEW TEST
test(`should have no accessibility issues on changelog page for scheme ${scheme}`, async ({
page,
makeAxeBuilder,
}, testInfo) => {
await gotoUrl(page, '/news/changelog'); // to have open accordion in sidebar

await enableDarkMode(page);
await a11yAnalyze(page, { suffix: 'dark', excludeSelector });
await enableDarkModeScheme(page);

const accessibilityScanResults = await makeAxeBuilder().exclude(excludeSelector).analyze();

await testInfo.attach(`a11y-scan-results-changelog-${scheme}`, {
body: JSON.stringify(accessibilityScanResults.violations, null, 2),
contentType: 'application/json',
});

expect(accessibilityScanResults.violations.length).toBe(0);
});
});
});

Expand All @@ -86,19 +116,32 @@ test.describe('within main element', () => {
for (const [url, index] of internalUrls.map<[string, number]>((url, i) => [url, i])) {
test(`should have no accessibility issues in main element for scheme-${scheme} at (${index + 1}/${internalUrls.length}) "${url}"`, async ({
page,
}) => {
makeAxeBuilder,
}, testInfo) => {
await gotoUrl(page, url);
await enableDarkMode(page);

// change the theme of component to dark if the option exists
if (scheme === 'dark' && (await page.locator('p-select[value="light"]').first().count())) {
const themeSwitch = page.locator('p-select[value="light"]').first();
await themeSwitch.click();
const option = themeSwitch.getByText('Dark');
await option.click();
if (scheme === 'dark') {
await enableDarkMode(page);
// change the theme of component to dark if the option exists
if (await page.locator('p-select[value="light"]').first().count()) {
const themeSwitch = page.locator('p-select[value="light"]').first();
await themeSwitch.click();
const option = themeSwitch.getByText('Dark');
await option.click();
}
}

await a11yAnalyze(page, { suffix: `main-scheme-${scheme}`, includeSelector });
const accessibilityScanResults = await makeAxeBuilder().exclude(includeSelector).analyze();

await testInfo.attach(`a11y-scan-results-main-${scheme}`, {
body: JSON.stringify(accessibilityScanResults.violations, null, 2),
contentType: 'application/json',
});

console.log(accessibilityScanResults.violations);

expect(accessibilityScanResults.violations.length).toBe(0);
});
}
});
Expand Down

0 comments on commit f6c6e84

Please sign in to comment.