@techsio/storybook-better-a11y 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{visionSimulatorFilters.js → 100.js} +23 -1
- package/dist/{apcaChecker.js → 699.js} +253 -1
- package/dist/index.js +6 -5
- package/dist/manager.js +1540 -11
- package/dist/postinstall.js +1 -1
- package/dist/preview.js +1 -68
- package/dist/rslib-runtime.js +37 -0
- package/package.json +1 -1
- package/dist/AccessibilityRuleMaps.js +0 -532
- package/dist/a11yRunner.js +0 -105
- package/dist/a11yRunner.test.js +0 -21
- package/dist/a11yRunnerUtils.js +0 -30
- package/dist/a11yRunnerUtils.test.js +0 -61
- package/dist/apcaChecker.test.js +0 -124
- package/dist/axeRuleMappingHelper.js +0 -4
- package/dist/components/A11YPanel.js +0 -140
- package/dist/components/A11YPanel.stories.js +0 -198
- package/dist/components/A11YPanel.test.js +0 -110
- package/dist/components/A11yContext.js +0 -438
- package/dist/components/A11yContext.test.js +0 -277
- package/dist/components/Report/Details.js +0 -169
- package/dist/components/Report/Report.js +0 -106
- package/dist/components/Report/Report.stories.js +0 -86
- package/dist/components/Tabs.js +0 -54
- package/dist/components/TestDiscrepancyMessage.js +0 -55
- package/dist/components/TestDiscrepancyMessage.stories.js +0 -40
- package/dist/components/VisionSimulator.js +0 -83
- package/dist/components/VisionSimulator.stories.js +0 -56
- package/dist/constants.js +0 -25
- package/dist/manager.test.js +0 -86
- package/dist/params.js +0 -0
- package/dist/preview.test.js +0 -215
- package/dist/results.mock.js +0 -874
- package/dist/types.js +0 -6
- package/dist/utils.js +0 -21
- package/dist/withVisionSimulator.js +0 -41
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
const ADDON_ID = 'storybook/a11y';
|
|
2
|
+
const PANEL_ID = `${ADDON_ID}/panel`;
|
|
3
|
+
"a11y";
|
|
4
|
+
"vision";
|
|
5
|
+
const RESULT = `${ADDON_ID}/result`;
|
|
6
|
+
const REQUEST = `${ADDON_ID}/request`;
|
|
7
|
+
const RUNNING = `${ADDON_ID}/running`;
|
|
8
|
+
const ERROR = `${ADDON_ID}/error`;
|
|
9
|
+
const MANUAL = `${ADDON_ID}/manual`;
|
|
10
|
+
const SELECT = `${ADDON_ID}/select`;
|
|
11
|
+
const DOCUMENTATION_LINK = 'writing-tests/accessibility-testing';
|
|
12
|
+
const DOCUMENTATION_DISCREPANCY_LINK = `${DOCUMENTATION_LINK}#why-are-my-tests-failing-in-different-environments`;
|
|
13
|
+
const EVENTS = {
|
|
14
|
+
RESULT: RESULT,
|
|
15
|
+
REQUEST: REQUEST,
|
|
16
|
+
RUNNING: RUNNING,
|
|
17
|
+
ERROR: ERROR,
|
|
18
|
+
MANUAL: MANUAL,
|
|
19
|
+
SELECT: SELECT
|
|
20
|
+
};
|
|
21
|
+
const STATUS_TYPE_ID_COMPONENT_TEST = 'storybook/component-test';
|
|
22
|
+
const STATUS_TYPE_ID_A11Y = 'storybook/a11y';
|
|
1
23
|
const filters = {
|
|
2
24
|
blurred: {
|
|
3
25
|
label: 'Blurred vision',
|
|
@@ -97,4 +119,4 @@ const filterDefs = `<svg id="storybook-a11y-vision-filters" style="display: none
|
|
|
97
119
|
</filter>
|
|
98
120
|
</defs>
|
|
99
121
|
</svg>`;
|
|
100
|
-
export { filterDefs, filters };
|
|
122
|
+
export { ADDON_ID, DOCUMENTATION_DISCREPANCY_LINK, EVENTS, PANEL_ID, STATUS_TYPE_ID_A11Y, STATUS_TYPE_ID_COMPONENT_TEST, filterDefs, filters };
|
|
@@ -1,4 +1,44 @@
|
|
|
1
|
+
import { __webpack_require__ } from "./rslib-runtime.js";
|
|
2
|
+
import { expect } from "storybook/test";
|
|
3
|
+
import { ElementA11yParameterError } from "storybook/internal/preview-errors";
|
|
1
4
|
import { global } from "@storybook/global";
|
|
5
|
+
import { addons, useCallback, useEffect, waitForAnimations } from "storybook/preview-api";
|
|
6
|
+
import { EVENTS, filters, filterDefs, PANEL_ID } from "./100.js";
|
|
7
|
+
var preview_namespaceObject = {};
|
|
8
|
+
__webpack_require__.r(preview_namespaceObject);
|
|
9
|
+
__webpack_require__.d(preview_namespaceObject, {
|
|
10
|
+
afterEach: ()=>afterEach,
|
|
11
|
+
decorators: ()=>decorators,
|
|
12
|
+
initialGlobals: ()=>initialGlobals,
|
|
13
|
+
parameters: ()=>preview_parameters
|
|
14
|
+
});
|
|
15
|
+
const { document: a11yRunnerUtils_document } = global;
|
|
16
|
+
const withLinkPaths = (results, storyId)=>{
|
|
17
|
+
const pathname = a11yRunnerUtils_document.location.pathname.replace(/iframe\.html$/, '');
|
|
18
|
+
const enhancedResults = {
|
|
19
|
+
...results
|
|
20
|
+
};
|
|
21
|
+
const propertiesToAugment = [
|
|
22
|
+
'incomplete',
|
|
23
|
+
'passes',
|
|
24
|
+
'violations'
|
|
25
|
+
];
|
|
26
|
+
propertiesToAugment.forEach((key)=>{
|
|
27
|
+
if (Array.isArray(results[key])) enhancedResults[key] = results[key].map((result)=>({
|
|
28
|
+
...result,
|
|
29
|
+
nodes: result.nodes.map((node, index)=>{
|
|
30
|
+
const id = `${key}.${result.id}.${index + 1}`;
|
|
31
|
+
const linkPath = `${pathname}?path=/story/${storyId}&addonPanel=${PANEL_ID}&a11ySelection=${id}`;
|
|
32
|
+
return {
|
|
33
|
+
id,
|
|
34
|
+
...node,
|
|
35
|
+
linkPath
|
|
36
|
+
};
|
|
37
|
+
})
|
|
38
|
+
}));
|
|
39
|
+
});
|
|
40
|
+
return enhancedResults;
|
|
41
|
+
};
|
|
2
42
|
const { document: apcaChecker_document } = global;
|
|
3
43
|
const DEFAULT_APCA_OPTIONS = {
|
|
4
44
|
level: 'bronze',
|
|
@@ -285,4 +325,216 @@ function getImpact(contrastValue, threshold, maxContrast) {
|
|
|
285
325
|
if (difference > 10) return 'moderate';
|
|
286
326
|
return 'minor';
|
|
287
327
|
}
|
|
288
|
-
|
|
328
|
+
const { document: a11yRunner_document } = global;
|
|
329
|
+
const channel = addons.getChannel();
|
|
330
|
+
const DEFAULT_PARAMETERS = {
|
|
331
|
+
config: {},
|
|
332
|
+
options: {}
|
|
333
|
+
};
|
|
334
|
+
const DISABLED_RULES = [
|
|
335
|
+
'region'
|
|
336
|
+
];
|
|
337
|
+
const queue = [];
|
|
338
|
+
let isRunning = false;
|
|
339
|
+
const runNext = async ()=>{
|
|
340
|
+
if (0 === queue.length) {
|
|
341
|
+
isRunning = false;
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
isRunning = true;
|
|
345
|
+
const next = queue.shift();
|
|
346
|
+
if (next) await next();
|
|
347
|
+
runNext();
|
|
348
|
+
};
|
|
349
|
+
const run = async (input = DEFAULT_PARAMETERS, storyId)=>{
|
|
350
|
+
const axeCore = await import("axe-core");
|
|
351
|
+
const axe = axeCore?.default || globalThis.axe;
|
|
352
|
+
const { config = {}, options = {} } = input;
|
|
353
|
+
if (input.element) throw new ElementA11yParameterError();
|
|
354
|
+
const context = {
|
|
355
|
+
include: a11yRunner_document?.body,
|
|
356
|
+
exclude: [
|
|
357
|
+
'.sb-wrapper',
|
|
358
|
+
'#storybook-docs',
|
|
359
|
+
'#storybook-highlights-root'
|
|
360
|
+
]
|
|
361
|
+
};
|
|
362
|
+
if (input.context) {
|
|
363
|
+
const hasInclude = 'object' == typeof input.context && 'include' in input.context && void 0 !== input.context.include;
|
|
364
|
+
const hasExclude = 'object' == typeof input.context && 'exclude' in input.context && void 0 !== input.context.exclude;
|
|
365
|
+
if (hasInclude) context.include = input.context.include;
|
|
366
|
+
else if (!hasInclude && !hasExclude) context.include = input.context;
|
|
367
|
+
if (hasExclude) context.exclude = context.exclude.concat(input.context.exclude);
|
|
368
|
+
}
|
|
369
|
+
axe.reset();
|
|
370
|
+
const configWithDefault = {
|
|
371
|
+
...config,
|
|
372
|
+
rules: [
|
|
373
|
+
...DISABLED_RULES.map((id)=>({
|
|
374
|
+
id,
|
|
375
|
+
enabled: false
|
|
376
|
+
})),
|
|
377
|
+
...config?.rules ?? []
|
|
378
|
+
]
|
|
379
|
+
};
|
|
380
|
+
axe.configure(configWithDefault);
|
|
381
|
+
return new Promise((resolve, reject)=>{
|
|
382
|
+
const highlightsRoot = a11yRunner_document?.getElementById('storybook-highlights-root');
|
|
383
|
+
if (highlightsRoot) highlightsRoot.style.display = 'none';
|
|
384
|
+
const task = async ()=>{
|
|
385
|
+
try {
|
|
386
|
+
const result = await axe.run(context, options);
|
|
387
|
+
let contextElement = a11yRunner_document;
|
|
388
|
+
if (context.include instanceof Element) contextElement = context.include;
|
|
389
|
+
else if (Array.isArray(context.include)) {
|
|
390
|
+
const first = context.include[0];
|
|
391
|
+
if (first instanceof Element) contextElement = first;
|
|
392
|
+
else if ('string' == typeof first) contextElement = a11yRunner_document.querySelector(first) || a11yRunner_document;
|
|
393
|
+
} else if ('string' == typeof context.include) contextElement = a11yRunner_document.querySelector(context.include) || a11yRunner_document;
|
|
394
|
+
const excludeSelectors = Array.isArray(context.exclude) ? context.exclude.filter((value)=>'string' == typeof value) : 'string' == typeof context.exclude ? [
|
|
395
|
+
context.exclude
|
|
396
|
+
] : [];
|
|
397
|
+
const apcaResult = await runAPCACheck(contextElement, input.apca, excludeSelectors);
|
|
398
|
+
if (apcaResult.nodes.length > 0) result.violations.push(apcaResult);
|
|
399
|
+
else result.passes.push(apcaResult);
|
|
400
|
+
const resultWithLinks = withLinkPaths(result, storyId);
|
|
401
|
+
globalThis.__TECHSIO_A11Y_RESULTS__ = {
|
|
402
|
+
storyId,
|
|
403
|
+
results: resultWithLinks,
|
|
404
|
+
timestamp: Date.now()
|
|
405
|
+
};
|
|
406
|
+
resolve(resultWithLinks);
|
|
407
|
+
} catch (error) {
|
|
408
|
+
reject(error);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
queue.push(task);
|
|
412
|
+
if (!isRunning) runNext();
|
|
413
|
+
if (highlightsRoot) highlightsRoot.style.display = '';
|
|
414
|
+
});
|
|
415
|
+
};
|
|
416
|
+
channel.on(EVENTS.MANUAL, async (storyId, input = DEFAULT_PARAMETERS)=>{
|
|
417
|
+
try {
|
|
418
|
+
await waitForAnimations();
|
|
419
|
+
const result = await run(input, storyId);
|
|
420
|
+
const resultJson = JSON.parse(JSON.stringify(result));
|
|
421
|
+
channel.emit(EVENTS.RESULT, resultJson, storyId);
|
|
422
|
+
} catch (error) {
|
|
423
|
+
channel.emit(EVENTS.ERROR, error);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
function getIsVitestStandaloneRun() {
|
|
427
|
+
try {
|
|
428
|
+
return 'false' === ({
|
|
429
|
+
MODE: "production",
|
|
430
|
+
DEV: false,
|
|
431
|
+
PROD: true,
|
|
432
|
+
BASE_URL: "/",
|
|
433
|
+
ASSET_PREFIX: "auto"
|
|
434
|
+
}).VITEST_STORYBOOK;
|
|
435
|
+
} catch (e) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
const knownFilters = Object.values(filters).map((f)=>f.filter);
|
|
440
|
+
const knownFiltersRegExp = new RegExp(`\\b(${knownFilters.join('|')})\\b`, 'g');
|
|
441
|
+
const withVisionSimulator = (StoryFn, { globals })=>{
|
|
442
|
+
const { vision } = globals;
|
|
443
|
+
const applyVisionFilter = useCallback(()=>{
|
|
444
|
+
const existingFilters = document.body.style.filter.replaceAll(knownFiltersRegExp, '').trim();
|
|
445
|
+
const visionFilter = filters[vision]?.filter;
|
|
446
|
+
if (visionFilter && document.body.classList.contains('sb-show-main')) if (existingFilters && 'none' !== existingFilters) document.body.style.filter = `${existingFilters} ${visionFilter}`;
|
|
447
|
+
else document.body.style.filter = visionFilter;
|
|
448
|
+
else document.body.style.filter = existingFilters || 'none';
|
|
449
|
+
return ()=>document.body.style.filter = existingFilters || 'none';
|
|
450
|
+
}, [
|
|
451
|
+
vision
|
|
452
|
+
]);
|
|
453
|
+
useEffect(()=>{
|
|
454
|
+
const cleanup = applyVisionFilter();
|
|
455
|
+
const observer = new MutationObserver(()=>applyVisionFilter());
|
|
456
|
+
observer.observe(document.body, {
|
|
457
|
+
attributeFilter: [
|
|
458
|
+
'class'
|
|
459
|
+
]
|
|
460
|
+
});
|
|
461
|
+
return ()=>{
|
|
462
|
+
cleanup();
|
|
463
|
+
observer.disconnect();
|
|
464
|
+
};
|
|
465
|
+
}, [
|
|
466
|
+
applyVisionFilter
|
|
467
|
+
]);
|
|
468
|
+
useEffect(()=>{
|
|
469
|
+
document.body.insertAdjacentHTML('beforeend', filterDefs);
|
|
470
|
+
return ()=>{
|
|
471
|
+
const filterDefsElement = document.getElementById('storybook-a11y-vision-filters');
|
|
472
|
+
filterDefsElement?.parentElement?.removeChild(filterDefsElement);
|
|
473
|
+
};
|
|
474
|
+
}, []);
|
|
475
|
+
return StoryFn();
|
|
476
|
+
};
|
|
477
|
+
let vitestMatchersExtended = false;
|
|
478
|
+
const decorators = [
|
|
479
|
+
withVisionSimulator
|
|
480
|
+
];
|
|
481
|
+
const afterEach = async ({ id: storyId, reporting, parameters, globals, viewMode })=>{
|
|
482
|
+
const a11yParameter = parameters.a11y;
|
|
483
|
+
const a11yGlobals = globals.a11y;
|
|
484
|
+
const shouldRunEnvironmentIndependent = a11yParameter?.disable !== true && a11yParameter?.test !== 'off' && a11yGlobals?.manual !== true;
|
|
485
|
+
const getMode = ()=>{
|
|
486
|
+
switch(a11yParameter?.test){
|
|
487
|
+
case 'todo':
|
|
488
|
+
return 'warning';
|
|
489
|
+
case 'error':
|
|
490
|
+
default:
|
|
491
|
+
return 'failed';
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
if (shouldRunEnvironmentIndependent && 'story' === viewMode) try {
|
|
495
|
+
const result = await run(a11yParameter, storyId);
|
|
496
|
+
if (result) {
|
|
497
|
+
const hasViolations = (result?.violations.length ?? 0) > 0;
|
|
498
|
+
reporting.addReport({
|
|
499
|
+
type: 'a11y',
|
|
500
|
+
version: 1,
|
|
501
|
+
result,
|
|
502
|
+
status: hasViolations ? getMode() : 'passed'
|
|
503
|
+
});
|
|
504
|
+
if (getIsVitestStandaloneRun()) {
|
|
505
|
+
if (hasViolations && 'failed' === getMode()) {
|
|
506
|
+
if (!vitestMatchersExtended) {
|
|
507
|
+
const { toHaveNoViolations } = await import("vitest-axe/matchers");
|
|
508
|
+
expect.extend({
|
|
509
|
+
toHaveNoViolations
|
|
510
|
+
});
|
|
511
|
+
vitestMatchersExtended = true;
|
|
512
|
+
}
|
|
513
|
+
expect(result).toHaveNoViolations();
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
} catch (e) {
|
|
518
|
+
reporting.addReport({
|
|
519
|
+
type: 'a11y',
|
|
520
|
+
version: 1,
|
|
521
|
+
result: {
|
|
522
|
+
error: e
|
|
523
|
+
},
|
|
524
|
+
status: 'failed'
|
|
525
|
+
});
|
|
526
|
+
if (getIsVitestStandaloneRun()) throw e;
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
const initialGlobals = {
|
|
530
|
+
a11y: {
|
|
531
|
+
manual: false
|
|
532
|
+
},
|
|
533
|
+
vision: void 0
|
|
534
|
+
};
|
|
535
|
+
const preview_parameters = {
|
|
536
|
+
a11y: {
|
|
537
|
+
test: 'todo'
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
export { afterEach, decorators, initialGlobals, preview_namespaceObject, preview_parameters as parameters };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { definePreviewAddon } from "storybook/internal/csf";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export
|
|
2
|
+
import { preview_namespaceObject } from "./699.js";
|
|
3
|
+
import "./100.js";
|
|
4
|
+
const src = ()=>definePreviewAddon(preview_namespaceObject);
|
|
5
|
+
var src_PARAM_KEY = "a11y";
|
|
6
|
+
export default src;
|
|
7
|
+
export { src_PARAM_KEY as PARAM_KEY };
|