mobile/android/base/tests/helpers/WaitHelper.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     5 package org.mozilla.gecko.tests.helpers;
     7 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
     8 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
    10 import java.util.regex.Pattern;
    12 import org.mozilla.gecko.Actions;
    13 import org.mozilla.gecko.Actions.EventExpecter;
    14 import org.mozilla.gecko.tests.UITestContext;
    15 import org.mozilla.gecko.tests.UITestContext.ComponentType;
    16 import org.mozilla.gecko.tests.components.ToolbarComponent;
    18 import com.jayway.android.robotium.solo.Condition;
    19 import com.jayway.android.robotium.solo.Solo;
    21 /**
    22  * Provides functionality related to waiting on certain events to happen.
    23  */
    24 public final class WaitHelper {
    25     // TODO: Make public for when Solo.waitForCondition is used directly (i.e. do not want
    26     // assertion from waitFor)?
    27     private static final int DEFAULT_MAX_WAIT_MS = 5000;
    28     private static final int PAGE_LOAD_WAIT_MS = 10000;
    29     private static final int CHANGE_WAIT_MS = 10000;
    31     // TODO: via lucasr - Add ThrobberVisibilityChangeVerifier?
    32     private static final ChangeVerifier[] PAGE_LOAD_VERIFIERS = new ChangeVerifier[] {
    33         new ToolbarTitleTextChangeVerifier()
    34     };
    36     private static UITestContext sContext;
    37     private static Solo sSolo;
    38     private static Actions sActions;
    40     private static ToolbarComponent sToolbar;
    42     private WaitHelper() { /* To disallow instantiation. */ }
    44     protected static void init(final UITestContext context) {
    45         sContext = context;
    46         sSolo = context.getSolo();
    47         sActions = context.getActions();
    49         sToolbar = (ToolbarComponent) context.getComponent(ComponentType.TOOLBAR);
    50     }
    52     /**
    53      * Waits for the given {@link solo.Condition} using the default wait duration; will throw an
    54      * AssertionError if the duration is elapsed and the condition is not satisfied.
    55      */
    56     public static void waitFor(String message, final Condition condition) {
    57         message = "Waiting for " + message + ".";
    58         fAssertTrue(message, sSolo.waitForCondition(condition, DEFAULT_MAX_WAIT_MS));
    59     }
    61     /**
    62      * Waits for the given {@link solo.Condition} using the given wait duration; will throw an
    63      * AssertionError if the duration is elapsed and the condition is not satisfied.
    64      */
    65     public static void waitFor(String message, final Condition condition, final int waitMillis) {
    66         message = "Waiting for " + message + " with timeout " + waitMillis + ".";
    67         fAssertTrue(message, sSolo.waitForCondition(condition, waitMillis));
    68     }
    70     /**
    71      * Waits for the Gecko event declaring the page has loaded. Takes in and runs a Runnable
    72      * that will perform the action that will cause the page to load.
    73      */
    74     public static void waitForPageLoad(final Runnable initiatingAction) {
    75         fAssertNotNull("initiatingAction is not null", initiatingAction);
    77         // Some changes to the UI occur in response to the same event we listen to for when
    78         // the page has finished loading (e.g. a page title update). As such, we ensure this
    79         // UI state has changed before returning from this method; here we store the initial
    80         // state.
    81         final ChangeVerifier[] pageLoadVerifiers = PAGE_LOAD_VERIFIERS;
    82         for (final ChangeVerifier verifier : pageLoadVerifiers) {
    83             verifier.storeState();
    84         }
    86         // Wait for the page load and title changed event.
    87         final EventExpecter contentEventExpecter = sActions.expectGeckoEvent("DOMContentLoaded");
    88         final EventExpecter titleEventExpecter = sActions.expectGeckoEvent("DOMTitleChanged");
    90         initiatingAction.run();
    92         contentEventExpecter.blockForEventDataWithTimeout(PAGE_LOAD_WAIT_MS);
    93         contentEventExpecter.unregisterListener();
    94         titleEventExpecter.blockForEventDataWithTimeout(PAGE_LOAD_WAIT_MS);
    95         titleEventExpecter.unregisterListener();
    97         // Verify remaining state has changed.
    98         for (final ChangeVerifier verifier : pageLoadVerifiers) {
    99             // If we timeout, either the state is set to the same value (which is fine), or
   100             // the state has not yet changed. Since we can't be sure it will ever change, move
   101             // on and let the assertions fail if applicable.
   102             final boolean hasTimedOut = !sSolo.waitForCondition(new Condition() {
   103                 @Override
   104                 public boolean isSatisfied() {
   105                     return verifier.hasStateChanged();
   106                 }
   107             }, CHANGE_WAIT_MS);
   109             sContext.dumpLog(verifier.getLogTag(),
   110                     (hasTimedOut ? "timed out." : "was satisfied."));
   111         }
   112     }
   114     /**
   115      * Implementations of this interface verify that the state of the test has changed from
   116      * the invocation of storeState to the invocation of hasStateChanged. A boolean will be
   117      * returned from hasStateChanged, indicating this change of status.
   118      */
   119     private static interface ChangeVerifier {
   120         public String getLogTag();
   122         /**
   123          * Stores the initial state of the system. This system state is used to diff against
   124          * the end state to determine if the system has changed. Since this is just a diff
   125          * (with a timeout), this method could potentially store state inconsistent with
   126          * what is visible to the user.
   127          */
   128         public void storeState();
   129         public boolean hasStateChanged();
   130     }
   132     private static class ToolbarTitleTextChangeVerifier implements ChangeVerifier {
   133         private static final String LOGTAG = ToolbarTitleTextChangeVerifier.class.getSimpleName();
   135         // A regex that matches the page title that shows up while the page is loading.
   136         private static final Pattern LOADING_PREFIX = Pattern.compile("[A-Za-z]{3,9}://");
   138         private CharSequence mOldTitleText;
   140         @Override
   141         public String getLogTag() {
   142             return LOGTAG;
   143         }
   145         @Override
   146         public void storeState() {
   147             mOldTitleText = sToolbar.getPotentiallyInconsistentTitle();
   148             sContext.dumpLog(LOGTAG, "stored title, \"" + mOldTitleText + "\".");
   149         }
   151         @Override
   152         public boolean hasStateChanged() {
   153             // TODO: Additionally, consider Solo.waitForText.
   154             // TODO: Robocop sleeps .5 sec between calls. Cache title view?
   155             final CharSequence title = sToolbar.getPotentiallyInconsistentTitle();
   157             // TODO: Handle the case where the URL is shown instead of page title by preference.
   158             // HACK: We want to wait until the title changes to the state a tester may assert
   159             // (e.g. the page title). However, the title is set to the URL before the title is
   160             // loaded from the server and set as the final page title; we ignore the
   161             // intermediate URL loading state here.
   162             final boolean isLoading = LOADING_PREFIX.matcher(title).lookingAt();
   163             final boolean hasStateChanged = !isLoading && !mOldTitleText.equals(title);
   165             if (hasStateChanged) {
   166                 sContext.dumpLog(LOGTAG, "state changed to title, \"" + title + "\".");
   167             }
   168             return hasStateChanged;
   169         }
   170     }
   171 }

mercurial