1 // Copyright 2015 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 "base/strings/stringprintf.h"
6 #include "chrome/browser/chrome_notification_types.h"
7 #include "chrome/browser/ui/browser_window.h"
8 #include "chrome/browser/ui/chrome_pages.h"
9 #include "chrome/browser/ui/tabs/tab_strip_model.h"
10 #include "chrome/common/url_constants.h"
11 #include "chrome/test/base/in_process_browser_test.h"
12 #include "chrome/test/base/interactive_test_utils.h"
13 #include "content/public/test/browser_test_utils.h"
17 // This class tests the language dictionary settings.
18 // This test is part of the interactive_ui_tests instead of browser_tests
19 // because it is necessary to emulate pushing the tab key.
20 class LanguageDictionaryWebUITest
: public InProcessBrowserTest
{
22 LanguageDictionaryWebUITest() {}
24 // Navigate to the editDictionary page.
25 void SetUpOnMainThread() override
{
26 const GURL url
= chrome::GetSettingsUrl("editDictionary");
27 ui_test_utils::NavigateToURL(browser(), url
);
31 const std::string kDictionaryListSelector
=
32 "#language-dictionary-overlay-word-list";
34 content::RenderFrameHost
* GetActiveFrame() {
35 return GetActiveWebContents()->GetFocusedFrame();
38 content::RenderViewHost
* GetRenderViewHost() {
39 return GetActiveWebContents()->GetRenderViewHost();
42 content::WebContents
* GetActiveWebContents() {
43 return browser()->tab_strip_model()->GetActiveWebContents();
46 // Add a few test words to the dictionary.
47 void SetTestWords(const std::string
& list_selector
) {
48 const std::string script
= base::StringPrintf(
49 "document.querySelector('%s').setWordList(['cat', 'dog', 'bird']);",
50 list_selector
.c_str());
51 EXPECT_TRUE(content::ExecuteScript(GetActiveFrame(), script
));
52 // Expected list size is 4: 3 word items + 1 placeholder.
53 EXPECT_EQ(4, GetListSize(list_selector
));
56 // Returns the number of items in the list.
57 int GetListSize(const std::string
& list_selector
) {
58 const std::string script
= base::StringPrintf(
59 "domAutomationController.send("
60 "document.querySelector('%s').items.length);",
61 list_selector
.c_str());
63 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
70 // Returns true if element contains document.activeElement.
71 bool ContainsActiveElement(const std::string
& element_selector
) {
72 const std::string script
= base::StringPrintf(
73 "domAutomationController.send("
74 "document.querySelector('%s').contains(document.activeElement));",
75 element_selector
.c_str());
77 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
84 // Returns true if list item[|index|] contains document.activeElement.
85 bool ListItemContainsActiveElement(const std::string
& list_selector
,
88 // EXPECT_TRUE will fail if index is out of bounds.
89 const std::string script
= base::StringPrintf(
90 "domAutomationController.send("
91 "document.querySelector('%s').items[%d].contains("
92 "document.activeElement));",
93 list_selector
.c_str(),
96 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
103 // Returns true if list item[|index|] has 'selected' attribute.
104 bool ListItemSelected(const std::string
& list_selector
, int index
) {
106 // EXPECT_TRUE will fail if index is out of bounds.
107 const std::string script
= base::StringPrintf(
108 "domAutomationController.send("
109 "document.querySelector('%s').items[%d].hasAttribute('selected'));",
110 list_selector
.c_str(),
113 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
120 // Returns true if list item[|index|] has 'selected' attribute and contains
121 // document.activeElement.
122 bool ListItemSelectedAndFocused(const std::string
& list_selector
,
125 return ListItemSelected(list_selector
, index
) &&
126 ListItemContainsActiveElement(list_selector
, index
);
129 // Press and release a key in the browser. This will wait for the element on
130 // the page to change.
131 bool PressKey(ui::KeyboardCode key_code
, bool shift
) {
132 return ui_test_utils::SendKeyPressAndWait(
139 content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE
,
140 content::Source
<content::RenderViewHost
>(GetRenderViewHost()));
143 void InitializeDomMessageQueue() {
144 dom_message_queue_
.reset(new content::DOMMessageQueue
);
147 // Wait for a message from the DOM automation controller.
148 void WaitForDomMessage(const std::string
& message
) {
149 const std::string expected
= "\"" + message
+ "\"";
150 std::string received
;
152 ASSERT_TRUE(dom_message_queue_
->WaitForMessage(&received
));
153 } while (received
!= expected
);
156 // Add a JavaScript event listener to send a DOM automation controller message
157 // whenever the |selected| property of the list item changes.
158 void ListenForItemSelectedChange(const std::string
& list_selector
,
161 // EXPECT_TRUE will fail if index is out of bounds.
162 const std::string script
= base::StringPrintf(
163 "document.querySelector('%s').items[%d].addEventListener("
164 "'selectedChange', function() {"
165 "domAutomationController.setAutomationId(0);"
166 "domAutomationController.send('selected=' + this.selected);"
168 list_selector
.c_str(),
171 EXPECT_TRUE(content::ExecuteScript(
177 scoped_ptr
<content::DOMMessageQueue
> dom_message_queue_
;
179 DISALLOW_COPY_AND_ASSIGN(LanguageDictionaryWebUITest
);
184 // Test InlineEditableItemList keyboard focus behavior in editDictionary
186 // editDictionary overlay doesn't exist on OSX so disable it there.
187 #if !defined(OS_MACOSX)
189 // Crashes on Win 7. http://crbug.com/500609
191 #define MAYBE_TestListKeyboardFocus DISABLED_TestListKeyboardFocus
193 #define MAYBE_TestListKeyboardFocus TestListKeyboardFocus
196 IN_PROC_BROWSER_TEST_F(LanguageDictionaryWebUITest
,
197 MAYBE_TestListKeyboardFocus
) {
198 const std::string list_selector
= kDictionaryListSelector
;
200 // Populate the list with some test words.
201 SetTestWords(list_selector
);
202 int placeholder_index
= GetListSize(list_selector
) - 1;
204 // Listen for changes of the placeholder item's |selected| property so that
205 // test can wait until change has taken place after key press before
207 InitializeDomMessageQueue();
208 ListenForItemSelectedChange(list_selector
, placeholder_index
);
210 // Press tab to focus the placeholder.
211 PressKey(ui::VKEY_TAB
, false);
213 // Wait for placeholder item to become selected.
214 WaitForDomMessage("selected=true");
216 // Verify that the placeholder is selected and has focus.
217 EXPECT_TRUE(ListItemSelectedAndFocused(list_selector
, placeholder_index
));
219 // Press up arrow to select item above the placeholder.
220 PressKey(ui::VKEY_UP
, false);
222 // Wait for placeholder to become unselected.
223 WaitForDomMessage("selected=false");
225 // Verify that the placeholder is no longer selected.
226 EXPECT_FALSE(ListItemSelected(list_selector
, placeholder_index
));
228 // Verify that the item above the placeholder is selected and has focus.
229 EXPECT_TRUE(ListItemSelectedAndFocused(list_selector
,
230 placeholder_index
- 1));
232 // Press tab to leave the list.
233 PressKey(ui::VKEY_TAB
, false);
235 // Verify that focus has left the list.
236 EXPECT_FALSE(ContainsActiveElement(list_selector
));
238 // Verify that the item above the placeholder is still selected.
239 EXPECT_TRUE(ListItemSelected(list_selector
, placeholder_index
- 1));
241 // Press shift+tab to go back to the list.
242 PressKey(ui::VKEY_TAB
, true);
244 // Verify that the item above the placeholder is selected and has focus.
245 EXPECT_TRUE(ListItemSelectedAndFocused(list_selector
,
246 placeholder_index
- 1));
248 #endif // !defined(OS_MACOSX)