Skip to content

Commit

Permalink
refactor(supports): extracting data uris to reduce size and console e…
Browse files Browse the repository at this point in the history
…rrors - #68
  • Loading branch information
rodneyrehm committed Dec 6, 2015
1 parent 201eb3a commit 06c565a
Show file tree
Hide file tree
Showing 19 changed files with 65 additions and 62 deletions.
23 changes: 1 addition & 22 deletions docs/api/supports.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ tags: internal

# Supports - Browser compatibility

The supports infrastructure is a set of tests determining browser behavior and compatibility at runtime. Because the tests change focus to detect compatibility and load invalid `<video>` and `<audio>` sources, results are cached in [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage).

For the tests to run properly, the document needs to have focus during execution. If it does not, e.g. because the browser's DevTools have focus, the warning »document requires focus for a11y support tests« will be logged to the console and the cache is voided.
The supports infrastructure is a set of tests determining browser behavior and compatibility at runtime. Because the tests change focus to detect compatibility and load invalid `<video>` and `<audio>` sources, results are cached in [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). For the tests to run properly, the document needs to have focus during execution. If it does not, e.g. because the browser's DevTools have focus, the cache is voided.


## Available compatibility tests
Expand Down Expand Up @@ -41,25 +39,6 @@ For the tests to run properly, the document needs to have focus during execution
| svg-focus-method | boolean | true if `SVGElement.prototype.focus` exists natively |


## Console warnings

This module logs things to the console:

```text
document requires focus for a11y support tests
```

Focus feature detection only works when the document has focus. That's not the case when your browser's developer tools have focus or the document's tab is in the background.

```text
GET data:audio/mp3;base64,audio-focus-test net::ERR_INVALID_URL
GET data:video/mp4;base64,video-focus-test net::ERR_INVALID_URL
GET data:image/png;base64,broken-image-test net::ERR_INVALID_URL
```

Focus feature detection works by temporarily adding certain elements to the DOM. For some reason Google Chrome logs invalid Data URIs as a network error of type invalid URL to the console. The Console tab's filter option knows "Hide network messages". The Network panel has the option "Hide data URLs" that prevents these resources from showing up there as well.


## Contributing

