| <!DOCTYPE html> <!-- webkit-test-runner [ ModelElementEnabled=true ] --> |
| <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", 10000); |
| 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); |
| |
| const reason = await model.ready.then( |
| value => assert_unreached("Unexpected ready promise resolution."), |
| ).catch(e => e); |
| assert_true(reason.toString().includes("AbortError"), "The ready promise is rejected with an AbortError."); |
| |
| const failedState = internals.modelElementState(model); |
| assert_true(failedState !== "Loaded", `Model should not be loaded after failure, got: ${failedState}`); |
| }, `<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"); |
| |
| const firstLoadTransform = await waitForEntityTransform(model); |
| assert_not_equals(firstLoadTransform, null, "entityTransform should not be null after first load"); |
| |
| window.scrollTo(0, 0); |
| await waitForModelState(model, "Unloaded", 10000); |
| assert_false(internals.isModelElementIntersectingViewport(model), "first unload viewport check"); |
| |
| scrollElementIntoView(model); |
| await waitForModelState(model, "Loaded"); |
| assert_true(internals.isModelElementIntersectingViewport(model), "second load viewport check"); |
| |
| const secondLoadTransform = await waitForEntityTransform(model); |
| 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", 10000); |
| assert_false(internals.isModelElementIntersectingViewport(model), "second unload viewport check"); |
| |
| scrollElementIntoView(model); |
| await waitForModelState(model, "Loaded"); |
| assert_true(internals.isModelElementIntersectingViewport(model), "third load viewport check"); |
| |
| const thirdLoadTransform = await waitForEntityTransform(model); |
| 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`); |
| |
| promise_test(async t => { |
| const [model, source] = createModelAndSource(t, "resources/heart.usdz"); |
| model.className = "model-element"; |
| |
| scrollElementIntoView(model); |
| await waitForModelState(model, "Loaded"); |
| await model.ready; |
| |
| const loadedTransform = model.entityTransform.rotate(0, 45, 0).scale(2, 2, 2); |
| model.entityTransform = loadedTransform; |
| assert_3d_matrix_equals(model.entityTransform, loadedTransform); |
| |
| window.scrollTo(0, 0); |
| await waitForModelState(model, "Unloaded", 10000); |
| |
| const unloadedTransform = model.entityTransform.translate(0, 0, -10).rotate(0, 30, 0).scale(0.5, 0.5, 0.5); |
| model.entityTransform = unloadedTransform; |
| assert_3d_matrix_equals(model.entityTransform, unloadedTransform); |
| |
| scrollElementIntoView(model); |
| await waitForModelState(model, "Loaded"); |
| await sleepForSeconds(0.1); |
| |
| assert_3d_matrix_equals(model.entityTransform, unloadedTransform); |
| }, `<model> entityTransform can be set while unloaded`); |
| |
| </script> |
| </body> |
| |