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.
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/logging.h"
12 #include "base/path_service.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "content/browser/accessibility/accessibility_tree_formatter.h"
18 #include "content/browser/accessibility/browser_accessibility.h"
19 #include "content/browser/accessibility/browser_accessibility_manager.h"
20 #include "content/browser/renderer_host/render_view_host_impl.h"
21 #include "content/port/browser/render_widget_host_view_port.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/common/content_paths.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/public/common/url_constants.h"
26 #include "content/public/test/content_browser_test.h"
27 #include "content/public/test/content_browser_test_utils.h"
28 #include "content/shell/browser/shell.h"
29 #include "content/test/accessibility_browser_test_utils.h"
30 #include "testing/gtest/include/gtest/gtest.h"
32 // TODO(aboxhall): Create expectations on Android for these
33 #if defined(OS_ANDROID)
34 #define MAYBE(x) DISABLED_##x
43 const char kCommentToken
= '#';
44 const char kMarkSkipFile
[] = "#<skip";
45 const char kMarkEndOfFile
[] = "<-- End-of-file -->";
46 const char kSignalDiff
[] = "*";
50 typedef AccessibilityTreeFormatter::Filter Filter
;
52 // This test takes a snapshot of the platform BrowserAccessibility tree and
53 // tests it against an expected baseline.
55 // The flow of the test is as outlined below.
56 // 1. Load an html file from chrome/test/data/accessibility.
57 // 2. Read the expectation.
58 // 3. Browse to the page and serialize the platform specific tree into a human
60 // 4. Perform a comparison between actual and expected and fail if they do not
62 class DumpAccessibilityTreeTest
: public ContentBrowserTest
{
64 // Utility helper that does a comment aware equality check.
65 // Returns array of lines from expected file which are different.
66 std::vector
<int> DiffLines(const std::vector
<std::string
>& expected_lines
,
67 const std::vector
<std::string
>& actual_lines
) {
68 int actual_lines_count
= actual_lines
.size();
69 int expected_lines_count
= expected_lines
.size();
70 std::vector
<int> diff_lines
;
72 while (i
< actual_lines_count
&& j
< expected_lines_count
) {
73 if (expected_lines
[j
].size() == 0 ||
74 expected_lines
[j
][0] == kCommentToken
) {
75 // Skip comment lines and blank lines in expected output.
80 if (actual_lines
[i
] != expected_lines
[j
])
81 diff_lines
.push_back(j
);
86 // Actual file has been fully checked.
90 void AddDefaultFilters(std::vector
<Filter
>* filters
) {
91 filters
->push_back(Filter(base::ASCIIToUTF16("FOCUSABLE"), Filter::ALLOW
));
92 filters
->push_back(Filter(base::ASCIIToUTF16("READONLY"), Filter::ALLOW
));
93 filters
->push_back(Filter(base::ASCIIToUTF16("*=''"), Filter::DENY
));
96 void ParseFilters(const std::string
& test_html
,
97 std::vector
<Filter
>* filters
) {
98 std::vector
<std::string
> lines
;
99 base::SplitString(test_html
, '\n', &lines
);
100 for (std::vector
<std::string
>::const_iterator iter
= lines
.begin();
103 const std::string
& line
= *iter
;
104 const std::string
& allow_empty_str
=
105 AccessibilityTreeFormatter::GetAllowEmptyString();
106 const std::string
& allow_str
=
107 AccessibilityTreeFormatter::GetAllowString();
108 const std::string
& deny_str
=
109 AccessibilityTreeFormatter::GetDenyString();
110 if (StartsWithASCII(line
, allow_empty_str
, true)) {
112 Filter(base::UTF8ToUTF16(line
.substr(allow_empty_str
.size())),
113 Filter::ALLOW_EMPTY
));
114 } else if (StartsWithASCII(line
, allow_str
, true)) {
115 filters
->push_back(Filter(base::UTF8ToUTF16(
116 line
.substr(allow_str
.size())),
118 } else if (StartsWithASCII(line
, deny_str
, true)) {
119 filters
->push_back(Filter(base::UTF8ToUTF16(
120 line
.substr(deny_str
.size())),
126 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
127 ContentBrowserTest::SetUpCommandLine(command_line
);
128 // Enable <dialog>, which is used in some tests.
129 CommandLine::ForCurrentProcess()->AppendSwitch(
130 switches::kEnableExperimentalWebPlatformFeatures
);
133 void RunTest(const base::FilePath::CharType
* file_path
);
136 void DumpAccessibilityTreeTest::RunTest(
137 const base::FilePath::CharType
* file_path
) {
138 NavigateToURL(shell(), GURL(kAboutBlankURL
));
141 base::FilePath dir_test_data
;
142 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA
, &dir_test_data
));
143 base::FilePath
test_path(
144 dir_test_data
.Append(FILE_PATH_LITERAL("accessibility")));
145 ASSERT_TRUE(base::PathExists(test_path
))
146 << test_path
.LossyDisplayName();
148 base::FilePath html_file
= test_path
.Append(base::FilePath(file_path
));
149 // Output the test path to help anyone who encounters a failure and needs
150 // to know where to look.
151 printf("Testing: %s\n", html_file
.MaybeAsASCII().c_str());
153 std::string html_contents
;
154 base::ReadFileToString(html_file
, &html_contents
);
156 // Read the expected file.
157 std::string expected_contents_raw
;
158 base::FilePath expected_file
=
159 base::FilePath(html_file
.RemoveExtension().value() +
160 AccessibilityTreeFormatter::GetExpectedFileSuffix());
161 base::ReadFileToString(expected_file
, &expected_contents_raw
);
163 // Tolerate Windows-style line endings (\r\n) in the expected file:
164 // normalize by deleting all \r from the file (if any) to leave only \n.
165 std::string expected_contents
;
166 base::RemoveChars(expected_contents_raw
, "\r", &expected_contents
);
168 if (!expected_contents
.compare(0, strlen(kMarkSkipFile
), kMarkSkipFile
)) {
169 printf("Skipping this test on this platform.\n");
174 base::string16 html_contents16
;
175 html_contents16
= base::UTF8ToUTF16(html_contents
);
176 GURL url
= GetTestUrl("accessibility",
177 html_file
.BaseName().MaybeAsASCII().c_str());
178 AccessibilityNotificationWaiter
waiter(
179 shell(), AccessibilityModeComplete
,
180 ui::AX_EVENT_LOAD_COMPLETE
);
181 NavigateToURL(shell(), url
);
182 waiter
.WaitForNotification();
184 RenderWidgetHostViewPort
* host_view
= RenderWidgetHostViewPort::FromRWHV(
185 shell()->web_contents()->GetRenderWidgetHostView());
186 AccessibilityTreeFormatter
formatter(
187 host_view
->GetBrowserAccessibilityManager()->GetRoot());
189 // Parse filters in the test file.
190 std::vector
<Filter
> filters
;
191 AddDefaultFilters(&filters
);
192 ParseFilters(html_contents
, &filters
);
193 formatter
.SetFilters(filters
);
195 // Perform a diff (or write the initial baseline).
196 base::string16 actual_contents_utf16
;
197 formatter
.FormatAccessibilityTree(&actual_contents_utf16
);
198 std::string actual_contents
= base::UTF16ToUTF8(actual_contents_utf16
);
199 std::vector
<std::string
> actual_lines
, expected_lines
;
200 Tokenize(actual_contents
, "\n", &actual_lines
);
201 Tokenize(expected_contents
, "\n", &expected_lines
);
202 // Marking the end of the file with a line of text ensures that
203 // file length differences are found.
204 expected_lines
.push_back(kMarkEndOfFile
);
205 actual_lines
.push_back(kMarkEndOfFile
);
207 std::vector
<int> diff_lines
= DiffLines(expected_lines
, actual_lines
);
208 bool is_different
= diff_lines
.size() > 0;
209 EXPECT_FALSE(is_different
);
211 // Mark the expected lines which did not match actual output with a *.
212 printf("* Line Expected\n");
213 printf("- ---- --------\n");
214 for (int line
= 0, diff_index
= 0;
215 line
< static_cast<int>(expected_lines
.size());
217 bool is_diff
= false;
218 if (diff_index
< static_cast<int>(diff_lines
.size()) &&
219 diff_lines
[diff_index
] == line
) {
223 printf("%1s %4d %s\n", is_diff
? kSignalDiff
: "", line
+ 1,
224 expected_lines
[line
].c_str());
226 printf("\nActual\n");
228 printf("%s\n", actual_contents
.c_str());
231 if (!base::PathExists(expected_file
)) {
232 base::FilePath actual_file
=
233 base::FilePath(html_file
.RemoveExtension().value() +
234 AccessibilityTreeFormatter::GetActualFileSuffix());
236 EXPECT_TRUE(base::WriteFile(
237 actual_file
, actual_contents
.c_str(), actual_contents
.size()));
239 ADD_FAILURE() << "No expectation found. Create it by doing:\n"
240 << "mv " << actual_file
.LossyDisplayName() << " "
241 << expected_file
.LossyDisplayName();
245 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityA
) {
246 RunTest(FILE_PATH_LITERAL("a.html"));
249 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityAddress
) {
250 RunTest(FILE_PATH_LITERAL("address.html"));
253 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityAName
) {
254 RunTest(FILE_PATH_LITERAL("a-name.html"));
257 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityAOnclick
) {
258 RunTest(FILE_PATH_LITERAL("a-onclick.html"));
261 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
262 AccessibilityAriaApplication
) {
263 RunTest(FILE_PATH_LITERAL("aria-application.html"));
266 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
267 AccessibilityAriaAutocomplete
) {
268 RunTest(FILE_PATH_LITERAL("aria-autocomplete.html"));
271 // crbug.com/98976 will cause new elements to be added to the Blink a11y tree
272 // Re-baseline after the Blink change goes in
273 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
274 DISABLED_AccessibilityAriaCombobox
) {
275 RunTest(FILE_PATH_LITERAL("aria-combobox.html"));
278 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
279 MAYBE(AccessibilityAriaFlowto
)) {
280 RunTest(FILE_PATH_LITERAL("aria-flowto.html"));
283 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityAriaInvalid
) {
284 RunTest(FILE_PATH_LITERAL("aria-invalid.html"));
287 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityAriaLevel
) {
288 RunTest(FILE_PATH_LITERAL("aria-level.html"));
291 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityAriaMenu
) {
292 RunTest(FILE_PATH_LITERAL("aria-menu.html"));
295 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
296 AccessibilityAriaMenuitemradio
) {
297 RunTest(FILE_PATH_LITERAL("aria-menuitemradio.html"));
300 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
301 AccessibilityAriaPressed
) {
302 RunTest(FILE_PATH_LITERAL("aria-pressed.html"));
305 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
306 AccessibilityAriaProgressbar
) {
307 RunTest(FILE_PATH_LITERAL("aria-progressbar.html"));
310 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
311 AccessibilityAriaToolbar
) {
312 RunTest(FILE_PATH_LITERAL("toolbar.html"));
315 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
316 AccessibilityAriaValueMin
) {
317 RunTest(FILE_PATH_LITERAL("aria-valuemin.html"));
320 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
321 AccessibilityAriaValueMax
) {
322 RunTest(FILE_PATH_LITERAL("aria-valuemax.html"));
325 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityArticle
) {
326 RunTest(FILE_PATH_LITERAL("article.html"));
329 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityAWithImg
) {
330 RunTest(FILE_PATH_LITERAL("a-with-img.html"));
333 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityBdo
) {
334 RunTest(FILE_PATH_LITERAL("bdo.html"));
337 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityBR
) {
338 RunTest(FILE_PATH_LITERAL("br.html"));
341 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityButtonNameCalc
) {
342 RunTest(FILE_PATH_LITERAL("button-name-calc.html"));
345 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityCanvas
) {
346 RunTest(FILE_PATH_LITERAL("canvas.html"));
349 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
350 AccessibilityCheckboxNameCalc
) {
351 RunTest(FILE_PATH_LITERAL("checkbox-name-calc.html"));
354 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityDialog
) {
355 RunTest(FILE_PATH_LITERAL("dialog.html"));
358 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityDiv
) {
359 RunTest(FILE_PATH_LITERAL("div.html"));
362 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityDl
) {
363 RunTest(FILE_PATH_LITERAL("dl.html"));
366 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
367 AccessibilityContenteditableDescendants
) {
368 RunTest(FILE_PATH_LITERAL("contenteditable-descendants.html"));
371 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityEm
) {
372 RunTest(FILE_PATH_LITERAL("em.html"));
375 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityFooter
) {
376 RunTest(FILE_PATH_LITERAL("footer.html"));
379 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityForm
) {
380 RunTest(FILE_PATH_LITERAL("form.html"));
383 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityHeading
) {
384 RunTest(FILE_PATH_LITERAL("heading.html"));
387 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityHR
) {
388 RunTest(FILE_PATH_LITERAL("hr.html"));
391 // crbug.com/179717 and crbug.com/224659
392 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
393 DISABLED_AccessibilityIframeCoordinates
) {
394 RunTest(FILE_PATH_LITERAL("iframe-coordinates.html"));
397 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityInputButton
) {
398 RunTest(FILE_PATH_LITERAL("input-button.html"));
401 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
402 AccessibilityInputButtonInMenu
) {
403 RunTest(FILE_PATH_LITERAL("input-button-in-menu.html"));
406 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityInputColor
) {
407 RunTest(FILE_PATH_LITERAL("input-color.html"));
410 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
411 AccessibilityInputImageButtonInMenu
) {
412 RunTest(FILE_PATH_LITERAL("input-image-button-in-menu.html"));
415 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityInputRange
) {
416 RunTest(FILE_PATH_LITERAL("input-range.html"));
419 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
420 AccessibilityInputTextNameCalc
) {
421 RunTest(FILE_PATH_LITERAL("input-text-name-calc.html"));
424 // crbug.com/98976 will cause new elements to be added to the Blink a11y tree
425 // Re-baseline after the Blink change goes in
426 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
427 DISABLED_AccessibilityInputTypes
) {
428 RunTest(FILE_PATH_LITERAL("input-types.html"));
431 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityLabel
) {
432 RunTest(FILE_PATH_LITERAL("label.html"));
435 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityLandmark
) {
436 RunTest(FILE_PATH_LITERAL("landmark.html"));
439 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityListMarkers
) {
440 RunTest(FILE_PATH_LITERAL("list-markers.html"));
443 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
444 AccessibilityModalDialogClosed
) {
445 RunTest(FILE_PATH_LITERAL("modal-dialog-closed.html"));
448 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
449 AccessibilityModalDialogOpened
) {
450 RunTest(FILE_PATH_LITERAL("modal-dialog-opened.html"));
453 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
454 AccessibilityModalDialogInIframeClosed
) {
455 RunTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-closed.html"));
458 // TODO(dmazzoni): fix this test after Blink change that broke it lands.
459 // http://crbug.com/353067
460 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
461 DISABLED_AccessibilityModalDialogInIframeOpened
) {
462 RunTest(FILE_PATH_LITERAL("modal-dialog-in-iframe-opened.html"));
465 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
466 AccessibilityModalDialogStack
) {
467 RunTest(FILE_PATH_LITERAL("modal-dialog-stack.html"));
470 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityP
) {
471 RunTest(FILE_PATH_LITERAL("p.html"));
474 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityRegion
) {
475 RunTest(FILE_PATH_LITERAL("region.html"));
478 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilitySelect
) {
479 RunTest(FILE_PATH_LITERAL("select.html"));
482 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilitySpan
) {
483 RunTest(FILE_PATH_LITERAL("span.html"));
486 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilitySpinButton
) {
487 RunTest(FILE_PATH_LITERAL("spinbutton.html"));
490 // TODO(dmazzoni): Rebaseline this test after Blink rolls past r155083.
491 // See http://crbug.com/265619
492 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, DISABLED_AccessibilitySvg
) {
493 RunTest(FILE_PATH_LITERAL("svg.html"));
496 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityTab
) {
497 RunTest(FILE_PATH_LITERAL("tab.html"));
500 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityTableSimple
) {
501 RunTest(FILE_PATH_LITERAL("table-simple.html"));
504 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityTableSpans
) {
505 RunTest(FILE_PATH_LITERAL("table-spans.html"));
508 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
,
509 AccessibilityToggleButton
) {
510 RunTest(FILE_PATH_LITERAL("togglebutton.html"));
513 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityUl
) {
514 RunTest(FILE_PATH_LITERAL("ul.html"));
517 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest
, AccessibilityWbr
) {
518 RunTest(FILE_PATH_LITERAL("wbr.html"));
521 } // namespace content