Skip to content
This repository was archived by the owner on Mar 19, 2021. It is now read-only.

Commit 1ae8e12

Browse files
authored
feat: Use chrome-headless as default browser replacing PhantomJS
BREAKING CHANGE: PhantomJS is no longer maintained. We will be replacing it with headless Chrome
1 parent 1cfbfc8 commit 1ae8e12

10 files changed

Lines changed: 1239 additions & 483 deletions

File tree

circle.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
machine:
2+
node:
3+
version: v6.1.0
4+
5+
dependencies:
6+
pre:
7+
# Update Google Chrome.
8+
- google-chrome --version
9+
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
10+
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb stable main" >> /etc/apt/sources.list.d/google.list'
11+
- sudo apt-get update
12+
- sudo apt-get --only-upgrade install google-chrome-stable
13+
- google-chrome --version

index.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,30 @@ program.version(version)
2020
.option('-b, --browser [browser-name]', 'Which browser to run (Webdriver required)')
2121
.option('-s, --save [filename]', 'Save the output as a JSON file. Filename is optional')
2222
.option('-d, --dir <path>', 'Output directory')
23-
.option('-a, --axe-source', 'Path to axe.js file')
23+
.option('-a, --axe-source <path>', 'Path to axe.js file')
2424
.option('-q, --exit', 'Exit with `1` failure code if any a11y tests fail')
2525
.option('--timeout <n>', 'Set how much time (second) axe has to run (default: 90)', 90)
2626
.option('--timer', 'Log the time it takes to run')
2727
.option('--show-errors', 'Display the full error stack')
2828
// TODO: Replace this with a reporter option, this required adding
2929
// a reporter option to axe-webdriverjs
3030
.option('--no-reporter', 'Turn the CLI reporter off')
31+
3132
// .option('-c, --config <file>', 'Path to custom axe configuration')
3233
.parse(process.argv);
3334

3435
program.browser = utils.parseBrowser(program.browser)
3536
program.axeSource = utils.getAxeSource(program.axeSource);
3637

