blob: 9691e7ee8a5a54a8c00d83a7bba71842f305f031 [file] [edit]
<!DOCTYPE html> <!-- webkit-test-runner [ SpatialPortalEnabled=true ModelElementEnabled=true ModelProcessEnabled=true allowTestOnlyIPC=true ] -->
<html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="../model-element/resources/model-utils.js"></script>
<script src="resources/spatial-portal-utils.js"></script>
<style>
.portal { spatial: portal; width: 400px; height: 300px; }
</style>
<body>
<script>
'use strict';
window.internals?.disableModelLoadDelaysForTesting();
const asset = "2x2x2-center.usdz";
const settledAnchor = (model, expected, description) =>
waitFor(() => internals.spatialPortalAnchorForModel(model) === expected, description);
async function anchoredPair(test, { positionAnchor = "--host" } = {}) {
const portal = createPortal(test);
const host = appendModel(portal, asset);
host.id = "host";
host.style.anchorName = "--host";
const child = appendModel(portal, asset);
child.id = "child";
child.style.positionAnchor = positionAnchor;
child.style.positionContext = "anchor";
await Promise.all([host.ready, child.ready]);
return { portal, host, child };
}
promise_test(async t => {
const { portal, host, child } = await anchoredPair(t);
await settledAnchor(child, host, "the child resolves to the host");
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.element, "#host", "the child's entity is reparented under the host's");
assert_equals(internals.spatialPortalAnchorForModel(host), null, "the host is not itself anchored");
}, `position-anchor with position-context: anchor resolves to the named model`);
promise_test(async t => {
const { portal, host, child } = await anchoredPair(t, { positionAnchor: "--host#Cube" });
await settledAnchor(child, host, "the child resolves to the host");
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.name, "Cube", "the child's entity is reparented under the placement");
child.style.positionAnchor = "--host#missing";
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.element, "#host", "an unknown placement falls back to the host's root");
}, `an anchor name with a placement resolves to the same model`);
promise_test(async t => {
const { portal, host, child } = await anchoredPair(t);
await settledAnchor(child, host, "anchored");
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.element, "#host", "the child's entity is under the host's");
child.style.positionAnchor = "";
await settledAnchor(child, null, "un-anchored");
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.name, "WebKit:PortalContainer", "the child's entity is back under the container");
}, `clearing position-anchor removes the anchor`);
promise_test(async t => {
const portal = createPortal(t);
const child = appendModel(portal, asset);
child.id = "child";
child.style.positionAnchor = "--later";
child.style.positionContext = "anchor";
const host = appendModel(portal, asset);
host.id = "host";
host.style.anchorName = "--later";
await Promise.all([host.ready, child.ready]);
await settledAnchor(child, host, "the child resolves to a host declared after it");
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.element, "#host", "the child's entity is reparented under the host's");
}, `an anchor declared after the anchored model still resolves`);
promise_test(async t => {
const portal = createPortal(t);
const first = appendModel(portal, asset);
first.id = "first";
first.style.anchorName = "--first";
const middle = appendModel(portal, asset);
middle.id = "middle";
middle.style.anchorName = "--middle";
middle.style.positionAnchor = "--first";
middle.style.positionContext = "anchor";
const last = appendModel(portal, asset);
last.id = "last";
last.style.positionAnchor = "--middle";
last.style.positionContext = "anchor";
await Promise.all([first.ready, middle.ready, last.ready]);
await settledAnchor(middle, first, "middle resolves to first");
await settledAnchor(last, middle, "last resolves to middle");
const entities = await modelSceneGraph(portal);
assert_equals(parentOfElement(entities, "#middle")?.element, "#first", "middle's entity is under first's");
assert_equals(parentOfElement(entities, "#last")?.element, "#middle", "last's entity is under middle's");
}, `a chain of anchors resolves at every step`);
promise_test(async t => {
const portal = createPortal(t);
const first = appendModel(portal, asset);
first.id = "first";
first.style.anchorName = "--host";
const second = appendModel(portal, asset);
second.id = "second";
second.style.anchorName = "--host";
const child = appendModel(portal, asset);
child.id = "child";
child.style.positionAnchor = "--host";
child.style.positionContext = "anchor";
await Promise.all([first.ready, second.ready, child.ready]);
await settledAnchor(child, second, "the child resolves to the last host in tree order");
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.element, "#second", "the child's entity is under the last host's");
portal.insertBefore(second, first);
await settledAnchor(child, first, "the child follows the hosts' new tree order");
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.element, "#first", "the child's entity moves under the new last host's");
}, `the last <model> in tree order wins when several declare the same anchor-name`);
promise_test(async t => {
const portal = createPortal(t);
const host = appendModel(portal, asset);
host.id = "host";
host.style.anchorName = "--host";
const child = appendModel(portal, asset);
child.id = "child";
child.style.anchorName = "--host";
child.style.positionAnchor = "--host";
child.style.positionContext = "anchor";
await Promise.all([host.ready, child.ready]);
await settledAnchor(child, host, "the child skips itself and resolves to the host");
assert_equals(parentOfElement(await modelSceneGraph(portal), "#child")?.element, "#host", "the child's entity is under the host's");
}, `a <model> anchored to an anchor-name it also declares resolves to the previous <model> with that name`);
</script>
</body>
</html>