@google/model-viewer
Version:
Easily display interactive 3D models on the web and in AR!
204 lines (156 loc) • 6.7 kB
text/typescript
/*
* Copyright 2018 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {LoadingMixin} from '../../../features/loading.js';
import {FINISHED_LOADING_ANNOUNCEMENT, INITIAL_STATUS_ANNOUNCEMENT, LoadingStatusAnnouncer} from '../../../features/loading/status-announcer.js';
import ModelViewerElementBase from '../../../model-viewer-base.js';
import {assetPath, isInDocumentTree, until, waitForEvent} from '../../helpers.js';
const expect = chai.expect;
suite('LoadingStatusAnnouncer', () => {
let nextId = 0;
let tagName: string;
let ModelViewerElement: any;
let loadingStatusAnnouncer: LoadingStatusAnnouncer;
setup(() => {
tagName = `model-viewer-loading-announcer-${nextId++}`;
ModelViewerElement = class extends LoadingMixin
(ModelViewerElementBase) {
static get is() {
return tagName;
}
};
customElements.define(tagName, ModelViewerElement);
loadingStatusAnnouncer = new LoadingStatusAnnouncer();
});
suite('when a model is registered', () => {
let element: any;
setup(() => {
element = new ModelViewerElement();
document.body.appendChild(element);
});
teardown(() => {
document.body.removeChild(element);
});
suite('that has a src', () => {
test('sets initial status', async () => {
element.poster = assetPath('Astronaut.png');
element.src = assetPath('Astronaut.glb');
loadingStatusAnnouncer.registerInstance(element);
await waitForEvent(loadingStatusAnnouncer, 'initial-status-announced');
const {statusElement} = loadingStatusAnnouncer;
expect(statusElement.textContent)
.to.be.equal(INITIAL_STATUS_ANNOUNCEMENT);
});
suite('after the model loads', () => {
test('sets the finished status', async () => {
element.src = assetPath('Astronaut.glb');
loadingStatusAnnouncer.registerInstance(element);
await Promise.all([
until(() => element.loaded),
waitForEvent(loadingStatusAnnouncer, 'finished-loading-announced')
]);
const {statusElement} = loadingStatusAnnouncer;
expect(statusElement.textContent)
.to.be.equal(FINISHED_LOADING_ANNOUNCEMENT);
});
});
suite('there are other registered models', () => {
let otherElement: any;
setup(() => {
otherElement = new ModelViewerElement();
document.body.appendChild(otherElement);
});
teardown(() => {
document.body.removeChild(otherElement);
});
test('sets finished status when all models are loaded', async () => {
element.src = otherElement.src = assetPath('Astronaut.glb');
loadingStatusAnnouncer.registerInstance(element);
loadingStatusAnnouncer.registerInstance(otherElement);
await Promise.all([
until(() => element.loaded && otherElement.loaded),
waitForEvent(loadingStatusAnnouncer, 'finished-loading-announced')
]);
const {statusElement} = loadingStatusAnnouncer;
expect(statusElement.textContent)
.to.be.equal(FINISHED_LOADING_ANNOUNCEMENT);
});
suite('one model is already loaded', () => {
test('eventually sets finished status', async () => {
element.src = assetPath('Astronaut.glb');
await until(() => element.loaded);
otherElement.src = assetPath('Astronaut.glb');
loadingStatusAnnouncer.registerInstance(element);
loadingStatusAnnouncer.registerInstance(otherElement);
await Promise.all([
until(() => otherElement.loaded),
waitForEvent(loadingStatusAnnouncer, 'finished-loading-announced')
]);
const {statusElement} = loadingStatusAnnouncer;
expect(statusElement.textContent)
.to.be.equal(FINISHED_LOADING_ANNOUNCEMENT);
});
});
suite('one model fails', () => {
test('eventually sets finished status', async () => {
const errorOccurs = waitForEvent(element, 'error');
element.src = assetPath('DOES_NOT_EXIST.glb');
otherElement.src = assetPath('Astronaut.glb');
loadingStatusAnnouncer.registerInstance(element);
loadingStatusAnnouncer.registerInstance(otherElement);
await Promise.all([
errorOccurs,
until(() => otherElement.loaded),
waitForEvent(loadingStatusAnnouncer, 'finished-loading-announced')
]);
const {statusElement} = loadingStatusAnnouncer;
expect(statusElement.textContent)
.to.be.equal(FINISHED_LOADING_ANNOUNCEMENT);
});
});
});
});
});
suite('many elements and first one is removed', () => {
let element: ModelViewerElementBase;
let otherElement: ModelViewerElementBase;
setup(() => {
// NOTE(cdata): We use ModelViewerElementBase here because we are
// testing behavior that is affected by connected/disconnected
// side-effects in LoadingMixin.
element = new ModelViewerElementBase();
otherElement = new ModelViewerElementBase();
document.body.appendChild(element);
document.body.appendChild(otherElement);
});
teardown(() => {
if (element.parentNode != null) {
document.body.removeChild(element);
}
if (otherElement.parentNode != null) {
document.body.removeChild(otherElement);
}
});
test('status element remains in the document tree', async () => {
const {statusElement} = loadingStatusAnnouncer;
loadingStatusAnnouncer.registerInstance(element);
expect(isInDocumentTree(statusElement)).to.be.equal(true);
loadingStatusAnnouncer.registerInstance(otherElement);
loadingStatusAnnouncer.unregisterInstance(element);
document.body.removeChild(element);
expect(isInDocumentTree(statusElement)).to.be.equal(true);
document.body.removeChild(otherElement);
});
});
});