Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / content / browser / accessibility / accessibility_win_browsertest.cc
blobb380f96a37334ebfd07f489e9714edcdf9fd0f1a
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.
5 #include <vector>
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "base/win/scoped_bstr.h"
10 #include "base/win/scoped_comptr.h"
11 #include "base/win/scoped_variant.h"
12 #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/render_frame_host.h"
17 #include "content/public/browser/render_widget_host_view.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/common/url_constants.h"
20 #include "content/public/test/content_browser_test.h"
21 #include "content/public/test/content_browser_test_utils.h"
22 #include "content/shell/browser/shell.h"
23 #include "content/test/accessibility_browser_test_utils.h"
24 #include "third_party/iaccessible2/ia2_api_all.h"
25 #include "third_party/isimpledom/ISimpleDOMNode.h"
27 // TODO(dmazzoni): Disabled accessibility tests on Win64. crbug.com/179717
28 #if defined(ARCH_CPU_X86_64)
29 #define MAYBE(x) DISABLED_##x
30 #else
31 #define MAYBE(x) x
32 #endif
34 namespace content {
36 namespace {
39 // Helpers --------------------------------------------------------------------
41 base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant(
42 IAccessible* parent,
43 VARIANT* var) {
44 base::win::ScopedComPtr<IAccessible> ptr;
45 switch (V_VT(var)) {
46 case VT_DISPATCH: {
47 IDispatch* dispatch = V_DISPATCH(var);
48 if (dispatch)
49 ptr.QueryFrom(dispatch);
50 break;
53 case VT_I4: {
54 base::win::ScopedComPtr<IDispatch> dispatch;
55 HRESULT hr = parent->get_accChild(*var, dispatch.Receive());
56 EXPECT_TRUE(SUCCEEDED(hr));
57 if (dispatch)
58 dispatch.QueryInterface(ptr.Receive());
59 break;
62 return ptr;
65 HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
66 // TODO(ctguil): For some reason querying the IAccessible2 interface from
67 // IAccessible fails.
68 base::win::ScopedComPtr<IServiceProvider> service_provider;
69 HRESULT hr = accessible->QueryInterface(service_provider.Receive());
70 return SUCCEEDED(hr) ?
71 service_provider->QueryService(IID_IAccessible2, accessible2) : hr;
74 // Recursively search through all of the descendants reachable from an
75 // IAccessible node and return true if we find one with the given role
76 // and name.
77 void RecursiveFindNodeInAccessibilityTree(IAccessible* node,
78 int32 expected_role,
79 const std::wstring& expected_name,
80 int32 depth,
81 bool* found) {
82 base::win::ScopedBstr name_bstr;
83 base::win::ScopedVariant childid_self(CHILDID_SELF);
84 node->get_accName(childid_self, name_bstr.Receive());
85 std::wstring name(name_bstr, name_bstr.Length());
86 base::win::ScopedVariant role;
87 node->get_accRole(childid_self, role.Receive());
88 ASSERT_EQ(VT_I4, role.type());
90 // Print the accessibility tree as we go, because if this test fails
91 // on the bots, this is really helpful in figuring out why.
92 for (int i = 0; i < depth; i++)
93 printf(" ");
94 printf("role=%d name=%s\n", V_I4(&role), base::WideToUTF8(name).c_str());
96 if (expected_role == V_I4(&role) && expected_name == name) {
97 *found = true;
98 return;
101 LONG child_count = 0;
102 HRESULT hr = node->get_accChildCount(&child_count);
103 ASSERT_EQ(S_OK, hr);
105 scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
106 LONG obtained_count = 0;
107 hr = AccessibleChildren(
108 node, 0, child_count, child_array.get(), &obtained_count);
109 ASSERT_EQ(S_OK, hr);
110 ASSERT_EQ(child_count, obtained_count);
112 for (int index = 0; index < obtained_count; index++) {
113 base::win::ScopedComPtr<IAccessible> child_accessible(
114 GetAccessibleFromResultVariant(node, &child_array.get()[index]));
115 if (child_accessible) {
116 RecursiveFindNodeInAccessibilityTree(
117 child_accessible.get(), expected_role, expected_name, depth + 1,
118 found);
119 if (*found)
120 return;
126 // AccessibilityWinBrowserTest ------------------------------------------------
128 class AccessibilityWinBrowserTest : public ContentBrowserTest {
129 public:
130 AccessibilityWinBrowserTest();
131 virtual ~AccessibilityWinBrowserTest();
133 protected:
134 void LoadInitialAccessibilityTreeFromHtml(const std::string& html);
135 IAccessible* GetRendererAccessible();
136 void ExecuteScript(const std::wstring& script);
138 private:
139 DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest);
142 AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
145 AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {
148 void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
149 const std::string& html) {
150 AccessibilityNotificationWaiter waiter(
151 shell(), AccessibilityModeComplete,
152 ui::AX_EVENT_LOAD_COMPLETE);
153 GURL html_data_url("data:text/html," + html);
154 NavigateToURL(shell(), html_data_url);
155 waiter.WaitForNotification();
158 // Retrieve the MSAA client accessibility object for the Render Widget Host View
159 // of the selected tab.
160 IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() {
161 HWND hwnd_render_widget_host_view =
162 shell()->web_contents()->GetRenderWidgetHostView()->GetNativeView();
164 // Invoke windows screen reader detection by sending the WM_GETOBJECT message
165 // with kIdCustom as the LPARAM.
166 const int32 kIdCustom = 1;
167 SendMessage(
168 hwnd_render_widget_host_view, WM_GETOBJECT, OBJID_CLIENT, kIdCustom);
170 IAccessible* accessible;
171 HRESULT hr = AccessibleObjectFromWindow(
172 hwnd_render_widget_host_view, OBJID_CLIENT,
173 IID_IAccessible, reinterpret_cast<void**>(&accessible));
175 EXPECT_EQ(S_OK, hr);
176 EXPECT_NE(accessible, reinterpret_cast<IAccessible*>(NULL));
178 return accessible;
181 void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) {
182 shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script);
186 // AccessibleChecker ----------------------------------------------------------
188 class AccessibleChecker {
189 public:
190 // This constructor can be used if the IA2 role will be the same as the MSAA
191 // role.
192 AccessibleChecker(const std::wstring& expected_name,
193 int32 expected_role,
194 const std::wstring& expected_value);
195 AccessibleChecker(const std::wstring& expected_name,
196 int32 expected_role,
197 int32 expected_ia2_role,
198 const std::wstring& expected_value);
199 AccessibleChecker(const std::wstring& expected_name,
200 const std::wstring& expected_role,
201 int32 expected_ia2_role,
202 const std::wstring& expected_value);
204 // Append an AccessibleChecker that verifies accessibility information for
205 // a child IAccessible. Order is important.
206 void AppendExpectedChild(AccessibleChecker* expected_child);
208 // Check that the name and role of the given IAccessible instance and its
209 // descendants match the expected names and roles that this object was
210 // initialized with.
211 void CheckAccessible(IAccessible* accessible);
213 // Set the expected value for this AccessibleChecker.
214 void SetExpectedValue(const std::wstring& expected_value);
216 // Set the expected state for this AccessibleChecker.
217 void SetExpectedState(LONG expected_state);
219 private:
220 typedef std::vector<AccessibleChecker*> AccessibleCheckerVector;
222 void CheckAccessibleName(IAccessible* accessible);
223 void CheckAccessibleRole(IAccessible* accessible);
224 void CheckIA2Role(IAccessible* accessible);
225 void CheckAccessibleValue(IAccessible* accessible);
226 void CheckAccessibleState(IAccessible* accessible);
227 void CheckAccessibleChildren(IAccessible* accessible);
228 base::string16 RoleVariantToString(const base::win::ScopedVariant& role);
230 // Expected accessible name. Checked against IAccessible::get_accName.
231 std::wstring name_;
233 // Expected accessible role. Checked against IAccessible::get_accRole.
234 base::win::ScopedVariant role_;
236 // Expected IAccessible2 role. Checked against IAccessible2::role.
237 int32 ia2_role_;
239 // Expected accessible value. Checked against IAccessible::get_accValue.
240 std::wstring value_;
242 // Expected accessible state. Checked against IAccessible::get_accState.
243 LONG state_;
245 // Expected accessible children. Checked using IAccessible::get_accChildCount
246 // and ::AccessibleChildren.
247 AccessibleCheckerVector children_;
250 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
251 int32 expected_role,
252 const std::wstring& expected_value)
253 : name_(expected_name),
254 role_(expected_role),
255 ia2_role_(expected_role),
256 value_(expected_value),
257 state_(-1) {
260 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
261 int32 expected_role,
262 int32 expected_ia2_role,
263 const std::wstring& expected_value)
264 : name_(expected_name),
265 role_(expected_role),
266 ia2_role_(expected_ia2_role),
267 value_(expected_value),
268 state_(-1) {
271 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
272 const std::wstring& expected_role,
273 int32 expected_ia2_role,
274 const std::wstring& expected_value)
275 : name_(expected_name),
276 role_(expected_role.c_str()),
277 ia2_role_(expected_ia2_role),
278 value_(expected_value),
279 state_(-1) {
282 void AccessibleChecker::AppendExpectedChild(
283 AccessibleChecker* expected_child) {
284 children_.push_back(expected_child);
287 void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
288 SCOPED_TRACE("while checking " +
289 base::UTF16ToUTF8(RoleVariantToString(role_)));
290 CheckAccessibleName(accessible);
291 CheckAccessibleRole(accessible);
292 CheckIA2Role(accessible);
293 CheckAccessibleValue(accessible);
294 CheckAccessibleState(accessible);
295 CheckAccessibleChildren(accessible);
298 void AccessibleChecker::SetExpectedValue(const std::wstring& expected_value) {
299 value_ = expected_value;
302 void AccessibleChecker::SetExpectedState(LONG expected_state) {
303 state_ = expected_state;
306 void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
307 base::win::ScopedBstr name;
308 base::win::ScopedVariant childid_self(CHILDID_SELF);
309 HRESULT hr = accessible->get_accName(childid_self, name.Receive());
311 if (name_.empty()) {
312 // If the object doesn't have name S_FALSE should be returned.
313 EXPECT_EQ(S_FALSE, hr);
314 } else {
315 // Test that the correct string was returned.
316 EXPECT_EQ(S_OK, hr);
317 EXPECT_EQ(name_, std::wstring(name, name.Length()));
321 void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) {
322 base::win::ScopedVariant role;
323 base::win::ScopedVariant childid_self(CHILDID_SELF);
324 HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
325 ASSERT_EQ(S_OK, hr);
326 EXPECT_EQ(0, role_.Compare(role))
327 << "Expected role: " << RoleVariantToString(role_)
328 << "\nGot role: " << RoleVariantToString(role);
331 void AccessibleChecker::CheckIA2Role(IAccessible* accessible) {
332 base::win::ScopedComPtr<IAccessible2> accessible2;
333 HRESULT hr = QueryIAccessible2(accessible, accessible2.Receive());
334 ASSERT_EQ(S_OK, hr);
335 long ia2_role = 0;
336 hr = accessible2->role(&ia2_role);
337 ASSERT_EQ(S_OK, hr);
338 EXPECT_EQ(ia2_role_, ia2_role)
339 << "Expected ia2 role: " << IAccessible2RoleToString(ia2_role_)
340 << "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role);
343 void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
344 // Don't check the value if if's a DOCUMENT role, because the value
345 // is supposed to be the url (and we don't keep track of that in the
346 // test expectations).
347 base::win::ScopedVariant role;
348 base::win::ScopedVariant childid_self(CHILDID_SELF);
349 HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
350 ASSERT_EQ(S_OK, hr);
351 if (role.type() == VT_I4 && V_I4(&role) == ROLE_SYSTEM_DOCUMENT)
352 return;
354 // Get the value.
355 base::win::ScopedBstr value;
356 hr = accessible->get_accValue(childid_self, value.Receive());
357 EXPECT_EQ(S_OK, hr);
359 // Test that the correct string was returned.
360 EXPECT_EQ(value_, std::wstring(value, value.Length()));
363 void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
364 if (state_ < 0)
365 return;
367 base::win::ScopedVariant state;
368 base::win::ScopedVariant childid_self(CHILDID_SELF);
369 HRESULT hr = accessible->get_accState(childid_self, state.Receive());
370 EXPECT_EQ(S_OK, hr);
371 ASSERT_EQ(VT_I4, state.type());
372 LONG obj_state = V_I4(&state);
373 // Avoid flakiness. The "offscreen" state depends on whether the browser
374 // window is frontmost or not, and "hottracked" depends on whether the
375 // mouse cursor happens to be over the element.
376 obj_state &= ~(STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_HOTTRACKED);
377 EXPECT_EQ(state_, obj_state)
378 << "Expected state: " << IAccessibleStateToString(state_)
379 << "\nGot state: " << IAccessibleStateToString(obj_state);
382 void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
383 LONG child_count = 0;
384 HRESULT hr = parent->get_accChildCount(&child_count);
385 EXPECT_EQ(S_OK, hr);
386 ASSERT_EQ(child_count, children_.size());
388 scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
389 LONG obtained_count = 0;
390 hr = AccessibleChildren(parent, 0, child_count,
391 child_array.get(), &obtained_count);
392 ASSERT_EQ(S_OK, hr);
393 ASSERT_EQ(child_count, obtained_count);
395 VARIANT* child = child_array.get();
396 for (AccessibleCheckerVector::iterator child_checker = children_.begin();
397 child_checker != children_.end();
398 ++child_checker, ++child) {
399 base::win::ScopedComPtr<IAccessible> child_accessible(
400 GetAccessibleFromResultVariant(parent, child));
401 ASSERT_TRUE(child_accessible.get());
402 (*child_checker)->CheckAccessible(child_accessible);
406 base::string16 AccessibleChecker::RoleVariantToString(
407 const base::win::ScopedVariant& role) {
408 if (role.type() == VT_I4)
409 return IAccessibleRoleToString(V_I4(&role));
410 if (role.type() == VT_BSTR)
411 return base::string16(V_BSTR(&role), SysStringLen(V_BSTR(&role)));
412 return base::string16();
415 } // namespace
418 // Tests ----------------------------------------------------------------------
420 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
421 MAYBE(TestBusyAccessibilityTree)) {
422 NavigateToURL(shell(), GURL(kAboutBlankURL));
424 // The initial accessible returned should have state STATE_SYSTEM_BUSY while
425 // the accessibility tree is being requested from the renderer.
426 AccessibleChecker document1_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
427 std::wstring());
428 document1_checker.SetExpectedState(
429 STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED |
430 STATE_SYSTEM_BUSY);
431 document1_checker.CheckAccessible(GetRendererAccessible());
434 // Flaky, http://crbug.com/167320 .
435 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
436 DISABLED_TestRendererAccessibilityTree) {
437 LoadInitialAccessibilityTreeFromHtml(
438 "<html><head><title>Accessibility Win Test</title></head>"
439 "<body><input type='button' value='push' /><input type='checkbox' />"
440 "</body></html>");
442 // Check the browser's copy of the renderer accessibility tree.
443 AccessibleChecker button_checker(L"push", ROLE_SYSTEM_PUSHBUTTON,
444 std::wstring());
445 AccessibleChecker checkbox_checker(std::wstring(), ROLE_SYSTEM_CHECKBUTTON,
446 std::wstring());
447 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
448 std::wstring());
449 AccessibleChecker document2_checker(L"Accessibility Win Test",
450 ROLE_SYSTEM_DOCUMENT, std::wstring());
451 body_checker.AppendExpectedChild(&button_checker);
452 body_checker.AppendExpectedChild(&checkbox_checker);
453 document2_checker.AppendExpectedChild(&body_checker);
454 document2_checker.CheckAccessible(GetRendererAccessible());
456 // Check that document accessible has a parent accessible.
457 base::win::ScopedComPtr<IAccessible> document_accessible(
458 GetRendererAccessible());
459 ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
460 base::win::ScopedComPtr<IDispatch> parent_dispatch;
461 HRESULT hr = document_accessible->get_accParent(parent_dispatch.Receive());
462 EXPECT_EQ(S_OK, hr);
463 EXPECT_NE(parent_dispatch, reinterpret_cast<IDispatch*>(NULL));
465 // Navigate to another page.
466 NavigateToURL(shell(), GURL(kAboutBlankURL));
468 // Verify that the IAccessible reference still points to a valid object and
469 // that calls to its methods fail since the tree is no longer valid after
470 // the page navagation.
471 base::win::ScopedBstr name;
472 base::win::ScopedVariant childid_self(CHILDID_SELF);
473 hr = document_accessible->get_accName(childid_self, name.Receive());
474 ASSERT_EQ(E_FAIL, hr);
477 // Periodically failing. See crbug.com/145537
478 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
479 DISABLED_TestNotificationActiveDescendantChanged) {
480 LoadInitialAccessibilityTreeFromHtml(
481 "<ul tabindex='-1' role='radiogroup' aria-label='ul'>"
482 "<li id='li'>li</li></ul>");
484 // Check the browser's copy of the renderer accessibility tree.
485 AccessibleChecker list_marker_checker(L"\x2022", ROLE_SYSTEM_TEXT,
486 std::wstring());
487 AccessibleChecker static_text_checker(L"li", ROLE_SYSTEM_TEXT,
488 std::wstring());
489 AccessibleChecker list_item_checker(std::wstring(), ROLE_SYSTEM_LISTITEM,
490 std::wstring());
491 list_item_checker.SetExpectedState(STATE_SYSTEM_READONLY);
492 AccessibleChecker radio_group_checker(L"ul", ROLE_SYSTEM_GROUPING,
493 IA2_ROLE_SECTION, std::wstring());
494 radio_group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
495 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
496 std::wstring());
497 list_item_checker.AppendExpectedChild(&list_marker_checker);
498 list_item_checker.AppendExpectedChild(&static_text_checker);
499 radio_group_checker.AppendExpectedChild(&list_item_checker);
500 document_checker.AppendExpectedChild(&radio_group_checker);
501 document_checker.CheckAccessible(GetRendererAccessible());
503 // Set focus to the radio group.
504 scoped_ptr<AccessibilityNotificationWaiter> waiter(
505 new AccessibilityNotificationWaiter(
506 shell(), AccessibilityModeComplete,
507 ui::AX_EVENT_FOCUS));
508 ExecuteScript(L"document.body.children[0].focus()");
509 waiter->WaitForNotification();
511 // Check that the accessibility tree of the browser has been updated.
512 radio_group_checker.SetExpectedState(
513 STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
514 document_checker.CheckAccessible(GetRendererAccessible());
516 // Set the active descendant of the radio group
517 waiter.reset(new AccessibilityNotificationWaiter(
518 shell(), AccessibilityModeComplete,
519 ui::AX_EVENT_FOCUS));
520 ExecuteScript(
521 L"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
522 waiter->WaitForNotification();
524 // Check that the accessibility tree of the browser has been updated.
525 list_item_checker.SetExpectedState(
526 STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
527 radio_group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
528 document_checker.CheckAccessible(GetRendererAccessible());
531 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
532 MAYBE(TestNotificationCheckedStateChanged)) {
533 LoadInitialAccessibilityTreeFromHtml(
534 "<body><input type='checkbox' /></body>");
536 // Check the browser's copy of the renderer accessibility tree.
537 AccessibleChecker checkbox_checker(std::wstring(), ROLE_SYSTEM_CHECKBUTTON,
538 std::wstring());
539 checkbox_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
540 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
541 std::wstring());
542 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
543 std::wstring());
544 body_checker.AppendExpectedChild(&checkbox_checker);
545 document_checker.AppendExpectedChild(&body_checker);
546 document_checker.CheckAccessible(GetRendererAccessible());
548 // Check the checkbox.
549 scoped_ptr<AccessibilityNotificationWaiter> waiter(
550 new AccessibilityNotificationWaiter(
551 shell(), AccessibilityModeComplete,
552 ui::AX_EVENT_CHECKED_STATE_CHANGED));
553 ExecuteScript(L"document.body.children[0].checked=true");
554 waiter->WaitForNotification();
556 // Check that the accessibility tree of the browser has been updated.
557 checkbox_checker.SetExpectedState(
558 STATE_SYSTEM_CHECKED | STATE_SYSTEM_FOCUSABLE);
559 document_checker.CheckAccessible(GetRendererAccessible());
562 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
563 MAYBE(TestNotificationChildrenChanged)) {
564 // The role attribute causes the node to be in the accessibility tree.
565 LoadInitialAccessibilityTreeFromHtml("<body role=group></body>");
567 // Check the browser's copy of the renderer accessibility tree.
568 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
569 std::wstring());
570 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
571 std::wstring());
572 document_checker.AppendExpectedChild(&group_checker);
573 document_checker.CheckAccessible(GetRendererAccessible());
575 // Change the children of the document body.
576 scoped_ptr<AccessibilityNotificationWaiter> waiter(
577 new AccessibilityNotificationWaiter(
578 shell(),
579 AccessibilityModeComplete,
580 ui::AX_EVENT_CHILDREN_CHANGED));
581 ExecuteScript(L"document.body.innerHTML='<b>new text</b>'");
582 waiter->WaitForNotification();
584 // Check that the accessibility tree of the browser has been updated.
585 AccessibleChecker text_checker(L"new text", ROLE_SYSTEM_TEXT, std::wstring());
586 group_checker.AppendExpectedChild(&text_checker);
587 document_checker.CheckAccessible(GetRendererAccessible());
590 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
591 MAYBE(TestNotificationChildrenChanged2)) {
592 // The role attribute causes the node to be in the accessibility tree.
593 LoadInitialAccessibilityTreeFromHtml(
594 "<div role=group style='visibility: hidden'>text</div>");
596 // Check the accessible tree of the browser.
597 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
598 std::wstring());
599 document_checker.CheckAccessible(GetRendererAccessible());
601 // Change the children of the document body.
602 scoped_ptr<AccessibilityNotificationWaiter> waiter(
603 new AccessibilityNotificationWaiter(
604 shell(), AccessibilityModeComplete,
605 ui::AX_EVENT_CHILDREN_CHANGED));
606 ExecuteScript(L"document.body.children[0].style.visibility='visible'");
607 waiter->WaitForNotification();
609 // Check that the accessibility tree of the browser has been updated.
610 AccessibleChecker static_text_checker(L"text", ROLE_SYSTEM_TEXT,
611 std::wstring());
612 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
613 std::wstring());
614 document_checker.AppendExpectedChild(&group_checker);
615 group_checker.AppendExpectedChild(&static_text_checker);
616 document_checker.CheckAccessible(GetRendererAccessible());
619 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
620 MAYBE(TestNotificationFocusChanged)) {
621 // The role attribute causes the node to be in the accessibility tree.
622 LoadInitialAccessibilityTreeFromHtml("<div role=group tabindex='-1'></div>");
624 // Check the browser's copy of the renderer accessibility tree.
625 SCOPED_TRACE("Check initial tree");
626 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
627 std::wstring());
628 group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
629 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
630 std::wstring());
631 document_checker.AppendExpectedChild(&group_checker);
632 document_checker.CheckAccessible(GetRendererAccessible());
634 // Focus the div in the document
635 scoped_ptr<AccessibilityNotificationWaiter> waiter(
636 new AccessibilityNotificationWaiter(
637 shell(), AccessibilityModeComplete,
638 ui::AX_EVENT_FOCUS));
639 ExecuteScript(L"document.body.children[0].focus()");
640 waiter->WaitForNotification();
642 // Check that the accessibility tree of the browser has been updated.
643 SCOPED_TRACE("Check updated tree after focusing div");
644 group_checker.SetExpectedState(
645 STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
646 document_checker.CheckAccessible(GetRendererAccessible());
648 // Focus the document accessible. This will un-focus the current node.
649 waiter.reset(
650 new AccessibilityNotificationWaiter(
651 shell(), AccessibilityModeComplete,
652 ui::AX_EVENT_BLUR));
653 base::win::ScopedComPtr<IAccessible> document_accessible(
654 GetRendererAccessible());
655 ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
656 base::win::ScopedVariant childid_self(CHILDID_SELF);
657 HRESULT hr = document_accessible->accSelect(SELFLAG_TAKEFOCUS, childid_self);
658 ASSERT_EQ(S_OK, hr);
659 waiter->WaitForNotification();
661 // Check that the accessibility tree of the browser has been updated.
662 SCOPED_TRACE("Check updated tree after focusing document again");
663 group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
664 document_checker.CheckAccessible(GetRendererAccessible());
667 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
668 MAYBE(TestNotificationValueChanged)) {
669 LoadInitialAccessibilityTreeFromHtml(
670 "<body><input type='text' value='old value'/></body>");
672 // Check the browser's copy of the renderer accessibility tree.
673 AccessibleChecker text_field_checker(std::wstring(), ROLE_SYSTEM_TEXT,
674 L"old value");
675 text_field_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
676 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
677 std::wstring());
678 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
679 std::wstring());
680 body_checker.AppendExpectedChild(&text_field_checker);
681 document_checker.AppendExpectedChild(&body_checker);
682 document_checker.CheckAccessible(GetRendererAccessible());
684 // Set the value of the text control
685 scoped_ptr<AccessibilityNotificationWaiter> waiter(
686 new AccessibilityNotificationWaiter(
687 shell(), AccessibilityModeComplete,
688 ui::AX_EVENT_VALUE_CHANGE));
689 ExecuteScript(L"document.body.children[0].value='new value'");
690 waiter->WaitForNotification();
692 // Check that the accessibility tree of the browser has been updated.
693 text_field_checker.SetExpectedValue(L"new value");
694 document_checker.CheckAccessible(GetRendererAccessible());
697 // This test verifies that the web content's accessibility tree is a
698 // descendant of the main browser window's accessibility tree, so that
699 // tools like AccExplorer32 or AccProbe can be used to examine Chrome's
700 // accessibility support.
702 // If you made a change and this test now fails, check that the NativeViewHost
703 // that wraps the tab contents returns the IAccessible implementation
704 // provided by RenderWidgetHostViewWin in GetNativeViewAccessible().
705 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
706 MAYBE(ContainsRendererAccessibilityTree)) {
707 LoadInitialAccessibilityTreeFromHtml(
708 "<html><head><title>MyDocument</title></head>"
709 "<body>Content</body></html>");
711 // Get the accessibility object for the browser window.
712 HWND browser_hwnd = shell()->window();
713 base::win::ScopedComPtr<IAccessible> browser_accessible;
714 HRESULT hr = AccessibleObjectFromWindow(
715 browser_hwnd,
716 OBJID_WINDOW,
717 IID_IAccessible,
718 reinterpret_cast<void**>(browser_accessible.Receive()));
719 ASSERT_EQ(S_OK, hr);
721 bool found = false;
722 RecursiveFindNodeInAccessibilityTree(
723 browser_accessible.get(), ROLE_SYSTEM_DOCUMENT, L"MyDocument", 0, &found);
724 ASSERT_EQ(found, true);
727 // Disabled because of http://crbug.com/144390.
728 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
729 DISABLED_TestToggleButtonRoleAndStates) {
730 AccessibleChecker* button_checker;
731 std::string button_html("data:text/html,");
732 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
733 std::wstring());
734 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
735 std::wstring());
736 document_checker.AppendExpectedChild(&body_checker);
738 // Temporary macro
739 #define ADD_BUTTON(html, ia2_role, state) \
740 button_html += html; \
741 button_checker = new AccessibleChecker(L"x", ROLE_SYSTEM_PUSHBUTTON, \
742 ia2_role, std::wstring()); \
743 button_checker->SetExpectedState(state); \
744 body_checker.AppendExpectedChild(button_checker)
746 // If aria-pressed is 'undefined', empty or not present, use PUSHBUTTON
747 // Otherwise use TOGGLE_BUTTON, even if the value is invalid.
748 // The spec does this in an attempt future-proof in case new values are added.
749 ADD_BUTTON("<span role='button' aria-pressed='false'>x</span>",
750 IA2_ROLE_TOGGLE_BUTTON, 0);
751 ADD_BUTTON("<span role='button' aria-pressed='true'>x</span>",
752 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_PRESSED);
753 ADD_BUTTON("<span role='button' aria-pressed='mixed'>x</span>",
754 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_MIXED);
755 ADD_BUTTON("<span role='button' aria-pressed='xyz'>x</span>",
756 IA2_ROLE_TOGGLE_BUTTON, 0);
757 ADD_BUTTON("<span role='button' aria-pressed=''>x</span>",
758 ROLE_SYSTEM_PUSHBUTTON, 0);
759 ADD_BUTTON("<span role='button' aria-pressed>x</span>",
760 ROLE_SYSTEM_PUSHBUTTON, 0);
761 ADD_BUTTON("<span role='button' aria-pressed='undefined'>x</span>",
762 ROLE_SYSTEM_PUSHBUTTON, 0);
763 ADD_BUTTON("<span role='button'>x</span>", ROLE_SYSTEM_PUSHBUTTON, 0);
764 ADD_BUTTON("<input type='button' aria-pressed='true' value='x'/>",
765 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_PRESSED);
766 ADD_BUTTON("<input type='button' aria-pressed='false' value='x'/>",
767 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
768 ADD_BUTTON("<input type='button' aria-pressed='mixed' value='x'>",
769 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_MIXED);
770 ADD_BUTTON("<input type='button' aria-pressed='xyz' value='x'/>",
771 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
772 ADD_BUTTON("<input type='button' aria-pressed='' value='x'/>",
773 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
774 ADD_BUTTON("<input type='button' aria-pressed value='x'>",
775 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
776 ADD_BUTTON("<input type='button' aria-pressed='undefined' value='x'>",
777 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
778 ADD_BUTTON("<input type='button' value='x'>",
779 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
780 ADD_BUTTON("<button aria-pressed='true'>x</button>",
781 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_PRESSED);
782 ADD_BUTTON("<button aria-pressed='false'>x</button>",
783 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
784 ADD_BUTTON("<button aria-pressed='mixed'>x</button>", IA2_ROLE_TOGGLE_BUTTON,
785 STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_MIXED);
786 ADD_BUTTON("<button aria-pressed='xyz'>x</button>", IA2_ROLE_TOGGLE_BUTTON,
787 STATE_SYSTEM_FOCUSABLE);
788 ADD_BUTTON("<button aria-pressed=''>x</button>",
789 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
790 ADD_BUTTON("<button aria-pressed>x</button>",
791 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
792 ADD_BUTTON("<button aria-pressed='undefined'>x</button>",
793 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
794 ADD_BUTTON("<button>x</button>", ROLE_SYSTEM_PUSHBUTTON,
795 STATE_SYSTEM_FOCUSABLE);
796 #undef ADD_BUTTON // Temporary macro
798 LoadInitialAccessibilityTreeFromHtml(button_html);
799 document_checker.CheckAccessible(GetRendererAccessible());
802 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
803 MAYBE(SupportsISimpleDOM)) {
804 LoadInitialAccessibilityTreeFromHtml(
805 "<body><input type='checkbox' /></body>");
807 // Get the IAccessible object for the document.
808 base::win::ScopedComPtr<IAccessible> document_accessible(
809 GetRendererAccessible());
810 ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
812 // Get the ISimpleDOM object for the document.
813 base::win::ScopedComPtr<IServiceProvider> service_provider;
814 HRESULT hr = static_cast<IAccessible*>(document_accessible)->QueryInterface(
815 service_provider.Receive());
816 ASSERT_EQ(S_OK, hr);
817 const GUID refguid = {0x0c539790, 0x12e4, 0x11cf,
818 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
819 base::win::ScopedComPtr<ISimpleDOMNode> document_isimpledomnode;
820 hr = static_cast<IServiceProvider *>(service_provider)->QueryService(
821 refguid, IID_ISimpleDOMNode,
822 reinterpret_cast<void**>(document_isimpledomnode.Receive()));
823 ASSERT_EQ(S_OK, hr);
825 base::win::ScopedBstr node_name;
826 short name_space_id; // NOLINT
827 base::win::ScopedBstr node_value;
828 unsigned int num_children;
829 unsigned int unique_id;
830 unsigned short node_type; // NOLINT
831 hr = document_isimpledomnode->get_nodeInfo(
832 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
833 &unique_id, &node_type);
834 ASSERT_EQ(S_OK, hr);
835 EXPECT_EQ(NODETYPE_DOCUMENT, node_type);
836 EXPECT_EQ(1, num_children);
837 node_name.Reset();
838 node_value.Reset();
840 base::win::ScopedComPtr<ISimpleDOMNode> body_isimpledomnode;
841 hr = document_isimpledomnode->get_firstChild(
842 body_isimpledomnode.Receive());
843 ASSERT_EQ(S_OK, hr);
844 hr = body_isimpledomnode->get_nodeInfo(
845 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
846 &unique_id, &node_type);
847 ASSERT_EQ(S_OK, hr);
848 EXPECT_EQ(L"body", std::wstring(node_name, node_name.Length()));
849 EXPECT_EQ(NODETYPE_ELEMENT, node_type);
850 EXPECT_EQ(1, num_children);
851 node_name.Reset();
852 node_value.Reset();
854 base::win::ScopedComPtr<ISimpleDOMNode> checkbox_isimpledomnode;
855 hr = body_isimpledomnode->get_firstChild(
856 checkbox_isimpledomnode.Receive());
857 ASSERT_EQ(S_OK, hr);
858 hr = checkbox_isimpledomnode->get_nodeInfo(
859 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
860 &unique_id, &node_type);
861 ASSERT_EQ(S_OK, hr);
862 EXPECT_EQ(L"input", std::wstring(node_name, node_name.Length()));
863 EXPECT_EQ(NODETYPE_ELEMENT, node_type);
864 EXPECT_EQ(0, num_children);
867 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, MAYBE(TestRoleGroup)) {
868 LoadInitialAccessibilityTreeFromHtml(
869 "<fieldset></fieldset><div role=group></div>");
871 // Check the browser's copy of the renderer accessibility tree.
872 AccessibleChecker grouping1_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
873 std::wstring());
874 AccessibleChecker grouping2_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
875 std::wstring());
876 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
877 std::wstring());
878 document_checker.AppendExpectedChild(&grouping1_checker);
879 document_checker.AppendExpectedChild(&grouping2_checker);
880 document_checker.CheckAccessible(GetRendererAccessible());
883 } // namespace content