diff --git a/Gruntfile.js b/Gruntfile.js
index f6df5e8266..9c007ecadc 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -34,7 +34,13 @@ module.exports = function(grunt) {
langs = [''];
}
- var webDriverTestBrowsers = ['firefox', 'chrome', 'ie', 'chrome-mobile'];
+ var webDriverTestBrowsers = [
+ 'firefox',
+ 'chrome',
+ 'ie',
+ 'chrome-mobile',
+ 'safari'
+ ];
process.env.NODE_NO_HTTP2 = 1; // to hide node warning - (node:18740) ExperimentalWarning: The http2 module is an experimental API.
diff --git a/build/tasks/test-webdriver.js b/build/tasks/test-webdriver.js
index ccc009b300..fb578136ae 100644
--- a/build/tasks/test-webdriver.js
+++ b/build/tasks/test-webdriver.js
@@ -87,8 +87,8 @@ module.exports = function(grunt) {
/*
* Build web driver depends whether REMOTE_SELENIUM_URL is set
*/
- function buildWebDriver(browser) {
- var webdriver, capabilities;
+ async function buildWebDriver(browser) {
+ var capabilities;
var mobileBrowser = browser.split('-mobile');
if (mobileBrowser.length > 1) {
browser = mobileBrowser[0];
@@ -106,21 +106,27 @@ module.exports = function(grunt) {
};
}
+ var webdriver = new WebDriver.Builder()
+ .withCapabilities(capabilities)
+ .forBrowser(browser);
+
if (process.env.REMOTE_SELENIUM_URL) {
- webdriver = new WebDriver.Builder()
- .forBrowser(browser)
- .withCapabilities(capabilities)
- .usingServer(process.env.REMOTE_SELENIUM_URL)
- .build();
- } else {
- webdriver = new WebDriver.Builder()
- .withCapabilities(capabilities)
- .forBrowser(browser)
- .build();
+ webdriver.usingServer(process.env.REMOTE_SELENIUM_URL);
+ }
+
+ // @see https://github.com/SeleniumHQ/selenium/issues/6026
+ if (browser === 'safari') {
+ var safari = require('selenium-webdriver/safari');
+ var server = await new safari.ServiceBuilder()
+ .addArguments('--legacy')
+ .build()
+ .start();
+
+ webdriver.usingServer(server);
}
return {
- driver: webdriver,
+ driver: webdriver.build(),
isMobile: mobileBrowser.length > 1
};
}
@@ -131,7 +137,7 @@ module.exports = function(grunt) {
grunt.registerMultiTask(
'test-webdriver',
'Task for launching Webdriver with options and running tests against options URLs',
- function() {
+ async function() {
var driver;
var isMobile = false;
var done = this.async();
@@ -160,7 +166,7 @@ module.exports = function(grunt) {
// try to load the browser
try {
- var webDriver = buildWebDriver(options.browser);
+ var webDriver = await buildWebDriver(options.browser);
driver = webDriver.driver;
isMobile = webDriver.isMobile;
// If load fails, warn user and move to the next task
diff --git a/lib/commons/color/contrast.js b/lib/commons/color/contrast.js
index 1b467a26ec..fead29d509 100644
--- a/lib/commons/color/contrast.js
+++ b/lib/commons/color/contrast.js
@@ -74,7 +74,13 @@ color.Color = function(red, green, blue, alpha) {
this.red = parseInt(match[1], 10);
this.green = parseInt(match[2], 10);
this.blue = parseInt(match[3], 10);
- this.alpha = parseFloat(match[4]);
+
+ // alpha values can be between 0 and 1, with browsers having
+ // different floating point precision. for example,
+ // 'rgba(0,0,0,0.5)' results in 'rgba(0,0,0,0.498039)' in Safari
+ // when getting the computed style background-color property. to
+ // fix this, we'll round all alpha values to 2 decimal points.
+ this.alpha = Math.round(parseFloat(match[4]) * 100) / 100;
return;
}
};
diff --git a/lib/commons/color/get-background-color.js b/lib/commons/color/get-background-color.js
index ef5b7f481f..d22925f362 100644
--- a/lib/commons/color/get-background-color.js
+++ b/lib/commons/color/get-background-color.js
@@ -118,6 +118,15 @@ color.filteredRectStack = function filteredRectStack(elm) {
const boundingStack = rectStack.shift();
let isSame;
+ // Safari v12.1 does not include labels as part of elementsFromPoint()
+ // if they wrap an input element (UNLESS the label has a background
+ // color). this results in two different rectStacks (since
+ // elm.getClientRects() returns two rects for the element) which
+ // returns null as isSame is false. we can fix this by adding in the
+ // missing label to the boundingStack before checking for isSame
+ // @see https://bugs.webkit.org/show_bug.cgi?id=197743
+ includeMissingElements(boundingStack, elm);
+
// iterating over arrays of DOMRects
rectStack.forEach((rectList, index) => {
if (index === 0) {
diff --git a/test/checks/keyboard/page-no-duplicate.js b/test/checks/keyboard/page-no-duplicate.js
index 556f55b4c0..8a7ec034d1 100644
--- a/test/checks/keyboard/page-no-duplicate.js
+++ b/test/checks/keyboard/page-no-duplicate.js
@@ -108,11 +108,11 @@ describe('page-no-duplicate', function() {
function() {
var options = {
selector: 'footer',
- nativeScopeFilter: 'main'
+ nativeScopeFilter: 'header'
};
var div = document.createElement('div');
- div.innerHTML = '';
+ div.innerHTML = '';
div.querySelector('#shadow').attachShadow({ mode: 'open' }).innerHTML =
'';
axe.testUtils.fixtureSetup(div);
diff --git a/test/commons/text/form-control-value.js b/test/commons/text/form-control-value.js
index af6dbc98ca..77672cd116 100644
--- a/test/commons/text/form-control-value.js
+++ b/test/commons/text/form-control-value.js
@@ -3,7 +3,6 @@ describe('text.formControlValue', function() {
var formControlValue = axe.commons.text.formControlValue;
var fixtureSetup = axe.testUtils.fixtureSetup;
var fixture = document.querySelector('#fixture');
- var isIE11 = axe.testUtils.isIE11;
function queryFixture(code, query) {
fixtureSetup(code);
@@ -120,33 +119,36 @@ describe('text.formControlValue', function() {
});
});
- // This currently breaks in IE11
- (isIE11 ? it.skip : it)(
- 'returns `` for non-text input elements',
- function() {
- fixtureSetup(
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- '' +
- ''
- );
- axe.utils
- .querySelectorAll(axe._tree[0], '#fixture input')
- .forEach(function(target) {
- assert.equal(
- nativeTextboxValue(target),
- '',
- 'Expected no value for ' + target.actualNode.outerHTML
- );
- });
- }
- );
+ it('returns `` for non-text input elements', function() {
+ fixtureSetup(
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ ''
+ );
+ axe.utils
+ .querySelectorAll(axe._tree[0], '#fixture input')
+ .forEach(function(target) {
+ // Safari and IE11 do not support the color input type
+ // and thus treat them as text inputs. ignore fallback
+ // inputs
+ if (target.actualNode.type === 'text') {
+ return;
+ }
+
+ assert.equal(
+ nativeTextboxValue(target),
+ '',
+ 'Expected no value for ' + target.actualNode.outerHTML
+ );
+ });
+ });
it('returns the value of DOM nodes', function() {
fixture.innerHTML = '';
diff --git a/test/rule-matches/landmark-has-body-context.js b/test/rule-matches/landmark-has-body-context.js
index 42b817b180..3a90f81ce7 100644
--- a/test/rule-matches/landmark-has-body-context.js
+++ b/test/rule-matches/landmark-has-body-context.js
@@ -34,11 +34,14 @@ describe('landmark-has-body-context', function() {
(shadowSupport ? it : xit)(
'returns false for elements contained in a landmark in a shadow DOM tree',
function() {
- var main = document.createElement('main');
- var shadow = main.attachShadow({ mode: 'open' });
- shadow.innerHTML = '