import global from 'global'; import { addons } from '@storybook/addons'; import { EVENTS } from './constants'; import { A11yParameters } from './params'; const { document, window: globalWindow } = global; if (module && module.hot && module.hot.decline) { module.hot.decline(); } const channel = addons.getChannel(); // Holds axe core running state let active = false; // Holds latest story we requested a run let activeStoryId: string | undefined; const getElement = () => { const storyRoot = document.getElementById('story-root'); return storyRoot ? storyRoot.childNodes : document.getElementById('root'); }; /** * Handle A11yContext events. * Because the event are sent without manual check, we split calls */ const handleRequest = async (storyId: string) => { const { manual } = await getParams(storyId); if (!manual) { await run(storyId); } }; const run = async (storyId: string) => { activeStoryId = storyId; try { const input = await getParams(storyId); if (!active) { active = true; channel.emit(EVENTS.RUNNING); const axe = await import('axe-core'); const { element = getElement(), config, options = {} } = input; axe.reset(); if (config) { axe.configure(config); } const result = await axe.run(element, options); // It's possible that we requested a new run on a different story. // Unfortunately, axe doesn't support a cancel method to abort current run. // We check if the story we run against is still the current one, // if not, trigger a new run using the current story if (activeStoryId === storyId) { channel.emit(EVENTS.RESULT, result); } else { active = false; run(activeStoryId); } } } catch (error) { channel.emit(EVENTS.ERROR, error); } finally { active = false; } }; /** Returns story parameters or default ones. */ const getParams = async (storyId: string): Promise => { const { parameters } = (await globalWindow.__STORYBOOK_STORY_STORE__.loadStory({ storyId })) || {}; return ( parameters.a11y || { config: {}, options: { restoreScroll: true, }, } ); }; channel.on(EVENTS.REQUEST, handleRequest); channel.on(EVENTS.MANUAL, run);