mirror of https://github.com/rancher/dashboard.git
231 lines
4.7 KiB
TypeScript
231 lines
4.7 KiB
TypeScript
/* eslint-disable no-console */
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as sha from 'sha.js';
|
|
import { createHtmlReport } from 'axe-html-reporter';
|
|
|
|
const calcHash = function(str) {
|
|
return sha.default('sha256').update(str).digest('hex');
|
|
};
|
|
|
|
function createPath(testPath: string[]) {
|
|
const currentSpec = chain[chain.length - 1];
|
|
|
|
let found = currentSpec;
|
|
|
|
for (const p of testPath) {
|
|
const f = found.children.filter((item) => item.name === p);
|
|
|
|
if (f.length === 1) {
|
|
found = f[0];
|
|
} else {
|
|
const c = {
|
|
name: p,
|
|
children: [],
|
|
violations: [],
|
|
leaf: false,
|
|
};
|
|
|
|
found.children.push(c);
|
|
found = c;
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
export type TestViolation = {
|
|
name: string;
|
|
children: TestViolation[];
|
|
violations: any[];
|
|
leaf: boolean;
|
|
screenshot?: string;
|
|
};
|
|
|
|
export type Options = {
|
|
violations: any[];
|
|
titlePath: string[];
|
|
};
|
|
|
|
type Screenshot = {
|
|
name: string;
|
|
specName: string;
|
|
path: string;
|
|
};
|
|
|
|
// Root chain
|
|
const chain: TestViolation[] = [{
|
|
name: 'Root',
|
|
children: [],
|
|
violations: [],
|
|
leaf: false,
|
|
}];
|
|
|
|
const allViolations = [] as any[];
|
|
const screenshots = [] as Screenshot[];
|
|
let folder;
|
|
|
|
// Tidy up the chain
|
|
function tidy(item: TestViolation) {
|
|
item.children.forEach((i) => tidy(i));
|
|
|
|
if (item.violations.length === 0 && item.children.length === 1) {
|
|
if (item.children[0].leaf) {
|
|
// Collapse up
|
|
item.violations = item.children[0].violations;
|
|
item.children = [];
|
|
}
|
|
}
|
|
}
|
|
|
|
export function a11yScreenshot(options: any) {
|
|
const { titlePath, props } = options;
|
|
const found = createPath(titlePath);
|
|
|
|
found.screenshot = props.path;
|
|
}
|
|
|
|
function deDuplicate(violations: any[]) {
|
|
const result: any[] = [];
|
|
const seen: {[key: string]: any} = {};
|
|
|
|
violations.forEach((item) => {
|
|
const copy = JSON.parse(JSON.stringify(item));
|
|
|
|
delete copy.nodes;
|
|
|
|
const hash = calcHash(JSON.stringify(copy));
|
|
|
|
if (!seen[hash]) {
|
|
seen[hash] = item;
|
|
result.push(item);
|
|
} else {
|
|
// Merge the nodes
|
|
const existing = seen[hash];
|
|
|
|
item.nodes.forEach((node) => {
|
|
const str = JSON.stringify(node);
|
|
const exists = existing.nodes.find((n) => JSON.stringify(n) === str);
|
|
|
|
if (!exists) {
|
|
existing.nodes.push(node);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
function registerHooks(on, config) {
|
|
// Get the folder to write the reports into
|
|
folder = config.env.a11yFolder;
|
|
|
|
// fs.rmdirSync(folder);
|
|
if (!fs.existsSync(folder)) {
|
|
fs.mkdirSync(folder);
|
|
}
|
|
|
|
on('task', {
|
|
a11y(options: Options) {
|
|
const { violations, titlePath } = options;
|
|
const found = createPath(titlePath);
|
|
|
|
allViolations.push(...violations);
|
|
|
|
found.violations.push(...violations);
|
|
found.leaf = true;
|
|
|
|
return null;
|
|
},
|
|
|
|
a11yScreenshot(options: any ) {
|
|
const { titlePath, name } = options;
|
|
const found = createPath(titlePath);
|
|
|
|
// Move the screenshot to the accessibility folder
|
|
const details = screenshots.find((s) => s.name === name);
|
|
|
|
if (details) {
|
|
const screenFolder = path.join(folder, details.specName);
|
|
const destFile = path.join(screenFolder, `${ name }.png`);
|
|
|
|
found.screenshot = path.join(details.specName, `${ name }.png`);
|
|
|
|
if (!fs.existsSync(screenFolder)) {
|
|
fs.mkdirSync(screenFolder);
|
|
}
|
|
fs.renameSync(details.path, destFile);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
});
|
|
|
|
on('task', {
|
|
log(message) {
|
|
console.log(message);
|
|
|
|
return null;
|
|
},
|
|
table(message) {
|
|
console.table(message);
|
|
|
|
return null;
|
|
}
|
|
});
|
|
|
|
on('before:spec', (spec) => {
|
|
const newSpec = {
|
|
name: spec.baseName,
|
|
children: [],
|
|
violations: [],
|
|
leaf: false,
|
|
};
|
|
|
|
chain[0].children.push(newSpec);
|
|
|
|
// Push the spec onto the chain
|
|
chain.push(newSpec);
|
|
});
|
|
|
|
on('after:spec', () => {
|
|
// Pop the spec off of the chain
|
|
chain.pop();
|
|
});
|
|
|
|
on('after:screenshot', (details) => {
|
|
const { name, specName, path } = details;
|
|
|
|
screenshots.push({
|
|
name,
|
|
specName,
|
|
path
|
|
});
|
|
});
|
|
|
|
on('after:run', () => {
|
|
const root = chain[0];
|
|
|
|
tidy(root);
|
|
|
|
fs.writeFileSync(path.join(folder, 'accessibility.json'), JSON.stringify(root.children, null, 2));
|
|
|
|
const reportHTML = createHtmlReport({
|
|
results: { violations: deDuplicate(allViolations) },
|
|
options: {
|
|
projectKey: 'Rancher Manager',
|
|
doNotCreateReportFile: true,
|
|
},
|
|
});
|
|
|
|
fs.writeFileSync(path.join(folder, 'accessibility.html'), reportHTML);
|
|
|
|
return null;
|
|
});
|
|
|
|
return config;
|
|
}
|
|
|
|
export default registerHooks;
|