Chromium Code Reviews| Index: chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java |
| diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..60c5b30d0dbbb83b0b650882f2d6c29b24dbdb10 |
| --- /dev/null |
| +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTest.java |
| @@ -0,0 +1,247 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.chrome.browser.vr_shell; |
| + |
| +import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_DAYDREAM_VIEW; |
| + |
| +import android.support.test.filters.SmallTest; |
| + |
| +import org.chromium.base.Log; |
| +import org.chromium.base.test.util.CommandLineFlags; |
| +import org.chromium.base.test.util.Restriction; |
| +import org.chromium.base.test.util.UrlUtils; |
| +import org.chromium.chrome.browser.media.RouterTestUtils; |
|
Lei Lei
2017/02/16 22:04:49
It is a little weird to util functions for other t
bsheedy
2017/02/16 23:30:13
Added a TODO to refactor this since that should be
|
| +import org.chromium.chrome.test.ChromeTabbedActivityTestBase; |
| +import org.chromium.content.browser.test.util.Criteria; |
| +import org.chromium.content.browser.test.util.CriteriaHelper; |
| +import org.chromium.content.browser.test.util.JavaScriptUtils; |
| +import org.chromium.content_public.browser.WebContents; |
| + |
| +import java.util.concurrent.Callable; |
| +import java.util.concurrent.TimeUnit; |
| +import java.util.concurrent.TimeoutException; |
| + |
| +/** |
| + * This is a workaround for testing aspects of WebVR that aren't testable with |
| + * WebVR's mocked layout tests, such as E2E tests. |
| + * |
| + * The general test flow is: |
| + * - Load the HTML file containing the test, which: |
| + * - Loads the WebVR boilerplate code and some test functions |
| + * - Sets up common elements like the canvas and synchronization variable |
| + * - Sets up any steps that need to be triggered by the Java code |
| + * - Check if any VRDisplay objects were found and fail the test if it doesn't |
| + * match what we expect for that test |
| + * - Repeat: |
| + * - Run any necessary Java-side code, e.g. trigger a user action |
| + * - Trigger the next Javascript test step and wait for it to finish |
| + * |
| + * The Javascript code will automatically process test results once all |
| + * testharness.js tests are done, just like in layout tests. Once the results |
| + * are processed, the Javascript code will automatically signal the Java code, |
| + * which can then grab the results and pass/fail the instrumentation test. |
| + */ |
| +@CommandLineFlags.Add("enable-webvr") |
| +public class WebVrTest extends ChromeTabbedActivityTestBase { |
| + private static final String TAG = "WebVrTest"; |
| + private static final String TEST_DIR = "chrome/test/data/android/webvr_instrumentation"; |
| + private static final int POLL_TIMEOUT_SHORT = 1000; |
| + private static final int POLL_TIMEOUT_LONG = 10000; |
| + |
| + private WebContents mWebContents; |
| + |
| + @Override |
| + protected void setUp() throws Exception { |
| + super.setUp(); |
| + mWebContents = getActivity().getActivityTab().getWebContents(); |
| + } |
| + |
| + @Override |
| + public void startMainActivity() throws InterruptedException { |
| + startMainActivityOnBlankPage(); |
| + } |
| + |
| + /** |
| + * Gets the file:// URL to the test file |
| + * @param testName The name of the test whose file will be retrieved |
| + * @return The file:// URL to the specified test file |
| + */ |
| + private String getHtmlTestFile(String testName) { |
| + return "file://" + UrlUtils.getIsolatedTestFilePath(TEST_DIR) + "/html/" + testName |
| + + ".html"; |
| + } |
| + |
| + /** |
| + * Blocks until the promise returned by nagivator.getVRDisplays() resolves, |
| + * then checks whether a VRDisplay was actually found. |
| + * @param webContents The WebContents to run the Javascript through |
| + * @return Whether a VRDisplay was found |
| + */ |
| + private boolean vrDisplayFound(WebContents webContents) { |
| + pollJavascriptBoolean(POLL_TIMEOUT_SHORT, "vrDisplayPromiseDone", webContents); |
| + String result = "null"; |
| + try { |
| + result = JavaScriptUtils.executeJavaScriptAndWaitForResult( |
| + webContents, "vrDisplay", POLL_TIMEOUT_SHORT, TimeUnit.MILLISECONDS); |
| + } catch (InterruptedException | TimeoutException e) { |
| + return false; |
| + } |
| + return !result.equals("null"); |
| + } |
| + |
| + /** |
| + * Helper function to run vrDisplayFound in the tab that's first opened by |
| + * the test, which is the case unless code is being run in multiple tabs. |
| + * @return Whether a VRDisplay was found on the page controlled by mWebContents |
| + */ |
| + private boolean vrDisplayFound() { |
| + return vrDisplayFound(mWebContents); |
| + } |
| + |
| + /** |
| + * Use to tap in the middle of the screen, triggering the canvas' onclick |
| + * to fulfil WebVR's gesture requirement for presenting. |
| + */ |
| + private void enterVrTap() { |
| + RouterTestUtils.mouseSingleClickView( |
| + getInstrumentation(), getActivity().getWindow().getDecorView().getRootView()); |
| + } |
| + |
| + /** |
| + * Use to simulate a Daydream View NFC scan without blocking afterwards |
| + */ |
| + private void simNfcScan() { |
| + VrUtils.simNfc(getActivity()); |
| + } |
| + |
| + /** |
| + * Simulate an NFC scan and wait for the Javascript code in the given |
| + * WebContents to signal that it is done with the step. |
| + * @param webContents The WebContents for the Javascript that will be polled |
| + */ |
| + private void simNfcScanAndWait(WebContents webContents) { |
| + simNfcScan(); |
| + pollJavascriptBoolean(POLL_TIMEOUT_LONG, "javascriptDone", webContents); |
| + // Reset the synchronization boolean |
| + JavaScriptUtils.executeJavaScript(webContents, "javascriptDone = false"); |
| + } |
| + |
| + /** |
| + * Ends the test harness test and checks whether there it passed |
| + * @return "Passed" if test passed, String with failure reason otherwise |
| + */ |
| + private String checkResults() { |
| + String result = "false"; |
| + try { |
| + result = JavaScriptUtils.executeJavaScriptAndWaitForResult( |
| + mWebContents, "testPassed", 50, TimeUnit.MILLISECONDS); |
| + } catch (InterruptedException | TimeoutException e) { |
| + // Do nothing - if it times out, the test will be marked as failed |
| + } |
| + if (result.equals("true")) { |
| + return "Passed"; |
| + } |
| + |
| + try { |
| + result = JavaScriptUtils.executeJavaScriptAndWaitForResult( |
| + mWebContents, "resultString", 50, TimeUnit.MILLISECONDS); |
| + } catch (InterruptedException | TimeoutException e) { |
| + result = "Unable to retrieve failure reason"; |
| + } |
| + return result; |
| + } |
| + |
| + /** |
| + * Helper function to end the test harness test and assert that it passed, |
| + * setting the failure reason as the description if it didn't. |
| + */ |
| + private void endTest() { |
| + String result = checkResults(); |
| + assertTrue(result, result.equals("Passed")); |
| + } |
| + |
| + /** |
| + * Polls the provided Javascript boolean until the timeout is reached or |
| + * the boolean is true. |
| + * @param timeoutMs The polling timeout in milliseconds |
| + * @param boolName The name of the Javascript boolean to poll |
| + * @param webContents The WebContents to run the Javascript through |
| + * @return True if the boolean evaluated to true, false if timed out |
| + */ |
| + private boolean pollJavascriptBoolean( |
| + int timeoutMs, final String boolName, final WebContents webContents) { |
| + try { |
| + CriteriaHelper.pollInstrumentationThread(Criteria.equals(true, new Callable<Boolean>() { |
| + @Override |
| + public Boolean call() { |
| + String result = "false"; |
| + try { |
| + result = JavaScriptUtils.executeJavaScriptAndWaitForResult( |
| + webContents, boolName, 50, TimeUnit.MILLISECONDS); |
| + } catch (InterruptedException | TimeoutException e) { |
| + // Expected to happen regularly, do nothing |
| + } |
| + return Boolean.parseBoolean(result); |
| + } |
| + }), timeoutMs, 100); |
| + } catch (AssertionError e) { |
| + Log.d(TAG, "pollJavascriptBoolean() timed out"); |
| + return false; |
| + } |
| + return true; |
| + } |
| + |
| + /** |
| + * Executes a Javascript step function using the given WebContents. |
| + * @param stepFunction The Javascript step function to call |
| + * @param webContents The WebContents for the tab the Javascript is in |
| + */ |
| + private void executeStepAndWait(String stepFunction, WebContents webContents) { |
| + // Run the step and block |
| + JavaScriptUtils.executeJavaScript(webContents, stepFunction); |
| + pollJavascriptBoolean(POLL_TIMEOUT_LONG, "javascriptDone", webContents); |
|
Lei Lei
2017/02/16 22:04:49
I think we need to check the return value from pol
bsheedy
2017/02/16 23:30:13
Done, and added to the check in simNfcScanAndWait
|
| + // Reset the synchronization boolean |
| + JavaScriptUtils.executeJavaScript(webContents, "javascriptDone = false"); |
| + } |
| + |
| + /** |
| + * Helper function to execute a step in the tab the test starts in, which |
| + * is usually the case unless test code is being executed in multiple tabs. |
| + * @param stepFunction The Javascript function to execute for this step |
| + */ |
| + private void executeStepAndWait(String stepFunction) { |
| + executeStepAndWait(stepFunction, mWebContents); |
| + } |
| + |
| + /** |
| + * Tests that scanning the Daydream View NFC tag on supported devices |
| + * fires the onvrdisplayactivate event. |
| + */ |
| + @SmallTest |
| + @Restriction(RESTRICTION_TYPE_DAYDREAM_VIEW) |
| + public void testNfcFiresOnvrdisplayactivate() throws InterruptedException { |
| + String testName = "test_nfc_fires_onvrdisplayactivate"; |
| + loadUrl(getHtmlTestFile(testName), 10); |
| + assertTrue("VRDisplay found", vrDisplayFound()); |
| + simNfcScanAndWait(mWebContents); |
| + endTest(); |
| + } |
| + |
| + /** |
| + * Tests that non-focused tabs cannot get pose information. |
| + */ |
| + @SmallTest |
| + public void testPoseDataUnfocusedTab() throws InterruptedException { |
| + String testName = "test_pose_data_unfocused_tab"; |
| + loadUrl(getHtmlTestFile(testName), 10); |
| + assertTrue("VRDisplay found", vrDisplayFound()); |
| + executeStepAndWait("stepCheckFrameDataWhileFocusedTab()"); |
| + |
| + loadUrlInNewTab("about:blank"); |
| + |
| + executeStepAndWait("stepCheckFrameDataWhileNonFocusedTab()"); |
| + endTest(); |
| + } |
| +} |