IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / browser / accessibility / accessibility_win_browsertest.cc
blob10e5bd6d74b54b47a641f8fe2f1247a711c3ffe3
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_view_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/shell/browser/shell.h"
21 #include "content/test/accessibility_browser_test_utils.h"
22 #include "content/test/content_browser_test.h"
23 #include "content/test/content_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()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
183 std::wstring(), script);
187 // AccessibleChecker ----------------------------------------------------------
189 class AccessibleChecker {
190 public:
191 // This constructor can be used if the IA2 role will be the same as the MSAA
192 // role.
193 AccessibleChecker(const std::wstring& expected_name,
194 int32 expected_role,
195 const std::wstring& expected_value);
196 AccessibleChecker(const std::wstring& expected_name,
197 int32 expected_role,
198 int32 expected_ia2_role,
199 const std::wstring& expected_value);
200 AccessibleChecker(const std::wstring& expected_name,
201 const std::wstring& expected_role,
202 int32 expected_ia2_role,
203 const std::wstring& expected_value);
205 // Append an AccessibleChecker that verifies accessibility information for
206 // a child IAccessible. Order is important.
207 void AppendExpectedChild(AccessibleChecker* expected_child);
209 // Check that the name and role of the given IAccessible instance and its
210 // descendants match the expected names and roles that this object was
211 // initialized with.
212 void CheckAccessible(IAccessible* accessible);
214 // Set the expected value for this AccessibleChecker.
215 void SetExpectedValue(const std::wstring& expected_value);
217 // Set the expected state for this AccessibleChecker.
218 void SetExpectedState(LONG expected_state);
220 private:
221 typedef std::vector<AccessibleChecker*> AccessibleCheckerVector;
223 void CheckAccessibleName(IAccessible* accessible);
224 void CheckAccessibleRole(IAccessible* accessible);
225 void CheckIA2Role(IAccessible* accessible);
226 void CheckAccessibleValue(IAccessible* accessible);
227 void CheckAccessibleState(IAccessible* accessible);
228 void CheckAccessibleChildren(IAccessible* accessible);
229 base::string16 RoleVariantToString(const base::win::ScopedVariant& role);
231 // Expected accessible name. Checked against IAccessible::get_accName.
232 std::wstring name_;
234 // Expected accessible role. Checked against IAccessible::get_accRole.
235 base::win::ScopedVariant role_;
237 // Expected IAccessible2 role. Checked against IAccessible2::role.
238 int32 ia2_role_;
240 // Expected accessible value. Checked against IAccessible::get_accValue.
241 std::wstring value_;
243 // Expected accessible state. Checked against IAccessible::get_accState.
244 LONG state_;
246 // Expected accessible children. Checked using IAccessible::get_accChildCount
247 // and ::AccessibleChildren.
248 AccessibleCheckerVector children_;
251 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
252 int32 expected_role,
253 const std::wstring& expected_value)
254 : name_(expected_name),
255 role_(expected_role),
256 ia2_role_(expected_role),
257 value_(expected_value),
258 state_(-1) {
261 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
262 int32 expected_role,
263 int32 expected_ia2_role,
264 const std::wstring& expected_value)
265 : name_(expected_name),
266 role_(expected_role),
267 ia2_role_(expected_ia2_role),
268 value_(expected_value),
269 state_(-1) {
272 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
273 const std::wstring& expected_role,
274 int32 expected_ia2_role,
275 const std::wstring& expected_value)
276 : name_(expected_name),
277 role_(expected_role.c_str()),
278 ia2_role_(expected_ia2_role),
279 value_(expected_value),
280 state_(-1) {
283 void AccessibleChecker::AppendExpectedChild(
284 AccessibleChecker* expected_child) {
285 children_.push_back(expected_child);
288 void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
289 SCOPED_TRACE("while checking " +
290 base::UTF16ToUTF8(RoleVariantToString(role_)));
291 CheckAccessibleName(accessible);
292 CheckAccessibleRole(accessible);
293 CheckIA2Role(accessible);
294 CheckAccessibleValue(accessible);
295 CheckAccessibleState(accessible);
296 CheckAccessibleChildren(accessible);
299 void AccessibleChecker::SetExpectedValue(const std::wstring& expected_value) {
300 value_ = expected_value;
303 void AccessibleChecker::SetExpectedState(LONG expected_state) {
304 state_ = expected_state;
307 void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
308 base::win::ScopedBstr name;
309 base::win::ScopedVariant childid_self(CHILDID_SELF);
310 HRESULT hr = accessible->get_accName(childid_self, name.Receive());
312 if (name_.empty()) {
313 // If the object doesn't have name S_FALSE should be returned.
314 EXPECT_EQ(S_FALSE, hr);
315 } else {
316 // Test that the correct string was returned.
317 EXPECT_EQ(S_OK, hr);
318 EXPECT_EQ(name_, std::wstring(name, name.Length()));
322 void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) {
323 base::win::ScopedVariant role;
324 base::win::ScopedVariant childid_self(CHILDID_SELF);
325 HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
326 ASSERT_EQ(S_OK, hr);
327 EXPECT_EQ(0, role_.Compare(role))
328 << "Expected role: " << RoleVariantToString(role_)
329 << "\nGot role: " << RoleVariantToString(role);
332 void AccessibleChecker::CheckIA2Role(IAccessible* accessible) {
333 base::win::ScopedComPtr<IAccessible2> accessible2;
334 HRESULT hr = QueryIAccessible2(accessible, accessible2.Receive());
335 ASSERT_EQ(S_OK, hr);
336 long ia2_role = 0;
337 hr = accessible2->role(&ia2_role);
338 ASSERT_EQ(S_OK, hr);
339 EXPECT_EQ(ia2_role_, ia2_role)
340 << "Expected ia2 role: " << IAccessible2RoleToString(ia2_role_)
341 << "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role);
344 void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
345 // Don't check the value if if's a DOCUMENT role, because the value
346 // is supposed to be the url (and we don't keep track of that in the
347 // test expectations).
348 base::win::ScopedVariant role;
349 base::win::ScopedVariant childid_self(CHILDID_SELF);
350 HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
351 ASSERT_EQ(S_OK, hr);
352 if (role.type() == VT_I4 && V_I4(&role) == ROLE_SYSTEM_DOCUMENT)
353 return;
355 // Get the value.
356 base::win::ScopedBstr value;
357 hr = accessible->get_accValue(childid_self, value.Receive());
358 EXPECT_EQ(S_OK, hr);
360 // Test that the correct string was returned.
361 EXPECT_EQ(value_, std::wstring(value, value.Length()));
364 void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
365 if (state_ < 0)
366 return;
368 base::win::ScopedVariant state;
369 base::win::ScopedVariant childid_self(CHILDID_SELF);
370 HRESULT hr = accessible->get_accState(childid_self, state.Receive());
371 EXPECT_EQ(S_OK, hr);
372 ASSERT_EQ(VT_I4, state.type());
373 LONG obj_state = V_I4(&state);
374 // Avoid flakiness. The "offscreen" state depends on whether the browser
375 // window is frontmost or not, and "hottracked" depends on whether the
376 // mouse cursor happens to be over the element.
377 obj_state &= ~(STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_HOTTRACKED);
378 EXPECT_EQ(state_, obj_state)
379 << "Expected state: " << IAccessibleStateToString(state_)
380 << "\nGot state: " << IAccessibleStateToString(obj_state);
383 void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
384 LONG child_count = 0;
385 HRESULT hr = parent->get_accChildCount(&child_count);
386 EXPECT_EQ(S_OK, hr);
387 ASSERT_EQ(child_count, children_.size());
389 scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
390 LONG obtained_count = 0;
391 hr = AccessibleChildren(parent, 0, child_count,
392 child_array.get(), &obtained_count);
393 ASSERT_EQ(S_OK, hr);
394 ASSERT_EQ(child_count, obtained_count);
396 VARIANT* child = child_array.get();
397 for (AccessibleCheckerVector::iterator child_checker = children_.begin();
398 child_checker != children_.end();
399 ++child_checker, ++child) {
400 base::win::ScopedComPtr<IAccessible> child_accessible(
401 GetAccessibleFromResultVariant(parent, child));
402 ASSERT_TRUE(child_accessible.get());
403 (*child_checker)->CheckAccessible(child_accessible);
407 base::string16 AccessibleChecker::RoleVariantToString(
408 const base::win::ScopedVariant& role) {
409 if (role.type() == VT_I4)
410 return IAccessibleRoleToString(V_I4(&role));
411 if (role.type() == VT_BSTR)
412 return base::string16(V_BSTR(&role), SysStringLen(V_BSTR(&role)));
413 return base::string16();
416 } // namespace
419 // Tests ----------------------------------------------------------------------
421 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
422 MAYBE(TestBusyAccessibilityTree)) {
423 NavigateToURL(shell(), GURL(kAboutBlankURL));
425 // The initial accessible returned should have state STATE_SYSTEM_BUSY while
426 // the accessibility tree is being requested from the renderer.
427 AccessibleChecker document1_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
428 std::wstring());
429 document1_checker.SetExpectedState(
430 STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED |
431 STATE_SYSTEM_BUSY);
432 document1_checker.CheckAccessible(GetRendererAccessible());
435 // Flaky, http://crbug.com/167320 .
436 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
437 DISABLED_TestRendererAccessibilityTree) {
438 LoadInitialAccessibilityTreeFromHtml(
439 "<html><head><title>Accessibility Win Test</title></head>"
440 "<body><input type='button' value='push' /><input type='checkbox' />"
441 "</body></html>");
443 // Check the browser's copy of the renderer accessibility tree.
444 AccessibleChecker button_checker(L"push", ROLE_SYSTEM_PUSHBUTTON,
445 std::wstring());
446 AccessibleChecker checkbox_checker(std::wstring(), ROLE_SYSTEM_CHECKBUTTON,
447 std::wstring());
448 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
449 std::wstring());
450 AccessibleChecker document2_checker(L"Accessibility Win Test",
451 ROLE_SYSTEM_DOCUMENT, std::wstring());
452 body_checker.AppendExpectedChild(&button_checker);
453 body_checker.AppendExpectedChild(&checkbox_checker);
454 document2_checker.AppendExpectedChild(&body_checker);
455 document2_checker.CheckAccessible(GetRendererAccessible());
457 // Check that document accessible has a parent accessible.
458 base::win::ScopedComPtr<IAccessible> document_accessible(
459 GetRendererAccessible());
460 ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
461 base::win::ScopedComPtr<IDispatch> parent_dispatch;
462 HRESULT hr = document_accessible->get_accParent(parent_dispatch.Receive());
463 EXPECT_EQ(S_OK, hr);
464 EXPECT_NE(parent_dispatch, reinterpret_cast<IDispatch*>(NULL));
466 // Navigate to another page.
467 NavigateToURL(shell(), GURL(kAboutBlankURL));
469 // Verify that the IAccessible reference still points to a valid object and
470 // that calls to its methods fail since the tree is no longer valid after
471 // the page navagation.
472 base::win::ScopedBstr name;
473 base::win::ScopedVariant childid_self(CHILDID_SELF);
474 hr = document_accessible->get_accName(childid_self, name.Receive());
475 ASSERT_EQ(E_FAIL, hr);
478 // Periodically failing. See crbug.com/145537
479 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
480 DISABLED_TestNotificationActiveDescendantChanged) {
481 LoadInitialAccessibilityTreeFromHtml(
482 "<ul tabindex='-1' role='radiogroup' aria-label='ul'>"
483 "<li id='li'>li</li></ul>");
485 // Check the browser's copy of the renderer accessibility tree.
486 AccessibleChecker list_marker_checker(L"\x2022", ROLE_SYSTEM_TEXT,
487 std::wstring());
488 AccessibleChecker static_text_checker(L"li", ROLE_SYSTEM_TEXT,
489 std::wstring());
490 AccessibleChecker list_item_checker(std::wstring(), ROLE_SYSTEM_LISTITEM,
491 std::wstring());
492 list_item_checker.SetExpectedState(STATE_SYSTEM_READONLY);
493 AccessibleChecker radio_group_checker(L"ul", ROLE_SYSTEM_GROUPING,
494 IA2_ROLE_SECTION, std::wstring());
495 radio_group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
496 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
497 std::wstring());
498 list_item_checker.AppendExpectedChild(&list_marker_checker);
499 list_item_checker.AppendExpectedChild(&static_text_checker);
500 radio_group_checker.AppendExpectedChild(&list_item_checker);
501 document_checker.AppendExpectedChild(&radio_group_checker);
502 document_checker.CheckAccessible(GetRendererAccessible());
504 // Set focus to the radio group.
505 scoped_ptr<AccessibilityNotificationWaiter> waiter(
506 new AccessibilityNotificationWaiter(
507 shell(), AccessibilityModeComplete,
508 ui::AX_EVENT_FOCUS));
509 ExecuteScript(L"document.body.children[0].focus()");
510 waiter->WaitForNotification();
512 // Check that the accessibility tree of the browser has been updated.
513 radio_group_checker.SetExpectedState(
514 STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
515 document_checker.CheckAccessible(GetRendererAccessible());
517 // Set the active descendant of the radio group
518 waiter.reset(new AccessibilityNotificationWaiter(
519 shell(), AccessibilityModeComplete,
520 ui::AX_EVENT_FOCUS));
521 ExecuteScript(
522 L"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
523 waiter->WaitForNotification();
525 // Check that the accessibility tree of the browser has been updated.
526 list_item_checker.SetExpectedState(
527 STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
528 radio_group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
529 document_checker.CheckAccessible(GetRendererAccessible());
532 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
533 MAYBE(TestNotificationCheckedStateChanged)) {
534 LoadInitialAccessibilityTreeFromHtml(
535 "<body><input type='checkbox' /></body>");
537 // Check the browser's copy of the renderer accessibility tree.
538 AccessibleChecker checkbox_checker(std::wstring(), ROLE_SYSTEM_CHECKBUTTON,
539 std::wstring());
540 checkbox_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
541 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
542 std::wstring());
543 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
544 std::wstring());
545 body_checker.AppendExpectedChild(&checkbox_checker);
546 document_checker.AppendExpectedChild(&body_checker);
547 document_checker.CheckAccessible(GetRendererAccessible());
549 // Check the checkbox.
550 scoped_ptr<AccessibilityNotificationWaiter> waiter(
551 new AccessibilityNotificationWaiter(
552 shell(), AccessibilityModeComplete,
553 ui::AX_EVENT_CHECKED_STATE_CHANGED));
554 ExecuteScript(L"document.body.children[0].checked=true");
555 waiter->WaitForNotification();
557 // Check that the accessibility tree of the browser has been updated.
558 checkbox_checker.SetExpectedState(
559 STATE_SYSTEM_CHECKED | STATE_SYSTEM_FOCUSABLE);
560 document_checker.CheckAccessible(GetRendererAccessible());
563 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
564 MAYBE(TestNotificationChildrenChanged)) {
565 // The role attribute causes the node to be in the accessibility tree.
566 LoadInitialAccessibilityTreeFromHtml("<body role=group></body>");
568 // Check the browser's copy of the renderer accessibility tree.
569 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
570 std::wstring());
571 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
572 std::wstring());
573 document_checker.AppendExpectedChild(&group_checker);
574 document_checker.CheckAccessible(GetRendererAccessible());
576 // Change the children of the document body.
577 scoped_ptr<AccessibilityNotificationWaiter> waiter(
578 new AccessibilityNotificationWaiter(
579 shell(),
580 AccessibilityModeComplete,
581 ui::AX_EVENT_CHILDREN_CHANGED));
582 ExecuteScript(L"document.body.innerHTML='<b>new text</b>'");
583 waiter->WaitForNotification();
585 // Check that the accessibility tree of the browser has been updated.
586 AccessibleChecker text_checker(L"new text", ROLE_SYSTEM_TEXT, std::wstring());
587 group_checker.AppendExpectedChild(&text_checker);
588 document_checker.CheckAccessible(GetRendererAccessible());
591 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
592 MAYBE(TestNotificationChildrenChanged2)) {
593 // The role attribute causes the node to be in the accessibility tree.
594 LoadInitialAccessibilityTreeFromHtml(
595 "<div role=group style='visibility: hidden'>text</div>");
597 // Check the accessible tree of the browser.
598 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
599 std::wstring());
600 document_checker.CheckAccessible(GetRendererAccessible());
602 // Change the children of the document body.
603 scoped_ptr<AccessibilityNotificationWaiter> waiter(
604 new AccessibilityNotificationWaiter(
605 shell(), AccessibilityModeComplete,
606 ui::AX_EVENT_CHILDREN_CHANGED));
607 ExecuteScript(L"document.body.children[0].style.visibility='visible'");
608 waiter->WaitForNotification();
610 // Check that the accessibility tree of the browser has been updated.
611 AccessibleChecker static_text_checker(L"text", ROLE_SYSTEM_TEXT,
612 std::wstring());
613 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
614 std::wstring());
615 document_checker.AppendExpectedChild(&group_checker);
616 group_checker.AppendExpectedChild(&static_text_checker);
617 document_checker.CheckAccessible(GetRendererAccessible());
620 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
621 MAYBE(TestNotificationFocusChanged)) {
622 // The role attribute causes the node to be in the accessibility tree.
623 LoadInitialAccessibilityTreeFromHtml("<div role=group tabindex='-1'></div>");
625 // Check the browser's copy of the renderer accessibility tree.
626 SCOPED_TRACE("Check initial tree");
627 AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
628 std::wstring());
629 group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
630 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
631 std::wstring());
632 document_checker.AppendExpectedChild(&group_checker);
633 document_checker.CheckAccessible(GetRendererAccessible());
635 // Focus the div in the document
636 scoped_ptr<AccessibilityNotificationWaiter> waiter(
637 new AccessibilityNotificationWaiter(
638 shell(), AccessibilityModeComplete,
639 ui::AX_EVENT_FOCUS));
640 ExecuteScript(L"document.body.children[0].focus()");
641 waiter->WaitForNotification();
643 // Check that the accessibility tree of the browser has been updated.
644 SCOPED_TRACE("Check updated tree after focusing div");
645 group_checker.SetExpectedState(
646 STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
647 document_checker.CheckAccessible(GetRendererAccessible());
649 // Focus the document accessible. This will un-focus the current node.
650 waiter.reset(
651 new AccessibilityNotificationWaiter(
652 shell(), AccessibilityModeComplete,
653 ui::AX_EVENT_BLUR));
654 base::win::ScopedComPtr<IAccessible> document_accessible(
655 GetRendererAccessible());
656 ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
657 base::win::ScopedVariant childid_self(CHILDID_SELF);
658 HRESULT hr = document_accessible->accSelect(SELFLAG_TAKEFOCUS, childid_self);
659 ASSERT_EQ(S_OK, hr);
660 waiter->WaitForNotification();
662 // Check that the accessibility tree of the browser has been updated.
663 SCOPED_TRACE("Check updated tree after focusing document again");
664 group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
665 document_checker.CheckAccessible(GetRendererAccessible());
668 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
669 MAYBE(TestNotificationValueChanged)) {
670 LoadInitialAccessibilityTreeFromHtml(
671 "<body><input type='text' value='old value'/></body>");
673 // Check the browser's copy of the renderer accessibility tree.
674 AccessibleChecker text_field_checker(std::wstring(), ROLE_SYSTEM_TEXT,
675 L"old value");
676 text_field_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
677 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
678 std::wstring());
679 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
680 std::wstring());
681 body_checker.AppendExpectedChild(&text_field_checker);
682 document_checker.AppendExpectedChild(&body_checker);
683 document_checker.CheckAccessible(GetRendererAccessible());
685 // Set the value of the text control
686 scoped_ptr<AccessibilityNotificationWaiter> waiter(
687 new AccessibilityNotificationWaiter(
688 shell(), AccessibilityModeComplete,
689 ui::AX_EVENT_VALUE_CHANGE));
690 ExecuteScript(L"document.body.children[0].value='new value'");
691 waiter->WaitForNotification();
693 // Check that the accessibility tree of the browser has been updated.
694 text_field_checker.SetExpectedValue(L"new value");
695 document_checker.CheckAccessible(GetRendererAccessible());
698 // This test verifies that the web content's accessibility tree is a
699 // descendant of the main browser window's accessibility tree, so that
700 // tools like AccExplorer32 or AccProbe can be used to examine Chrome's
701 // accessibility support.
703 // If you made a change and this test now fails, check that the NativeViewHost
704 // that wraps the tab contents returns the IAccessible implementation
705 // provided by RenderWidgetHostViewWin in GetNativeViewAccessible().
706 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
707 MAYBE(ContainsRendererAccessibilityTree)) {
708 LoadInitialAccessibilityTreeFromHtml(
709 "<html><head><title>MyDocument</title></head>"
710 "<body>Content</body></html>");
712 // Get the accessibility object for the browser window.
713 HWND browser_hwnd = shell()->window();
714 base::win::ScopedComPtr<IAccessible> browser_accessible;
715 HRESULT hr = AccessibleObjectFromWindow(
716 browser_hwnd,
717 OBJID_WINDOW,
718 IID_IAccessible,
719 reinterpret_cast<void**>(browser_accessible.Receive()));
720 ASSERT_EQ(S_OK, hr);
722 bool found = false;
723 RecursiveFindNodeInAccessibilityTree(
724 browser_accessible.get(), ROLE_SYSTEM_DOCUMENT, L"MyDocument", 0, &found);
725 ASSERT_EQ(found, true);
728 // Disabled because of http://crbug.com/144390.
729 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
730 DISABLED_TestToggleButtonRoleAndStates) {
731 AccessibleChecker* button_checker;
732 std::string button_html("data:text/html,");
733 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
734 std::wstring());
735 AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
736 std::wstring());
737 document_checker.AppendExpectedChild(&body_checker);
739 // Temporary macro
740 #define ADD_BUTTON(html, ia2_role, state) \
741 button_html += html; \
742 button_checker = new AccessibleChecker(L"x", ROLE_SYSTEM_PUSHBUTTON, \
743 ia2_role, std::wstring()); \
744 button_checker->SetExpectedState(state); \
745 body_checker.AppendExpectedChild(button_checker)
747 // If aria-pressed is 'undefined', empty or not present, use PUSHBUTTON
748 // Otherwise use TOGGLE_BUTTON, even if the value is invalid.
749 // The spec does this in an attempt future-proof in case new values are added.
750 ADD_BUTTON("<span role='button' aria-pressed='false'>x</span>",
751 IA2_ROLE_TOGGLE_BUTTON, 0);
752 ADD_BUTTON("<span role='button' aria-pressed='true'>x</span>",
753 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_PRESSED);
754 ADD_BUTTON("<span role='button' aria-pressed='mixed'>x</span>",
755 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_MIXED);
756 ADD_BUTTON("<span role='button' aria-pressed='xyz'>x</span>",
757 IA2_ROLE_TOGGLE_BUTTON, 0);
758 ADD_BUTTON("<span role='button' aria-pressed=''>x</span>",
759 ROLE_SYSTEM_PUSHBUTTON, 0);
760 ADD_BUTTON("<span role='button' aria-pressed>x</span>",
761 ROLE_SYSTEM_PUSHBUTTON, 0);
762 ADD_BUTTON("<span role='button' aria-pressed='undefined'>x</span>",
763 ROLE_SYSTEM_PUSHBUTTON, 0);
764 ADD_BUTTON("<span role='button'>x</span>", ROLE_SYSTEM_PUSHBUTTON, 0);
765 ADD_BUTTON("<input type='button' aria-pressed='true' value='x'/>",
766 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_PRESSED);
767 ADD_BUTTON("<input type='button' aria-pressed='false' value='x'/>",
768 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
769 ADD_BUTTON("<input type='button' aria-pressed='mixed' value='x'>",
770 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_MIXED);
771 ADD_BUTTON("<input type='button' aria-pressed='xyz' value='x'/>",
772 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
773 ADD_BUTTON("<input type='button' aria-pressed='' value='x'/>",
774 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
775 ADD_BUTTON("<input type='button' aria-pressed value='x'>",
776 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
777 ADD_BUTTON("<input type='button' aria-pressed='undefined' value='x'>",
778 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
779 ADD_BUTTON("<input type='button' value='x'>",
780 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
781 ADD_BUTTON("<button aria-pressed='true'>x</button>",
782 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_PRESSED);
783 ADD_BUTTON("<button aria-pressed='false'>x</button>",
784 IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
785 ADD_BUTTON("<button aria-pressed='mixed'>x</button>", IA2_ROLE_TOGGLE_BUTTON,
786 STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_MIXED);
787 ADD_BUTTON("<button aria-pressed='xyz'>x</button>", IA2_ROLE_TOGGLE_BUTTON,
788 STATE_SYSTEM_FOCUSABLE);
789 ADD_BUTTON("<button aria-pressed=''>x</button>",
790 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
791 ADD_BUTTON("<button aria-pressed>x</button>",
792 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
793 ADD_BUTTON("<button aria-pressed='undefined'>x</button>",
794 ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
795 ADD_BUTTON("<button>x</button>", ROLE_SYSTEM_PUSHBUTTON,
796 STATE_SYSTEM_FOCUSABLE);
797 #undef ADD_BUTTON // Temporary macro
799 LoadInitialAccessibilityTreeFromHtml(button_html);
800 document_checker.CheckAccessible(GetRendererAccessible());
803 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
804 MAYBE(SupportsISimpleDOM)) {
805 LoadInitialAccessibilityTreeFromHtml(
806 "<body><input type='checkbox' /></body>");
808 // Get the IAccessible object for the document.
809 base::win::ScopedComPtr<IAccessible> document_accessible(
810 GetRendererAccessible());
811 ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
813 // Get the ISimpleDOM object for the document.
814 base::win::ScopedComPtr<IServiceProvider> service_provider;
815 HRESULT hr = static_cast<IAccessible*>(document_accessible)->QueryInterface(
816 service_provider.Receive());
817 ASSERT_EQ(S_OK, hr);
818 const GUID refguid = {0x0c539790, 0x12e4, 0x11cf,
819 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
820 base::win::ScopedComPtr<ISimpleDOMNode> document_isimpledomnode;
821 hr = static_cast<IServiceProvider *>(service_provider)->QueryService(
822 refguid, IID_ISimpleDOMNode,
823 reinterpret_cast<void**>(document_isimpledomnode.Receive()));
824 ASSERT_EQ(S_OK, hr);
826 base::win::ScopedBstr node_name;
827 short name_space_id; // NOLINT
828 base::win::ScopedBstr node_value;
829 unsigned int num_children;
830 unsigned int unique_id;
831 unsigned short node_type; // NOLINT
832 hr = document_isimpledomnode->get_nodeInfo(
833 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
834 &unique_id, &node_type);
835 ASSERT_EQ(S_OK, hr);
836 EXPECT_EQ(NODETYPE_DOCUMENT, node_type);
837 EXPECT_EQ(1, num_children);
838 node_name.Reset();
839 node_value.Reset();
841 base::win::ScopedComPtr<ISimpleDOMNode> body_isimpledomnode;
842 hr = document_isimpledomnode->get_firstChild(
843 body_isimpledomnode.Receive());
844 ASSERT_EQ(S_OK, hr);
845 hr = body_isimpledomnode->get_nodeInfo(
846 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
847 &unique_id, &node_type);
848 ASSERT_EQ(S_OK, hr);
849 EXPECT_EQ(L"body", std::wstring(node_name, node_name.Length()));
850 EXPECT_EQ(NODETYPE_ELEMENT, node_type);
851 EXPECT_EQ(1, num_children);
852 node_name.Reset();
853 node_value.Reset();
855 base::win::ScopedComPtr<ISimpleDOMNode> checkbox_isimpledomnode;
856 hr = body_isimpledomnode->get_firstChild(
857 checkbox_isimpledomnode.Receive());
858 ASSERT_EQ(S_OK, hr);
859 hr = checkbox_isimpledomnode->get_nodeInfo(
860 node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
861 &unique_id, &node_type);
862 ASSERT_EQ(S_OK, hr);
863 EXPECT_EQ(L"input", std::wstring(node_name, node_name.Length()));
864 EXPECT_EQ(NODETYPE_ELEMENT, node_type);
865 EXPECT_EQ(0, num_children);
868 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, MAYBE(TestRoleGroup)) {
869 LoadInitialAccessibilityTreeFromHtml(
870 "<fieldset></fieldset><div role=group></div>");
872 // Check the browser's copy of the renderer accessibility tree.
873 AccessibleChecker grouping1_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
874 std::wstring());
875 AccessibleChecker grouping2_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
876 std::wstring());
877 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
878 std::wstring());
879 document_checker.AppendExpectedChild(&grouping1_checker);
880 document_checker.AppendExpectedChild(&grouping2_checker);
881 document_checker.CheckAccessible(GetRendererAccessible());
884 } // namespace content