From 924dc00ecf483c1cd21c01bcadaf53d95911155d Mon Sep 17 00:00:00 2001 From: Diego Marcos Segura Date: Thu, 23 Nov 2023 01:40:43 -0500 Subject: [PATCH] Fix issue when the el.hasLoaded flag can be true but not all components have initialized. A init method of a component might check the flag and assume all components have initialized --- src/core/a-entity.js | 4 ++-- src/core/a-node.js | 2 +- src/core/component.js | 2 +- tests/components/animation.test.js | 2 +- tests/components/line.test.js | 5 ++--- tests/components/vive-controls.test.js | 2 +- tests/core/a-entity.test.js | 23 ++++++++++++++++++++++- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/core/a-entity.js b/src/core/a-entity.js index 27fbb798721..014bee38a2f 100644 --- a/src/core/a-entity.js +++ b/src/core/a-entity.js @@ -404,7 +404,7 @@ class AEntity extends ANode { var name; var componentsToUpdate = this.componentsToUpdate; - if (!this.hasLoaded) { return; } + if (!this.hasLoaded && !this.sceneEl) { return; } // Gather mixin-defined components. for (i = 0; i < this.mixinEls.length; i++) { @@ -511,7 +511,7 @@ class AEntity extends ANode { var key; // Already playing. - if (this.isPlaying || !this.hasLoaded) { return; } + if (this.isPlaying || (!this.hasLoaded && !this.sceneEl)) { return; } this.isPlaying = true; // Wake up all components. diff --git a/src/core/a-node.js b/src/core/a-node.js index 45ea3801de0..eee93e8026e 100644 --- a/src/core/a-node.js +++ b/src/core/a-node.js @@ -145,9 +145,9 @@ class ANode extends HTMLElement { } }); - self.hasLoaded = true; self.setupMutationObserver(); if (cb) { cb(); } + self.hasLoaded = true; self.emit('loaded', undefined, false); }); } diff --git a/src/core/component.js b/src/core/component.js index a179cca48fa..4c068b15aac 100644 --- a/src/core/component.js +++ b/src/core/component.js @@ -278,7 +278,7 @@ Component.prototype = { // Just cache the attribute if the entity has not loaded // Components are not initialized until the entity has loaded - if (!el.hasLoaded) { + if (!el.hasLoaded && !el.sceneEl) { this.updateCachedAttrValue(attrValue); return; } diff --git a/tests/components/animation.test.js b/tests/components/animation.test.js index 0f93bc9b23c..c1d6678da3a 100644 --- a/tests/components/animation.test.js +++ b/tests/components/animation.test.js @@ -10,7 +10,6 @@ suite('animation', function () { setup(function (done) { this.done = false; el = entityFactory(); - el.setAttribute('animation', ''); el.addEventListener('componentinitialized', function handler (evt) { if (evt.detail.name !== 'animation' || this.done) { return; } component = el.components.animation; @@ -18,6 +17,7 @@ suite('animation', function () { el.removeEventListener('componentinitialized', handler); done(); }); + el.setAttribute('animation', ''); }); suite('basic animation', () => { diff --git a/tests/components/line.test.js b/tests/components/line.test.js index 63468d213ce..3abaa1edb92 100644 --- a/tests/components/line.test.js +++ b/tests/components/line.test.js @@ -9,9 +9,6 @@ suite('line', function () { setup(function (done) { var count = 0; el = this.el = entityFactory(); - el.setAttribute('line', ''); - el.setAttribute('line__suffix', ''); - if (el.hasLoaded) { done(); } el.addEventListener('componentinitialized', function (evt) { if (evt.detail.name !== 'line' && evt.detail.name !== 'line__suffix') { return; } @@ -22,6 +19,8 @@ suite('line', function () { done(); } }); + el.setAttribute('line', ''); + el.setAttribute('line__suffix', ''); }); suite('init', function () { diff --git a/tests/components/vive-controls.test.js b/tests/components/vive-controls.test.js index cc514e64704..39955c93575 100644 --- a/tests/components/vive-controls.test.js +++ b/tests/components/vive-controls.test.js @@ -17,7 +17,7 @@ suite('vive-controls', function () { controlsSystem = el.sceneEl.systems['tracked-controls-webvr']; done(); }); - el.setAttribute('vive-controls', 'hand: right; model: false'); // To ensure index = 0. + el.setAttribute('vive-controls', 'hand: right; model: true'); // To ensure index = 0. }); suite('checkIfControllerPresent', function () { diff --git a/tests/core/a-entity.test.js b/tests/core/a-entity.test.js index 08eb0811cfd..db1e688ad4d 100644 --- a/tests/core/a-entity.test.js +++ b/tests/core/a-entity.test.js @@ -121,6 +121,27 @@ suite('a-entity', function () { } }); + test('entity has not loaded until all components have loaded', function (done) { + const parentEl = el; + const el2 = document.createElement('a-entity'); + registerComponent('test', { + schema: {array: {type: 'array'}}, + init: function () { + assert.notOk(this.el.hasLoaded); + this.el.addEventListener('loaded', function () { + assert.ok(el2.components.geometry); + assert.ok(el2.components.material); + assert.ok(el2.components.test); + done(); + }); + } + }); + el2.setAttribute('geometry', 'primitive:plane'); + el2.setAttribute('test', ''); + el2.setAttribute('material', 'color:blue'); + parentEl.appendChild(el2); + }); + suite('attachedCallback', function () { test('initializes 3D object', function (done) { elFactory().then(el => { @@ -169,7 +190,7 @@ suite('a-entity', function () { this.sinon.spy(AEntity.prototype, 'play'); el2.addEventListener('play', function () { - assert.ok(el2.hasLoaded); + assert.ok(!el2.hasLoaded && el2.sceneEl); sinon.assert.called(AEntity.prototype.play); done(); });