By Marcy Sutton / @MarcySutton
Senior Front-End Engineer, aXe-core team
Deque Systems
https://reactjs.org/docs/accessibility.html
var element = document.body;
axe.utils.getFlattenedTree(element, shadowId)
//returns:
[{
actualNode: body,
children: [virtualNodes],
shadowId: undefined
}]
import React from 'react';
class AdoptAPetViewer extends React.Component {
componentDidMount: function() {},
componentWillUnMount: function() {},
componentDidUpdate: function() {},
componentWillReceiveProps: function() {},
render() {
return (<div>Your Sweet Accessible App</div>)
}
}
window.addEventListener('DOMContentLoaded', function() {
React.render(<AdoptAPetViewer />, document.getElementById('root'))
})
import { Wrapper, Button, Menu, MenuItem } from '../../src';
render() {
return (
{menuItemElements}
);
}
class PizzaButton extends React.Component {
handleClick(e) {}
handleKeyDown(e) {}
render() {
return (
<button
onClick={this.handleClick}
onKeyDown={this.handleKeyDown}
>
Get Pizza
</button>
)
}
})
export default PizzaButton
SyntheticEvent
is a wrapper utility focus() {
this.textInput.focus();
}
render() {
return (
<input
type="text"
ref={(input) => { this.textInput = input; }}
/>
);
}
}
By Ryan Florence
this.setState({ gotEmail: true }, () => {
this.refs.thanks.getDOMNode().focus();
// display a "thank you" for two seconds
setTimeout(() => {
var focusHasNotMoved =
(this.refs.thanks.getDOMNode() ===
document.activeElement);
this.setState({ gotEmail: false }, () => {
if (focusHasNotMoved)
this.getDOMNode().focus();
});
}, 2000);
});
componentDidUpdate () {
const ourNode = ReactDOM.findDOMNode(this)
if (document.activeElement &&
ourNode.contains(document.activeElement)) {
// if the focussed element is a child of our DOM, return
return
}
// focus one of our elements
ourNode.querySelector('button').focus()
}
https://facebook.github.io/react/docs/test-utils.html
Lets you render a component "one level deep" and test what its render method returns, without worrying about child components, which are not instantiated or rendered. Does not require a DOM.
var shallow = require('enzyme').shallow;
// more code
it('escape key', function() {
var wrapper = shallow(el(Button, null, 'foo'), shallowOptions);
wrapper.simulate('keyDown', escapeEvent);
expect(ambManager.handleMenuKey).toHaveBeenCalledTimes(1);
expect(ambManager.handleMenuKey.mock.calls[0][0].key).toBe('Escape');
});
…attaching code to the DOM
import {mount} from 'enzyme';
let wrapper = mount(app, { attachTo: div })
import App from '../app/components/App';
import a11yHelper from "./a11yHelper";
describe('Accessibility', function () {
this.timeout(10000);
it('Has no errors', function () {
let config = {
"rules": {
"color-contrast": { enabled: false }
}
};
a11yHelper.testEnzymeComponent(<App/>, config, (error, results) => {
expect(results.violations.length).to.equal(0);
});
});
});
a11yHelper.testEnzymeComponent = (app, config, callback) => {
let div = document.createElement('div');
document.body.appendChild(div);
let wrapper = mount(app, { attachTo: div });
let node = findDOMNode(wrapper.component);
if (typeof config === 'function') {
config = {};
}
this.runAxe(node, config, callback);
document.body.removeChild(div);
}
a11yHelper.runAxe = (node, config, callback) => {
var oldNode = global.Node;
global.Node = node.ownerDocument.defaultView.Node;
axeCore.run(node, config, (error, results) => {
global.Node = oldNode;
callback(results);
});
}
documentElement
error import { jsdom } from 'jsdom'
import 'jsdom-global/register'
export function jsdomSetup () {
if (global.document && global.window) {
global.document = jsdom('<!doctype html><html><body></body></html>')
global.window = global.document.defaultView
return
}
// Make all window properties available on the mocha global
Object.keys(global.window)
.filter(key => !(key in global))
.forEach(key => {
global[key] = global.window[key]
})
}
“Frontend bugs have occurred in the boundary between components or layers of our app – for example, between the API and the data layer, the data layer and our components, or between a parent and child component.”
const WebDriver = require('selenium-webdriver'),
AxeBuilder = require('axe-webdriverjs');
describe('Accessibility', function() {
this.timeout(10000);
let driver;
beforeEach(function(done) {
driver = new WebDriver.Builder()
.forBrowser('chrome')
.build();
driver
.get(`http://localhost:${port}`)
.then(function() {
done();
});
});
afterEach(function(done) {
driver.quit().then(function() {
done();
});
});
it('should find no violations in the modal', function(done) {
driver
.findElement(WebDriver.By.css('.signup-btn'))
.then(function(element) {
element.sendKeys(WebDriver.Key.ENTER)
})
.then(function() {
new AxeBuilder(driver)
.analyze(function (results) {
TestUtils.printViolations(results.violations);
assert.equal(results.violations.length, 0);
done();
});
});
});
});
https://egghead.io/courses/start-building-accessible-web-applications-today