Tests go in `src/supports` and either use the `./detect-focus.js` helper like most of the tests, or the `./supports-cache.js` API directly, like `./css-shadow-piercing-deep-combinator.js` shows.
Expand Down
4 changes: 2 additions & 2 deletions src/supports/focus-area-img-tabindex.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import detectFocus from './detect-focus';
import gif from './media/gif';

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-usemap
export default detectFocus({
Expand All @@ -8,8 +9,7 @@ export default detectFocus({
mutate: function(element) {
element.innerHTML = '<map name="image-map-tabindex-test">'
+ '<area shape="rect" coords="63,19,144,45"></map>'
+ '<img usemap="#image-map-tabindex-test" tabindex="-1" alt="" '
+ 'src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">';
+ '<img usemap="#image-map-tabindex-test" tabindex="-1" alt="" src="' + gif + '">';

return element.querySelector('area');
},
Expand Down
4 changes: 2 additions & 2 deletions src/supports/focus-area-tabindex.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

import platform from 'platform';
import detectFocus from './detect-focus';
import gif from './media/gif';

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-usemap
export default detectFocus({
Expand All @@ -9,8 +10,7 @@ export default detectFocus({
mutate: function(element) {
element.innerHTML = '<map name="image-map-tabindex-test">'
+ '<area href="#void" tabindex="-1" shape="rect" coords="63,19,144,45"></map>'
+ '<img usemap="#image-map-tabindex-test" alt="" '
+ 'src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">';
+ '<img usemap="#image-map-tabindex-test" alt="" src="' + gif + '">';

return element.querySelector('area');
},
Expand Down
4 changes: 2 additions & 2 deletions src/supports/focus-area-without-href.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

import platform from 'platform';
import detectFocus from './detect-focus';
import gif from './media/gif';

// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-usemap
export default detectFocus({
Expand All @@ -9,8 +10,7 @@ export default detectFocus({
mutate: function(element) {
element.innerHTML = '<map name="image-map-area-href-test">'
+ '<area shape="rect" coords="63,19,144,45"></map>'
+ '<img usemap="#image-map-area-href-test" alt="" '
+ 'src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">';
+ '<img usemap="#image-map-area-href-test" alt="" src="' + gif + '">';

return element.querySelector('area');
},
Expand Down
3 changes: 2 additions & 1 deletion src/supports/focus-audio-without-controls.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@

import detectFocus from './detect-focus';
import mp3 from './media/mp3';

export default detectFocus({
name: 'can-focus-audio-without-controls',
element: 'audio',
mutate: function(element) {
// invalid media file can trigger warning in console, data-uri to prevent HTTP request
element.setAttribute('src', 'data:audio/mp3;base64,' + 'audio-focus-test');
element.setAttribute('src', mp3);
},
});
3 changes: 2 additions & 1 deletion src/supports/focus-broken-image-map.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import detectFocus from './detect-focus';
import invalidGif from './media/gif.invalid';

// NOTE: https://github.com/medialize/ally.js/issues/35
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-usemap
Expand All @@ -8,7 +9,7 @@ export default detectFocus({
element: 'div',
mutate: function(element) {
element.innerHTML = '<map name="broken-image-map-test"><area href="#void" shape="rect" coords="63,19,144,45"></map>'
+ '<img usemap="#broken-image-map-test" alt="" src="data:image/png;base64,broken-image-test">';
+ '<img usemap="#broken-image-map-test" alt="" src="' + invalidGif + '">';

return element.querySelector('area');
},
Expand Down
3 changes: 2 additions & 1 deletion src/supports/focus-img-ismap.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import detectFocus from './detect-focus';
import gif from './media/gif';

// NOTE: https://github.com/medialize/ally.js/issues/35
// fixes https://github.com/medialize/ally.js/issues/20
Expand All @@ -9,7 +10,7 @@ export default detectFocus({
element: 'a',
mutate: function(element) {
element.href = '#void';
element.innerHTML = '<img ismap src="data:image/png;base64,broken-image-test" alt="">';
element.innerHTML = '<img ismap src="' + gif + '" alt="">';
return element.querySelector('img');
},
});
3 changes: 2 additions & 1 deletion src/supports/focus-img-usemap-tabindex.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import detectFocus from './detect-focus';
import gif from './media/gif';

// NOTE: https://github.com/medialize/ally.js/issues/35
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-usemap
Expand All @@ -9,7 +10,7 @@ export default detectFocus({
mutate: function(element) {
element.innerHTML = '<map name="image-map-tabindex-test"><area href="#void" shape="rect" coords="63,19,144,45"></map>'
+ '<img usemap="#image-map-tabindex-test" tabindex="-1" alt="" '
+ 'src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">';
+ 'src="' + gif + '">';

return element.querySelector('img');
},
Expand Down
6 changes: 2 additions & 4 deletions src/supports/focus-object-svg.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@

import platform from 'platform';
import detectFocus from './detect-focus';
import svg from './media/svg';

let support = detectFocus({
name: 'can-focus-object-svg',
element: 'object',
mutate: function(element) {
const svg = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk'
+ '5L3hsaW5rIiBpZD0ic3ZnIj48dGV4dCB4PSIxMCIgeT0iMjAiIGlkPSJzdmctbGluay10ZXh0Ij50ZXh0PC90ZXh0Pjwvc3ZnPg==';

element.setAttribute('type', 'image/svg+xml');
element.setAttribute('data', 'data:image/svg+xml,base64,' + svg);
element.setAttribute('data', svg);
element.setAttribute('width', '200');
element.setAttribute('height', '50');
},
Expand Down
3 changes: 2 additions & 1 deletion src/supports/focus-video-without-controls.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@

import detectFocus from './detect-focus';
import mp4 from './media/mp4';

export default detectFocus({
name: 'can-focus-video-without-controls',
element: 'video',
mutate: function(element) {
// invalid media file can trigger warning in console, data-uri to prevent HTTP request
element.setAttribute('src', 'data:video/mp4;base64,' + 'video-focus-test');
element.setAttribute('src', mp4);
},
});
2 changes: 2 additions & 0 deletions src/supports/media/gif.invalid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export default 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ';
2 changes: 2 additions & 0 deletions src/supports/media/gif.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export default 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
4 changes: 4 additions & 0 deletions src/supports/media/mp3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

//export default 'data:audio/mp3;base64,audio-focus-test';
import gif from './gif';
export default gif;
4 changes: 4 additions & 0 deletions src/supports/media/mp4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

//export default 'data:video/mp4;base64,video-focus-test';
import gif from './gif';
export default gif;
4 changes: 4 additions & 0 deletions src/supports/media/svg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export default 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtb'
+ 'G5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBpZD0ic3ZnIj48dGV4dCB4PSIxMCIgeT0iMjAiIGlkPSJ'
+ 'zdmctbGluay10ZXh0Ij50ZXh0PC90ZXh0Pjwvc3ZnPg==';
33 changes: 17 additions & 16 deletions test/helper/fixtures/focusable.fixture.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
define(['./custom.fixture'], function(customFixture) {
var gifDataUri = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
var svgDataUri = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtb'
+ 'G5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBpZD0ic3ZnIj48dGV4dCB4PSIxMCIgeT0iMjAiIGlkPSJ'
+ 'zdmctbGluay10ZXh0Ij50ZXh0PC90ZXh0Pjwvc3ZnPg==';

define([
'./custom.fixture',
'ally/supports/media/gif',
'ally/supports/media/svg',
'ally/supports/media/mp3',
'ally/supports/media/mp4',
], function(customFixture, gif, svg, mp3, mp4) {
return function(context) {
return customFixture([
/*eslint-disable indent */
Expand All @@ -24,22 +25,22 @@ define(['./custom.fixture'], function(customFixture) {
'<area id="image-map-area" href="#void" shape="rect" coords="63,19,144,45">',
'<area id="image-map-area-nolink" shape="rect" coords="63,19,144,45">',
'</map>',
'<img id="img-usemap" usemap="#image-map" src="' + gifDataUri + '" alt="">',
'<img id="img-usemap" usemap="#image-map" src="' + gif + '" alt="">',
// embedded content
'<object type="image/svg+xml" id="object-svg" data="' + svgDataUri + '" width="200" height="50"></object>',
'<object type="image/svg+xml" id="object-tabindex-svg" tabindex="-1" data="' + svgDataUri + '" width="200" height="50"></object>',
'<object type="image/svg+xml" id="object-svg" data="' + svg + '" width="200" height="50"></object>',
'<object type="image/svg+xml" id="object-tabindex-svg" tabindex="-1" data="' + svg + '" width="200" height="50"></object>',
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg">',
'<a xlink:href="#void" id="svg-link">',
'<text x="10" y="20" id="svg-link-text">text</text>',
'</a>',
'</svg>',
'<embed id="embed" type="video/mp4" src="data:video/mp4;base64,embed-focus-test" width="640" height="480">',
'<embed id="embed-tabindex-0" type="video/mp4" src="data:video/mp4;base64,embed-tabindex-focus-test" width="640" height="480" tabindex="0">',
'<embed type="image/svg+xml" id="embed-svg" data="' + svgDataUri + '" width="200" height="50">',
'<embed type="image/svg+xml" id="embed-tabindex-svg" tabindex="-1" data="' + svgDataUri + '" width="200" height="50">',
'<embed id="embed" type="video/mp4" src="' + mp4 + '" width="640" height="480">',
'<embed id="embed-tabindex-0" type="video/mp4" src="' + mp4 + '" width="640" height="480" tabindex="0">',
'<embed type="image/svg+xml" id="embed-svg" data="' + svg + '" width="200" height="50">',
'<embed type="image/svg+xml" id="embed-tabindex-svg" tabindex="-1" data="' + svg + '" width="200" height="50">',
// interactive content
'<audio id="audio" src="data:audio/mp3;base64,audio-focus-test"></audio>',
'<audio id="audio-controls" controls src="data:audio/mp3;base64,audio-focus-test"></audio>',
'<audio id="audio" src="' + mp3 + '"></audio>',
'<audio id="audio-controls" controls src="' + mp3 + '"></audio>',
// input elements
'<label id="label">text</label>',
'<input type="text" id="input">',
Expand All @@ -53,7 +54,7 @@ define(['./custom.fixture'], function(customFixture) {
'<span contenteditable id="span-contenteditable"></span>',
'<span style="-webkit-user-modify: read-write" id="span-user-modify"></span>',
// browser quirks
'<a href="#void" id="img-ismap-link"><img id="img-ismap" src="data:image/png;base64,broken-image-test" ismap alt=""></a>',
'<a href="#void" id="img-ismap-link"><img id="img-ismap" src="' + gif + '" ismap alt=""></a>',
// scrolling containers,
'<div id="scroll-container" style="width: 100px; height: 50px; overflow: auto;">',
'<div id="scroll-body" style="width: 500px; height: 40px;">scrollable content</div>',
Expand Down
5 changes: 3 additions & 2 deletions test/unit/element.disabled.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ define([
'../helper/fixtures/custom.fixture',
'../helper/supports',
'ally/element/disabled',
], function(registerSuite, expect, customFixture, supports, elementDisabled) {
'ally/supports/media/mp4',
], function(registerSuite, expect, customFixture, supports, elementDisabled, mp4) {

registerSuite(function() {
var fixture;
Expand Down Expand Up @@ -139,7 +140,7 @@ define([
expect(element.style.pointerEvents).to.equal('', 'after disable undo');
},
'disable removes video controls': function() {
var element = fixture.add('<video controls src="data:video/mp4;base64,video-focus-test"></audio>').firstElementChild;
var element = fixture.add('<video controls src="' + mp4 + '"></video>').firstElementChild;
expect(element.hasAttribute('controls')).to.equal(true, 'before disable');

elementDisabled(element, true);
Expand Down
12 changes: 7 additions & 5 deletions test/unit/is.valid-area.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ define([
'../helper/fixtures/custom.fixture',
'../helper/supports',
'ally/is/valid-area',
], function(registerSuite, expect, customFixture, supports, isValidArea) {
'ally/supports/media/gif',
'ally/supports/media/gif.invalid',
], function(registerSuite, expect, customFixture, supports, isValidArea, gif, invalidGif) {

registerSuite(function() {
var fixture;
Expand All @@ -24,25 +26,25 @@ define([
'<area id="image-map-area" href="#void" shape="rect" coords="63,19,144,45">',
'<area id="image-map-area-nolink" shape="rect" coords="63,19,144,45">',
'</map>',
'<img usemap="#image-map" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="">',
'<img usemap="#image-map" src="' + gif + '" alt="">',

'<map id="noname-map">',
'<area id="image-map-area" href="#void" shape="rect" coords="63,19,144,45">',
'<area id="image-map-area-nolink" shape="rect" coords="63,19,144,45">',
'</map>',
'<img usemap="#noname-map" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="">',
'<img usemap="#noname-map" src="' + gif + '" alt="">',

'<map name="interactive-map">',
'<area id="interactive-map-area" href="#void" shape="rect" coords="63,19,144,45">',
'</map>',
'<a href="#">',
'<img usemap="#interactive-map" src="data:image/gif;base64,broken-image" alt="">',
'<img usemap="#interactive-map" src="' + invalidGif + '" alt="">',
'</a>',

'<map name="broken-map">',
'<area id="broken-map-area" href="#void" shape="rect" coords="63,19,144,45">',
'</map>',
'<img usemap="#broken-map" src="data:image/gif;base64,broken-image" alt="">',
'<img usemap="#broken-map" src="' + invalidGif + '" alt="">',
/*eslint-enable indent */
].join(''));
},
Expand Down
5 changes: 3 additions & 2 deletions test/unit/is.visible.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ define([
'intern/chai!expect',
'../helper/fixtures/custom.fixture',
'ally/is/visible',
], function(registerSuite, expect, customFixture, isVisible) {
'ally/supports/media/mp3',
], function(registerSuite, expect, customFixture, isVisible, mp3) {

registerSuite(function() {
var fixture;
Expand Down Expand Up @@ -52,7 +53,7 @@ define([
'<area id="disconnected-area" href="#void" shape="rect" coords="63,19,144,45">',
'</map>',
// unknown dimension elements
'<audio id="unknown-dimension-audio" controls src="data:audio/mp3;base64,audio"></audio>',
'<audio id="unknown-dimension-audio" controls src="' + mp3 + '"></audio>',
// details/summary
'<details id="details-closed"><summary id="summary"></summary> <a href="#void" id="details-closed-link">link</a></details>',
'<details id="details-open" open><summary id="summary"></summary> <a href="#void" id="details-open-link">link</a></details>',
Expand Down

0 comments on commit 06c565a

Please sign in to comment.