Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addon-a11y: Support manual run #8883

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions addons/a11y/README.md
Expand Up @@ -69,6 +69,8 @@ export default {
config: {},
// axe-core optionsParameter (https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter)
options: {},
// optional flag to prevent the automatic check
manual: true,
},
},
};
Expand Down
144 changes: 45 additions & 99 deletions addons/a11y/src/components/A11YPanel.test.js
@@ -1,19 +1,18 @@
import React from 'react';
import { mount } from 'enzyme';
import { EventEmitter } from 'events';

import { ThemeProvider, themes, convert } from '@storybook/theming';
import { STORY_RENDERED } from '@storybook/core-events';
import { ScrollArea } from '@storybook/components';

import { A11YPanel } from './A11YPanel';
import { EVENTS } from '../constants';

function createApi() {
return {
emit: jest.fn(),
on: jest.fn(),
off: jest.fn(),
};
const emitter = new EventEmitter();
jest.spyOn(emitter, 'emit');
jest.spyOn(emitter, 'on');
jest.spyOn(emitter, 'off');
return emitter;
}

const axeResult = {
Expand Down Expand Up @@ -63,7 +62,7 @@ function ThemedA11YPanel(props) {
}

describe('A11YPanel', () => {
it('should register STORY_RENDERED, RESULT and ERROR updater on mount', () => {
it('should register event listener on mount', () => {
// given
const api = createApi();
expect(api.on).not.toHaveBeenCalled();
Expand All @@ -73,152 +72,99 @@ describe('A11YPanel', () => {

// then
expect(api.on.mock.calls.length).toBe(3);
expect(api.on.mock.calls[0][0]).toBe(STORY_RENDERED);
expect(api.on.mock.calls[1][0]).toBe(EVENTS.RESULT);
expect(api.on.mock.calls[2][0]).toBe(EVENTS.ERROR);
expect(api.on.mock.calls[0][0]).toBe(EVENTS.RESULT);
expect(api.on.mock.calls[1][0]).toBe(EVENTS.ERROR);
expect(api.on.mock.calls[2][0]).toBe(EVENTS.MANUAL);
});

it('should request a run on tab activation', () => {
it('should deregister event listener on unmount', () => {
// given
const api = createApi();

const wrapper = mount(<ThemedA11YPanel api={api} />);
expect(api.emit).not.toHaveBeenCalled();

// when
wrapper.setProps({ active: true });
wrapper.update();

// then
expect(api.emit).toHaveBeenCalledWith(EVENTS.REQUEST);
expect(wrapper.find(ScrollArea).length).toBe(0);
});

it('should deregister STORY_RENDERED, RESULT and ERROR updater on unmount', () => {
// given
const api = createApi();
const wrapper = mount(<ThemedA11YPanel api={api} />);
expect(api.off).not.toHaveBeenCalled();

// when
const wrapper = mount(<ThemedA11YPanel api={api} />);
wrapper.unmount();

// then
expect(api.off.mock.calls.length).toBe(3);
expect(api.off.mock.calls[0][0]).toBe(STORY_RENDERED);
expect(api.off.mock.calls[1][0]).toBe(EVENTS.RESULT);
expect(api.off.mock.calls[2][0]).toBe(EVENTS.ERROR);
expect(api.off.mock.calls[0][0]).toBe(EVENTS.RESULT);
expect(api.off.mock.calls[1][0]).toBe(EVENTS.ERROR);
expect(api.off.mock.calls[2][0]).toBe(EVENTS.MANUAL);
});

it('should update run result', () => {
it('should handle "initial" status', () => {
// given
const api = createApi();
const wrapper = mount(<ThemedA11YPanel api={api} active />);
const onUpdate = api.on.mock.calls.find(([event]) => event === EVENTS.RESULT)[1];

expect(
wrapper
.find('button')
.last()
.text()
.trim()
).toBe('Rerun tests');

// when
onUpdate(axeResult);

// then
expect(
wrapper
.find('button')
.last()
.text()
.trim()
).toBe('Tests completed');
});

it('should request run', () => {
// given
const api = createApi();
const wrapper = mount(<ThemedA11YPanel api={api} active />);
const request = api.on.mock.calls.find(([event]) => event === STORY_RENDERED)[1];

expect(
wrapper
.find('button')
.last()
.text()
.trim()
).toBe('Rerun tests');
expect(api.emit).not.toHaveBeenCalled();

// when
request();

// then
expect(
wrapper
.find('button')
.last()
.text()
.trim()
).toBe('Running test');
expect(api.emit).toHaveBeenCalledWith(EVENTS.REQUEST);
expect(api.emit).not.toHaveBeenCalled();
expect(wrapper.text()).toMatch(/Initializing/);
});

it('should NOT request run on inactive tab', () => {
it('should handle "manual" status', () => {
// given
const api = createApi();
mount(<ThemedA11YPanel api={api} active={false} />);
const request = api.on.mock.calls.find(([event]) => event === STORY_RENDERED)[1];
expect(api.emit).not.toHaveBeenCalled();
const wrapper = mount(<ThemedA11YPanel api={api} active />);

// when
request();
api.emit(EVENTS.MANUAL, true);
wrapper.update();

// then
expect(api.emit).not.toHaveBeenCalled();
expect(wrapper.text()).toMatch(/Manually run the accessibility scan/);
expect(api.emit).not.toHaveBeenCalledWith(EVENTS.REQUEST);
});

it('should render report', () => {
it('should handle "running" status', () => {
// given
const api = createApi();
const wrapper = mount(<ThemedA11YPanel api={api} active />);
const onUpdate = api.on.mock.calls.find(([event]) => event === EVENTS.RESULT)[1];

// when
onUpdate(axeResult);
api.emit(EVENTS.MANUAL, false);
wrapper.update();

// then
expect(wrapper.find(A11YPanel)).toMatchSnapshot();
expect(wrapper.text()).toMatch(/Please wait while the accessibility scan is running/);
expect(api.emit).toHaveBeenCalledWith(EVENTS.REQUEST);
});

it("should render loader when it's running", () => {
it('should handle "ran" status', () => {
// given
const api = createApi();
const wrapper = mount(<ThemedA11YPanel api={api} active />);
const request = api.on.mock.calls.find(([event]) => event === STORY_RENDERED)[1];

// when
request();
api.emit(EVENTS.RESULT, axeResult);
wrapper.update();

// then
expect(wrapper.find('ScrollArea').length).toBe(0);
expect(wrapper.find('Loader').length).toBe(1);
expect(wrapper.find('ActionBar').length).toBe(1);
expect(wrapper.find('Loader')).toMatchSnapshot();
expect(
wrapper
.find('button')
.last()
.text()
.trim()
).toBe('Tests completed');
expect(wrapper.find('Tabs').prop('tabs').length).toBe(3);
expect(wrapper.find('Tabs').prop('tabs')[0].label.props.children).toEqual([1, ' Violations']);
expect(wrapper.find('Tabs').prop('tabs')[1].label.props.children).toEqual([1, ' Passes']);
expect(wrapper.find('Tabs').prop('tabs')[2].label.props.children).toEqual([1, ' Incomplete']);
});

it('should NOT anything when tab is not active', () => {
it('should handle inactive state', () => {
// given
const api = createApi();

// when
const wrapper = mount(<ThemedA11YPanel api={api} active={false} />);

// then
expect(wrapper.find('ScrollArea').length).toBe(0);
expect(wrapper.find('ActionBar').length).toBe(0);
expect(wrapper.text()).toBe('');
expect(api.emit).not.toHaveBeenCalled();
});
});