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 = '