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.
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"
26 #include "ui/aura/window.h"
27 #include "ui/aura/window_tree_host.h"
33 // Helpers --------------------------------------------------------------------
35 base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant(
38 base::win::ScopedComPtr<IAccessible> ptr;
41 IDispatch* dispatch = V_DISPATCH(var);
43 ptr.QueryFrom(dispatch);
48 base::win::ScopedComPtr<IDispatch> dispatch;
49 HRESULT hr = parent->get_accChild(*var, dispatch.Receive());
50 EXPECT_TRUE(SUCCEEDED(hr));
52 dispatch.QueryInterface(ptr.Receive());
59 HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
60 // TODO(ctguil): For some reason querying the IAccessible2 interface from
62 base::win::ScopedComPtr<IServiceProvider> service_provider;
63 HRESULT hr = accessible->QueryInterface(service_provider.Receive());
64 return SUCCEEDED(hr) ?
65 service_provider->QueryService(IID_IAccessible2, accessible2) : hr;
68 // Recursively search through all of the descendants reachable from an
69 // IAccessible node and return true if we find one with the given role
71 void RecursiveFindNodeInAccessibilityTree(IAccessible* node,
73 const std::wstring& expected_name,
76 base::win::ScopedBstr name_bstr;
77 base::win::ScopedVariant childid_self(CHILDID_SELF);
78 node->get_accName(childid_self, name_bstr.Receive());
79 std::wstring name(name_bstr, name_bstr.Length());
80 base::win::ScopedVariant role;
81 node->get_accRole(childid_self, role.Receive());
82 ASSERT_EQ(VT_I4, role.type());
84 // Print the accessibility tree as we go, because if this test fails
85 // on the bots, this is really helpful in figuring out why.
86 for (int i = 0; i < depth; i++)
88 printf("role=%s name=%s\n",
89 base::WideToUTF8(IAccessibleRoleToString(V_I4(&role))).c_str(),
90 base::WideToUTF8(name).c_str());
92 if (expected_role == V_I4(&role) && expected_name == name) {
98 HRESULT hr = node->get_accChildCount(&child_count);
101 scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
102 LONG obtained_count = 0;
103 hr = AccessibleChildren(
104 node, 0, child_count, child_array.get(), &obtained_count);
106 ASSERT_EQ(child_count, obtained_count);
108 for (int index = 0; index < obtained_count; index++) {
109 base::win::ScopedComPtr<IAccessible> child_accessible(
110 GetAccessibleFromResultVariant(node, &child_array.get()[index]));
111 if (child_accessible) {
112 RecursiveFindNodeInAccessibilityTree(
113 child_accessible.get(), expected_role, expected_name, depth + 1,
122 // AccessibilityWinBrowserTest ------------------------------------------------
124 class AccessibilityWinBrowserTest : public ContentBrowserTest {
126 AccessibilityWinBrowserTest();
127 virtual ~AccessibilityWinBrowserTest();
130 void LoadInitialAccessibilityTreeFromHtml(const std::string& html);
131 IAccessible* GetRendererAccessible();
132 void ExecuteScript(const std::wstring& script);
135 DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest);
138 AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
141 AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {
144 void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
145 const std::string& html) {
146 AccessibilityNotificationWaiter waiter(
147 shell(), AccessibilityModeComplete,
148 ui::AX_EVENT_LOAD_COMPLETE);
149 GURL html_data_url("data:text/html," + html);
150 NavigateToURL(shell(), html_data_url);
151 waiter.WaitForNotification();
154 // Retrieve the MSAA client accessibility object for the Render Widget Host View
155 // of the selected tab.
156 IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() {
157 content::WebContents* web_contents = shell()->web_contents();
158 return web_contents->GetRenderWidgetHostView()->GetNativeViewAccessible();
161 void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) {
162 shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script);
166 // AccessibleChecker ----------------------------------------------------------
168 class AccessibleChecker {
170 // This constructor can be used if the IA2 role will be the same as the MSAA
172 AccessibleChecker(const std::wstring& expected_name,
174 const std::wstring& expected_value);
175 AccessibleChecker(const std::wstring& expected_name,
177 int32 expected_ia2_role,
178 const std::wstring& expected_value);
179 AccessibleChecker(const std::wstring& expected_name,
180 const std::wstring& expected_role,
181 int32 expected_ia2_role,
182 const std::wstring& expected_value);
184 // Append an AccessibleChecker that verifies accessibility information for
185 // a child IAccessible. Order is important.
186 void AppendExpectedChild(AccessibleChecker* expected_child);
188 // Check that the name and role of the given IAccessible instance and its
189 // descendants match the expected names and roles that this object was
191 void CheckAccessible(IAccessible* accessible);
193 // Set the expected value for this AccessibleChecker.
194 void SetExpectedValue(const std::wstring& expected_value);
196 // Set the expected state for this AccessibleChecker.
197 void SetExpectedState(LONG expected_state);
200 typedef std::vector<AccessibleChecker*> AccessibleCheckerVector;
202 void CheckAccessibleName(IAccessible* accessible);
203 void CheckAccessibleRole(IAccessible* accessible);
204 void CheckIA2Role(IAccessible* accessible);
205 void CheckAccessibleValue(IAccessible* accessible);
206 void CheckAccessibleState(IAccessible* accessible);
207 void CheckAccessibleChildren(IAccessible* accessible);
208 base::string16 RoleVariantToString(const base::win::ScopedVariant& role);
210 // Expected accessible name. Checked against IAccessible::get_accName.
213 // Expected accessible role. Checked against IAccessible::get_accRole.
214 base::win::ScopedVariant role_;
216 // Expected IAccessible2 role. Checked against IAccessible2::role.
219 // Expected accessible value. Checked against IAccessible::get_accValue.
222 // Expected accessible state. Checked against IAccessible::get_accState.
225 // Expected accessible children. Checked using IAccessible::get_accChildCount
226 // and ::AccessibleChildren.
227 AccessibleCheckerVector children_;
230 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
232 const std::wstring& expected_value)
233 : name_(expected_name),
234 role_(expected_role),
235 ia2_role_(expected_role),
236 value_(expected_value),
240 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
242 int32 expected_ia2_role,
243 const std::wstring& expected_value)
244 : name_(expected_name),
245 role_(expected_role),
246 ia2_role_(expected_ia2_role),
247 value_(expected_value),
251 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
252 const std::wstring& expected_role,
253 int32 expected_ia2_role,
254 const std::wstring& expected_value)
255 : name_(expected_name),
256 role_(expected_role.c_str()),
257 ia2_role_(expected_ia2_role),
258 value_(expected_value),
262 void AccessibleChecker::AppendExpectedChild(
263 AccessibleChecker* expected_child) {
264 children_.push_back(expected_child);
267 void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
268 SCOPED_TRACE("while checking " +
269 base::UTF16ToUTF8(RoleVariantToString(role_)));
270 CheckAccessibleName(accessible);
271 CheckAccessibleRole(accessible);
272 CheckIA2Role(accessible);
273 CheckAccessibleValue(accessible);
274 CheckAccessibleState(accessible);
275 CheckAccessibleChildren(accessible);
278 void AccessibleChecker::SetExpectedValue(const std::wstring& expected_value) {
279 value_ = expected_value;
282 void AccessibleChecker::SetExpectedState(LONG expected_state) {
283 state_ = expected_state;
286 void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
287 base::win::ScopedBstr name;
288 base::win::ScopedVariant childid_self(CHILDID_SELF);
289 HRESULT hr = accessible->get_accName(childid_self, name.Receive());
292 // If the object doesn't have name S_FALSE should be returned.
293 EXPECT_EQ(S_FALSE, hr);
295 // Test that the correct string was returned.
297 EXPECT_EQ(name_, std::wstring(name, name.Length()));
301 void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) {
302 base::win::ScopedVariant role;
303 base::win::ScopedVariant childid_self(CHILDID_SELF);
304 HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
306 EXPECT_EQ(0, role_.Compare(role))
307 << "Expected role: " << RoleVariantToString(role_)
308 << "\nGot role: " << RoleVariantToString(role);
311 void AccessibleChecker::CheckIA2Role(IAccessible* accessible) {
312 base::win::ScopedComPtr<IAccessible2> accessible2;
313 HRESULT hr = QueryIAccessible2(accessible, accessible2.Receive());
316 hr = accessible2->role(&ia2_role);
318 EXPECT_EQ(ia2_role_, ia2_role)
319 << "Expected ia2 role: " << IAccessible2RoleToString(ia2_role_)
320 << "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role);
323 void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
324 // Don't check the value if if's a DOCUMENT role, because the value
325 // is supposed to be the url (and we don't keep track of that in the
326 // test expectations).
327 base::win::ScopedVariant role;
328 base::win::ScopedVariant childid_self(CHILDID_SELF);
329 HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
331 if (role.type() == VT_I4 && V_I4(&role) == ROLE_SYSTEM_DOCUMENT)
335 base::win::ScopedBstr value;
336 hr = accessible->get_accValue(childid_self, value.Receive());
339 // Test that the correct string was returned.
340 EXPECT_EQ(value_, std::wstring(value, value.Length()));
343 void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
347 base::win::ScopedVariant state;
348 base::win::ScopedVariant childid_self(CHILDID_SELF);
349 HRESULT hr = accessible->get_accState(childid_self, state.Receive());
351 ASSERT_EQ(VT_I4, state.type());
352 LONG obj_state = V_I4(&state);
353 // Avoid flakiness. The "offscreen" state depends on whether the browser
354 // window is frontmost or not, and "hottracked" depends on whether the
355 // mouse cursor happens to be over the element.
356 obj_state &= ~(STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_HOTTRACKED);
357 EXPECT_EQ(state_, obj_state)
358 << "Expected state: " << IAccessibleStateToString(state_)
359 << "\nGot state: " << IAccessibleStateToString(obj_state);
362 void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
363 LONG child_count = 0;
364 HRESULT hr = parent->get_accChildCount(&child_count);
366 ASSERT_EQ(child_count, children_.size());
368 scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
369 LONG obtained_count = 0;
370 hr = AccessibleChildren(parent, 0, child_count,
371 child_array.get(), &obtained_count);
373 ASSERT_EQ(child_count, obtained_count);
375 VARIANT* child = child_array.get();
376 for (AccessibleCheckerVector::iterator child_checker = children_.begin();
377 child_checker != children_.end();
378 ++child_checker, ++child) {
379 base::win::ScopedComPtr<IAccessible> child_accessible(
380 GetAccessibleFromResultVariant(parent, child));
381 ASSERT_TRUE(child_accessible.get());
382 (*child_checker)->CheckAccessible(child_accessible);
386 base::string16 AccessibleChecker::RoleVariantToString(
387 const base::win::ScopedVariant& role) {
388 if (role.type() == VT_I4)
389 return IAccessibleRoleToString(V_I4(&role));
390 if (role.type() == VT_BSTR)
391 return base::string16(V_BSTR(&role), SysStringLen(V_BSTR(&role)));
392 return base::string16();
398 // Tests ----------------------------------------------------------------------
400 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
401 TestBusyAccessibilityTree) {
402 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
404 // The initial accessible returned should have state STATE_SYSTEM_BUSY while
405 // the accessibility tree is being requested from the renderer.
406 AccessibleChecker document1_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
408 document1_checker.SetExpectedState(
409 STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED |
411 document1_checker.CheckAccessible(GetRendererAccessible());
414 // Periodically failing. See crbug.com/145537
415 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
416 DISABLED_TestNotificationActiveDescendantChanged) {
417 LoadInitialAccessibilityTreeFromHtml(
418 "<ul tabindex='-1' role='radiogroup' aria-label='ul'>"
419 "<li id='li'>li</li></ul>");
421 // Check the browser's copy of the renderer accessibility tree.
422 AccessibleChecker list_marker_checker(L"\x2022", ROLE_SYSTEM_TEXT,
424 AccessibleChecker static_text_checker(L"li", ROLE_SYSTEM_TEXT,
426 AccessibleChecker list_item_checker(std::wstring(), ROLE_SYSTEM_LISTITEM,
428 list_item_checker.SetExpectedState(STATE_SYSTEM_READONLY);
429 AccessibleChecker radio_group_checker(L"ul", ROLE_SYSTEM_GROUPING,
430 IA2_ROLE_SECTION, std::wstring());
431 radio_group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
432 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
434 list_item_checker.AppendExpectedChild(&list_marker_checker);
435 list_item_checker.AppendExpectedChild(&static_text_checker);
436 radio_group_checker.AppendExpectedChild(&list_item_checker);
437 document_checker.AppendExpectedChild(&radio_group_checker);
438 document_checker.CheckAccessible(GetRendererAccessible());
440 // Set focus to the radio group.
441 scoped_ptr<AccessibilityNotificationWaiter> waiter(
442 new AccessibilityNotificationWaiter(
443 shell(), AccessibilityModeComplete,
444 ui::AX_EVENT_FOCUS));
445 ExecuteScript(L"document.body.children[0].focus()");
446 waiter->WaitForNotification();
448 // Check that the accessibility tree of the browser has been updated.
449 radio_group_checker.SetExpectedState(
450 STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
451 document_checker.CheckAccessible(GetRendererAccessible());
453 // Set the active descendant of the radio group
454 waiter.reset(new AccessibilityNotificationWaiter(
455 shell(), AccessibilityModeComplete,
456 ui::AX_EVENT_FOCUS));
458 L"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
459 waiter->WaitForNotification();
461 // Check that the accessibility tree of the browser has been updated.
462 list_item_checker.SetExpectedState(
463 STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
464 radio_group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
465 document_checker.CheckAccessible(GetRendererAccessible());
468 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
469 TestNotificationCheckedStateChanged) {
470 LoadInitialAccessibilityTreeFromHtml(
471 "<body><input type='checkbox' /></body>");
473 // Check the browser's copy of the renderer accessibility tree.
474 AccessibleChecker checkbox_checker(std::wstring(), ROLE_SYSTEM_CHECKBUTTON,
476 checkbox_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
477 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
479 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
481 body_checker.AppendExpectedChild(&checkbox_checker);
482 document_checker.AppendExpectedChild(&body_checker);
483 document_checker.CheckAccessible(GetRendererAccessible());
485 // Check the checkbox.
486 scoped_ptr<AccessibilityNotificationWaiter> waiter(
487 new AccessibilityNotificationWaiter(
488 shell(), AccessibilityModeComplete,
489 ui::AX_EVENT_CHECKED_STATE_CHANGED));
490 ExecuteScript(L"document.body.children[0].checked=true");
491 waiter->WaitForNotification();
493 // Check that the accessibility tree of the browser has been updated.
494 checkbox_checker.SetExpectedState(
495 STATE_SYSTEM_CHECKED | STATE_SYSTEM_FOCUSABLE);
496 document_checker.CheckAccessible(GetRendererAccessible());
499 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
500 TestNotificationChildrenChanged) {
501 // The role attribute causes the node to be in the accessibility tree.
502 LoadInitialAccessibilityTreeFromHtml("<body role=group></body>");
504 // Check the browser's copy of the renderer accessibility tree.
505 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
507 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
509 document_checker.AppendExpectedChild(&group_checker);
510 document_checker.CheckAccessible(GetRendererAccessible());
512 // Change the children of the document body.
513 scoped_ptr<AccessibilityNotificationWaiter> waiter(
514 new AccessibilityNotificationWaiter(
516 AccessibilityModeComplete,
517 ui::AX_EVENT_CHILDREN_CHANGED));
518 ExecuteScript(L"document.body.innerHTML='<b>new text</b>'");
519 waiter->WaitForNotification();
521 // Check that the accessibility tree of the browser has been updated.
522 AccessibleChecker text_checker(
523 L"new text", ROLE_SYSTEM_STATICTEXT, std::wstring());
524 group_checker.AppendExpectedChild(&text_checker);
525 document_checker.CheckAccessible(GetRendererAccessible());
528 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
529 TestNotificationChildrenChanged2) {
530 // The role attribute causes the node to be in the accessibility tree.
531 LoadInitialAccessibilityTreeFromHtml(
532 "<div role=group style='visibility: hidden'>text</div>");
534 // Check the accessible tree of the browser.
535 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
537 document_checker.CheckAccessible(GetRendererAccessible());
539 // Change the children of the document body.
540 scoped_ptr<AccessibilityNotificationWaiter> waiter(
541 new AccessibilityNotificationWaiter(
542 shell(), AccessibilityModeComplete,
543 ui::AX_EVENT_CHILDREN_CHANGED));
544 ExecuteScript(L"document.body.children[0].style.visibility='visible'");
545 waiter->WaitForNotification();
547 // Check that the accessibility tree of the browser has been updated.
548 AccessibleChecker static_text_checker(L"text", ROLE_SYSTEM_STATICTEXT,
550 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
552 document_checker.AppendExpectedChild(&group_checker);
553 group_checker.AppendExpectedChild(&static_text_checker);
554 document_checker.CheckAccessible(GetRendererAccessible());
557 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
558 TestNotificationFocusChanged) {
559 // The role attribute causes the node to be in the accessibility tree.
560 LoadInitialAccessibilityTreeFromHtml("<div role=group tabindex='-1'></div>");
562 // Check the browser's copy of the renderer accessibility tree.
563 SCOPED_TRACE("Check initial tree");
564 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
566 group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
567 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
569 document_checker.AppendExpectedChild(&group_checker);
570 document_checker.CheckAccessible(GetRendererAccessible());
572 // Focus the div in the document
573 scoped_ptr<AccessibilityNotificationWaiter> waiter(
574 new AccessibilityNotificationWaiter(
575 shell(), AccessibilityModeComplete,
576 ui::AX_EVENT_FOCUS));
577 ExecuteScript(L"document.body.children[0].focus()");
578 waiter->WaitForNotification();
580 // Check that the accessibility tree of the browser has been updated.
581 SCOPED_TRACE("Check updated tree after focusing div");
582 group_checker.SetExpectedState(
583 STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
584 document_checker.CheckAccessible(GetRendererAccessible());
586 // Focus the document accessible. This will un-focus the current node.
588 new AccessibilityNotificationWaiter(
589 shell(), AccessibilityModeComplete,
591 base::win::ScopedComPtr<IAccessible> document_accessible(
592 GetRendererAccessible());
593 ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
594 base::win::ScopedVariant childid_self(CHILDID_SELF);
595 HRESULT hr = document_accessible->accSelect(SELFLAG_TAKEFOCUS, childid_self);
597 waiter->WaitForNotification();
599 // Check that the accessibility tree of the browser has been updated.
600 SCOPED_TRACE("Check updated tree after focusing document again");
601 group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
602 document_checker.CheckAccessible(GetRendererAccessible());
605 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
606 TestNotificationValueChanged) {
607 LoadInitialAccessibilityTreeFromHtml(
608 "<body><input type='text' value='old value'/></body>");
610 // Check the browser's copy of the renderer accessibility tree.
611 AccessibleChecker text_field_checker(std::wstring(), ROLE_SYSTEM_TEXT,
613 text_field_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
614 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
616 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
618 body_checker.AppendExpectedChild(&text_field_checker);
619 document_checker.AppendExpectedChild(&body_checker);
620 document_checker.CheckAccessible(GetRendererAccessible());
622 // Set the value of the text control
623 scoped_ptr<AccessibilityNotificationWaiter> waiter(
624 new AccessibilityNotificationWaiter(
625 shell(), AccessibilityModeComplete,
626 ui::AX_EVENT_VALUE_CHANGED));
627 ExecuteScript(L"document.body.children[0].value='new value'");
628 waiter->WaitForNotification();
630 // Check that the accessibility tree of the browser has been updated.
631 text_field_checker.SetExpectedValue(L"new value");
632 document_checker.CheckAccessible(GetRendererAccessible());
635 // This test verifies that the web content's accessibility tree is a
636 // descendant of the main browser window's accessibility tree, so that
637 // tools like AccExplorer32 or AccProbe can be used to examine Chrome's
638 // accessibility support.
640 // If you made a change and this test now fails, check that the NativeViewHost
641 // that wraps the tab contents returns the IAccessible implementation
642 // provided by RenderWidgetHostViewWin in GetNativeViewAccessible().
643 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
644 ContainsRendererAccessibilityTree) {
645 LoadInitialAccessibilityTreeFromHtml(
646 "<html><head><title>MyDocument</title></head>"
647 "<body>Content</body></html>");
649 // Get the accessibility object for the window tree host.
650 aura::Window* window = shell()->window();
652 aura::WindowTreeHost* window_tree_host = window->GetHost();
653 CHECK(window_tree_host);
654 HWND hwnd = window_tree_host->GetAcceleratedWidget();
656 base::win::ScopedComPtr<IAccessible> browser_accessible;
657 HRESULT hr = AccessibleObjectFromWindow(
661 reinterpret_cast<void**>(browser_accessible.Receive()));
665 RecursiveFindNodeInAccessibilityTree(
666 browser_accessible.get(), ROLE_SYSTEM_DOCUMENT, L"MyDocument", 0, &found);
667 ASSERT_EQ(found, true);
670 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
671 SupportsISimpleDOM) {
672 LoadInitialAccessibilityTreeFromHtml(
673 "<body><input type='checkbox' /></body>");
675 // Get the IAccessible object for the document.
676 base::win::ScopedComPtr<IAccessible> document_accessible(
677 GetRendererAccessible());
678 ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
680 // Get the ISimpleDOM object for the document.
681 base::win::ScopedComPtr<IServiceProvider> service_provider;
682 HRESULT hr = static_cast<IAccessible*>(document_accessible)->QueryInterface(
683 service_provider.Receive());
685 const GUID refguid = {0x0c539790, 0x12e4, 0x11cf,
686 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
687 base::win::ScopedComPtr<ISimpleDOMNode> document_isimpledomnode;
688 hr = static_cast<IServiceProvider *>(service_provider)->QueryService(
689 refguid, IID_ISimpleDOMNode,
690 reinterpret_cast<void**>(document_isimpledomnode.Receive()));
693 base::win::ScopedBstr node_name;
694 short name_space_id; // NOLINT
695 base::win::ScopedBstr node_value;
696 unsigned int num_children;
697 unsigned int unique_id;
698 unsigned short node_type; // NOLINT
699 hr = document_isimpledomnode->get_nodeInfo(
700 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
701 &unique_id, &node_type);
703 EXPECT_EQ(NODETYPE_DOCUMENT, node_type);
704 EXPECT_EQ(1, num_children);
708 base::win::ScopedComPtr<ISimpleDOMNode> body_isimpledomnode;
709 hr = document_isimpledomnode->get_firstChild(
710 body_isimpledomnode.Receive());
712 hr = body_isimpledomnode->get_nodeInfo(
713 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
714 &unique_id, &node_type);
716 EXPECT_EQ(L"body", std::wstring(node_name, node_name.Length()));
717 EXPECT_EQ(NODETYPE_ELEMENT, node_type);
718 EXPECT_EQ(1, num_children);
722 base::win::ScopedComPtr<ISimpleDOMNode> checkbox_isimpledomnode;
723 hr = body_isimpledomnode->get_firstChild(
724 checkbox_isimpledomnode.Receive());
726 hr = checkbox_isimpledomnode->get_nodeInfo(
727 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
728 &unique_id, &node_type);
730 EXPECT_EQ(L"input", std::wstring(node_name, node_name.Length()));
731 EXPECT_EQ(NODETYPE_ELEMENT, node_type);
732 EXPECT_EQ(0, num_children);
735 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, TestRoleGroup) {
736 LoadInitialAccessibilityTreeFromHtml(
737 "<fieldset></fieldset><div role=group></div>");
739 // Check the browser's copy of the renderer accessibility tree.
740 AccessibleChecker grouping1_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
742 AccessibleChecker grouping2_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
744 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
746 document_checker.AppendExpectedChild(&grouping1_checker);
747 document_checker.AppendExpectedChild(&grouping2_checker);
748 document_checker.CheckAccessible(GetRendererAccessible());
751 } // namespace content