1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Tests to ensure that the accessibility audit and mechanisms
7 * to enable/disable it work as expected.
8 * @author aboxhall@google.com (Alice Boxhall)
13 * Test fixture for accessibility audit test.
15 * @extends testing.Test
17 function WebUIAccessibilityAuditBrowserTest() {}
19 WebUIAccessibilityAuditBrowserTest.prototype = {
20 __proto__: testing.Test.prototype,
22 browsePreload: 'chrome://terms',
24 runAccessibilityChecks: true,
25 accessibilityIssuesAreErrors: true,
28 * Number of expected accessibility errors, if it should be checked, otherwise
29 * null. Note: 'a11y' is short for 'accessibility'
32 expectedWarnings: null,
35 * Number of expected accessibility warnings, if it should be checked,
45 this.accessibilityAuditConfig.auditRulesToIgnore = [];
46 this.accessibilityAuditConfig.auditRulesToRun = ['lowContrastElements',
48 'controlsWithoutLabel'];
51 tearDown: function() {
52 var accessibilityResults = this.getAccessibilityResults();
53 var numAccessibilityErrors = 0;
54 var numAccessibilityWarnings = 0;
55 for (var i = 0; i < accessibilityResults.length; i++) {
56 var result = accessibilityResults[i];
57 if (result.rule.severity == axs.constants.Severity.Warning)
58 numAccessibilityWarnings++;
60 numAccessibilityErrors++;
63 if (this.expectedErrors != null)
64 expectEquals(this.expectedErrors, numAccessibilityErrors);
65 if (this.expectedWarnings != null) {
66 expectEquals(this.expectedWarnings, numAccessibilityWarnings);
68 testing.Test.prototype.tearDown.call(this);
73 * Test fixture for tests that are expected to fail.
75 function WebUIAccessibilityAuditBrowserTest_ShouldFail() {}
77 WebUIAccessibilityAuditBrowserTest_ShouldFail.prototype = {
78 __proto__: WebUIAccessibilityAuditBrowserTest.prototype,
84 * Adds some canned audit failures to the page being tested:
85 * - A low-contrast (white on white) element
86 * - An element with a non-existent ARIA role
87 * - A control without a label
89 function addAuditFailures() {
91 var style = document.createElement('style');
92 style.innerText = 'body { background-color: #ffff }\n' +
93 'p { color: #ffffff }';
94 document.head.appendChild(style);
97 var div = document.createElement('div');
98 div.setAttribute('role', 'not-a-role');
99 document.body.appendChild(div);
101 // Unlabelled control
102 var input = document.createElement('input');
104 document.body.appendChild(input);
108 * Adds an expectation that console.warn() will be called at least once with
109 * a string matching '.*accessibility.*'.
111 function expectReportConsoleWarning() {
112 function StubConsole() {};
113 StubConsole.prototype.warn = function() {};
114 StubConsole.prototype.log = function() {};
115 StubConsole.prototype.info = function() {};
116 StubConsole.prototype.error = function() {};
117 var mockConsole = mock(StubConsole);
118 mockConsole.expects(atLeastOnce()).warn(stringContains('accessibility'));
119 mockConsole.stubs().log(ANYTHING);
120 mockConsole.stubs().info(ANYTHING);
121 mockConsole.stubs().error(ANYTHING);
122 console = mockConsole.proxy();
126 * Creates a mock axs.Audit object.
127 * @return {object} a mock object with a run() method.
129 function createMockAudit() {
130 function StubAudit() {};
131 StubAudit.prototype.run = function() {};
133 return mock(StubAudit);
137 * Creates an expectation that the global axs.Audit object will never have its
138 * run() method called.
140 function expectAuditWillNotRun() {
141 var audit = createMockAudit();
142 audit.expects(never()).run();
143 axs.Audit = audit.proxy();
147 * Creates an expectation that the global axs.Audit object will have its run()
148 * method called |times| times.
149 * This creates an interstitial mock axs.Audit object with the expectation, and
150 * delegates to the real axs.Audit object to run the actual audit.
151 * @param {number} times The number of times the audit is expected to run.
153 function expectAuditWillRun(times, auditConfig) {
154 var audit = createMockAudit();
155 var realAudit = axs.Audit;
156 var expectedInvocation = audit.expects(exactly(times)).run(ANYTHING);
158 for (var i = 0; i < times; i++)
159 willArgs.push(callFunction(realAudit.run, auditConfig));
160 expectedInvocation.will.apply(expectedInvocation, willArgs);
161 axs.Audit = audit.proxy();
162 axs.Audit.createReport = realAudit.createReport;
163 axs.Audit.auditResults = realAudit.auditResults;
164 axs.Audit.accessibilityErrorMessage = realAudit.accessibilityErrorMessage;
167 // Test that an audit failure causes a test failure, if both
168 // |runAccessibilityChecks| and |accessibilityIssuesAreErrors| are true.
169 TEST_F('WebUIAccessibilityAuditBrowserTest_ShouldFail', 'testWithAuditFailures',
171 expectAuditWillRun(1, this.accessibilityAuditConfig);
175 // Test that the accessibility audit does not run if |runAccessibilityChecks|
177 TEST_F('WebUIAccessibilityAuditBrowserTest',
178 'testWithAuditFailures_a11yChecksDisabled',
180 expectAuditWillNotRun();
181 this.disableAccessibilityChecks();
185 // Tests that the accessibility audit will run but not cause a test failure when
186 // accessibilityIssuesAreErrors(false) is called in the test function
187 TEST_F('WebUIAccessibilityAuditBrowserTest',
188 'testWithAuditFailures_a11yIssuesAreWarnings',
190 this.accessibilityIssuesAreErrors = false;
191 expectAuditWillRun(1, this.accessibilityAuditConfig);
192 expectReportConsoleWarning();
194 this.expectedWarnings = 1;
195 this.expectedErrors = 2;
196 this.enableAccessibilityChecks();
201 * Test fixture with |runAccessibilityChecks| set to false.
203 * @extends {WebUIAccessibilityAuditBrowserTest}
205 function WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture() {}
207 WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture.prototype = {
208 __proto__: WebUIAccessibilityAuditBrowserTest.prototype,
210 runAccessibilityChecks: false,
211 accessibilityIssuesAreErrors: true,
215 * Test fixture with |runAccessibilityChecks| set to false for tests that should
218 * @extends {WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture}
220 function WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture_ShouldFail()
223 WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture_ShouldFail.prototype =
226 WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture.prototype,
233 // Test that the accessibility audit does not run when |runAccessibilityChecks|
234 // is set to false in the test fixture.
235 TEST_F('WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture',
236 'testWithAuditFailures_a11yChecksNotEnabled',
238 expectAuditWillNotRun();
242 // Test that the accessibility audit does run if the enableAccessibilityChecks()
243 // method is called in the test function.
244 TEST_F('WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture_ShouldFail',
245 'testWithAuditFailures',
247 expectAuditWillRun(1, this.accessibilityAuditConfig);
248 this.enableAccessibilityChecks();
252 // Test that the accessibility audit runs when the expectAccessibilityOk()
254 TEST_F('WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture',
255 'testRunningAuditManually_noErrors',
257 expectAuditWillRun(1, this.accessibilityAuditConfig);
258 expectAccessibilityOk();
261 // Test that calling expectAccessibilityOk() when there are accessibility issues
262 // on the page causes the test to fail.
263 TEST_F('WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture_ShouldFail',
264 'testRunningAuditManually_withErrors',
266 expectAuditWillRun(1, this.accessibilityAuditConfig);
268 expectAccessibilityOk();
271 // Test that calling expectAccessibilityOk() multiple times will cause the
272 // accessibility audit to run multiple times.
273 TEST_F('WebUIAccessibilityAuditBrowserTest_TestsDisabledInFixture',
274 'testRunningAuditManuallySeveralTimes', function() {
275 expectAuditWillRun(2, this.accessibilityAuditConfig);
276 expectAccessibilityOk();
277 expectAccessibilityOk();
281 * Test fixture with |accessibilityIssuesAreErrors| set to false.
283 * @extends {WebUIAccessibilityAuditBrowserTest}
285 function WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings() {}
287 WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings.prototype = {
288 __proto__: WebUIAccessibilityAuditBrowserTest.prototype,
290 accessibilityIssuesAreErrors: false,
294 * Test fixture with |accessibilityIssuesAreErrors| set to false for tests that
297 * @extends {WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings}
299 function WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings_ShouldFail() {}
301 WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings_ShouldFail.prototype = {
302 __proto__: WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings.prototype,
308 // Tests that the accessibility audit will run but not cause a test failure when
309 // |accessibilityIssuesAreErrors| is false in the test fixture.
310 TEST_F('WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings',
311 'testWithAuditFailures',
313 expectAuditWillRun(1, this.accessibilityAuditConfig);
314 expectReportConsoleWarning();
315 this.expectedWarnings = 1;
316 this.expectedErrors = 2;
318 this.enableAccessibilityChecks();
322 // Tests that the accessibility audit will run and call a test failure when
323 // accessibilityIssuesAreErrors(true) is called in the test function.
324 TEST_F('WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings_ShouldFail',
325 'testWithAuditFailuresAndIssuesAreErrors',
327 expectAuditWillRun(1, this.accessibilityAuditConfig);
328 this.expectedWarnings = 1;
329 this.expectedErrors = 2;
331 this.accessibilityIssuesAreErrors = true;
332 this.enableAccessibilityChecks();
337 // Tests that the accessibility audit will run twice if expectAccessibilityOk()
338 // is called during the test function and |runAccessibilityChecks| is true in
340 TEST_F('WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings',
341 'testWithAuditFailuresAndExpectA11yOk',
343 expectAuditWillRun(2, this.accessibilityAuditConfig);
345 expectAccessibilityOk();
347 this.expectedWarnings = 1;
348 this.expectedErrors = 2;
349 expectReportConsoleWarning();
351 this.enableAccessibilityChecks();
356 // Tests that parts of the page can be ignored on a per-audit rule basis.
357 TEST_F('WebUIAccessibilityAuditBrowserTest_IssuesAreWarnings',
358 'testCanIgnoreSelectors',
360 this.disableAccessibilityChecks();
362 var accessibilityResults = [];
364 assertAccessibilityOk(accessibilityResults);
366 // Expected error from assertion
368 expectEquals(3, accessibilityResults.length);
370 accessibilityResults.length = 0;
371 this.accessibilityAuditConfig.ignoreSelectors('lowContrastElements', '*');
373 assertAccessibilityOk(accessibilityResults);
375 // Expected error from assertion
377 expectEquals(2, accessibilityResults.length);
378 for (var i = 0; i < accessibilityResults.length; i++) {
379 expectFalse(accessibilityResults[i].rule.name == 'lowContrastElements');