From 55820cfc29dad1826847eac2e0dbe8f4e89bba15 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 28 May 2019 13:59:25 -0400 Subject: [PATCH] fix: Include body as part of background color checks when element does not intersect (#1520) * fix: include body as part of background color checks when element does not intersect * add test coverage for html element * logic fix + general comments --- build/tasks/test-webdriver.js | 17 ++++---- lib/commons/color/get-background-color.js | 21 ++++++++-- test/commons/color/get-background-color.js | 47 ++++++++++++++++++++++ test/commons/dom/visually-overlaps.js | 3 +- test/runner.tmpl | 7 +++- 5 files changed, 82 insertions(+), 13 deletions(-) diff --git a/build/tasks/test-webdriver.js b/build/tasks/test-webdriver.js index fb578136ae..33c51b622a 100644 --- a/build/tasks/test-webdriver.js +++ b/build/tasks/test-webdriver.js @@ -41,20 +41,23 @@ module.exports = function(grunt) { .get(url) // Get results .then(function() { - let driverBrowser = driver - .getCapabilities() - .then(capabilities => capabilities.get('browserName')); - return Promise.all([driverBrowser, collectTestResults(driver)]); + return Promise.all([ + driver.getCapabilities(), + collectTestResults(driver) + ]); }) // And process them - .then(function([browser, result]) { - grunt.log.writeln(url + ' [' + browser + ']'); + .then(function([capabilities, result]) { + let browserName = + capabilities.get('browserName') + + (capabilities.get('mobileEmulationEnabled') ? '-mobile' : ''); + grunt.log.writeln(url + ' [' + browserName + ']'); // Remember the errors (result.reports || []).forEach(function(err) { grunt.log.error(err.message); err.url = url; - err.browser = browser; + err.browser = browserName; errors.push(err); }); diff --git a/lib/commons/color/get-background-color.js b/lib/commons/color/get-background-color.js index d22925f362..d0d2d0af2f 100644 --- a/lib/commons/color/get-background-color.js +++ b/lib/commons/color/get-background-color.js @@ -217,16 +217,29 @@ function sortPageBackground(elmStack) { let bodyIndex = elmStack.indexOf(document.body); let bgNodes = elmStack; + // Body can sometimes appear out of order in the stack: + // 1) Body is not the first element due to negative z-index elements + // 2) Elements are positioned outside of body's rect coordinates + // (see https://github.com/dequelabs/axe-core/issues/1456) + // In those instances we want to reinsert body back into the element stack + // when not using the root document element as the html canvas for bgcolor + // prettier-ignore + let sortBodyElement = + bodyIndex > 1 || // negative z-index elements + bodyIndex === -1; // element does not intersect with body + if ( - // Check that the body background is the page's background - bodyIndex > 1 && // only if there are negative z-index elements + sortBodyElement && !color.elementHasImage(document.documentElement) && color.getOwnBackgroundColor( window.getComputedStyle(document.documentElement) ).alpha === 0 ) { - // Remove body and html from it's current place - bgNodes.splice(bodyIndex, 1); + // Only remove document.body if it was originally contained within the element stack + if (bodyIndex > 1) { + bgNodes.splice(bodyIndex, 1); + } + // Remove document element since body will be used for bgcolor bgNodes.splice(elmStack.indexOf(document.documentElement), 1); // Put the body background as the lowest element diff --git a/test/commons/color/get-background-color.js b/test/commons/color/get-background-color.js index cecc58bcae..88bbad5b53 100644 --- a/test/commons/color/get-background-color.js +++ b/test/commons/color/get-background-color.js @@ -740,6 +740,53 @@ describe('color.getBackgroundColor', function() { assert.closeTo(actual.alpha, 1, 0); }); + it('should return the html canvas inherited from body bgColor when element content does not overlap with body', function() { + fixture.innerHTML = + '
Text
'; + + // size body element so that target element is positioned outside of background + var originalHeight = document.body.style.height; + var originalBg = document.body.style.background; + document.body.style.height = '1px'; + document.body.style.background = '#000'; + + var target = fixture.querySelector('#target'); + var actual = axe.commons.color.getBackgroundColor(target, []); + + assert.closeTo(actual.red, 0, 0); + assert.closeTo(actual.green, 0, 0); + assert.closeTo(actual.blue, 0, 0); + assert.closeTo(actual.alpha, 1, 0); + + document.body.style.height = originalHeight; + document.body.style.background = originalBg; + }); + + it('should return the html canvas bgColor when element content does not overlap with body', function() { + fixture.innerHTML = + '
Text
'; + + // size body element so that target element is positioned outside of background + var originalHeight = document.body.style.height; + var originalBg = document.body.style.background; + var originalRootBg = document.documentElement.style.background; + document.body.style.height = '1px'; + document.body.style.background = '#0f0'; + document.documentElement.style.background = '#f00'; + + var target = fixture.querySelector('#target'); + var actual = axe.commons.color.getBackgroundColor(target, []); + + assert.closeTo(actual.red, 255, 0); + assert.closeTo(actual.green, 0, 0); + assert.closeTo(actual.blue, 0, 0); + assert.closeTo(actual.alpha, 1, 0); + + document.body.style.height = originalHeight; + document.body.style.background = originalBg; + document.documentElement.style.background = originalRootBg; + }); + (shadowSupported ? it : xit)('finds colors in shadow boundaries', function() { fixture.innerHTML = '
'; var container = fixture.querySelector('#container'); diff --git a/test/commons/dom/visually-overlaps.js b/test/commons/dom/visually-overlaps.js index b830649c87..dc844976d7 100644 --- a/test/commons/dom/visually-overlaps.js +++ b/test/commons/dom/visually-overlaps.js @@ -22,12 +22,13 @@ describe('dom.visuallyOverlaps', function() { it('should return false when rect has no overlap', function() { fixture.innerHTML = '
' + + ' width: 30px; background-color: red;">' + '
' + '
'; var target = fixture.querySelector('#target'); var targetRect = target.getBoundingClientRect(); + assert.isFalse( axe.commons.dom.visuallyOverlaps(targetRect, target.parentNode) ); diff --git a/test/runner.tmpl b/test/runner.tmpl index 4f820b473b..5094a254f5 100644 --- a/test/runner.tmpl +++ b/test/runner.tmpl @@ -14,6 +14,11 @@ word-wrap: break-word; hyphens: auto; } + + /* mocha stats having a fixed position can interfere with some tests when intersecting with elements */ + #mocha-stats { + position: static; + } <% tests.forEach(function (file) { %>