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_mode_helper.h"
13 #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_types.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/render_widget_host_view.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/common/url_constants.h"
21 #include "content/public/test/content_browser_test.h"
22 #include "content/public/test/content_browser_test_utils.h"
23 #include "content/shell/browser/shell.h"
24 #include "content/test/accessibility_browser_test_utils.h"
25 #include "third_party/iaccessible2/ia2_api_all.h"
26 #include "third_party/isimpledom/ISimpleDOMNode.h"
27 #include "ui/aura/window.h"
28 #include "ui/aura/window_tree_host.h"
34 // Helpers --------------------------------------------------------------------
36 base::win::ScopedComPtr
<IAccessible
> GetAccessibleFromResultVariant(
39 base::win::ScopedComPtr
<IAccessible
> ptr
;
42 IDispatch
* dispatch
= V_DISPATCH(var
);
44 ptr
.QueryFrom(dispatch
);
49 base::win::ScopedComPtr
<IDispatch
> dispatch
;
50 HRESULT hr
= parent
->get_accChild(*var
, dispatch
.Receive());
51 EXPECT_TRUE(SUCCEEDED(hr
));
53 dispatch
.QueryInterface(ptr
.Receive());
60 HRESULT
QueryIAccessible2(IAccessible
* accessible
, IAccessible2
** accessible2
) {
61 // TODO(ctguil): For some reason querying the IAccessible2 interface from
63 base::win::ScopedComPtr
<IServiceProvider
> service_provider
;
64 HRESULT hr
= accessible
->QueryInterface(service_provider
.Receive());
65 return SUCCEEDED(hr
) ?
66 service_provider
->QueryService(IID_IAccessible2
, accessible2
) : hr
;
69 // Recursively search through all of the descendants reachable from an
70 // IAccessible node and return true if we find one with the given role
72 void RecursiveFindNodeInAccessibilityTree(IAccessible
* node
,
74 const std::wstring
& expected_name
,
77 base::win::ScopedBstr name_bstr
;
78 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
79 node
->get_accName(childid_self
, name_bstr
.Receive());
80 std::wstring
name(name_bstr
, name_bstr
.Length());
81 base::win::ScopedVariant role
;
82 node
->get_accRole(childid_self
, role
.Receive());
83 ASSERT_EQ(VT_I4
, role
.type());
85 // Print the accessibility tree as we go, because if this test fails
86 // on the bots, this is really helpful in figuring out why.
87 for (int i
= 0; i
< depth
; i
++)
89 printf("role=%s name=%s\n",
90 base::WideToUTF8(IAccessibleRoleToString(V_I4(&role
))).c_str(),
91 base::WideToUTF8(name
).c_str());
93 if (expected_role
== V_I4(&role
) && expected_name
== name
) {
99 HRESULT hr
= node
->get_accChildCount(&child_count
);
102 scoped_ptr
<VARIANT
[]> child_array(new VARIANT
[child_count
]);
103 LONG obtained_count
= 0;
104 hr
= AccessibleChildren(
105 node
, 0, child_count
, child_array
.get(), &obtained_count
);
107 ASSERT_EQ(child_count
, obtained_count
);
109 for (int index
= 0; index
< obtained_count
; index
++) {
110 base::win::ScopedComPtr
<IAccessible
> child_accessible(
111 GetAccessibleFromResultVariant(node
, &child_array
.get()[index
]));
112 if (child_accessible
.get()) {
113 RecursiveFindNodeInAccessibilityTree(
114 child_accessible
.get(), expected_role
, expected_name
, depth
+ 1,
123 // AccessibilityWinBrowserTest ------------------------------------------------
125 class AccessibilityWinBrowserTest
: public ContentBrowserTest
{
127 AccessibilityWinBrowserTest();
128 virtual ~AccessibilityWinBrowserTest();
131 void LoadInitialAccessibilityTreeFromHtml(const std::string
& html
);
132 IAccessible
* GetRendererAccessible();
133 void ExecuteScript(const std::wstring
& script
);
136 DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest
);
139 AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
142 AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {
145 void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
146 const std::string
& html
) {
147 AccessibilityNotificationWaiter
waiter(
148 shell(), AccessibilityModeComplete
,
149 ui::AX_EVENT_LOAD_COMPLETE
);
150 GURL
html_data_url("data:text/html," + html
);
151 NavigateToURL(shell(), html_data_url
);
152 waiter
.WaitForNotification();
155 // Retrieve the MSAA client accessibility object for the Render Widget Host View
156 // of the selected tab.
157 IAccessible
* AccessibilityWinBrowserTest::GetRendererAccessible() {
158 content::WebContents
* web_contents
= shell()->web_contents();
159 return web_contents
->GetRenderWidgetHostView()->GetNativeViewAccessible();
162 void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring
& script
) {
163 shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script
);
167 // AccessibleChecker ----------------------------------------------------------
169 class AccessibleChecker
{
171 // This constructor can be used if the IA2 role will be the same as the MSAA
173 AccessibleChecker(const std::wstring
& expected_name
,
175 const std::wstring
& expected_value
);
176 AccessibleChecker(const std::wstring
& expected_name
,
178 int32 expected_ia2_role
,
179 const std::wstring
& expected_value
);
180 AccessibleChecker(const std::wstring
& expected_name
,
181 const std::wstring
& expected_role
,
182 int32 expected_ia2_role
,
183 const std::wstring
& expected_value
);
185 // Append an AccessibleChecker that verifies accessibility information for
186 // a child IAccessible. Order is important.
187 void AppendExpectedChild(AccessibleChecker
* expected_child
);
189 // Check that the name and role of the given IAccessible instance and its
190 // descendants match the expected names and roles that this object was
192 void CheckAccessible(IAccessible
* accessible
);
194 // Set the expected value for this AccessibleChecker.
195 void SetExpectedValue(const std::wstring
& expected_value
);
197 // Set the expected state for this AccessibleChecker.
198 void SetExpectedState(LONG expected_state
);
201 typedef std::vector
<AccessibleChecker
*> AccessibleCheckerVector
;
203 void CheckAccessibleName(IAccessible
* accessible
);
204 void CheckAccessibleRole(IAccessible
* accessible
);
205 void CheckIA2Role(IAccessible
* accessible
);
206 void CheckAccessibleValue(IAccessible
* accessible
);
207 void CheckAccessibleState(IAccessible
* accessible
);
208 void CheckAccessibleChildren(IAccessible
* accessible
);
209 base::string16
RoleVariantToString(const base::win::ScopedVariant
& role
);
211 // Expected accessible name. Checked against IAccessible::get_accName.
214 // Expected accessible role. Checked against IAccessible::get_accRole.
215 base::win::ScopedVariant role_
;
217 // Expected IAccessible2 role. Checked against IAccessible2::role.
220 // Expected accessible value. Checked against IAccessible::get_accValue.
223 // Expected accessible state. Checked against IAccessible::get_accState.
226 // Expected accessible children. Checked using IAccessible::get_accChildCount
227 // and ::AccessibleChildren.
228 AccessibleCheckerVector children_
;
231 AccessibleChecker::AccessibleChecker(const std::wstring
& expected_name
,
233 const std::wstring
& expected_value
)
234 : name_(expected_name
),
235 role_(expected_role
),
236 ia2_role_(expected_role
),
237 value_(expected_value
),
241 AccessibleChecker::AccessibleChecker(const std::wstring
& expected_name
,
243 int32 expected_ia2_role
,
244 const std::wstring
& expected_value
)
245 : name_(expected_name
),
246 role_(expected_role
),
247 ia2_role_(expected_ia2_role
),
248 value_(expected_value
),
252 AccessibleChecker::AccessibleChecker(const std::wstring
& expected_name
,
253 const std::wstring
& expected_role
,
254 int32 expected_ia2_role
,
255 const std::wstring
& expected_value
)
256 : name_(expected_name
),
257 role_(expected_role
.c_str()),
258 ia2_role_(expected_ia2_role
),
259 value_(expected_value
),
263 void AccessibleChecker::AppendExpectedChild(
264 AccessibleChecker
* expected_child
) {
265 children_
.push_back(expected_child
);
268 void AccessibleChecker::CheckAccessible(IAccessible
* accessible
) {
269 SCOPED_TRACE("while checking " +
270 base::UTF16ToUTF8(RoleVariantToString(role_
)));
271 CheckAccessibleName(accessible
);
272 CheckAccessibleRole(accessible
);
273 CheckIA2Role(accessible
);
274 CheckAccessibleValue(accessible
);
275 CheckAccessibleState(accessible
);
276 CheckAccessibleChildren(accessible
);
279 void AccessibleChecker::SetExpectedValue(const std::wstring
& expected_value
) {
280 value_
= expected_value
;
283 void AccessibleChecker::SetExpectedState(LONG expected_state
) {
284 state_
= expected_state
;
287 void AccessibleChecker::CheckAccessibleName(IAccessible
* accessible
) {
288 base::win::ScopedBstr name
;
289 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
290 HRESULT hr
= accessible
->get_accName(childid_self
, name
.Receive());
293 // If the object doesn't have name S_FALSE should be returned.
294 EXPECT_EQ(S_FALSE
, hr
);
296 // Test that the correct string was returned.
298 EXPECT_EQ(name_
, std::wstring(name
, name
.Length()));
302 void AccessibleChecker::CheckAccessibleRole(IAccessible
* accessible
) {
303 base::win::ScopedVariant role
;
304 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
305 HRESULT hr
= accessible
->get_accRole(childid_self
, role
.Receive());
307 EXPECT_EQ(0, role_
.Compare(role
))
308 << "Expected role: " << RoleVariantToString(role_
)
309 << "\nGot role: " << RoleVariantToString(role
);
312 void AccessibleChecker::CheckIA2Role(IAccessible
* accessible
) {
313 base::win::ScopedComPtr
<IAccessible2
> accessible2
;
314 HRESULT hr
= QueryIAccessible2(accessible
, accessible2
.Receive());
317 hr
= accessible2
->role(&ia2_role
);
319 EXPECT_EQ(ia2_role_
, ia2_role
)
320 << "Expected ia2 role: " << IAccessible2RoleToString(ia2_role_
)
321 << "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role
);
324 void AccessibleChecker::CheckAccessibleValue(IAccessible
* accessible
) {
325 // Don't check the value if if's a DOCUMENT role, because the value
326 // is supposed to be the url (and we don't keep track of that in the
327 // test expectations).
328 base::win::ScopedVariant role
;
329 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
330 HRESULT hr
= accessible
->get_accRole(childid_self
, role
.Receive());
332 if (role
.type() == VT_I4
&& V_I4(&role
) == ROLE_SYSTEM_DOCUMENT
)
336 base::win::ScopedBstr value
;
337 hr
= accessible
->get_accValue(childid_self
, value
.Receive());
340 // Test that the correct string was returned.
341 EXPECT_EQ(value_
, std::wstring(value
, value
.Length()));
344 void AccessibleChecker::CheckAccessibleState(IAccessible
* accessible
) {
348 base::win::ScopedVariant state
;
349 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
350 HRESULT hr
= accessible
->get_accState(childid_self
, state
.Receive());
352 ASSERT_EQ(VT_I4
, state
.type());
353 LONG obj_state
= V_I4(&state
);
354 // Avoid flakiness. The "offscreen" state depends on whether the browser
355 // window is frontmost or not, and "hottracked" depends on whether the
356 // mouse cursor happens to be over the element.
357 obj_state
&= ~(STATE_SYSTEM_OFFSCREEN
| STATE_SYSTEM_HOTTRACKED
);
358 EXPECT_EQ(state_
, obj_state
)
359 << "Expected state: " << IAccessibleStateToString(state_
)
360 << "\nGot state: " << IAccessibleStateToString(obj_state
);
363 void AccessibleChecker::CheckAccessibleChildren(IAccessible
* parent
) {
364 LONG child_count
= 0;
365 HRESULT hr
= parent
->get_accChildCount(&child_count
);
367 ASSERT_EQ(child_count
, children_
.size());
369 scoped_ptr
<VARIANT
[]> child_array(new VARIANT
[child_count
]);
370 LONG obtained_count
= 0;
371 hr
= AccessibleChildren(parent
, 0, child_count
,
372 child_array
.get(), &obtained_count
);
374 ASSERT_EQ(child_count
, obtained_count
);
376 VARIANT
* child
= child_array
.get();
377 for (AccessibleCheckerVector::iterator child_checker
= children_
.begin();
378 child_checker
!= children_
.end();
379 ++child_checker
, ++child
) {
380 base::win::ScopedComPtr
<IAccessible
> child_accessible(
381 GetAccessibleFromResultVariant(parent
, child
));
382 ASSERT_TRUE(child_accessible
.get());
383 (*child_checker
)->CheckAccessible(child_accessible
.get());
387 base::string16
AccessibleChecker::RoleVariantToString(
388 const base::win::ScopedVariant
& role
) {
389 if (role
.type() == VT_I4
)
390 return IAccessibleRoleToString(V_I4(&role
));
391 if (role
.type() == VT_BSTR
)
392 return base::string16(V_BSTR(&role
), SysStringLen(V_BSTR(&role
)));
393 return base::string16();
399 // Tests ----------------------------------------------------------------------
401 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
402 TestBusyAccessibilityTree
) {
403 if (GetBaseAccessibilityMode() != AccessibilityModeOff
)
406 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
408 // The initial accessible returned should have state STATE_SYSTEM_BUSY while
409 // the accessibility tree is being requested from the renderer.
410 AccessibleChecker
document1_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT
,
412 document1_checker
.SetExpectedState(
413 STATE_SYSTEM_READONLY
| STATE_SYSTEM_FOCUSABLE
| STATE_SYSTEM_FOCUSED
|
415 document1_checker
.CheckAccessible(GetRendererAccessible());
418 // Periodically failing. See crbug.com/145537
419 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
420 DISABLED_TestNotificationActiveDescendantChanged
) {
421 LoadInitialAccessibilityTreeFromHtml(
422 "<ul tabindex='-1' role='radiogroup' aria-label='ul'>"
423 "<li id='li'>li</li></ul>");
425 // Check the browser's copy of the renderer accessibility tree.
426 AccessibleChecker
list_marker_checker(L
"\x2022", ROLE_SYSTEM_TEXT
,
428 AccessibleChecker
static_text_checker(L
"li", ROLE_SYSTEM_TEXT
,
430 AccessibleChecker
list_item_checker(std::wstring(), ROLE_SYSTEM_LISTITEM
,
432 list_item_checker
.SetExpectedState(STATE_SYSTEM_READONLY
);
433 AccessibleChecker
radio_group_checker(L
"ul", ROLE_SYSTEM_GROUPING
,
434 IA2_ROLE_SECTION
, std::wstring());
435 radio_group_checker
.SetExpectedState(STATE_SYSTEM_FOCUSABLE
);
436 AccessibleChecker
document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT
,
438 list_item_checker
.AppendExpectedChild(&list_marker_checker
);
439 list_item_checker
.AppendExpectedChild(&static_text_checker
);
440 radio_group_checker
.AppendExpectedChild(&list_item_checker
);
441 document_checker
.AppendExpectedChild(&radio_group_checker
);
442 document_checker
.CheckAccessible(GetRendererAccessible());
444 // Set focus to the radio group.
445 scoped_ptr
<AccessibilityNotificationWaiter
> waiter(
446 new AccessibilityNotificationWaiter(
447 shell(), AccessibilityModeComplete
,
448 ui::AX_EVENT_FOCUS
));
449 ExecuteScript(L
"document.body.children[0].focus()");
450 waiter
->WaitForNotification();
452 // Check that the accessibility tree of the browser has been updated.
453 radio_group_checker
.SetExpectedState(
454 STATE_SYSTEM_FOCUSABLE
| STATE_SYSTEM_FOCUSED
);
455 document_checker
.CheckAccessible(GetRendererAccessible());
457 // Set the active descendant of the radio group
458 waiter
.reset(new AccessibilityNotificationWaiter(
459 shell(), AccessibilityModeComplete
,
460 ui::AX_EVENT_FOCUS
));
462 L
"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
463 waiter
->WaitForNotification();
465 // Check that the accessibility tree of the browser has been updated.
466 list_item_checker
.SetExpectedState(
467 STATE_SYSTEM_READONLY
| STATE_SYSTEM_FOCUSED
);
468 radio_group_checker
.SetExpectedState(STATE_SYSTEM_FOCUSABLE
);
469 document_checker
.CheckAccessible(GetRendererAccessible());
472 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
473 TestNotificationCheckedStateChanged
) {
474 LoadInitialAccessibilityTreeFromHtml(
475 "<body><input type='checkbox' /></body>");
477 // Check the browser's copy of the renderer accessibility tree.
478 AccessibleChecker
checkbox_checker(std::wstring(), ROLE_SYSTEM_CHECKBUTTON
,
480 checkbox_checker
.SetExpectedState(STATE_SYSTEM_FOCUSABLE
);
481 AccessibleChecker
body_checker(std::wstring(), L
"body", IA2_ROLE_SECTION
,
483 AccessibleChecker
document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT
,
485 body_checker
.AppendExpectedChild(&checkbox_checker
);
486 document_checker
.AppendExpectedChild(&body_checker
);
487 document_checker
.CheckAccessible(GetRendererAccessible());
489 // Check the checkbox.
490 scoped_ptr
<AccessibilityNotificationWaiter
> waiter(
491 new AccessibilityNotificationWaiter(
492 shell(), AccessibilityModeComplete
,
493 ui::AX_EVENT_CHECKED_STATE_CHANGED
));
494 ExecuteScript(L
"document.body.children[0].checked=true");
495 waiter
->WaitForNotification();
497 // Check that the accessibility tree of the browser has been updated.
498 checkbox_checker
.SetExpectedState(
499 STATE_SYSTEM_CHECKED
| STATE_SYSTEM_FOCUSABLE
);
500 document_checker
.CheckAccessible(GetRendererAccessible());
503 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
504 TestNotificationChildrenChanged
) {
505 // The role attribute causes the node to be in the accessibility tree.
506 LoadInitialAccessibilityTreeFromHtml("<body role=group></body>");
508 // Check the browser's copy of the renderer accessibility tree.
509 AccessibleChecker
group_checker(std::wstring(), ROLE_SYSTEM_GROUPING
,
511 AccessibleChecker
document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT
,
513 document_checker
.AppendExpectedChild(&group_checker
);
514 document_checker
.CheckAccessible(GetRendererAccessible());
516 // Change the children of the document body.
517 scoped_ptr
<AccessibilityNotificationWaiter
> waiter(
518 new AccessibilityNotificationWaiter(
520 AccessibilityModeComplete
,
521 ui::AX_EVENT_CHILDREN_CHANGED
));
522 ExecuteScript(L
"document.body.innerHTML='<b>new text</b>'");
523 waiter
->WaitForNotification();
525 // Check that the accessibility tree of the browser has been updated.
526 AccessibleChecker
text_checker(
527 L
"new text", ROLE_SYSTEM_STATICTEXT
, std::wstring());
528 group_checker
.AppendExpectedChild(&text_checker
);
529 document_checker
.CheckAccessible(GetRendererAccessible());
532 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
533 TestNotificationChildrenChanged2
) {
534 // The role attribute causes the node to be in the accessibility tree.
535 LoadInitialAccessibilityTreeFromHtml(
536 "<div role=group style='visibility: hidden'>text</div>");
538 // Check the accessible tree of the browser.
539 AccessibleChecker
document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT
,
541 document_checker
.CheckAccessible(GetRendererAccessible());
543 // Change the children of the document body.
544 scoped_ptr
<AccessibilityNotificationWaiter
> waiter(
545 new AccessibilityNotificationWaiter(
546 shell(), AccessibilityModeComplete
,
547 ui::AX_EVENT_CHILDREN_CHANGED
));
548 ExecuteScript(L
"document.body.children[0].style.visibility='visible'");
549 waiter
->WaitForNotification();
551 // Check that the accessibility tree of the browser has been updated.
552 AccessibleChecker
static_text_checker(L
"text", ROLE_SYSTEM_STATICTEXT
,
554 AccessibleChecker
group_checker(std::wstring(), ROLE_SYSTEM_GROUPING
,
556 document_checker
.AppendExpectedChild(&group_checker
);
557 group_checker
.AppendExpectedChild(&static_text_checker
);
558 document_checker
.CheckAccessible(GetRendererAccessible());
561 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
562 TestNotificationFocusChanged
) {
563 // The role attribute causes the node to be in the accessibility tree.
564 LoadInitialAccessibilityTreeFromHtml("<div role=group tabindex='-1'></div>");
566 // Check the browser's copy of the renderer accessibility tree.
567 SCOPED_TRACE("Check initial tree");
568 AccessibleChecker
group_checker(std::wstring(), ROLE_SYSTEM_GROUPING
,
570 group_checker
.SetExpectedState(STATE_SYSTEM_FOCUSABLE
);
571 AccessibleChecker
document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT
,
573 document_checker
.AppendExpectedChild(&group_checker
);
574 document_checker
.CheckAccessible(GetRendererAccessible());
576 // Focus the div in the document
577 scoped_ptr
<AccessibilityNotificationWaiter
> waiter(
578 new AccessibilityNotificationWaiter(
579 shell(), AccessibilityModeComplete
,
580 ui::AX_EVENT_FOCUS
));
581 ExecuteScript(L
"document.body.children[0].focus()");
582 waiter
->WaitForNotification();
584 // Check that the accessibility tree of the browser has been updated.
585 SCOPED_TRACE("Check updated tree after focusing div");
586 group_checker
.SetExpectedState(
587 STATE_SYSTEM_FOCUSABLE
| STATE_SYSTEM_FOCUSED
);
588 document_checker
.CheckAccessible(GetRendererAccessible());
590 // Focus the document accessible. This will un-focus the current node.
592 new AccessibilityNotificationWaiter(
593 shell(), AccessibilityModeComplete
,
595 base::win::ScopedComPtr
<IAccessible
> document_accessible(
596 GetRendererAccessible());
597 ASSERT_NE(document_accessible
.get(), reinterpret_cast<IAccessible
*>(NULL
));
598 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
599 HRESULT hr
= document_accessible
->accSelect(SELFLAG_TAKEFOCUS
, childid_self
);
601 waiter
->WaitForNotification();
603 // Check that the accessibility tree of the browser has been updated.
604 SCOPED_TRACE("Check updated tree after focusing document again");
605 group_checker
.SetExpectedState(STATE_SYSTEM_FOCUSABLE
);
606 document_checker
.CheckAccessible(GetRendererAccessible());
609 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
610 TestNotificationValueChanged
) {
611 LoadInitialAccessibilityTreeFromHtml(
612 "<body><input type='text' value='old value'/></body>");
614 // Check the browser's copy of the renderer accessibility tree.
615 AccessibleChecker
text_field_checker(std::wstring(), ROLE_SYSTEM_TEXT
,
617 text_field_checker
.SetExpectedState(STATE_SYSTEM_FOCUSABLE
);
618 AccessibleChecker
body_checker(std::wstring(), L
"body", IA2_ROLE_SECTION
,
620 AccessibleChecker
document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT
,
622 body_checker
.AppendExpectedChild(&text_field_checker
);
623 document_checker
.AppendExpectedChild(&body_checker
);
624 document_checker
.CheckAccessible(GetRendererAccessible());
626 // Set the value of the text control
627 scoped_ptr
<AccessibilityNotificationWaiter
> waiter(
628 new AccessibilityNotificationWaiter(
629 shell(), AccessibilityModeComplete
,
630 ui::AX_EVENT_VALUE_CHANGED
));
631 ExecuteScript(L
"document.body.children[0].value='new value'");
632 waiter
->WaitForNotification();
634 // Check that the accessibility tree of the browser has been updated.
635 text_field_checker
.SetExpectedValue(L
"new value");
636 document_checker
.CheckAccessible(GetRendererAccessible());
639 // This test verifies that the web content's accessibility tree is a
640 // descendant of the main browser window's accessibility tree, so that
641 // tools like AccExplorer32 or AccProbe can be used to examine Chrome's
642 // accessibility support.
644 // If you made a change and this test now fails, check that the NativeViewHost
645 // that wraps the tab contents returns the IAccessible implementation
646 // provided by RenderWidgetHostViewWin in GetNativeViewAccessible().
647 // flaky: http://crbug.com/402190
648 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
649 DISABLED_ContainsRendererAccessibilityTree
) {
650 LoadInitialAccessibilityTreeFromHtml(
651 "<html><head><title>MyDocument</title></head>"
652 "<body>Content</body></html>");
654 // Get the accessibility object for the window tree host.
655 aura::Window
* window
= shell()->window();
657 aura::WindowTreeHost
* window_tree_host
= window
->GetHost();
658 CHECK(window_tree_host
);
659 HWND hwnd
= window_tree_host
->GetAcceleratedWidget();
661 base::win::ScopedComPtr
<IAccessible
> browser_accessible
;
662 HRESULT hr
= AccessibleObjectFromWindow(
666 reinterpret_cast<void**>(browser_accessible
.Receive()));
670 RecursiveFindNodeInAccessibilityTree(
671 browser_accessible
.get(), ROLE_SYSTEM_DOCUMENT
, L
"MyDocument", 0, &found
);
672 ASSERT_EQ(found
, true);
675 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
,
676 SupportsISimpleDOM
) {
677 LoadInitialAccessibilityTreeFromHtml(
678 "<body><input type='checkbox' /></body>");
680 // Get the IAccessible object for the document.
681 base::win::ScopedComPtr
<IAccessible
> document_accessible(
682 GetRendererAccessible());
683 ASSERT_NE(document_accessible
.get(), reinterpret_cast<IAccessible
*>(NULL
));
685 // Get the ISimpleDOM object for the document.
686 base::win::ScopedComPtr
<IServiceProvider
> service_provider
;
687 HRESULT hr
= static_cast<IAccessible
*>(document_accessible
.get())
688 ->QueryInterface(service_provider
.Receive());
690 const GUID refguid
= {0x0c539790, 0x12e4, 0x11cf,
691 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
692 base::win::ScopedComPtr
<ISimpleDOMNode
> document_isimpledomnode
;
693 hr
= static_cast<IServiceProvider
*>(service_provider
.get())
695 refguid
, IID_ISimpleDOMNode
,
696 reinterpret_cast<void**>(document_isimpledomnode
.Receive()));
699 base::win::ScopedBstr node_name
;
700 short name_space_id
; // NOLINT
701 base::win::ScopedBstr node_value
;
702 unsigned int num_children
;
703 unsigned int unique_id
;
704 unsigned short node_type
; // NOLINT
705 hr
= document_isimpledomnode
->get_nodeInfo(
706 node_name
.Receive(), &name_space_id
, node_value
.Receive(), &num_children
,
707 &unique_id
, &node_type
);
709 EXPECT_EQ(NODETYPE_DOCUMENT
, node_type
);
710 EXPECT_EQ(1, num_children
);
714 base::win::ScopedComPtr
<ISimpleDOMNode
> body_isimpledomnode
;
715 hr
= document_isimpledomnode
->get_firstChild(
716 body_isimpledomnode
.Receive());
718 hr
= body_isimpledomnode
->get_nodeInfo(
719 node_name
.Receive(), &name_space_id
, node_value
.Receive(), &num_children
,
720 &unique_id
, &node_type
);
722 EXPECT_EQ(L
"body", std::wstring(node_name
, node_name
.Length()));
723 EXPECT_EQ(NODETYPE_ELEMENT
, node_type
);
724 EXPECT_EQ(1, num_children
);
728 base::win::ScopedComPtr
<ISimpleDOMNode
> checkbox_isimpledomnode
;
729 hr
= body_isimpledomnode
->get_firstChild(
730 checkbox_isimpledomnode
.Receive());
732 hr
= checkbox_isimpledomnode
->get_nodeInfo(
733 node_name
.Receive(), &name_space_id
, node_value
.Receive(), &num_children
,
734 &unique_id
, &node_type
);
736 EXPECT_EQ(L
"input", std::wstring(node_name
, node_name
.Length()));
737 EXPECT_EQ(NODETYPE_ELEMENT
, node_type
);
738 EXPECT_EQ(0, num_children
);
741 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest
, TestRoleGroup
) {
742 LoadInitialAccessibilityTreeFromHtml(
743 "<fieldset></fieldset><div role=group></div>");
745 // Check the browser's copy of the renderer accessibility tree.
746 AccessibleChecker
grouping1_checker(std::wstring(), ROLE_SYSTEM_GROUPING
,
748 AccessibleChecker
grouping2_checker(std::wstring(), ROLE_SYSTEM_GROUPING
,
750 AccessibleChecker
document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT
,
752 document_checker
.AppendExpectedChild(&grouping1_checker
);
753 document_checker
.AppendExpectedChild(&grouping2_checker
);
754 document_checker
.CheckAccessible(GetRendererAccessible());
757 } // namespace content