- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / accessibility / accessibility_win_browsertest.cc
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.
4
5 #include <vector>
6
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"
26
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
33
34 namespace content {
35
36 namespace {
37
38
39 // Helpers --------------------------------------------------------------------
40
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;
51     }
52
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;
60     }
61   }
62   return ptr;
63 }
64
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;
72 }
73
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());
89
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), WideToUTF8(name).c_str());
95
96   if (expected_role == V_I4(&role) && expected_name == name) {
97     *found = true;
98     return;
99   }
100
101   LONG child_count = 0;
102   HRESULT hr = node->get_accChildCount(&child_count);
103   ASSERT_EQ(S_OK, hr);
104
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);
111
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;
121     }
122   }
123 }
124
125
126 // AccessibilityWinBrowserTest ------------------------------------------------
127
128 class AccessibilityWinBrowserTest : public ContentBrowserTest {
129  public:
130   AccessibilityWinBrowserTest();
131   virtual ~AccessibilityWinBrowserTest();
132
133  protected:
134   void LoadInitialAccessibilityTreeFromHtml(const std::string& html);
135   IAccessible* GetRendererAccessible();
136   void ExecuteScript(const std::wstring& script);
137
138  private:
139   DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest);
140 };
141
142 AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
143 }
144
145 AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {
146 }
147
148 void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
149     const std::string& html) {
150   AccessibilityNotificationWaiter waiter(
151       shell(), AccessibilityModeComplete,
152       WebKit::WebAXEventLoadComplete);
153   GURL html_data_url("data:text/html," + html);
154   NavigateToURL(shell(), html_data_url);
155   waiter.WaitForNotification();
156 }
157
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();
163
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);
169
170   IAccessible* accessible;
171   HRESULT hr = AccessibleObjectFromWindow(
172       hwnd_render_widget_host_view, OBJID_CLIENT,
173       IID_IAccessible, reinterpret_cast<void**>(&accessible));
174
175   EXPECT_EQ(S_OK, hr);
176   EXPECT_NE(accessible, reinterpret_cast<IAccessible*>(NULL));
177
178   return accessible;
179 }
180
181 void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) {
182   shell()->web_contents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
183       std::wstring(), script);
184 }
185
186
187 // AccessibleChecker ----------------------------------------------------------
188
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);
204
205   // Append an AccessibleChecker that verifies accessibility information for
206   // a child IAccessible. Order is important.
207   void AppendExpectedChild(AccessibleChecker* expected_child);
208
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);
213
214   // Set the expected value for this AccessibleChecker.
215   void SetExpectedValue(const std::wstring& expected_value);
216
217   // Set the expected state for this AccessibleChecker.
218   void SetExpectedState(LONG expected_state);
219
220  private:
221   typedef std::vector<AccessibleChecker*> AccessibleCheckerVector;
222
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   string16 RoleVariantToString(const base::win::ScopedVariant& role);
230
231   // Expected accessible name. Checked against IAccessible::get_accName.
232   std::wstring name_;
233
234   // Expected accessible role. Checked against IAccessible::get_accRole.
235   base::win::ScopedVariant role_;
236
237   // Expected IAccessible2 role. Checked against IAccessible2::role.
238   int32 ia2_role_;
239
240   // Expected accessible value. Checked against IAccessible::get_accValue.
241   std::wstring value_;
242
243   // Expected accessible state. Checked against IAccessible::get_accState.
244   LONG state_;
245
246   // Expected accessible children. Checked using IAccessible::get_accChildCount
247   // and ::AccessibleChildren.
248   AccessibleCheckerVector children_;
249 };
250
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) {
259 }
260
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) {
270 }
271
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) {
281 }
282
283 void AccessibleChecker::AppendExpectedChild(
284     AccessibleChecker* expected_child) {
285   children_.push_back(expected_child);
286 }
287
288 void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
289   SCOPED_TRACE("while checking " + UTF16ToUTF8(RoleVariantToString(role_)));
290   CheckAccessibleName(accessible);
291   CheckAccessibleRole(accessible);
292   CheckIA2Role(accessible);
293   CheckAccessibleValue(accessible);
294   CheckAccessibleState(accessible);
295   CheckAccessibleChildren(accessible);
296 }
297
298 void AccessibleChecker::SetExpectedValue(const std::wstring& expected_value) {
299   value_ = expected_value;
300 }
301
302 void AccessibleChecker::SetExpectedState(LONG expected_state) {
303   state_ = expected_state;
304 }
305
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());
310
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()));
318   }
319 }
320
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);
329 }
330
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);
341 }
342
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;
353
354   // Get the value.
355   base::win::ScopedBstr value;
356   hr = accessible->get_accValue(childid_self, value.Receive());
357   EXPECT_EQ(S_OK, hr);
358
359   // Test that the correct string was returned.
360   EXPECT_EQ(value_, std::wstring(value, value.Length()));
361 }
362
363 void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
364   if (state_ < 0)
365     return;
366
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);
380 }
381
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());
387
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);
394
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);
403   }
404 }
405
406 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 string16(V_BSTR(&role), SysStringLen(V_BSTR(&role)));
412   return string16();
413 }
414
415 }  // namespace
416
417
418 // Tests ----------------------------------------------------------------------
419
420 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
421                        MAYBE(TestBusyAccessibilityTree)) {
422   NavigateToURL(shell(), GURL(kAboutBlankURL));
423
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());
432 }
433
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>");
441
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());
455
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));
464
465   // Navigate to another page.
466   NavigateToURL(shell(), GURL(kAboutBlankURL));
467
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);
475 }
476
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>");
483
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());
502
503   // Set focus to the radio group.
504   scoped_ptr<AccessibilityNotificationWaiter> waiter(
505       new AccessibilityNotificationWaiter(
506           shell(), AccessibilityModeComplete,
507           WebKit::WebAXEventFocus));
508   ExecuteScript(L"document.body.children[0].focus()");
509   waiter->WaitForNotification();
510
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());
515
516   // Set the active descendant of the radio group
517   waiter.reset(new AccessibilityNotificationWaiter(
518       shell(), AccessibilityModeComplete,
519       WebKit::WebAXEventFocus));
520   ExecuteScript(
521       L"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
522   waiter->WaitForNotification();
523
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());
529 }
530
531 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
532                        MAYBE(TestNotificationCheckedStateChanged)) {
533   LoadInitialAccessibilityTreeFromHtml(
534       "<body><input type='checkbox' /></body>");
535
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());
547
548   // Check the checkbox.
549   scoped_ptr<AccessibilityNotificationWaiter> waiter(
550       new AccessibilityNotificationWaiter(
551           shell(), AccessibilityModeComplete,
552           WebKit::WebAXEventCheckedStateChanged));
553   ExecuteScript(L"document.body.children[0].checked=true");
554   waiter->WaitForNotification();
555
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());
560 }
561
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>");
566
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());
574
575   // Change the children of the document body.
576   scoped_ptr<AccessibilityNotificationWaiter> waiter(
577       new AccessibilityNotificationWaiter(
578           shell(),
579           AccessibilityModeComplete,
580           WebKit::WebAXEventChildrenChanged));
581   ExecuteScript(L"document.body.innerHTML='<b>new text</b>'");
582   waiter->WaitForNotification();
583
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());
588 }
589
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>");
595
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());
600
601   // Change the children of the document body.
602   scoped_ptr<AccessibilityNotificationWaiter> waiter(
603       new AccessibilityNotificationWaiter(
604           shell(), AccessibilityModeComplete,
605           WebKit::WebAXEventChildrenChanged));
606   ExecuteScript(L"document.body.children[0].style.visibility='visible'");
607   waiter->WaitForNotification();
608
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());
617 }
618
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>");
623
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());
633
634   // Focus the div in the document
635   scoped_ptr<AccessibilityNotificationWaiter> waiter(
636       new AccessibilityNotificationWaiter(
637           shell(), AccessibilityModeComplete,
638           WebKit::WebAXEventFocus));
639   ExecuteScript(L"document.body.children[0].focus()");
640   waiter->WaitForNotification();
641
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());
647
648   // Focus the document accessible. This will un-focus the current node.
649   waiter.reset(
650       new AccessibilityNotificationWaiter(
651           shell(), AccessibilityModeComplete,
652           WebKit::WebAXEventBlur));
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();
660
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());
665 }
666
667 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
668                        MAYBE(TestNotificationValueChanged)) {
669   LoadInitialAccessibilityTreeFromHtml(
670       "<body><input type='text' value='old value'/></body>");
671
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());
683
684   // Set the value of the text control
685   scoped_ptr<AccessibilityNotificationWaiter> waiter(
686       new AccessibilityNotificationWaiter(
687           shell(), AccessibilityModeComplete,
688           WebKit::WebAXEventValueChanged));
689   ExecuteScript(L"document.body.children[0].value='new value'");
690   waiter->WaitForNotification();
691
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());
695 }
696
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.
701 //
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>");
710
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);
720
721   bool found = false;
722   RecursiveFindNodeInAccessibilityTree(
723       browser_accessible.get(), ROLE_SYSTEM_DOCUMENT, L"MyDocument", 0, &found);
724   ASSERT_EQ(found, true);
725 }
726
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);
737
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)
745
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
797
798   LoadInitialAccessibilityTreeFromHtml(button_html);
799   document_checker.CheckAccessible(GetRendererAccessible());
800 }
801
802 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
803                        MAYBE(SupportsISimpleDOM)) {
804   LoadInitialAccessibilityTreeFromHtml(
805       "<body><input type='checkbox' /></body>");
806
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));
811
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);
824
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();
839
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();
853
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);
865 }
866
867 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, MAYBE(TestRoleGroup)) {
868   LoadInitialAccessibilityTreeFromHtml(
869       "<fieldset></fieldset><div role=group></div>");
870
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());
881 }
882
883 }  // namespace content