]>
git.r.bdr.sh - rbdr/serpentity/blob - test/integration.js
1 import Code
from '@hapi/code'; // assertion library
2 import Lab
from '@hapi/lab';
3 import Serpentity
, { Component
, Entity
, Node
, System
} from '../lib/serpentity.js';
7 system: class TestSystem
extends System
{
10 this.testNodes
= engine
.getNodes(internals
.node
);
11 this.addedCalled
= true;
12 this.addedEngine
= engine
;
17 this.testNodes
= null;
18 this.removedCalled
= true;
19 this.removedEngine
= engine
;
24 this.updateCalled
= Date
.now();
27 for (const node
of this.testNodes
) {
28 node
.test
.called
= true;
29 node
.entity
.called
= true;
32 while (Date
.now() === this.updateCalled
) { /* pass some time */ }
35 component: class TestComponent
extends Component
{
43 node: class TestNode
extends Node
{},
47 // adds a component to the node
48 internals
.node
.types
= {
49 test: internals
.component
52 const lab
= Lab
.script({
56 const { beforeEach
, experiment
, test
} = lab
;
57 const { expect
} = Code
;
59 experiment('loading', () => {
61 test('Serpentity should be exported', () => {
63 expect(typeof Serpentity
).to
.not
.be
.undefined();
66 test('Serpentity should include the Entity class', () => {
68 expect(typeof Entity
).to
.not
.be
.undefined();
71 test('Serpentity should include the Component class', () => {
73 expect(typeof Component
).to
.not
.be
.undefined();
76 test('Serpentity should include the System class', () => {
78 expect(typeof System
).to
.not
.be
.undefined();
81 test('Serpentity should include the Node class', () => {
83 expect(typeof Node
).to
.not
.be
.undefined();
86 test('Serpentity should include the NodeCollection class', () => {
88 expect(typeof NodeCollection
).to
.not
.be
.undefined();
92 experiment('Engine Tests', () => {
96 internals
.context
.engine
= new Serpentity();
98 internals
.context
.regularSystem
= new internals
.system();
99 internals
.context
.highPrioritySystem
= new internals
.system();
100 internals
.context
.lowPrioritySystem
= new internals
.system();
102 internals
.context
.firstEntity
= new Entity();
103 internals
.context
.firstEntity
.addComponent(new internals
.component());
104 internals
.context
.secondEntity
= new Entity();
105 internals
.context
.secondEntity
.addComponent(new internals
.component());
106 internals
.context
.emptyEntity
= new Entity();
108 // Add entity before the systems
109 internals
.context
.engine
.addEntity(internals
.context
.firstEntity
);
111 internals
.context
.engine
.addSystem(internals
.context
.regularSystem
, 100);
112 internals
.context
.engine
.addSystem(internals
.context
.highPrioritySystem
, 0);
113 internals
.context
.engine
.addSystem(internals
.context
.lowPrioritySystem
, 1000);
115 // Add entity after the systems
116 internals
.context
.engine
.addEntity(internals
.context
.secondEntity
);
117 internals
.context
.engine
.addEntity(internals
.context
.emptyEntity
);
120 test('Engine should call added callback on added systems', () => {
122 // Ensure the added callback is being called
123 expect(internals
.context
.regularSystem
.addedCalled
).to
.be
.true();
124 expect(internals
.context
.highPrioritySystem
.addedCalled
).to
.be
.true();
125 expect(internals
.context
.lowPrioritySystem
.addedCalled
).to
.be
.true();
128 test('Engine should send the engine instance in added callback', () => {
130 // Ensure the added callback is sending the engine
131 expect(internals
.context
.regularSystem
.addedEngine
instanceof Serpentity
).to
.be
.true();
132 expect(internals
.context
.highPrioritySystem
.addedEngine
instanceof Serpentity
).to
.be
.true();
133 expect(internals
.context
.lowPrioritySystem
.addedEngine
instanceof Serpentity
).to
.be
.true();
136 test('Engine should not add duplicate systems', () => {
138 const originalSystemsLength
= internals
.context
.engine
.systems
.length
;
139 const added
= internals
.context
.engine
.addSystem(internals
.context
.regularSystem
, 0);
140 const newSystemsLength
= internals
.context
.engine
.systems
.length
;
142 // Ensure we don't add the same system twice
143 expect(added
).to
.be
.false();
144 expect(originalSystemsLength
).to
.be
.equal(newSystemsLength
);
147 test('Engine should call update callback on added systems', () => {
149 internals
.context
.engine
.update(internals
.delta
);
151 // Ensure update function called
152 expect(!!internals
.context
.regularSystem
.updateCalled
).to
.be
.true();
153 expect(!!internals
.context
.highPrioritySystem
.updateCalled
).to
.be
.true();
154 expect(!!internals
.context
.lowPrioritySystem
.updateCalled
).to
.be
.true();
157 test('Engine should call update callback in the order of priorities', () => {
159 internals
.context
.engine
.update(internals
.delta
);
161 // Ensure order of priorities
162 expect(internals
.context
.regularSystem
.updateCalled
).to
.be
.lessThan(internals
.context
.lowPrioritySystem
.updateCalled
);
163 expect(internals
.context
.regularSystem
.updateCalled
).to
.be
.greaterThan(internals
.context
.highPrioritySystem
.updateCalled
);
166 test('Engine should send the delta in the update callback', () => {
168 internals
.context
.engine
.update(internals
.delta
);
170 // Ensure delta is being sent
171 expect(internals
.context
.regularSystem
.updateDt
).to
.be
.equal(internals
.delta
);
172 expect(internals
.context
.highPrioritySystem
.updateDt
).to
.be
.equal(internals
.delta
);
173 expect(internals
.context
.lowPrioritySystem
.updateDt
).to
.be
.equal(internals
.delta
);
176 test('System remove callback', () => {
178 const originalSystemLength
= internals
.context
.engine
.systems
.length
;
179 const originalRemoved
= internals
.context
.engine
.removeSystem(internals
.context
.lowPrioritySystem
);
180 const intermediateSystemLength
= internals
.context
.engine
.systems
.length
;
181 const finalRemoved
= internals
.context
.engine
.removeSystem(internals
.context
.lowPrioritySystem
);
182 const finalSystemLength
= internals
.context
.engine
.systems
.length
;
183 internals
.context
.engine
.update(internals
.delta
);
185 // Check for return value
186 expect(originalRemoved
).to
.be
.true();
187 expect(finalRemoved
).to
.be
.false();
189 // Confirm that only removed if found by checking length of systems
191 expect(originalSystemLength
).to
.be
.above(intermediateSystemLength
);
192 expect(finalSystemLength
).to
.be
.equal(intermediateSystemLength
);
194 // Ensure callback is sent
195 expect(!!internals
.context
.regularSystem
.removedCalled
).to
.be
.false();
196 expect(!!internals
.context
.highPrioritySystem
.removedCalled
).to
.be
.false();
197 expect(!!internals
.context
.lowPrioritySystem
.removedCalled
).to
.be
.true();
199 // Ensure update is no longer sent
200 expect(!!internals
.context
.regularSystem
.updateCalled
).to
.be
.true();
201 expect(!!internals
.context
.highPrioritySystem
.updateCalled
).to
.be
.true();
202 expect(!!internals
.context
.lowPrioritySystem
.updateCalled
).to
.be
.false();
205 test('Entity node selection', () => {
207 internals
.context
.engine
.update(internals
.delta
);
209 // Ensure component is called for each entity
210 expect(!!internals
.context
.firstEntity
._components
[0].called
).to
.be
.true();
211 expect(!!internals
.context
.secondEntity
._components
[0].called
).to
.be
.true();
213 // Ensure entity not in node collection not called
214 expect(!!internals
.context
.firstEntity
.called
).to
.be
.true();
215 expect(!!internals
.context
.secondEntity
.called
).to
.be
.true();
216 expect(!!internals
.context
.emptyEntity
.called
).to
.be
.false();
219 test('Entity node removal', () => {
221 internals
.context
.engine
.removeEntity(internals
.context
.secondEntity
);
222 internals
.context
.engine
.update(internals
.delta
);
224 expect(!!internals
.context
.firstEntity
._components
[0].called
).to
.be
.true();
225 expect(!!internals
.context
.secondEntity
._components
[0].called
).to
.be
.false();
227 expect(!!internals
.context
.firstEntity
.called
).to
.be
.true();
228 expect(!!internals
.context
.secondEntity
.called
).to
.be
.false();
229 expect(!!internals
.context
.emptyEntity
.called
).to
.be
.false();
232 test('Entity should not add duplicate components', () => {
234 const originalComponentsLength
= internals
.context
.secondEntity
._components
.length
;
235 const result
= internals
.context
.secondEntity
.addComponent(new internals
.component());
236 const newComponentsLength
= internals
.context
.secondEntity
._components
.length
;
238 expect(result
).to
.be
.false();
239 expect(originalComponentsLength
).to
.be
.equal(newComponentsLength
);
242 test('Entity should allow access to components by class', () => {
244 const firstComponent
= internals
.context
.firstEntity
.getComponent(internals
.component
);
245 const emptyComponent
= internals
.context
.emptyEntity
.getComponent(internals
.component
);
247 expect(firstComponent
instanceof internals
.component
).to
.be
.true();
248 expect(emptyComponent
).to
.be
.equal(undefined);
251 test('Engine should not add duplicate entities', () => {
253 const originalEntitiesLength
= internals
.context
.engine
.entities
.length
;
254 const added
= internals
.context
.engine
.addEntity(internals
.context
.firstEntity
);
255 const finalEntitiesLength
= internals
.context
.engine
.entities
.length
;
257 expect(added
).to
.be
.false();
259 expect(originalEntitiesLength
).to
.be
.equal(finalEntitiesLength
);
262 test('Engine should remove entities', () => {
264 const originalEntityLength
= internals
.context
.engine
.entities
.length
;
265 const originalRemoved
= internals
.context
.engine
.removeEntity(internals
.context
.firstEntity
);
266 const intermediateEntityLength
= internals
.context
.engine
.entities
.length
;
267 const finalRemoved
= internals
.context
.engine
.removeEntity(internals
.context
.firstEntity
);
268 const finalEntityLength
= internals
.context
.engine
.entities
.length
;
269 internals
.context
.engine
.update(internals
.delta
);
271 // Check for return value
272 expect(originalRemoved
).to
.be
.true();
273 expect(finalRemoved
).to
.be
.false();
275 // Confirm that only removed if found by checking length of systems
277 expect(originalEntityLength
).to
.be
.above(intermediateEntityLength
);
278 expect(finalEntityLength
).to
.be
.equal(intermediateEntityLength
);
280 // Ensure callback is sent
281 expect(!!internals
.context
.firstEntity
.called
).to
.be
.false();
282 expect(!!internals
.context
.secondEntity
.called
).to
.be
.true();
286 Lab
.report(lab
).then((result
) => process
.exit(result
.code
));