38+
if (!program.axeSource) {
39+
console.log(error(
40+
'Unable to find the axe-core source file.'
41+
));
42+
return
43+
}
44+
3745
let cliReporter;
38-
if (program['no-reporter']) {
46+
if (program.reporter === false) {
3947
cliReporter = function () {};
4048
} else {
4149
cliReporter = function (...args) {

lib/axe-test-urls.js

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
const WebDriver = require('selenium-webdriver');
44
const AxeBuilder = require('axe-webdriverjs');
5-
6-
const startDriver = require('./webdriver').startDriver;
7-
const stopDriver = require('./webdriver').stopDriver;
5+
const { startDriver, stopDriver } = require('./webdriver');
86

97
function testPages(urls, config, events) {
108
const driver = config.driver;
@@ -17,8 +15,8 @@ function testPages(urls, config, events) {
1715

1816
// End of the line, no more page left
1917
if (urls.length === 0) {
20-
stopDriver(config);
21-
return Promise.resolve([]);
18+
stopDriver(config)
19+
return Promise.resolve([])
2220
}
2321

2422
return new Promise((resolve, reject) => {
@@ -35,17 +33,17 @@ function testPages(urls, config, events) {
3533

3634
driver.get(currentUrl)
3735
.then(function () {
38-
// Wait for the page to be loaded
39-
return driver.executeAsyncScript(function(callback) {
40-
var script = document.createElement('script');
41-
script.innerHTML = 'document.documentElement.classList.add("deque-axe-is-ready");';
42-
document.documentElement.appendChild(script);
43-
callback();
44-
});
45-
})
46-
.then(function () {
47-
return driver.wait(WebDriver.until.elementsLocated(WebDriver.By.css('.deque-axe-is-ready')));
48-
})
36+
// Wait for the page to be loaded
37+
return driver.executeAsyncScript(function (callback) {
38+
var script = document.createElement('script');
39+
script.innerHTML = 'document.documentElement.classList.add("deque-axe-is-ready");';
40+
document.documentElement.appendChild(script);
41+
callback();
42+
});
43+
})
44+
.then(function () {
45+
return driver.wait(WebDriver.until.elementsLocated(WebDriver.By.css('.deque-axe-is-ready')));
46+
})
4947
.then(() => {
5048
if (config.timer) {
5149
console.timeEnd('page load time');
@@ -74,7 +72,7 @@ function testPages(urls, config, events) {
7472
console.time('axe-core execution time');
7573
}
7674

77-
// Run axe
75+
// Run axe
7876
axe.analyze(function (results) {
7977
if (config.timer) {
8078
console.timeEnd('axe-core execution time');
@@ -89,7 +87,7 @@ function testPages(urls, config, events) {
8987
.then(out => {
9088
resolve([results].concat(out))
9189
});
92-
});
90+
});
9391
}).catch((e) => {
9492
driver.quit();
9593
reject(e)

lib/utils.js

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module.exports.parseUrl = function parseUrl(url) {
77

88
module.exports.parseBrowser = function parseBrowser(browser) {
99
if (!browser) {
10-
return 'phantomjs'
10+
return 'chrome-headless'
1111
}
1212

1313
const l = browser.length;
@@ -35,37 +35,37 @@ module.exports.parseBrowser = function parseBrowser(browser) {
3535
case 'microsoftedge'.substr(0,l):
3636
return 'MicrosoftEdge';
3737

38-
case 'phantomjs'.substr(0,l):
39-
return 'phantomjs';
40-
4138
default: throw new Error('Unknown browser ' + browser)
4239
}
4340
}
4441

4542
module.exports.getAxeSource = function getAxeSource(axePath) {
4643
const path = require('path')
4744
const fs = require('fs')
45+
// Abort if axePath should exist, and it isn't
46+
if (axePath && !fs.existsSync(axePath)) {
47+
return
48+
// Look for axe in CWD
49+
} else if (!axePath) {
50+
axePath = path.join(process.cwd(), './axe.js')
51+
}
4852

49-
axePath = path.join(process.cwd(), axePath || './axe.js');
50-
51-
// Look for axe in CWD
52-
if (!fs.existsSync(axePath)) {
53-
axePath = path.join(process.cwd(), './axe.js');
53+
if (!fs.existsSync(axePath)) {
54+
// Look for axe in CDW ./node_modules
55+
axePath = path.join(process.cwd(), './node_modules/axe-core/axe.js')
5456
}
55-
if (!fs.existsSync(axePath)) {
56-
// Look for axe in CDW ./node_modules
57-
axePath = path.join(process.cwd(), './node_modules/axe-core/axe.js')
58-
}
59-
if (!fs.existsSync(axePath)) {
60-
// if all else fails, use the locally installed axe
61-
axePath = path.join(__dirname, '../node_modules/axe-core/axe.js')
62-
}
63-
return fs.readFileSync(axePath, 'utf8');
57+
if (!fs.existsSync(axePath)) {
58+
// if all else fails, use the locally installed axe
59+
axePath = path.join(__dirname, '../node_modules/axe-core/axe.js')
60+
}
61+
62+
return fs.readFileSync(axePath, 'utf8')
6463
}
6564

6665

6766
module.exports.getAxeVersion = function getAxeVersion(source) {
68-
return source.match(/\.version\s*=\s'([^']+)'/)[1]
67+
const match = source.match(/\.version\s*=\s'([^']+)'/)
68+
return (match ? match[1] : 'unknown version')
6969
}
7070

7171

lib/webdriver.js

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,43 @@
1-
const WebDriverBuilder = require('selenium-webdriver').Builder;
2-
const phantomjs = require('phantomjs-prebuilt');
1+
const chromedriver = require('chromedriver')
2+
const { Builder, Capabilities } = require('selenium-webdriver')
3+
const chrome = require('selenium-webdriver/chrome')
34

45
module.exports = {
56
startDriver: startDriver,
67
stopDriver: stopDriver,
78
}
89

9-
function startDriver(config) {
10-
const builder = new WebDriverBuilder().forBrowser(config.browser)
11-
const scriptTimeout = config.timeout * 1000;
12-
13-
if (config.browser !== 'phantomjs') {
14-
// Launch a browser
15-
config.driver = builder.build();
16-
config.driver.manage().timeouts().setScriptTimeout(scriptTimeout);
17-
18-
return Promise.resolve(config);
19-
20-
} else {
21-
// Start phantomjs-prebuilt
22-
return phantomjs.run('--webdriver=4444')
23-
.then(phantom => {
24-
// Save phantom, so we can close it when we are done
25-
config.phantom = phantom;
26-
27-
// And connect selenium to our phantom server
28-
config.driver = builder.usingServer('http://localhost:4444/wd/hub').build();
29-
config.driver.manage().timeouts().setScriptTimeout(scriptTimeout);
30-
31-
return Promise.resolve(config);
32-
})
33-
34-
}
10+
function startDriver (config) {
11+
let builder
12+
const scriptTimeout = (config.timeout || 20) * 1000.00
13+
14+
if (config.browser === 'chrome-headless') {
15+
// Tell selenium use the driver in node_modules
16+
const service = new chrome.ServiceBuilder(
17+
chromedriver.path
18+
).build()
19+
chrome.setDefaultService(service)
20+
21+
const chromeCapabilities = Capabilities.chrome();
22+
chromeCapabilities.set('chromeOptions', {
23+
'args': ['--headless']
24+
})
25+
26+
builder = new Builder().forBrowser('chrome')
27+
.withCapabilities(chromeCapabilities)
28+
} else {
29+
builder = new Builder().forBrowser(config.browser)
30+
}
31+
32+
// Launch a browser
33+
config.driver = builder.build()
34+
config.builder = builder
35+
36+
return config.driver.manage()
37+
.timeouts().setScriptTimeout(scriptTimeout)
38+
.then(() => config)
3539
}
3640

37-
function stopDriver(config) {
38-
if (config.browser !== 'phantomjs') {
39-
config.driver.quit();
40-
}
41-
if (config.phantom) {
42-
config.phantom.kill();
43-
}
41+
function stopDriver (config) {
42+
config.driver.quit()
4443
}

0 commit comments

Comments
 (0)