chromium/chrome/browser/vr/webxr_vr_transition_browser_test.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/vr/test/mock_xr_device_hook_base.h"
#include "chrome/browser/vr/test/multi_class_browser_test.h"
#include "chrome/browser/vr/test/webxr_vr_browser_test.h"
#include "device/vr/buildflags/buildflags.h"

// Browser test equivalent of
// chrome/android/javatests/src/.../browser/vr/WebXrVrTransitionTest.java.
// End-to-end tests for transitioning between immersive and non-immersive
// sessions.

namespace vr {

// Tests that WebXR is not exposed if the flag is not on and the page does
// not have an origin trial token.
void TestApiDisabledWithoutFlagSetImpl(WebXrVrBrowserTestBase* t,
                                       std::string filename) {
  t->LoadFileAndAwaitInitialization(filename);
  t->WaitOnJavaScriptStep();
  t->EndTest();
}

#if BUILDFLAG(ENABLE_OPENXR)
IN_PROC_MULTI_CLASS_BROWSER_TEST_F1(WebXrVrOpenXrBrowserTestWebXrDisabled,
                                    WebXrVrBrowserTestBase,
                                    TestWebXrDisabledWithoutFlagSet) {
  TestApiDisabledWithoutFlagSetImpl(t, "test_webxr_disabled_without_flag_set");
}
#endif  // BUILDFLAG(ENABLE_OPENXR)

// Tests that window.requestAnimationFrame continues to fire when we have a
// non-immersive WebXR session.
WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(
    TestWindowRafFiresDuringNonImmersiveSession) {
  t->LoadFileAndAwaitInitialization(
      "test_window_raf_fires_during_non_immersive_session");
  t->WaitOnJavaScriptStep();
  t->EndTest();
}

// Tests that a successful requestPresent or requestSession call enters
// an immersive session.
void TestPresentationEntryImpl(WebXrVrBrowserTestBase* t,
                               std::string filename) {
  t->LoadFileAndAwaitInitialization(filename);
  t->EnterSessionWithUserGestureOrFail();
  t->AssertNoJavaScriptErrors();
}

WEBXR_VR_ALL_RUNTIMES_PLUS_INCOGNITO_BROWSER_TEST_F(
    TestRequestSessionEntersVr) {
  TestPresentationEntryImpl(t, "generic_webxr_page");
}

// Tests that window.requestAnimationFrame continues to fire while in
// WebXR presentation since the tab is still visible.
void TestWindowRafFiresWhilePresentingImpl(WebXrVrBrowserTestBase* t,
                                           std::string filename) {
  t->LoadFileAndAwaitInitialization(filename);
  t->ExecuteStepAndWait("stepVerifyBeforePresent()");
  t->EnterSessionWithUserGestureOrFail();
  t->ExecuteStepAndWait("stepVerifyDuringPresent()");
  t->EndSessionOrFail();
  t->ExecuteStepAndWait("stepVerifyAfterPresent()");
  t->EndTest();
}

WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestWindowRafFiresWhilePresenting) {
  TestWindowRafFiresWhilePresentingImpl(
      t, "webxr_test_window_raf_fires_while_presenting");
}

// Tests that non-immersive sessions stop receiving rAFs during an immersive
// session, but resume once the immersive session ends.
WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestNonImmersiveStopsDuringImmersive) {
  t->LoadFileAndAwaitInitialization(
      "test_non_immersive_stops_during_immersive");
  t->ExecuteStepAndWait("stepBeforeImmersive()");
  t->EnterSessionWithUserGestureOrFail();
  t->ExecuteStepAndWait("stepDuringImmersive()");
  t->EndSessionOrFail();
  t->ExecuteStepAndWait("stepAfterImmersive()");
  t->EndTest();
}

#if BUILDFLAG(ENABLE_OPENXR)
// Tests that WebXR session ends when certain events are received.
void TestWebXRSessionEndWhenEventTriggered(
    WebXrVrBrowserTestBase* t,
    device_test::mojom::EventType event_type) {
  MockXRDeviceHookBase transition_mock;
  t->LoadFileAndAwaitInitialization("test_webxr_presentation_ended");
  t->EnterSessionWithUserGestureOrFail();

  // Wait for JavaScript to submit at least one frame.
  ASSERT_TRUE(
      t->PollJavaScriptBoolean("hasPresentedFrame", t->kPollTimeoutMedium))
      << "No frame submitted";
  device_test::mojom::EventData data = {};
  data.type = event_type;
  transition_mock.PopulateEvent(data);
  // Tell JavaScript that it is done with the test.
  t->WaitOnJavaScriptStep();
  t->EndTest();
}

IN_PROC_BROWSER_TEST_F(WebXrVrOpenXrBrowserTest, TestSessionEnded) {
  TestWebXRSessionEndWhenEventTriggered(
      this, device_test::mojom::EventType::kSessionLost);
}

IN_PROC_BROWSER_TEST_F(WebXrVrOpenXrBrowserTest, TestInsanceLost) {
  TestWebXRSessionEndWhenEventTriggered(
      this, device_test::mojom::EventType::kInstanceLost);
}

IN_PROC_BROWSER_TEST_F(WebXrVrOpenXrBrowserTest, TestSessionExited) {
  // Set the device up to reject the session request. This should translate to
  // immediately translating the device to the "Exited" state.
  MockXRDeviceHookBase transition_mock;
  transition_mock.SetCanCreateSession(false);

  this->LoadFileAndAwaitInitialization("generic_webxr_page");

  // Not using "EnterSessionWithUserGestureOrFail" because we actually expect
  // the session to reject. So instead we check that an error got set.
  this->EnterSessionWithUserGesture();
  this->PollJavaScriptBooleanOrFail(
      "sessionInfos[sessionTypes.IMMERSIVE].error != null", kPollTimeoutLong);

  // Tell JavaScript that it is done with the test.
  this->RunJavaScriptOrFail("done()");
  this->EndTest();
}

IN_PROC_BROWSER_TEST_F(WebXrVrOpenXrBrowserTest, TestVisibilityChanged) {
  MockXRDeviceHookBase transition_mock;
  this->LoadFileAndAwaitInitialization("webxr_test_visibility_changed");
  this->EnterSessionWithUserGestureOrFail();

  // Wait for JavaScript to submit at least one frame.
  ASSERT_TRUE(this->PollJavaScriptBoolean("hasPresentedFrame",
                                          this->kPollTimeoutMedium))
      << "No frame submitted";

  this->PollJavaScriptBooleanOrFail("isVisibilityEqualTo('visible')",
                                    this->kPollTimeoutMedium);

  device_test::mojom::EventData event_data = {};
  event_data.type = device_test::mojom::EventType::kVisibilityVisibleBlurred;
  transition_mock.PopulateEvent(event_data);

  // TODO(crbug.com/40646813): visible-blurred is forced to hidden in WebXR
  this->PollJavaScriptBooleanOrFail("isVisibilityEqualTo('hidden')",
                                    this->kPollTimeoutMedium);
  this->RunJavaScriptOrFail("done()");
  this->EndTest();
}
#endif  // BUILDFLAG(ENABLE_OPENXR)

}  // namespace vr