1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 package org.mozilla.gecko.tests.components;
6 
7 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
8 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertFalse;
9 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
10 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
11 
12 import org.mozilla.gecko.R;
13 import org.mozilla.gecko.tests.UITestContext;
14 import org.mozilla.gecko.tests.helpers.DeviceHelper;
15 import org.mozilla.gecko.tests.helpers.NavigationHelper;
16 import org.mozilla.gecko.tests.helpers.WaitHelper;
17 import org.mozilla.gecko.toolbar.PageActionLayout;
18 
19 import android.view.View;
20 import android.widget.EditText;
21 import android.widget.ImageButton;
22 import android.widget.TextView;
23 
24 import com.robotium.solo.Condition;
25 import com.robotium.solo.Solo;
26 
27 /**
28  * A class representing any interactions that take place on the Toolbar.
29  */
30 public class ToolbarComponent extends BaseComponent {
31 
32     private static final String URL_HTTP_PREFIX = "http://";
33 
34     // We are waiting up to 30 seconds instead of the default waiting time because reader mode
35     // parsing can take quite some time on slower devices (Bug 1142699)
36     private static final int READER_MODE_WAIT_MS = 30000;
37 
ToolbarComponent(final UITestContext testContext)38     public ToolbarComponent(final UITestContext testContext) {
39         super(testContext);
40     }
41 
assertIsEditing()42     public ToolbarComponent assertIsEditing() {
43         fAssertTrue("The toolbar is in the editing state", isEditing());
44         return this;
45     }
46 
assertIsNotEditing()47     public ToolbarComponent assertIsNotEditing() {
48         fAssertFalse("The toolbar is not in the editing state", isEditing());
49         return this;
50     }
51 
assertTitle(final String url)52     public ToolbarComponent assertTitle(final String url) {
53         fAssertNotNull("The url argument is not null", url);
54 
55         final String expected;
56         final String absoluteURL = NavigationHelper.adjustUrl(url);
57 
58         if (mStringHelper.ABOUT_HOME_URL.equals(absoluteURL)) {
59             expected = mStringHelper.ABOUT_HOME_TITLE;
60         } else if (absoluteURL.startsWith(URL_HTTP_PREFIX)) {
61             expected = absoluteURL.substring(URL_HTTP_PREFIX.length());
62         } else {
63             expected = absoluteURL;
64         }
65 
66         // Since we only display a shortened "base domain" (See bug 1236431) we use the content
67         // description to obtain the full URL.
68         fAssertEquals("The Toolbar title is " + expected, expected, getUrlFromContentDescription());
69         return this;
70     }
71 
assertUrl(final String expected)72     public ToolbarComponent assertUrl(final String expected) {
73         assertIsEditing();
74         fAssertEquals("The Toolbar url is " + expected, expected, getUrlEditText().getText());
75         return this;
76     }
77 
assertIsUrlEditTextSelected()78     public ToolbarComponent assertIsUrlEditTextSelected() {
79         fAssertTrue("The edit text is selected", isUrlEditTextSelected());
80         return this;
81     }
82 
assertIsUrlEditTextNotSelected()83     public ToolbarComponent assertIsUrlEditTextNotSelected() {
84         fAssertFalse("The edit text is not selected", isUrlEditTextSelected());
85         return this;
86     }
87 
assertBackButtonIsNotEnabled()88     public ToolbarComponent assertBackButtonIsNotEnabled() {
89         fAssertFalse("The back button is not enabled", isBackButtonEnabled());
90         return this;
91     }
92 
93     /**
94      * Returns the root View for the browser toolbar.
95      */
getToolbarView()96     private View getToolbarView() {
97         mSolo.waitForView(R.id.browser_toolbar);
98         return mSolo.getView(R.id.browser_toolbar);
99     }
100 
getUrlEditText()101     private EditText getUrlEditText() {
102         return (EditText) getToolbarView().findViewById(R.id.url_edit_text);
103     }
104 
getUrlDisplayLayout()105     private View getUrlDisplayLayout() {
106         return getToolbarView().findViewById(R.id.display_layout);
107     }
108 
getUrlTitleText()109     private TextView getUrlTitleText() {
110         return (TextView) getToolbarView().findViewById(R.id.url_bar_title);
111     }
112 
getBackButton()113     private ImageButton getBackButton() {
114         DeviceHelper.assertIsTablet();
115         return (ImageButton) getToolbarView().findViewById(R.id.back);
116     }
117 
getForwardButton()118     private ImageButton getForwardButton() {
119         DeviceHelper.assertIsTablet();
120         return (ImageButton) getToolbarView().findViewById(R.id.forward);
121     }
122 
getReloadButton()123     private ImageButton getReloadButton() {
124         DeviceHelper.assertIsTablet();
125         return (ImageButton) getToolbarView().findViewById(R.id.reload);
126     }
127 
getPageActionLayout()128     private PageActionLayout getPageActionLayout() {
129         return (PageActionLayout) getToolbarView().findViewById(R.id.page_action_layout);
130     }
131 
getReaderModeButton()132     private ImageButton getReaderModeButton() {
133         final PageActionLayout pageActionLayout = getPageActionLayout();
134         final int count = pageActionLayout.getChildCount();
135 
136         for (int i = 0; i < count; i++) {
137             final View view = pageActionLayout.getChildAt(i);
138             if (mStringHelper.CONTENT_DESCRIPTION_READER_MODE_BUTTON.equals(view.getContentDescription())) {
139                 return (ImageButton) view;
140             }
141         }
142 
143         return null;
144     }
145 
146     /**
147      * Returns the View for the edit cancel button in the browser toolbar.
148      */
getEditCancelButton()149     private View getEditCancelButton() {
150         return getToolbarView().findViewById(R.id.edit_cancel);
151     }
152 
getUrlFromContentDescription()153     private String getUrlFromContentDescription() {
154         assertIsNotEditing();
155 
156         final CharSequence contentDescription = getUrlDisplayLayout().getContentDescription();
157         if (contentDescription == null) {
158             return "";
159         } else {
160             return contentDescription.toString();
161         }
162     }
163 
164     /**
165      * Returns the title of the page. Note that this makes no assertions to Toolbar state and
166      * may return a value that may never be visible to the user. Callers likely want to use
167      * {@link assertTitle} instead.
168      */
getPotentiallyInconsistentTitle()169     public String getPotentiallyInconsistentTitle() {
170         return getTitleHelper(false);
171     }
172 
getTitleHelper(final boolean shouldAssertNotEditing)173     private String getTitleHelper(final boolean shouldAssertNotEditing) {
174         if (shouldAssertNotEditing) {
175             assertIsNotEditing();
176         }
177 
178         return getUrlTitleText().getText().toString();
179     }
180 
isEditing()181     private boolean isEditing() {
182         return getUrlDisplayLayout().getVisibility() != View.VISIBLE &&
183                 getUrlEditText().getVisibility() == View.VISIBLE;
184     }
185 
enterEditingMode()186     public ToolbarComponent enterEditingMode() {
187         assertIsNotEditing();
188 
189         mSolo.clickOnView(getUrlTitleText(), true);
190 
191         waitForEditing();
192         WaitHelper.waitFor("UrlEditText to be input method target", new Condition() {
193             @Override
194             public boolean isSatisfied() {
195                 return getUrlEditText().isInputMethodTarget();
196             }
197         });
198 
199         return this;
200     }
201 
commitEditingMode()202     public ToolbarComponent commitEditingMode() {
203         assertIsEditing();
204 
205         WaitHelper.waitForPageLoad(new Runnable() {
206             @Override
207             public void run() {
208                 mSolo.sendKey(Solo.ENTER);
209             }
210         });
211         waitForNotEditing();
212 
213         return this;
214     }
215 
dismissEditingMode()216     public ToolbarComponent dismissEditingMode() {
217         assertIsEditing();
218 
219         if (DeviceHelper.isTablet()) {
220             final EditText urlEditText = getUrlEditText();
221             if (urlEditText.isFocused()) {
222                 mSolo.goBack();
223             }
224             mSolo.goBack();
225         } else {
226             mSolo.clickOnView(getEditCancelButton());
227         }
228 
229         waitForNotEditing();
230 
231         return this;
232     }
233 
enterUrl(final String url)234     public ToolbarComponent enterUrl(final String url) {
235         fAssertNotNull("url is not null", url);
236 
237         assertIsEditing();
238 
239         final EditText urlEditText = getUrlEditText();
240         fAssertTrue("The UrlEditText is the input method target",
241                 urlEditText.isInputMethodTarget());
242 
243         mSolo.clearEditText(urlEditText);
244         mSolo.typeText(urlEditText, url);
245 
246         return this;
247     }
248 
pressBackButton()249     public ToolbarComponent pressBackButton() {
250         final ImageButton backButton = getBackButton();
251         return pressButton(backButton, "back");
252     }
253 
pressForwardButton()254     public ToolbarComponent pressForwardButton() {
255         final ImageButton forwardButton = getForwardButton();
256         return pressButton(forwardButton, "forward");
257     }
258 
pressReloadButton()259     public ToolbarComponent pressReloadButton() {
260         final ImageButton reloadButton = getReloadButton();
261         return pressButton(reloadButton, "reload");
262     }
263 
pressReaderModeButton()264     public ToolbarComponent pressReaderModeButton() {
265         final ImageButton readerModeButton = waitForReaderModeButton();
266         pressButton(readerModeButton, "reader mode");
267 
268         return this;
269     }
270 
pressButton(final View view, final String buttonName)271     private ToolbarComponent pressButton(final View view, final String buttonName) {
272         fAssertNotNull("The " + buttonName + " button View is not null", view);
273         fAssertTrue("The " + buttonName + " button is enabled", view.isEnabled());
274         fAssertEquals("The " + buttonName + " button is visible",
275                 View.VISIBLE, view.getVisibility());
276         assertIsNotEditing();
277 
278         WaitHelper.waitForPageLoad(new Runnable() {
279             @Override
280             public void run() {
281                 mSolo.clickOnView(view);
282             }
283         });
284 
285         return this;
286     }
287 
waitForEditing()288     private void waitForEditing() {
289         WaitHelper.waitFor("Toolbar to enter editing mode", new Condition() {
290             @Override
291             public boolean isSatisfied() {
292                 return isEditing();
293             }
294         });
295     }
296 
waitForNotEditing()297     private void waitForNotEditing() {
298         WaitHelper.waitFor("Toolbar to exit editing mode", new Condition() {
299             @Override
300             public boolean isSatisfied() {
301                 return !isEditing();
302             }
303         });
304     }
305 
waitForReaderModeButton()306     private ImageButton waitForReaderModeButton() {
307         final ImageButton[] readerModeButton = new ImageButton[1];
308 
309         WaitHelper.waitFor("the Reader mode button to be visible", new Condition() {
310             @Override
311             public boolean isSatisfied() {
312                 return (readerModeButton[0] = getReaderModeButton()) != null;
313             }
314         }, READER_MODE_WAIT_MS);
315 
316         return readerModeButton[0];
317     }
318 
isUrlEditTextSelected()319     private boolean isUrlEditTextSelected() {
320         return getUrlEditText().isSelected();
321     }
322 
isBackButtonEnabled()323     private boolean isBackButtonEnabled() {
324         return getBackButton().isEnabled();
325     }
326 }
327