Home | History | Annotate | Download | only in accessibility
      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 <string>
      6 #include <vector>
      7 
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "content/browser/renderer_host/render_view_host_impl.h"
     10 #include "content/public/browser/notification_service.h"
     11 #include "content/public/browser/notification_types.h"
     12 #include "content/public/browser/render_widget_host_view.h"
     13 #include "content/public/test/content_browser_test.h"
     14 #include "content/public/test/content_browser_test_utils.h"
     15 #include "content/shell/browser/shell.h"
     16 #include "content/test/accessibility_browser_test_utils.h"
     17 #include "ui/accessibility/ax_node.h"
     18 #include "ui/accessibility/ax_tree.h"
     19 
     20 #if defined(OS_WIN)
     21 #include <atlbase.h>
     22 #include <atlcom.h>
     23 #include "base/win/scoped_com_initializer.h"
     24 #include "ui/base/win/atl_module.h"
     25 #endif
     26 
     27 // TODO(dmazzoni): Disabled accessibility tests on Win64. crbug.com/179717
     28 #if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
     29 #define MAYBE_TableSpan DISABLED_TableSpan
     30 #else
     31 #define MAYBE_TableSpan TableSpan
     32 #endif
     33 
     34 namespace content {
     35 
     36 class CrossPlatformAccessibilityBrowserTest : public ContentBrowserTest {
     37  public:
     38   CrossPlatformAccessibilityBrowserTest() {}
     39 
     40   // Tell the renderer to send an accessibility tree, then wait for the
     41   // notification that it's been received.
     42   const ui::AXTree& GetAXTree(
     43       AccessibilityMode accessibility_mode = AccessibilityModeComplete) {
     44     AccessibilityNotificationWaiter waiter(
     45         shell(), accessibility_mode, ui::AX_EVENT_LAYOUT_COMPLETE);
     46     waiter.WaitForNotification();
     47     return waiter.GetAXTree();
     48   }
     49 
     50   // Make sure each node in the tree has an unique id.
     51   void RecursiveAssertUniqueIds(
     52       const ui::AXNode* node, base::hash_set<int>* ids) {
     53     ASSERT_TRUE(ids->find(node->id()) == ids->end());
     54     ids->insert(node->id());
     55     for (int i = 0; i < node->child_count(); i++)
     56       RecursiveAssertUniqueIds(node->ChildAtIndex(i), ids);
     57   }
     58 
     59   // ContentBrowserTest
     60   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
     61   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE;
     62 
     63  protected:
     64   std::string GetAttr(const ui::AXNode* node,
     65                       const ui::AXStringAttribute attr);
     66   int GetIntAttr(const ui::AXNode* node,
     67                  const ui::AXIntAttribute attr);
     68   bool GetBoolAttr(const ui::AXNode* node,
     69                    const ui::AXBoolAttribute attr);
     70 
     71  private:
     72 #if defined(OS_WIN)
     73   scoped_ptr<base::win::ScopedCOMInitializer> com_initializer_;
     74 #endif
     75 
     76   DISALLOW_COPY_AND_ASSIGN(CrossPlatformAccessibilityBrowserTest);
     77 };
     78 
     79 void CrossPlatformAccessibilityBrowserTest::SetUpInProcessBrowserTestFixture() {
     80 #if defined(OS_WIN)
     81   ui::win::CreateATLModuleIfNeeded();
     82   com_initializer_.reset(new base::win::ScopedCOMInitializer());
     83 #endif
     84 }
     85 
     86 void
     87 CrossPlatformAccessibilityBrowserTest::TearDownInProcessBrowserTestFixture() {
     88 #if defined(OS_WIN)
     89   com_initializer_.reset();
     90 #endif
     91 }
     92 
     93 // Convenience method to get the value of a particular AXNode
     94 // attribute as a UTF-8 string.
     95 std::string CrossPlatformAccessibilityBrowserTest::GetAttr(
     96     const ui::AXNode* node,
     97     const ui::AXStringAttribute attr) {
     98   const ui::AXNodeData& data = node->data();
     99   for (size_t i = 0; i < data.string_attributes.size(); ++i) {
    100     if (data.string_attributes[i].first == attr)
    101       return data.string_attributes[i].second;
    102   }
    103   return std::string();
    104 }
    105 
    106 // Convenience method to get the value of a particular AXNode
    107 // integer attribute.
    108 int CrossPlatformAccessibilityBrowserTest::GetIntAttr(
    109     const ui::AXNode* node,
    110     const ui::AXIntAttribute attr) {
    111   const ui::AXNodeData& data = node->data();
    112   for (size_t i = 0; i < data.int_attributes.size(); ++i) {
    113     if (data.int_attributes[i].first == attr)
    114       return data.int_attributes[i].second;
    115   }
    116   return -1;
    117 }
    118 
    119 // Convenience method to get the value of a particular AXNode
    120 // boolean attribute.
    121 bool CrossPlatformAccessibilityBrowserTest::GetBoolAttr(
    122     const ui::AXNode* node,
    123     const ui::AXBoolAttribute attr) {
    124   const ui::AXNodeData& data = node->data();
    125   for (size_t i = 0; i < data.bool_attributes.size(); ++i) {
    126     if (data.bool_attributes[i].first == attr)
    127       return data.bool_attributes[i].second;
    128   }
    129   return false;
    130 }
    131 
    132 // Marked flaky per http://crbug.com/101984
    133 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    134                        DISABLED_WebpageAccessibility) {
    135   // Create a data url and load it.
    136   const char url_str[] =
    137       "data:text/html,"
    138       "<!doctype html>"
    139       "<html><head><title>Accessibility Test</title></head>"
    140       "<body><input type='button' value='push' /><input type='checkbox' />"
    141       "</body></html>";
    142   GURL url(url_str);
    143   NavigateToURL(shell(), url);
    144   const ui::AXTree& tree = GetAXTree();
    145   const ui::AXNode* root = tree.GetRoot();
    146 
    147   // Check properties of the root element of the tree.
    148   EXPECT_STREQ(url_str,
    149                GetAttr(root, ui::AX_ATTR_DOC_URL).c_str());
    150   EXPECT_STREQ(
    151       "Accessibility Test",
    152       GetAttr(root, ui::AX_ATTR_DOC_TITLE).c_str());
    153   EXPECT_STREQ(
    154       "html", GetAttr(root, ui::AX_ATTR_DOC_DOCTYPE).c_str());
    155   EXPECT_STREQ(
    156       "text/html",
    157       GetAttr(root, ui::AX_ATTR_DOC_MIMETYPE).c_str());
    158   EXPECT_STREQ(
    159       "Accessibility Test",
    160       GetAttr(root, ui::AX_ATTR_NAME).c_str());
    161   EXPECT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, root->data().role);
    162 
    163   // Check properites of the BODY element.
    164   ASSERT_EQ(1, root->child_count());
    165   const ui::AXNode* body = root->ChildAtIndex(0);
    166   EXPECT_EQ(ui::AX_ROLE_GROUP, body->data().role);
    167   EXPECT_STREQ("body",
    168                GetAttr(body, ui::AX_ATTR_HTML_TAG).c_str());
    169   EXPECT_STREQ("block",
    170                GetAttr(body, ui::AX_ATTR_DISPLAY).c_str());
    171 
    172   // Check properties of the two children of the BODY element.
    173   ASSERT_EQ(2, body->child_count());
    174 
    175   const ui::AXNode* button = body->ChildAtIndex(0);
    176   EXPECT_EQ(ui::AX_ROLE_BUTTON, button->data().role);
    177   EXPECT_STREQ(
    178       "input", GetAttr(button, ui::AX_ATTR_HTML_TAG).c_str());
    179   EXPECT_STREQ(
    180       "push",
    181       GetAttr(button, ui::AX_ATTR_NAME).c_str());
    182   EXPECT_STREQ(
    183       "inline-block",
    184       GetAttr(button, ui::AX_ATTR_DISPLAY).c_str());
    185   ASSERT_EQ(2U, button->data().html_attributes.size());
    186   EXPECT_STREQ("type", button->data().html_attributes[0].first.c_str());
    187   EXPECT_STREQ("button", button->data().html_attributes[0].second.c_str());
    188   EXPECT_STREQ("value", button->data().html_attributes[1].first.c_str());
    189   EXPECT_STREQ("push", button->data().html_attributes[1].second.c_str());
    190 
    191   const ui::AXNode* checkbox = body->ChildAtIndex(1);
    192   EXPECT_EQ(ui::AX_ROLE_CHECK_BOX, checkbox->data().role);
    193   EXPECT_STREQ(
    194       "input", GetAttr(checkbox, ui::AX_ATTR_HTML_TAG).c_str());
    195   EXPECT_STREQ(
    196       "inline-block",
    197       GetAttr(checkbox, ui::AX_ATTR_DISPLAY).c_str());
    198   ASSERT_EQ(1U, checkbox->data().html_attributes.size());
    199   EXPECT_STREQ("type", checkbox->data().html_attributes[0].first.c_str());
    200   EXPECT_STREQ("checkbox", checkbox->data().html_attributes[0].second.c_str());
    201 }
    202 
    203 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    204                        UnselectedEditableTextAccessibility) {
    205   // Create a data url and load it.
    206   const char url_str[] =
    207       "data:text/html,"
    208       "<!doctype html>"
    209       "<body>"
    210       "<input value=\"Hello, world.\"/>"
    211       "</body></html>";
    212   GURL url(url_str);
    213   NavigateToURL(shell(), url);
    214 
    215   const ui::AXTree& tree = GetAXTree();
    216   const ui::AXNode* root = tree.GetRoot();
    217   ASSERT_EQ(1, root->child_count());
    218   const ui::AXNode* body = root->ChildAtIndex(0);
    219   ASSERT_EQ(1, body->child_count());
    220   const ui::AXNode* text = body->ChildAtIndex(0);
    221   EXPECT_EQ(ui::AX_ROLE_TEXT_FIELD, text->data().role);
    222   EXPECT_STREQ(
    223       "input", GetAttr(text, ui::AX_ATTR_HTML_TAG).c_str());
    224   EXPECT_EQ(0, GetIntAttr(text, ui::AX_ATTR_TEXT_SEL_START));
    225   EXPECT_EQ(0, GetIntAttr(text, ui::AX_ATTR_TEXT_SEL_END));
    226   EXPECT_STREQ(
    227       "Hello, world.",
    228       GetAttr(text, ui::AX_ATTR_VALUE).c_str());
    229 
    230   // TODO(dmazzoni): as soon as more accessibility code is cross-platform,
    231   // this code should test that the accessible info is dynamically updated
    232   // if the selection or value changes.
    233 }
    234 
    235 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    236                        SelectedEditableTextAccessibility) {
    237   // Create a data url and load it.
    238   const char url_str[] =
    239       "data:text/html,"
    240       "<!doctype html>"
    241       "<body onload=\"document.body.children[0].select();\">"
    242       "<input value=\"Hello, world.\"/>"
    243       "</body></html>";
    244   GURL url(url_str);
    245   NavigateToURL(shell(), url);
    246 
    247   const ui::AXTree& tree = GetAXTree();
    248   const ui::AXNode* root = tree.GetRoot();
    249   ASSERT_EQ(1, root->child_count());
    250   const ui::AXNode* body = root->ChildAtIndex(0);
    251   ASSERT_EQ(1, body->child_count());
    252   const ui::AXNode* text = body->ChildAtIndex(0);
    253   EXPECT_EQ(ui::AX_ROLE_TEXT_FIELD, text->data().role);
    254   EXPECT_STREQ(
    255       "input", GetAttr(text, ui::AX_ATTR_HTML_TAG).c_str());
    256   EXPECT_EQ(0, GetIntAttr(text, ui::AX_ATTR_TEXT_SEL_START));
    257   EXPECT_EQ(13, GetIntAttr(text, ui::AX_ATTR_TEXT_SEL_END));
    258   EXPECT_STREQ(
    259       "Hello, world.",
    260       GetAttr(text, ui::AX_ATTR_VALUE).c_str());
    261 }
    262 
    263 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    264                        MultipleInheritanceAccessibility) {
    265   // In a WebKit accessibility render tree for a table, each cell is a
    266   // child of both a row and a column, so it appears to use multiple
    267   // inheritance. Make sure that the ui::AXNodeDataObject tree only
    268   // keeps one copy of each cell, and uses an indirect child id for the
    269   // additional reference to it.
    270   const char url_str[] =
    271       "data:text/html,"
    272       "<!doctype html>"
    273       "<table border=1><tr><td>1</td><td>2</td></tr></table>";
    274   GURL url(url_str);
    275   NavigateToURL(shell(), url);
    276 
    277   const ui::AXTree& tree = GetAXTree();
    278   const ui::AXNode* root = tree.GetRoot();
    279   ASSERT_EQ(1, root->child_count());
    280   const ui::AXNode* table = root->ChildAtIndex(0);
    281   EXPECT_EQ(ui::AX_ROLE_TABLE, table->data().role);
    282   const ui::AXNode* row = table->ChildAtIndex(0);
    283   EXPECT_EQ(ui::AX_ROLE_ROW, row->data().role);
    284   const ui::AXNode* cell1 = row->ChildAtIndex(0);
    285   EXPECT_EQ(ui::AX_ROLE_CELL, cell1->data().role);
    286   const ui::AXNode* cell2 = row->ChildAtIndex(1);
    287   EXPECT_EQ(ui::AX_ROLE_CELL, cell2->data().role);
    288   const ui::AXNode* column1 = table->ChildAtIndex(1);
    289   EXPECT_EQ(ui::AX_ROLE_COLUMN, column1->data().role);
    290   EXPECT_EQ(0, column1->child_count());
    291   EXPECT_EQ(1U, column1->data().intlist_attributes.size());
    292   EXPECT_EQ(ui::AX_ATTR_INDIRECT_CHILD_IDS,
    293             column1->data().intlist_attributes[0].first);
    294   const std::vector<int32> column1_indirect_child_ids =
    295       column1->data().intlist_attributes[0].second;
    296   EXPECT_EQ(1U, column1_indirect_child_ids.size());
    297   EXPECT_EQ(cell1->id(), column1_indirect_child_ids[0]);
    298   const ui::AXNode* column2 = table->ChildAtIndex(2);
    299   EXPECT_EQ(ui::AX_ROLE_COLUMN, column2->data().role);
    300   EXPECT_EQ(0, column2->child_count());
    301   EXPECT_EQ(ui::AX_ATTR_INDIRECT_CHILD_IDS,
    302             column2->data().intlist_attributes[0].first);
    303   const std::vector<int32> column2_indirect_child_ids =
    304       column2->data().intlist_attributes[0].second;
    305   EXPECT_EQ(1U, column2_indirect_child_ids.size());
    306   EXPECT_EQ(cell2->id(), column2_indirect_child_ids[0]);
    307 }
    308 
    309 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    310                        MultipleInheritanceAccessibility2) {
    311   // Here's another html snippet where WebKit puts the same node as a child
    312   // of two different parents. Instead of checking the exact output, just
    313   // make sure that no id is reused in the resulting tree.
    314   const char url_str[] =
    315       "data:text/html,"
    316       "<!doctype html>"
    317       "<script>\n"
    318       "  document.writeln('<q><section></section></q><q><li>');\n"
    319       "  setTimeout(function() {\n"
    320       "    document.close();\n"
    321       "  }, 1);\n"
    322       "</script>";
    323   GURL url(url_str);
    324   NavigateToURL(shell(), url);
    325 
    326   const ui::AXTree& tree = GetAXTree();
    327   const ui::AXNode* root = tree.GetRoot();
    328   base::hash_set<int> ids;
    329   RecursiveAssertUniqueIds(root, &ids);
    330 }
    331 
    332 // TODO(dmazzoni): Needs to be rebaselined. http://crbug.com/347464
    333 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    334                        DISABLED_IframeAccessibility) {
    335   // Create a data url and load it.
    336   const char url_str[] =
    337       "data:text/html,"
    338       "<!doctype html><html><body>"
    339       "<button>Button 1</button>"
    340       "<iframe src='data:text/html,"
    341       "<!doctype html><html><body><button>Button 2</button></body></html>"
    342       "'></iframe>"
    343       "<button>Button 3</button>"
    344       "</body></html>";
    345   GURL url(url_str);
    346   NavigateToURL(shell(), url);
    347 
    348   const ui::AXTree& tree = GetAXTree();
    349   const ui::AXNode* root = tree.GetRoot();
    350   ASSERT_EQ(1, root->child_count());
    351   const ui::AXNode* body = root->ChildAtIndex(0);
    352   ASSERT_EQ(3, body->child_count());
    353 
    354   const ui::AXNode* button1 = body->ChildAtIndex(0);
    355   EXPECT_EQ(ui::AX_ROLE_BUTTON, button1->data().role);
    356   EXPECT_STREQ(
    357       "Button 1",
    358       GetAttr(button1, ui::AX_ATTR_NAME).c_str());
    359 
    360   const ui::AXNode* iframe = body->ChildAtIndex(1);
    361   EXPECT_STREQ("iframe",
    362                GetAttr(iframe, ui::AX_ATTR_HTML_TAG).c_str());
    363   ASSERT_EQ(1, iframe->child_count());
    364 
    365   const ui::AXNode* scroll_area = iframe->ChildAtIndex(0);
    366   EXPECT_EQ(ui::AX_ROLE_SCROLL_AREA, scroll_area->data().role);
    367   ASSERT_EQ(1, scroll_area->child_count());
    368 
    369   const ui::AXNode* sub_document = scroll_area->ChildAtIndex(0);
    370   EXPECT_EQ(ui::AX_ROLE_WEB_AREA, sub_document->data().role);
    371   ASSERT_EQ(1, sub_document->child_count());
    372 
    373   const ui::AXNode* sub_body = sub_document->ChildAtIndex(0);
    374   ASSERT_EQ(1, sub_body->child_count());
    375 
    376   const ui::AXNode* button2 = sub_body->ChildAtIndex(0);
    377   EXPECT_EQ(ui::AX_ROLE_BUTTON, button2->data().role);
    378   EXPECT_STREQ("Button 2",
    379                GetAttr(button2, ui::AX_ATTR_NAME).c_str());
    380 
    381   const ui::AXNode* button3 = body->ChildAtIndex(2);
    382   EXPECT_EQ(ui::AX_ROLE_BUTTON, button3->data().role);
    383   EXPECT_STREQ("Button 3",
    384                GetAttr(button3, ui::AX_ATTR_NAME).c_str());
    385 }
    386 
    387 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    388                        DuplicateChildrenAccessibility) {
    389   // Here's another html snippet where WebKit has a parent node containing
    390   // two duplicate child nodes. Instead of checking the exact output, just
    391   // make sure that no id is reused in the resulting tree.
    392   const char url_str[] =
    393       "data:text/html,"
    394       "<!doctype html>"
    395       "<em><code ><h4 ></em>";
    396   GURL url(url_str);
    397   NavigateToURL(shell(), url);
    398 
    399   const ui::AXTree& tree = GetAXTree();
    400   const ui::AXNode* root = tree.GetRoot();
    401   base::hash_set<int> ids;
    402   RecursiveAssertUniqueIds(root, &ids);
    403 }
    404 
    405 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    406                        MAYBE_TableSpan) {
    407   // +---+---+---+
    408   // |   1   | 2 |
    409   // +---+---+---+
    410   // | 3 |   4   |
    411   // +---+---+---+
    412 
    413   const char url_str[] =
    414       "data:text/html,"
    415       "<!doctype html>"
    416       "<table border=1>"
    417       " <tr>"
    418       "  <td colspan=2>1</td><td>2</td>"
    419       " </tr>"
    420       " <tr>"
    421       "  <td>3</td><td colspan=2>4</td>"
    422       " </tr>"
    423       "</table>";
    424   GURL url(url_str);
    425   NavigateToURL(shell(), url);
    426 
    427   const ui::AXTree& tree = GetAXTree();
    428   const ui::AXNode* root = tree.GetRoot();
    429   const ui::AXNode* table = root->ChildAtIndex(0);
    430   EXPECT_EQ(ui::AX_ROLE_TABLE, table->data().role);
    431   ASSERT_GE(table->child_count(), 5);
    432   EXPECT_EQ(ui::AX_ROLE_ROW, table->ChildAtIndex(0)->data().role);
    433   EXPECT_EQ(ui::AX_ROLE_ROW, table->ChildAtIndex(1)->data().role);
    434   EXPECT_EQ(ui::AX_ROLE_COLUMN, table->ChildAtIndex(2)->data().role);
    435   EXPECT_EQ(ui::AX_ROLE_COLUMN, table->ChildAtIndex(3)->data().role);
    436   EXPECT_EQ(ui::AX_ROLE_COLUMN, table->ChildAtIndex(4)->data().role);
    437   EXPECT_EQ(3,
    438             GetIntAttr(table, ui::AX_ATTR_TABLE_COLUMN_COUNT));
    439   EXPECT_EQ(2, GetIntAttr(table, ui::AX_ATTR_TABLE_ROW_COUNT));
    440 
    441   const ui::AXNode* cell1 = table->ChildAtIndex(0)->ChildAtIndex(0);
    442   const ui::AXNode* cell2 = table->ChildAtIndex(0)->ChildAtIndex(1);
    443   const ui::AXNode* cell3 = table->ChildAtIndex(1)->ChildAtIndex(0);
    444   const ui::AXNode* cell4 = table->ChildAtIndex(1)->ChildAtIndex(1);
    445 
    446   ASSERT_EQ(ui::AX_ATTR_CELL_IDS,
    447             table->data().intlist_attributes[0].first);
    448   const std::vector<int32>& table_cell_ids =
    449       table->data().intlist_attributes[0].second;
    450   ASSERT_EQ(6U, table_cell_ids.size());
    451   EXPECT_EQ(cell1->id(), table_cell_ids[0]);
    452   EXPECT_EQ(cell1->id(), table_cell_ids[1]);
    453   EXPECT_EQ(cell2->id(), table_cell_ids[2]);
    454   EXPECT_EQ(cell3->id(), table_cell_ids[3]);
    455   EXPECT_EQ(cell4->id(), table_cell_ids[4]);
    456   EXPECT_EQ(cell4->id(), table_cell_ids[5]);
    457 
    458   EXPECT_EQ(0, GetIntAttr(cell1,
    459                           ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX));
    460   EXPECT_EQ(0, GetIntAttr(cell1,
    461                           ui::AX_ATTR_TABLE_CELL_ROW_INDEX));
    462   EXPECT_EQ(2, GetIntAttr(cell1,
    463                           ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN));
    464   EXPECT_EQ(1, GetIntAttr(cell1,
    465                           ui::AX_ATTR_TABLE_CELL_ROW_SPAN));
    466   EXPECT_EQ(2, GetIntAttr(cell2,
    467                           ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX));
    468   EXPECT_EQ(1, GetIntAttr(cell2,
    469                           ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN));
    470   EXPECT_EQ(0, GetIntAttr(cell3,
    471                           ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX));
    472   EXPECT_EQ(1, GetIntAttr(cell3,
    473                           ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN));
    474   EXPECT_EQ(1, GetIntAttr(cell4,
    475                           ui::AX_ATTR_TABLE_CELL_COLUMN_INDEX));
    476   EXPECT_EQ(2, GetIntAttr(cell4,
    477                           ui::AX_ATTR_TABLE_CELL_COLUMN_SPAN));
    478 }
    479 
    480 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
    481                        WritableElement) {
    482   const char url_str[] =
    483       "data:text/html,"
    484       "<!doctype html>"
    485       "<div role='textbox' tabindex=0>"
    486       " Some text"
    487       "</div>";
    488   GURL url(url_str);
    489   NavigateToURL(shell(), url);
    490   const ui::AXTree& tree = GetAXTree();
    491   const ui::AXNode* root = tree.GetRoot();
    492   ASSERT_EQ(1, root->child_count());
    493   const ui::AXNode* textbox = root->ChildAtIndex(0);
    494   EXPECT_EQ(true, GetBoolAttr(textbox, ui::AX_ATTR_CAN_SET_VALUE));
    495 }
    496 
    497 }  // namespace content
    498