| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <title><model> state transitions</title> |
| <script src="../resources/testharness.js"></script> |
| <script src="../resources/testharnessreport.js"></script> |
| <script src="resources/model-element-test-utils.js"></script> |
| <script src="resources/model-utils.js"></script> |
| <style> |
| .spacer { |
| height: 200vh; |
| } |
| .model-element { |
| width: 300px; |
| height: 300px; |
| } |
| </style> |
| <body> |
| <div class="spacer"></div> |
| <script> |
| 'use strict'; |
| |
| promise_test(async t => { |
| const [model, source] = createModelAndSource(t, "resources/heart.usdz"); |
| model.className = "model-element"; |
| assert_equals(internals.modelElementState(model), "Deferred"); |
| assert_false(internals.isModelElementIntersectingViewport(model)); |
| |
| scrollElementIntoView(model); |
| |
| await waitForModelState(model, "Loaded"); |
| assert_true(internals.isModelElementIntersectingViewport(model)); |
| |
| window.scrollTo(0, 0) |
| |
| await waitForModelState(model, "Unloaded"); |
| assert_false(internals.isModelElementIntersectingViewport(model)); |
| }, `<model> main load/unload transitions`); |
| |
| promise_test(async t => { |
| const [model, source] = createModelAndSource(t, "resources/heart.usdz"); |
| model.className = "model-element"; |
| assert_equals(internals.modelElementState(model), "Deferred"); |
| assert_false(internals.isModelElementIntersectingViewport(model)); |
| |
| scrollElementIntoView(model); |
| |
| const intermediateState = internals.modelElementState(model); |
| assert_true(intermediateState !== "Loaded"); |
| |
| window.scrollTo(0, 0) |
| |
| await waitForModelState(model, "Deferred"); |
| assert_false(internals.isModelElementIntersectingViewport(model)); |
| }, `<model> jump back to deferred when quickly scrolled through`); |
| |
| promise_test(async t => { |
| const [model, source] = createModelAndSource(t, "resources/does-not-exist.usdz"); |
| model.className = "model-element"; |
| assert_equals(internals.modelElementState(model), "Deferred"); |
| assert_false(internals.isModelElementIntersectingViewport(model)); |
| |
| scrollElementIntoView(model); |
| await sleepForSeconds(2.0); |
| |
| const failedState = internals.modelElementState(model); |
| assert_true(failedState !== "Loading" && failedState !== "Loaded", "Model should not be loaded"); |
| assert_true(internals.isModelElementIntersectingViewport(model)); |
| return model.ready.then( |
| value => assert_unreached("Unexpected ready promise resolution."), |
| reason => assert_true(reason.toString().includes("NetworkError"), "The ready promise is rejected with a NetworkError.") |
| ); |
| }, `<model> invalid state if usdz does not exist`); |
| |
| promise_test(async t => { |
| const [model, source] = createModelAndSource(t, "resources/error-case.usdz"); |
| model.className = "model-element"; |
| assert_equals(internals.modelElementState(model), "Deferred"); |
| assert_false(internals.isModelElementIntersectingViewport(model)); |
| |
| scrollElementIntoView(model); |
| await sleepForSeconds(2.0); |
| |
| const failedState = internals.modelElementState(model); |
| |
| assert_true(failedState !== "Loaded", "Model should not be loaded"); |
| assert_true(internals.isModelElementIntersectingViewport(model)); |
| return model.ready.then( |
| value => assert_unreached("Unexpected ready promise resolution."), |
| reason => assert_true(reason.toString().includes("AbortError"), "The ready promise is rejected with an AbortError.") |
| ); |
| }, `<model> invalid state for incorrect usdz file`); |
| |
| promise_test(async t => { |
| const [model, source] = createModelAndSource(t, "resources/heart.usdz"); |
| model.className = "model-element"; |
| assert_equals(internals.modelElementState(model), "Deferred"); |
| assert_false(internals.isModelElementIntersectingViewport(model)); |
| |
| scrollElementIntoView(model); |
| await model.ready; |
| |
| source.src = "resources/cube.usdz"; |
| await model.ready; |
| }, `<model> reload visible model after source change`); |
| |
| promise_test(async t => { |
| const [model, source] = createModelAndSource(t, "resources/heart.usdz"); |
| model.className = "model-element"; |
| model.setAttribute("stage-mode", "orbit"); |
| |
| scrollElementIntoView(model); |
| await waitForModelState(model, "Loaded"); |
| assert_true(internals.isModelElementIntersectingViewport(model), "first load viewport check"); |
| |
| await sleepForSeconds(0.5); // make sure entityTransform is synced |
| const firstLoadTransform = model.entityTransform; |
| assert_not_equals(firstLoadTransform, null, "entityTransform should not be null after first load"); |
| |
| window.scrollTo(0, 0); |
| await waitForModelState(model, "Unloaded"); |
| assert_false(internals.isModelElementIntersectingViewport(model), "first unload viewport check"); |
| |
| scrollElementIntoView(model); |
| await waitForModelState(model, "Loaded"); |
| assert_true(internals.isModelElementIntersectingViewport(model), "second load viewport check"); |
| |
| await sleepForSeconds(0.5); // make sure entityTransform is synced |
| const secondLoadTransform = model.entityTransform; |
| assert_not_equals(secondLoadTransform, null, "entityTransform should not be null after second load"); |
| assert_equals(firstLoadTransform.toString(), secondLoadTransform.toString(), "entityTransform should be preserved after second load"); |
| |
| window.scrollTo(0, 0); |
| await waitForModelState(model, "Unloaded"); |
| assert_false(internals.isModelElementIntersectingViewport(model), "second unload viewport check"); |
| |
| scrollElementIntoView(model); |
| await waitForModelState(model, "Loaded"); |
| assert_true(internals.isModelElementIntersectingViewport(model), "third load viewport check"); |
| |
| await sleepForSeconds(0.5); // make sure entityTransform is synced |
| const thirdLoadTransform = model.entityTransform; |
| assert_not_equals(thirdLoadTransform, null, "entityTransform should not be null after third load"); |
| assert_equals(firstLoadTransform.toString(), thirdLoadTransform.toString(), "entityTransform should be preserved after third load"); |
| |
| }, `<model> stage-mode orbit survives multiple unload-reload cycles`); |
| |
| </script> |
| </body> |