summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webxr/anchors
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webxr/anchors')
-rw-r--r--testing/web-platform/tests/webxr/anchors/META.yml1
-rw-r--r--testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_create_move.https.html94
-rw-r--r--testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_delay_creation.https.html122
-rw-r--r--testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_failure.https.html72
-rw-r--r--testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_pause_resume_stop.https.html115
-rw-r--r--testing/web-platform/tests/webxr/anchors/ar_anchor_getAnchors.https.html58
-rw-r--r--testing/web-platform/tests/webxr/anchors/ar_anchor_states.https.html114
-rw-r--r--testing/web-platform/tests/webxr/anchors/idlharness.https.window.js16
8 files changed, 592 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webxr/anchors/META.yml b/testing/web-platform/tests/webxr/anchors/META.yml
new file mode 100644
index 0000000000..0b7f740ac5
--- /dev/null
+++ b/testing/web-platform/tests/webxr/anchors/META.yml
@@ -0,0 +1 @@
+spec: https://immersive-web.github.io/anchors/
diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_create_move.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_create_move.https.html
new file mode 100644
index 0000000000..87f7556007
--- /dev/null
+++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_create_move.https.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/webxr_util.js"></script>
+<script src="../resources/webxr_test_asserts.js"></script>
+<script src="../resources/webxr_test_constants.js"></script>
+<script src="../resources/webxr_test_constants_fake_world.js"></script>
+
+<script>
+
+// 1m above world origin.
+const VIEWER_ORIGIN_TRANSFORM = {
+ position: [0, 1, 0],
+ orientation: [0, 0, 0, 1],
+};
+
+const fakeDeviceInitParams = {
+ supportedModes: ["immersive-ar"],
+ views: VALID_VIEWS,
+ supportedFeatures: ALL_FEATURES,
+ viewerOrigin: VIEWER_ORIGIN_TRANSFORM,
+};
+
+// All test cases require anchors.
+const sessionInit = { 'requiredFeatures': ['anchors'] };
+
+// Create an anchor, move it and verify that new pose gets propagated to the caller.
+const anchorCreateAndMove = function(session, fakeDeviceController, t) {
+ const debug = xr_debug.bind(this, 'anchorCreateAndMove');
+
+ let anchorController = null;
+ fakeDeviceController.setAnchorCreationCallback((parameters, controller) => {
+ anchorController = controller;
+ return Promise.resolve(true);
+ });
+
+ const watcherDone = new Event("watcherdone");
+ const eventWatcher = new EventWatcher(t, session, ["watcherdone"]);
+ const eventPromise = eventWatcher.wait_for(["watcherdone"]);
+
+ session.requestReferenceSpace('local').then((localRefSpace) => {
+ debug("requesting animation frame");
+
+ session.requestAnimationFrame((time, frame) => {
+ debug("rAF 1");
+
+ let createdAnchor = null;
+ frame.createAnchor(new XRRigidTransform(), localRefSpace)
+ .then((anchor) => {
+ createdAnchor = anchor;
+ });
+
+ session.requestAnimationFrame((time_2, frame_2) => {
+ debug("rAF 2");
+
+ const pre_move_pose = frame_2.getPose(createdAnchor.anchorSpace, localRefSpace);
+
+ t.step(() => {
+ assert_true(frame_2.trackedAnchors.has(createdAnchor),
+ "Newly created anchor must be in tracked anchors set on subsequent RAF (2)!");
+ // We have created an anchor with an identity pose relative to local space and have not moved it yet:
+ assert_matrix_approx_equals(pre_move_pose.transform.matrix,
+ IDENTITY_MATRIX, FLOAT_EPSILON);
+ });
+
+ anchorController.setAnchorOrigin(VALID_POSE_TRANSFORM);
+
+ session.requestAnimationFrame((time_3, frame_3) => {
+ debug("rAF 3");
+
+ const post_move_pose = frame_3.getPose(createdAnchor.anchorSpace, localRefSpace);
+
+ t.step(() => {
+ assert_true(frame_3.trackedAnchors.has(createdAnchor),
+ "Newly created anchor must be in tracked anchors set on subsequent RAF (3)!");
+ // The anchor was moved by VALID_POSE_TRANSFORM, validate that its pose got adjusted:
+ assert_matrix_approx_equals(post_move_pose.transform.matrix,
+ VALID_POSE_MATRIX, FLOAT_EPSILON);
+ });
+
+ session.dispatchEvent(watcherDone);
+ });
+ });
+ });
+ }); // session.requestReferenceSpace(...).then({...});
+
+ return eventPromise;
+};
+
+xr_session_promise_test(
+ "Ensures free-floating anchor move gets propagated to anchor poses",
+ anchorCreateAndMove, fakeDeviceInitParams, 'immersive-ar', sessionInit);
+
+</script>
diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_delay_creation.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_delay_creation.https.html
new file mode 100644
index 0000000000..686eacf848
--- /dev/null
+++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_delay_creation.https.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/webxr_util.js"></script>
+<script src="../resources/webxr_test_asserts.js"></script>
+<script src="../resources/webxr_test_constants.js"></script>
+<script src="../resources/webxr_test_constants_fake_world.js"></script>
+
+<script>
+
+// 1m above world origin.
+const VIEWER_ORIGIN_TRANSFORM = {
+ position: [0, 1, 0],
+ orientation: [0, 0, 0, 1],
+};
+
+const fakeDeviceInitParams = {
+ supportedModes: ["immersive-ar"],
+ views: VALID_VIEWS,
+ supportedFeatures: ALL_FEATURES,
+ viewerOrigin: VIEWER_ORIGIN_TRANSFORM,
+};
+
+// All test cases require anchors.
+const sessionInit = { 'requiredFeatures': ['anchors'] };
+
+// Creates a test function that will attempt to create an anchor with a delay.
+// In case the anchor creation is expected to succeed, the test will then
+// validate whether the anchor belongs to frame.trackedAnchors, has a valid pose,
+// and that after deleting it, it no longer allows access to its anchorSpace.
+// |shouldSucceed| - true if the anchor creation is expected to succeed.
+const anchorCreationDelayedCreator = function(shouldSucceed) {
+ return function(session, fakeDeviceController, t) {
+ const debug = xr_debug.bind(this, 'anchorCreationDelayed' + (shouldSucceed ? 'Success' : 'Failure'));
+
+ let anchorCreationResolve = null;
+ fakeDeviceController.setAnchorCreationCallback((parameters, controller) => {
+ return new Promise((resolve) => {
+ anchorCreationResolve = resolve;
+ });
+ });
+
+ const watcherDone = new Event("watcherdone");
+ const creationDelayedEvent = new Event("creationdelayed");
+ const eventWatcher = new EventWatcher(t, session, ["creationdelayed", "watcherdone"]);
+ const eventPromise = eventWatcher.wait_for(["creationdelayed", "watcherdone"]);
+
+ session.requestReferenceSpace('local').then((localRefSpace) => {
+ debug("requesting animation frame");
+
+ session.requestAnimationFrame((time, frame) => {
+ debug("rAF 1");
+
+ let createdAnchor = null;
+ frame.createAnchor(new XRRigidTransform(), localRefSpace)
+ .then((anchor) => {
+ createdAnchor = anchor;
+
+ t.step(() => {
+ assert_true(anchor != null, "Returned anchor should not be null!");
+ assert_true(shouldSucceed,
+ "Anchor creation succeeded when it was expected to fail!");
+ });
+ })
+ .catch((error) => {
+ t.step(() => {
+ assert_false(shouldSucceed,
+ "Anchor creation failed when it was expected to succeed!");
+ });
+
+ session.dispatchEvent(watcherDone);
+ });
+
+ session.requestAnimationFrame(() => {
+ debug("rAF 2");
+
+ session.dispatchEvent(creationDelayedEvent);
+
+ anchorCreationResolve(shouldSucceed);
+
+ session.requestAnimationFrame((time_2, frame_2) => {
+ debug("rAF 3");
+
+ if(shouldSucceed) {
+ t.step(() => {
+ assert_true(createdAnchor != null);
+ assert_true(frame_2.trackedAnchors.has(createdAnchor),
+ "Newly created anchor must be in tracked anchors set!");
+ assert_true(createdAnchor.anchorSpace != null,
+ "Newly created anchor must have a non-null anchor space!");
+ assert_true(frame_2.getPose(createdAnchor.anchorSpace, localRefSpace) != null,
+ "Newly created anchor should have a pose!");
+ });
+
+ createdAnchor.delete();
+
+ t.step(() => {
+ assert_throws_dom('InvalidStateError', () => {
+ createdAnchor.anchorSpace;
+ });
+ });
+
+ session.dispatchEvent(watcherDone);
+ }
+ });
+ });
+ });
+ }); // session.requestReferenceSpace(...).then({...});
+
+ return eventPromise;
+ };
+};
+
+xr_session_promise_test(
+ "Ensures free-floating anchor creation with delayed success is handled correctly",
+ anchorCreationDelayedCreator(true), fakeDeviceInitParams, 'immersive-ar', sessionInit);
+
+xr_session_promise_test(
+ "Ensures free-floating anchor creation with delayed failure is handled correctly",
+ anchorCreationDelayedCreator(false), fakeDeviceInitParams, 'immersive-ar', sessionInit);
+
+</script>
diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_failure.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_failure.https.html
new file mode 100644
index 0000000000..dd03be0ad5
--- /dev/null
+++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_failure.https.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/webxr_util.js"></script>
+<script src="../resources/webxr_test_asserts.js"></script>
+<script src="../resources/webxr_test_constants.js"></script>
+<script src="../resources/webxr_test_constants_fake_world.js"></script>
+
+<script>
+
+// 1m above world origin.
+const VIEWER_ORIGIN_TRANSFORM = {
+ position: [0, 1, 0],
+ orientation: [0, 0, 0, 1],
+};
+
+const fakeDeviceInitParams = {
+ supportedModes: ["immersive-ar"],
+ views: VALID_VIEWS,
+ supportedFeatures: ALL_FEATURES,
+ viewerOrigin: VIEWER_ORIGIN_TRANSFORM,
+};
+
+// All test cases require anchors.
+const sessionInit = { 'requiredFeatures': ['anchors'] };
+
+// Fail the anchor creation & see if it gets communicated to the caller.
+// The concrete error is not specified by the WebXR Test API / WebXR Anchors.
+const anchorCreationFail = function(session, fakeDeviceController, t) {
+ const debug = xr_debug.bind(this, 'anchorCreationFail');
+
+ fakeDeviceController.setAnchorCreationCallback((parameters, controller) => {
+ // Immediately fail anchor creation.
+ return Promise.resolve(false);
+ });
+
+ const watcherDone = new Event("watcherdone");
+ const eventWatcher = new EventWatcher(t, session, ["watcherdone"]);
+ const eventPromise = eventWatcher.wait_for(["watcherdone"]);
+
+ session.requestReferenceSpace('local').then((localRefSpace) => {
+ debug("requesting animation frame");
+
+ session.requestAnimationFrame((time, frame) => {
+ debug("rAF 1");
+
+ frame.createAnchor(new XRRigidTransform(), localRefSpace)
+ .then((anchor) => {
+ t.step(() => {
+ assert_false(true, "Anchor creation should fail!");
+ });
+ })
+ .catch((error) => {
+ session.dispatchEvent(watcherDone);
+ });
+
+ // Anchor result will only take effect with frame data - schedule
+ // a frame after we requested anchor creation, otherwise the test will time out.
+ session.requestAnimationFrame(() => {
+ debug("rAF 2");
+ });
+ });
+ }); // session.requestReferenceSpace(...).then({...});
+
+ return eventPromise;
+}
+
+xr_session_promise_test(
+ "Ensures free-floating anchor creation failure is handled correctly",
+ anchorCreationFail, fakeDeviceInitParams, 'immersive-ar', sessionInit);
+
+</script>
diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_pause_resume_stop.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_pause_resume_stop.https.html
new file mode 100644
index 0000000000..6eb6bc76e6
--- /dev/null
+++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_freefloating_pause_resume_stop.https.html
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/webxr_util.js"></script>
+<script src="../resources/webxr_test_asserts.js"></script>
+<script src="../resources/webxr_test_constants.js"></script>
+<script src="../resources/webxr_test_constants_fake_world.js"></script>
+
+<script>
+
+// 1m above world origin.
+const VIEWER_ORIGIN_TRANSFORM = {
+ position: [0, 1, 0],
+ orientation: [0, 0, 0, 1],
+};
+
+const fakeDeviceInitParams = {
+ supportedModes: ["immersive-ar"],
+ views: VALID_VIEWS,
+ supportedFeatures: ALL_FEATURES,
+ viewerOrigin: VIEWER_ORIGIN_TRANSFORM,
+};
+
+// All test cases require anchors.
+const sessionInit = { 'requiredFeatures': ['anchors'] };
+
+// Create an anchor, pause tracking, resume tracking, & stop tracking and validate
+// that the state changes are propagated to the caller.
+const anchorCreatePauseTrackingResumeAndDelete = function(session, fakeDeviceController, t) {
+ const debug = xr_debug.bind(this, 'anchorCreatePauseTrackingResumeAndDelete');
+
+ let anchorController = null;
+ fakeDeviceController.setAnchorCreationCallback((parameters, controller) => {
+ anchorController = controller;
+ return Promise.resolve(true);
+ });
+
+ const watcherDone = new Event("watcherdone");
+ const eventWatcher = new EventWatcher(t, session, ["watcherdone"]);
+ const eventPromise = eventWatcher.wait_for(["watcherdone"]);
+
+ session.requestReferenceSpace('local').then((localRefSpace) => {
+ debug("requesting animation frame");
+
+ session.requestAnimationFrame((time, frame) => {
+ debug("rAF 1");
+
+ let createdAnchor = null;
+ frame.createAnchor(new XRRigidTransform(), localRefSpace)
+ .then((anchor) => {
+ createdAnchor = anchor;
+ });
+
+ session.requestAnimationFrame((time_2, frame_2) => {
+ debug("rAF 2");
+
+ t.step(() => {
+ assert_true(frame_2.getPose(createdAnchor.anchorSpace, localRefSpace) != null,
+ "Newly created anchor should have a pose!");
+ assert_true(frame_2.trackedAnchors.has(createdAnchor),
+ "Newly created anchor must be in tracked anchors set on subsequent RAF (2)!");
+ });
+
+ anchorController.pauseTracking();
+
+ session.requestAnimationFrame((time_3, frame_3) => {
+ debug("rAF 3");
+
+ t.step(() => {
+ assert_true(frame_3.getPose(createdAnchor.anchorSpace, localRefSpace) == null,
+ "Newly created anchor with paused tracking should not have a pose!");
+ assert_true(frame_3.trackedAnchors.has(createdAnchor),
+ "Newly created anchor with paused tracking must be in tracked anchors set on subsequent RAF (3)!");
+ });
+
+ anchorController.resumeTracking();
+
+ session.requestAnimationFrame((time_4, frame_4) => {
+ debug("rAF 4");
+
+ t.step(() => {
+ assert_true(frame_4.trackedAnchors.has(createdAnchor),
+ "Newly created anchor with resumed tracking must be in tracked anchors set on subsequent RAF (4)!");
+ assert_true(frame_4.getPose(createdAnchor.anchorSpace, localRefSpace) != null,
+ "Newly created anchor with resumed tracking should have a pose!");
+ });
+
+ anchorController.stopTracking();
+
+ session.requestAnimationFrame((time_5, frame_5) => {
+ debug("rAF 5");
+
+ t.step(() => {
+ assert_false(frame_5.trackedAnchors.has(createdAnchor),
+ "Newly created anchor with stopped tracking must not be in tracked anchors set on subsequent RAF (5)!");
+ });
+
+ session.dispatchEvent(watcherDone);
+ });
+ });
+ });
+ });
+ });
+ }); // session.requestReferenceSpace(...).then({...});
+
+ return eventPromise;
+};
+
+
+xr_session_promise_test(
+ "Ensures free-floating anchor state changes get propagated",
+ anchorCreatePauseTrackingResumeAndDelete, fakeDeviceInitParams,
+ 'immersive-ar', sessionInit);
+
+</script>
diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_getAnchors.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_getAnchors.https.html
new file mode 100644
index 0000000000..50664b0a4b
--- /dev/null
+++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_getAnchors.https.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/webxr_util.js"></script>
+<script src="../resources/webxr_test_asserts.js"></script>
+<script src="../resources/webxr_test_constants.js"></script>
+<script src="../resources/webxr_test_constants_fake_world.js"></script>
+
+<script>
+
+// 1m above world origin.
+const VIEWER_ORIGIN_TRANSFORM = {
+ position: [0, 1, 0],
+ orientation: [0, 0, 0, 1],
+};
+
+const fakeDeviceInitParams = {
+ supportedModes: ["immersive-ar"],
+ views: VALID_VIEWS,
+ supportedFeatures: ALL_FEATURES,
+ viewerOrigin: VIEWER_ORIGIN_TRANSFORM,
+};
+
+// Attempts to access XRFrame.trackedAnchors and expects to get empty set
+// since no anchors are being created.
+const testFunction = function(session, fakeDeviceController, t) {
+ const debug = xr_debug.bind(this, 'testGetAnchors');
+
+ let done = false;
+
+ session.requestReferenceSpace('local').then((localRefSpace) => {
+ const onFrame = function(time, frame) {
+ const trackedAnchors = frame.trackedAnchors;
+ t.step(() => {
+ assert_equals(trackedAnchors.size, 0);
+ });
+
+ done = true;
+ };
+
+ session.requestAnimationFrame(onFrame);
+ }); // session.requestReferenceSpace(...)
+
+ return t.step_wait(() => done);
+}; // testFunction
+
+
+xr_session_promise_test("XRFrame's trackedAnchors is empty when the feature was not requested",
+ testFunction,
+ fakeDeviceInitParams,
+ 'immersive-ar', { });
+
+xr_session_promise_test("XRFrame's trackedAnchors is empty when the feature was requested",
+ testFunction,
+ fakeDeviceInitParams,
+ 'immersive-ar', { 'requiredFeatures': ['anchors'] });
+
+</script>
diff --git a/testing/web-platform/tests/webxr/anchors/ar_anchor_states.https.html b/testing/web-platform/tests/webxr/anchors/ar_anchor_states.https.html
new file mode 100644
index 0000000000..8369549852
--- /dev/null
+++ b/testing/web-platform/tests/webxr/anchors/ar_anchor_states.https.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/webxr_util.js"></script>
+<script src="../resources/webxr_test_asserts.js"></script>
+<script src="../resources/webxr_test_constants.js"></script>
+<script src="../resources/webxr_test_constants_fake_world.js"></script>
+
+<script>
+
+// 1m above world origin.
+const VIEWER_ORIGIN_TRANSFORM = {
+ position: [0, 1, 0],
+ orientation: [0, 0, 0, 1],
+};
+
+const fakeDeviceInitParams = {
+ supportedModes: ["immersive-ar"],
+ views: VALID_VIEWS,
+ supportedFeatures: ALL_FEATURES,
+ viewerOrigin: VIEWER_ORIGIN_TRANSFORM,
+};
+
+// Creates a test method that leverages anchors API.
+// |expectSucceeded| - true if the anchors creation request is expected to succeed, false otherwise
+// |endSession| - true if the test case should call session.end() prior to creating an anchor
+// |expectedError| - expected error name that should be returned in case expectSucceeded is false
+const testFunctionGenerator = function(expectSucceeded, endSession, expectedError) {
+
+ const testFunction = function(session, fakeDeviceController, t) {
+
+ const debug = xr_debug.bind(this, 'testAnchorStates');
+
+ fakeDeviceController.setAnchorCreationCallback((parameters, controller) => {
+ // All anchor creation requests that reach this stage should be marked as successful.
+ // If this test is expected to fail, the failure will happen earlier in the anchor
+ // creation process.
+ return Promise.resolve(true);
+ });
+
+ const watcherDone = new Event("watcherdone");
+ const eventWatcher = new EventWatcher(t, session, ["watcherdone"]);
+ const eventPromise = eventWatcher.wait_for(["watcherdone"]);
+
+ session.requestReferenceSpace('local').then((localRefSpace) => {
+
+ const onFrame = function(time, frame) {
+ debug("rAF 1");
+
+ let setUpPromise = Promise.resolve();
+ if(endSession) {
+ debug("ending session");
+ setUpPromise = session.end();
+ }
+
+ setUpPromise.then(() => {
+ debug("creating anchor");
+ frame.createAnchor(new XRRigidTransform(), localRefSpace)
+ .then((anchor) => {
+ debug("anchor created");
+
+ t.step(() => {
+ assert_true(expectSucceeded,
+ "`createAnchor` succeeded when it was expected to fail");
+ });
+
+ session.dispatchEvent(watcherDone);
+ }).catch((error) => {
+ debug("anchor creation failed");
+
+ t.step(() => {
+ assert_false(expectSucceeded,
+ "`createAnchor` failed when it was expected to succeed, error: " + error);
+ assert_equals(error.name, expectedError,
+ "`createAnchor` failed with unexpected error name");
+ });
+
+ session.dispatchEvent(watcherDone);
+ });
+
+ // Anchor result will only take effect with frame data - schedule
+ // a frame after we requested anchor creation, otherwise the test will time out.
+ session.requestAnimationFrame(() => {
+ debug("rAF 2");
+ });
+ }); // setUpPromise.then(() => { ... })
+ }; // onFrame() { ... }
+
+ debug("requesting animation frame");
+ session.requestAnimationFrame(onFrame);
+ }); // session.requestReferenceSpace(...)
+
+ return eventPromise;
+ }; // testFunction
+
+ return testFunction;
+};
+
+xr_session_promise_test("Anchor creation succeeds if the feature was requested",
+ testFunctionGenerator(/*expectSucceeded=*/true, /*endSession=*/false),
+ fakeDeviceInitParams,
+ 'immersive-ar', { 'requiredFeatures': ['anchors'] });
+
+xr_session_promise_test("Anchor creation fails if the feature was not requested",
+ testFunctionGenerator(/*expectSucceeded=*/false, /*endSession=*/false, "NotSupportedError"),
+ fakeDeviceInitParams,
+ 'immersive-ar', {});
+
+xr_session_promise_test("Anchor creation fails if the feature was requested but the session already ended",
+ testFunctionGenerator(/*expectSucceeded=*/false, /*endSession=*/true, "InvalidStateError"),
+ fakeDeviceInitParams,
+ 'immersive-ar', { 'requiredFeatures': ['anchors'] });
+
+</script>
diff --git a/testing/web-platform/tests/webxr/anchors/idlharness.https.window.js b/testing/web-platform/tests/webxr/anchors/idlharness.https.window.js
new file mode 100644
index 0000000000..b69a327229
--- /dev/null
+++ b/testing/web-platform/tests/webxr/anchors/idlharness.https.window.js
@@ -0,0 +1,16 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+// https://immersive-web.github.io/anchors/
+
+idl_test(
+ ['anchors'],
+ ['webxr-hit-test', 'webxr', 'dom'],
+ async idl_array => {
+ idl_array.add_objects({
+ // TODO: Add object instances
+ });
+ }
+);