XR Browser Tests

Introduction

This documentation concerns xr_browser_test.h, xr_browser_test.cc, and files that use them or their subclasses.

These files port the framework used by XR instrumentation tests (located in //chrome/android/javatests/src/org/chromium/chrome/browser/vr/ and documented in //chrome/android/javatests/src/org/chromium/chrome/browser/vr/*.md) for use in browser tests in order to test XR features on desktop platforms.

This is pretty much a direct port, with the same JavaScript/HTML files being used for both and the Java/C++ code being functionally equivalent to each other, so the instrumentation test's documentation on writing tests using the framework is applicable here, too. As such, this documentation only covers any notable differences between the two implementations.

Restrictions

Both the instrumentation tests and browser tests have hardware/software restrictions - in the case of browser tests, XR is only supported on Windows 8 and later (or Windows 7 with a non-standard patch applied) with a GPU that supports DirectX 11.1, although several tests exist that don‘t actually use XR functionality, and thus don’t have these requirements.

Runtime restrictions in browser tests are handled via the macros in conditional_skipping.h. To add a runtime requirement to a test class, simply append it to the runtime_requirements_ vector that each class has. The test setup will automatically skip tests that don't meet all requirements.

One-off skipping within a test can also be done by using the XR_CONDITIONAL_SKIP macro directly in a test.

The bots can be made to ignore these runtime requirement checks if we expect the requirements to always be met (and thus we want the tests to fail if they aren't) via the --ignore-runtime-requirements argument. This takes a comma-separated list of requirements to ignore, or the wildcard (*) to ignore all requirements. For example, --ignore-runtime-requirements=DirectX_11.1 would cause a test that requires a DirectX 11.1 device to be run even if a suitable device is not found.

New requirements can be added by adding to the XrTestRequirement enum in conditional_skipping.h and adding its associated checking logic in conditional_skipping.cc.

Command Line Switches

Instrumentation tests are able to add and remove command line switches on a per-test-case basis using @CommandLine annotations, but equivalent functionality does not exist in browser tests.

Instead, if different command line flags are needed, a new class will need to be created that extends the correct type of *BrowserTestBase and overrides the flags that are set in its SetUp function.

Compiling And Running

The tests are compiled in the xr_browser_tests target. This is a combination of the xr_browser_tests_binary target, which is the actual test, and the xr_browser_tests_runner target, which is a wrapper script that ensures special setup is completed before running the tests.

Once compiled, the tests can be run using the following command line:

run_xr_browser_tests.py --enable-gpu --test-launcher-jobs=1 --enable-pixel-output-in-tests

Additional options such as test filtering can be found by running xr_browser_tests.exe --help and xr_browser_tests.exe --gtest_help.

Because the “test” is actually a Python wrapper script, you may need to prepend python to the front of the command on Windows if Python file association is not set up on your machine.

Adding New Files

If you are adding a new test or infrastructure file to the target, you‘ll need to consider whether it’s useful with the enable_vr gn arg set to false or not. If it is, then it should be included in //chrome/test:xr_browser_tests_common, otherwise it should be included in //chrome/browser/vr:xr_browser_tests_vr_required.

If including in //chrome/test:xr_browser_tests_common, you may need to hide some VR-specific functionality in the file behind #if BUILDFLAG(ENABLE_VR).

Running A Test Multiple Times With Different Runtimes

The macros provided by //chrome/browser/vr/test/multi_class_browser_test.h provide a shorthand method for running a test multiple times with different classes/runtimes. This is effectively the same as declaring some implementation function that takes a reference to some base class shared by all the subclasses you want to run the test with, then having each test call that implementation.

These macros help cut down on boilerplate code, but if you need either:

  1. Class-specific setup before running the implementation
  2. Different test logic in the implementation depending on the provided class

You should consider using the standard IN_PROC_BROWSER_TEST_F macros instead. Small snippets of runtime-specific code are acceptable, but if it affects readability significantly, the tests should probably remain separate.

Most tests simply use the standard WebXrVrOpenVrBrowserTest and WebXrVrWmrBrowserTest classes. In this case, you can instead use the WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F macro, which only needs to take the test name, further cutting down on boilerplate code.

You can also use WEBXR_VR_ALL_RUNTIMES_PLUS_INCOGNITO_BROWSER_TEST_F if you want the same functionality as WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F, but also want the test run in Incognito mode in addition to regular Chrome.

Test Class Names

The test classes that are used to provide feature and runtime-specific setup and functions are named in the following order:

  1. Feature
  2. Runtime
  3. “BrowserTest”
  4. Optional Descriptor/special flags

For example, WebXrVrOpenVrBrowserTest is meant for testing the WebXR for VR feature using the OpenVR runtime with standard flags enabled, i.e. the flags required for using WebXR and the OpenVR runtime with other runtimes disabled. WebXrVrRuntimelessBrowserTestSensorless on the other hand would be for testing WebVR for VR without any runtimes and with the orientation sensor device explicitly disabled.

In general, classes ending in “Base” should not be used directly.

Controller and Head Input

The XR browser tests provide a way to plumb controller and headset data (e.g. currently touched/pressed buttons and poses) from the test through the runtime being tested. Details about what goes on under the hood can be found in //chrome/browser/vr/test/xr_browser_test_details.md, but below is a quick guide on how to use them.

In order to let a test provide data to a runtime, it must create an instance of MockXRDeviceHookBase or some subclass of it. This should be created at the beginning of the test before any attempts to enter VR are made, as there are currently assumptions that prevent switching to or from the mock runtimes once they have been attempted to be started.

Once created, the runtime being used will call the various functions inherited from VRTestHook whenever it would normally acquire or submit data from or to an actual device. For example, WaitGetControllerData() will be called every time the runtime would normally check the state of a real controller, and OnFrameSubmitted() will be called each time the runtime submits a finished frame to the headset.

For real examples on how to use the input capabilities, look at the tests in //chrome/browser/vr/webxr_vr_input_browser_test.cc.

Assumptions

There are currently several assumptions made that must be adhered to in order for input to work properly in both OpenVR and Windows Mixed Reality.

WMR and Incomplete Gamepads

OpenVR supports arbitrary controller mappings, but WMR only supports one actual controller type (+ voice input). What this means is that WMR will always report a certain set of buttons and axes when a controller is connected, regardless of which buttons and axes are set as supported. This means that tests involving things not supported by WMR (e.g. a third touchpad/joystick) must be restricted to OpenVR.