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)
188 IN_PROC_BROWSER_TEST_F(LanguageDictionaryWebUITest
,
189 TestListKeyboardFocus
) {
190 const std::string list_selector
= kDictionaryListSelector
;
192 // Populate the list with some test words.
193 SetTestWords(list_selector
);
194 int placeholder_index
= GetListSize(list_selector
) - 1;
196 // Listen for changes of the placeholder item's |selected| property so that
197 // test can wait until change has taken place after key press before
199 InitializeDomMessageQueue();
200 ListenForItemSelectedChange(list_selector
, placeholder_index
);
202 // Press tab to focus the placeholder.
203 PressKey(ui::VKEY_TAB
, false);
205 // Wait for placeholder item to become selected.
206 WaitForDomMessage("selected=true");
208 // Verify that the placeholder is selected and has focus.
209 EXPECT_TRUE(ListItemSelectedAndFocused(list_selector
, placeholder_index
));
211 // Press up arrow to select item above the placeholder.
212 PressKey(ui::VKEY_UP
, false);
214 // Wait for placeholder to become unselected.
215 WaitForDomMessage("selected=false");
217 // Verify that the placeholder is no longer selected.
218 EXPECT_FALSE(ListItemSelected(list_selector
, placeholder_index
));
220 // Verify that the item above the placeholder is selected and has focus.
221 EXPECT_TRUE(ListItemSelectedAndFocused(list_selector
,
222 placeholder_index
- 1));
224 // Press tab to leave the list.
225 PressKey(ui::VKEY_TAB
, false);
227 // Verify that focus has left the list.
228 EXPECT_FALSE(ContainsActiveElement(list_selector
));
230 // Verify that the item above the placeholder is still selected.
231 EXPECT_TRUE(ListItemSelected(list_selector
, placeholder_index
- 1));
233 // Press shift+tab to go back to the list.
234 PressKey(ui::VKEY_TAB
, true);
236 // Verify that the item above the placeholder is selected and has focus.
237 EXPECT_TRUE(ListItemSelectedAndFocused(list_selector
,
238 placeholder_index
- 1));
240 #endif // !defined(OS_MACOSX)