feedbacks and fixes

This commit is contained in:
Clément Dungler 2020-04-19 18:21:38 +02:00
parent 748503ad69
commit 4547b366f1
4 changed files with 72 additions and 59 deletions

View File

@ -18,6 +18,7 @@ const getElement = () => {
};
const run = async (storyId: string) => {
console.log('Running', storyId);
try {
const input = getParams(storyId);
@ -55,6 +56,5 @@ const getParams = (storyId: string): Setup => {
);
};
channel.on(STORY_RENDERED, run);
channel.on(EVENTS.REQUEST, run);
channel.on(EVENTS.MANUAL, run);

View File

@ -54,7 +54,6 @@ export const A11YPanel: React.FC = () => {
const [status, setStatus] = useAddonState<Status>(ADDON_ID, 'initial');
const [error, setError] = React.useState<unknown>(undefined);
const { setResults, results } = useA11yContext();
const { passes, incomplete, violations } = results;
const { storyId } = useStorybookState();
const { manual } = useParameter<Pick<A11yParameters, 'manual'>>('a11y', {
manual: false,
@ -114,6 +113,43 @@ export const A11YPanel: React.FC = () => {
],
[status, handleManual]
);
const tabs = useMemo(() => {
const { passes, incomplete, violations } = results;
return [
{
label: <Violations>{violations.length} Violations</Violations>,
panel: (
<Report
items={violations}
type={RuleType.VIOLATION}
empty="No accessibility violations found."
/>
),
items: violations,
type: RuleType.VIOLATION,
},
{
label: <Passes>{passes.length} Passes</Passes>,
panel: (
<Report items={passes} type={RuleType.PASS} empty="No accessibility checks passed." />
),
items: passes,
type: RuleType.PASS,
},
{
label: <Incomplete>{incomplete.length} Incomplete</Incomplete>,
panel: (
<Report
items={incomplete}
type={RuleType.INCOMPLETION}
empty="No accessibility checks incomplete."
/>
),
items: incomplete,
type: RuleType.INCOMPLETION,
},
];
}, [results]);
return (
<>
{status === 'initial' && <Centered>Initializing...</Centered>}
@ -132,47 +168,7 @@ export const A11YPanel: React.FC = () => {
{(status === 'ready' || status === 'ran') && (
<>
<ScrollArea vertical horizontal>
<Tabs
key="tabs"
tabs={[
{
label: <Violations>{violations.length} Violations</Violations>,
panel: (
<Report
items={violations}
type={RuleType.VIOLATION}
empty="No accessibility violations found."
/>
),
items: violations,
type: RuleType.VIOLATION,
},
{
label: <Passes>{passes.length} Passes</Passes>,
panel: (
<Report
items={passes}
type={RuleType.PASS}
empty="No accessibility checks passed."
/>
),
items: passes,
type: RuleType.PASS,
},
{
label: <Incomplete>{incomplete.length} Incomplete</Incomplete>,
panel: (
<Report
items={incomplete}
type={RuleType.INCOMPLETION}
empty="No accessibility checks incomplete."
/>
),
items: incomplete,
type: RuleType.INCOMPLETION,
},
]}
/>
<Tabs key="tabs" tabs={tabs} />
</ScrollArea>
<ActionBar key="actionbar" actionItems={readyActionItems} />
</>

View File

@ -9,11 +9,17 @@ import { EVENTS } from '../constants';
jest.mock('@storybook/api');
const mockedApi = api as jest.Mocked<typeof api>;
const storyId = 'jest';
describe('A11YPanel', () => {
beforeEach(() => {
mockedApi.useChannel.mockReset();
mockedApi.useStorybookState.mockReset();
mockedApi.useChannel.mockReturnValue(jest.fn());
const state: Partial<api.State> = { storyId };
// Lazy to mock entire state
mockedApi.useStorybookState.mockReturnValue(state as any);
});
it('should render children', () => {
@ -26,27 +32,30 @@ describe('A11YPanel', () => {
});
it('should not render when inactive', () => {
const emit = jest.fn();
mockedApi.useChannel.mockReturnValue(emit);
const { queryByTestId } = render(
<A11yContextProvider active={false}>
<div data-testid="child" />
</A11yContextProvider>
);
expect(queryByTestId('child')).toBeFalsy();
expect(emit).not.toHaveBeenCalledWith(EVENTS.REQUEST);
});
it('should emit request when moving from inactive to active', () => {
const emit = jest.fn();
mockedApi.useChannel.mockReturnValue(emit);
const { rerender } = render(<A11yContextProvider active={false} />);
rerender(<A11yContextProvider active />);
expect(emit).toHaveBeenLastCalledWith(EVENTS.REQUEST, storyId);
});
it('should emit highlight with no values when inactive', () => {
const emit = jest.fn();
mockedApi.useChannel.mockReturnValue(emit);
const { rerender } = render(
<A11yContextProvider active>
<div data-testid="child" />
</A11yContextProvider>
);
rerender(
<A11yContextProvider active={false}>
<div data-testid="child" />
</A11yContextProvider>
);
const { rerender } = render(<A11yContextProvider active />);
rerender(<A11yContextProvider active={false} />);
expect(emit).toHaveBeenLastCalledWith(
EVENTS.HIGHLIGHT,
expect.objectContaining({

View File

@ -1,8 +1,8 @@
import * as React from 'react';
import { themes, convert } from '@storybook/theming';
import { Result } from 'axe-core';
import { useChannel } from '@storybook/api';
import { STORY_CHANGED } from '@storybook/core-events';
import { useChannel, useStorybookState } from '@storybook/api';
import { STORY_CHANGED, STORY_RENDERED } from '@storybook/core-events';
import { EVENTS } from '../constants';
interface Results {
@ -55,13 +55,18 @@ export const A11yContextProvider: React.FC<A11yContextProviderProps> = ({ active
const [results, setResults] = React.useState<Results>(defaultResult);
const [tab, setTab] = React.useState(0);
const [highlighted, setHighlighted] = React.useState<string[]>([]);
const handleToggleHighlight = React.useCallback((target: string[], hightlight: boolean) => {
const { storyId } = useStorybookState();
const handleToggleHighlight = React.useCallback((target: string[], highlight: boolean) => {
setHighlighted((prevHighlighted) =>
hightlight
highlight
? [...prevHighlighted, ...target]
: prevHighlighted.filter((t) => !target.includes(t))
);
}, []);
const handleRun = React.useCallback(() => {
emit(EVENTS.REQUEST, storyId);
}, [storyId]);
const handleClearHighlights = React.useCallback(() => setHighlighted([]), []);
const handleSetTab = React.useCallback((index: number) => {
handleClearHighlights();
@ -75,6 +80,7 @@ export const A11yContextProvider: React.FC<A11yContextProviderProps> = ({ active
}, []);
const emit = useChannel({
[STORY_RENDERED]: handleRun,
[STORY_CHANGED]: handleReset,
});
@ -83,10 +89,12 @@ export const A11yContextProvider: React.FC<A11yContextProviderProps> = ({ active
}, [highlighted, tab]);
React.useEffect(() => {
if (!active) {
if (active) {
handleRun();
} else {
handleClearHighlights();
}
}, [active, handleClearHighlights]);
}, [active, handleClearHighlights, emit, storyId]);
if (!active) return null;