OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 package org.chromium.chrome.test.util; |
| 6 |
| 7 import android.app.Instrumentation; |
| 8 import android.test.InstrumentationTestCase; |
| 9 import android.text.TextUtils; |
| 10 import android.util.Log; |
| 11 |
| 12 import com.google.android.apps.chrome.R; |
| 13 |
| 14 import junit.framework.Assert; |
| 15 |
| 16 import org.chromium.base.ThreadUtils; |
| 17 import org.chromium.chrome.browser.ChromeActivity; |
| 18 import org.chromium.chrome.browser.ChromeTabbedActivity; |
| 19 import org.chromium.chrome.browser.EmptyTabObserver; |
| 20 import org.chromium.chrome.browser.Tab; |
| 21 import org.chromium.chrome.browser.compositor.layouts.components.CompositorButto
n; |
| 22 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelper; |
| 23 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; |
| 24 import org.chromium.chrome.browser.tabmodel.TabModel; |
| 25 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
| 26 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; |
| 27 import org.chromium.chrome.browser.tabmodel.TabModelObserver; |
| 28 import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
| 29 import org.chromium.chrome.browser.tabmodel.TabModelUtils; |
| 30 import org.chromium.chrome.test.ChromeTabbedActivityTestBase; |
| 31 import org.chromium.content.browser.test.util.CallbackHelper; |
| 32 import org.chromium.ui.base.DeviceFormFactor; |
| 33 |
| 34 import java.util.concurrent.Callable; |
| 35 import java.util.concurrent.TimeUnit; |
| 36 import java.util.concurrent.TimeoutException; |
| 37 |
| 38 /** |
| 39 * A utility class that contains methods generic to all Tabs tests. |
| 40 */ |
| 41 public class ChromeTabUtils { |
| 42 private static final String TAG = "ChromeTabUtils"; |
| 43 |
| 44 /** |
| 45 * Waits for the given tab to finish loading it's current page. |
| 46 * |
| 47 * @param tab The tab to wait for the page loading to be complete. |
| 48 * @param url The URL that will be waited to load for. Pass in null if load
ing the |
| 49 * current page is sufficient. |
| 50 */ |
| 51 public static void waitForTabPageLoaded(final Tab tab, final String url) |
| 52 throws InterruptedException { |
| 53 Assert.assertFalse(ThreadUtils.runningOnUiThread()); |
| 54 |
| 55 final boolean checkUrl = url != null; |
| 56 |
| 57 final CallbackHelper loadedCallback = new CallbackHelper(); |
| 58 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 59 @Override |
| 60 public void run() { |
| 61 if (!tab.isLoading() |
| 62 && (!checkUrl || TextUtils.equals(tab.getUrl(), url)) |
| 63 && !tab.getWebContents().isLoadingToDifferentDocument())
{ |
| 64 loadedCallback.notifyCalled(); |
| 65 return; |
| 66 } |
| 67 |
| 68 tab.addObserver(new EmptyTabObserver() { |
| 69 @Override |
| 70 public void onPageLoadFinished(Tab tab) { |
| 71 if (!checkUrl || TextUtils.equals(tab.getUrl(), url)) { |
| 72 loadedCallback.notifyCalled(); |
| 73 tab.removeObserver(this); |
| 74 } |
| 75 } |
| 76 }); |
| 77 } |
| 78 }); |
| 79 |
| 80 try { |
| 81 loadedCallback.waitForCallback(0); |
| 82 } catch (TimeoutException e) { |
| 83 Assert.fail("Failed to load URL: " + url + ", final URL: " + tab.get
Url()); |
| 84 } |
| 85 } |
| 86 |
| 87 /** |
| 88 * Waits for the given tab to finish loading it's current page. |
| 89 * |
| 90 * @param tab The tab to wait for the page loading to be complete. |
| 91 * @param loadTrigger The trigger action that will result in a page load fin
ished event |
| 92 * to be fired (not run on the UI thread by default). |
| 93 */ |
| 94 public static void waitForTabPageLoaded(final Tab tab, Runnable loadTrigger) |
| 95 throws InterruptedException { |
| 96 waitForTabPageLoaded(tab, loadTrigger, CallbackHelper.WAIT_TIMEOUT_SECON
DS); |
| 97 } |
| 98 |
| 99 /** |
| 100 * Waits for the given tab to finish loading it's current page. |
| 101 * |
| 102 * @param tab The tab to wait for the page loading to be complete. |
| 103 * @param loadTrigger The trigger action that will result in a page load fin
ished event |
| 104 * to be fired (not run on the UI thread by default). |
| 105 * @param secondsToWait The number of seconds to wait for the page to be loa
ded. |
| 106 */ |
| 107 public static void waitForTabPageLoaded( |
| 108 final Tab tab, Runnable loadTrigger, long secondsToWait) |
| 109 throws InterruptedException { |
| 110 final CallbackHelper loadedCallback = new CallbackHelper(); |
| 111 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 112 @Override |
| 113 public void run() { |
| 114 tab.addObserver(new EmptyTabObserver() { |
| 115 @Override |
| 116 public void onPageLoadFinished(Tab tab) { |
| 117 loadedCallback.notifyCalled(); |
| 118 tab.removeObserver(this); |
| 119 } |
| 120 }); |
| 121 } |
| 122 }); |
| 123 loadTrigger.run(); |
| 124 try { |
| 125 loadedCallback.waitForCallback(0, 1, secondsToWait, TimeUnit.SECONDS
); |
| 126 } catch (TimeoutException e) { |
| 127 Assert.fail("Page did not load. Tab information at time of failure
--" |
| 128 + " url: " + tab.getUrl() |
| 129 + ", load progress: " + tab.getProgress() |
| 130 + ", is loading: " + Boolean.toString(tab.isLoading())); |
| 131 } |
| 132 } |
| 133 |
| 134 /** |
| 135 * Waits for the given tab to start loading it's current page. |
| 136 * |
| 137 * @param tab The tab to wait for the page loading to be started. |
| 138 * @param loadTrigger The trigger action that will result in a page load sta
rted event |
| 139 * to be fired (not run on the UI thread by default). |
| 140 * @param secondsToWait The number of seconds to wait for the page to be loa
d to be started. |
| 141 */ |
| 142 public static void waitForTabPageLoadStart( |
| 143 final Tab tab, Runnable loadTrigger, long secondsToWait) |
| 144 throws InterruptedException { |
| 145 final CallbackHelper startedCallback = new CallbackHelper(); |
| 146 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 147 @Override |
| 148 public void run() { |
| 149 tab.addObserver(new EmptyTabObserver() { |
| 150 @Override |
| 151 public void onPageLoadStarted(Tab tab) { |
| 152 startedCallback.notifyCalled(); |
| 153 tab.removeObserver(this); |
| 154 } |
| 155 }); |
| 156 } |
| 157 }); |
| 158 loadTrigger.run(); |
| 159 try { |
| 160 startedCallback.waitForCallback(0, 1, secondsToWait, TimeUnit.SECOND
S); |
| 161 } catch (TimeoutException e) { |
| 162 Assert.fail("Page did not start loading. Tab information at time of
failure --" |
| 163 + " url: " + tab.getUrl() |
| 164 + ", load progress: " + tab.getProgress() |
| 165 + ", is loading: " + Boolean.toString(tab.isLoading())); |
| 166 } |
| 167 } |
| 168 |
| 169 /** |
| 170 * Switch to the given TabIndex in the current tabModel. |
| 171 * @param tabIndex |
| 172 */ |
| 173 public static void switchTabInCurrentTabModel(final ChromeActivity activity, |
| 174 final int tabIndex) { |
| 175 ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
| 176 @Override |
| 177 public void run() { |
| 178 TabModelUtils.setIndex(activity.getCurrentTabModel(), tabIndex); |
| 179 } |
| 180 }); |
| 181 } |
| 182 |
| 183 /** |
| 184 * Simulates a click to the normal (not incognito) new tab button. |
| 185 * <p> |
| 186 * Does not wait for the tab to be loaded. |
| 187 */ |
| 188 public static void clickNewTabButton(InstrumentationTestCase test, |
| 189 ChromeTabbedActivityTestBase base) throws InterruptedException { |
| 190 final TabModel normalTabModel = base.getActivity().getTabModelSelector()
.getModel(false); |
| 191 final CallbackHelper createdCallback = new CallbackHelper(); |
| 192 normalTabModel.addObserver( |
| 193 new EmptyTabModelObserver() { |
| 194 @Override |
| 195 public void didAddTab(Tab tab, TabLaunchType type) { |
| 196 createdCallback.notifyCalled(); |
| 197 normalTabModel.removeObserver(this); |
| 198 } |
| 199 }); |
| 200 // Tablet and phone have different new tab buttons; click the right one. |
| 201 if (DeviceFormFactor.isTablet(base.getActivity())) { |
| 202 StripLayoutHelper strip = |
| 203 TabStripUtils.getStripLayoutHelper(base.getActivity(), false
/* incognito */); |
| 204 CompositorButton newTabButton = strip.getNewTabButton(); |
| 205 TabStripUtils.clickCompositorButton(newTabButton, base); |
| 206 test.getInstrumentation().waitForIdleSync(); |
| 207 } else { |
| 208 base.singleClickView(base.getActivity().findViewById(R.id.new_tab_bu
tton)); |
| 209 } |
| 210 |
| 211 try { |
| 212 createdCallback.waitForCallback(0); |
| 213 } catch (TimeoutException e) { |
| 214 Assert.fail("Never received tab creation event"); |
| 215 } |
| 216 } |
| 217 |
| 218 /** |
| 219 * New a tab by invoking the 'New Tab' menu item. |
| 220 * <p> |
| 221 * Returns when the tab has been created and has finished navigating. |
| 222 */ |
| 223 public static void newTabFromMenu(Instrumentation instrumentation, |
| 224 final ChromeTabbedActivity activity) |
| 225 throws InterruptedException { |
| 226 final CallbackHelper createdCallback = new CallbackHelper(); |
| 227 final CallbackHelper selectedCallback = new CallbackHelper(); |
| 228 |
| 229 TabModel tabModel = activity.getTabModelSelector().getModel(false); |
| 230 TabModelObserver observer = new EmptyTabModelObserver() { |
| 231 @Override |
| 232 public void didAddTab(Tab tab, TabLaunchType type) { |
| 233 createdCallback.notifyCalled(); |
| 234 } |
| 235 |
| 236 @Override |
| 237 public void didSelectTab(Tab tab, TabSelectionType type, int lastId)
{ |
| 238 selectedCallback.notifyCalled(); |
| 239 } |
| 240 }; |
| 241 tabModel.addObserver(observer); |
| 242 |
| 243 MenuUtils.invokeCustomMenuActionSync(instrumentation, activity, |
| 244 R.id.new_tab_menu_id); |
| 245 |
| 246 try { |
| 247 createdCallback.waitForCallback(0); |
| 248 } catch (TimeoutException ex) { |
| 249 Assert.fail("Never received tab created event"); |
| 250 } |
| 251 try { |
| 252 selectedCallback.waitForCallback(0); |
| 253 } catch (TimeoutException ex) { |
| 254 Assert.fail("Never received tab selected event"); |
| 255 } |
| 256 tabModel.removeObserver(observer); |
| 257 |
| 258 Tab tab = activity.getActivityTab(); |
| 259 waitForTabPageLoaded(tab, (String) null); |
| 260 Assert.assertTrue("NTP never fully loaded.", |
| 261 NewTabPageTestUtils.waitForNtpLoaded(tab)); |
| 262 instrumentation.waitForIdleSync(); |
| 263 Log.d(TAG, "newTabFromMenu <<"); |
| 264 } |
| 265 |
| 266 /** |
| 267 * New multiple tabs by invoking the 'new' menu item n times. |
| 268 * @param n The number of tabs you want to create. |
| 269 */ |
| 270 public static void newTabsFromMenu(Instrumentation instrumentation, |
| 271 ChromeTabbedActivity activity, int n) |
| 272 throws InterruptedException { |
| 273 while (n > 0) { |
| 274 newTabFromMenu(instrumentation, activity); |
| 275 --n; |
| 276 } |
| 277 } |
| 278 |
| 279 /** |
| 280 * Ensure that at least some given number of tabs are open. |
| 281 */ |
| 282 public static void ensureNumOpenTabs(Instrumentation instrumentation, |
| 283 ChromeTabbedActivity activity, int newCount) |
| 284 throws InterruptedException { |
| 285 int curCount = getNumOpenTabs(activity); |
| 286 if (curCount < newCount) { |
| 287 newTabsFromMenu(instrumentation, activity, newCount - curCount); |
| 288 } |
| 289 } |
| 290 |
| 291 /** |
| 292 * Fetch the number of tabs open in the current model. |
| 293 */ |
| 294 public static int getNumOpenTabs(final ChromeActivity activity) { |
| 295 return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer
>() { |
| 296 @Override |
| 297 public Integer call() throws Exception { |
| 298 return activity.getCurrentTabModel().getCount(); |
| 299 } |
| 300 }); |
| 301 } |
| 302 |
| 303 /** |
| 304 * Closes the current tab through TabModelSelector. |
| 305 * <p> |
| 306 * Returns after the tab has been closed. |
| 307 */ |
| 308 public static void closeCurrentTab(final Instrumentation instrumentation, |
| 309 final ChromeTabbedActivity activity) |
| 310 throws InterruptedException { |
| 311 closeTabWithAction(instrumentation, activity, new Runnable() { |
| 312 @Override |
| 313 public void run() { |
| 314 instrumentation.runOnMainSync(new Runnable() { |
| 315 @Override |
| 316 public void run() { |
| 317 TabModelUtils.closeCurrentTab(activity.getCurrentTabMode
l()); |
| 318 } |
| 319 }); |
| 320 } |
| 321 }); |
| 322 } |
| 323 |
| 324 /** |
| 325 * Closes a tab with the given action and waits for a tab closure to be obse
rved. |
| 326 */ |
| 327 public static void closeTabWithAction(Instrumentation instrumentation, |
| 328 final ChromeTabbedActivity activity, Runnable action) throws Interru
ptedException { |
| 329 final CallbackHelper closeCallback = new CallbackHelper(); |
| 330 final TabModelObserver observer = new EmptyTabModelObserver() { |
| 331 @Override |
| 332 public void willCloseTab(Tab tab, boolean animate) { |
| 333 closeCallback.notifyCalled(); |
| 334 } |
| 335 }; |
| 336 instrumentation.runOnMainSync(new Runnable() { |
| 337 @Override |
| 338 public void run() { |
| 339 TabModelSelector selector = activity.getTabModelSelector(); |
| 340 for (TabModel tabModel : selector.getModels()) { |
| 341 tabModel.addObserver(observer); |
| 342 } |
| 343 } |
| 344 }); |
| 345 |
| 346 action.run(); |
| 347 |
| 348 try { |
| 349 closeCallback.waitForCallback(0); |
| 350 } catch (TimeoutException e) { |
| 351 Assert.fail("Tab closed event was never received"); |
| 352 } |
| 353 instrumentation.runOnMainSync(new Runnable() { |
| 354 @Override |
| 355 public void run() { |
| 356 TabModelSelector selector = activity.getTabModelSelector(); |
| 357 for (TabModel tabModel : selector.getModels()) { |
| 358 tabModel.removeObserver(observer); |
| 359 } |
| 360 } |
| 361 }); |
| 362 instrumentation.waitForIdleSync(); |
| 363 Log.d(TAG, "closeTabWithAction <<"); |
| 364 } |
| 365 |
| 366 /** |
| 367 * Selects a tab with the given action and waits for the selection event to
be observed. |
| 368 */ |
| 369 public static void selectTabWithAction(Instrumentation instrumentation, |
| 370 final ChromeTabbedActivity activity, Runnable action) throws Interru
ptedException { |
| 371 final CallbackHelper selectCallback = new CallbackHelper(); |
| 372 final TabModelObserver observer = new EmptyTabModelObserver() { |
| 373 @Override |
| 374 public void didSelectTab(Tab tab, TabSelectionType type, int lastId)
{ |
| 375 selectCallback.notifyCalled(); |
| 376 } |
| 377 }; |
| 378 instrumentation.runOnMainSync(new Runnable() { |
| 379 @Override |
| 380 public void run() { |
| 381 TabModelSelector selector = activity.getTabModelSelector(); |
| 382 for (TabModel tabModel : selector.getModels()) { |
| 383 tabModel.addObserver(observer); |
| 384 } |
| 385 } |
| 386 }); |
| 387 |
| 388 action.run(); |
| 389 |
| 390 try { |
| 391 selectCallback.waitForCallback(0); |
| 392 } catch (TimeoutException e) { |
| 393 Assert.fail("Tab selected event was never received"); |
| 394 } |
| 395 instrumentation.runOnMainSync(new Runnable() { |
| 396 @Override |
| 397 public void run() { |
| 398 TabModelSelector selector = activity.getTabModelSelector(); |
| 399 for (TabModel tabModel : selector.getModels()) { |
| 400 tabModel.removeObserver(observer); |
| 401 } |
| 402 } |
| 403 }); |
| 404 } |
| 405 } |
OLD | NEW |