]>
git.r.bdr.sh - rbdr/serpentity/blob - test/integration.js
1 import { describe
, it
, beforeEach
} from 'node:test';
2 import assert
from 'node:assert';
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
;
13 super.added(); // not needed, but takes care of coverage :P
18 this.testNodes
= null;
19 this.removedCalled
= true;
20 this.removedEngine
= engine
;
21 super.removed(); // not needed, but takes care of coverage :P
26 this.updateCalled
= Date
.now();
29 for (const node
of this.testNodes
) {
30 node
.test
.called
= true;
31 node
.entity
.called
= true;
34 while (Date
.now() === this.updateCalled
) { /* pass some time */ }
35 super.update(); // not needed, but takes care of coverage :P
38 component: class TestComponent
extends Component
{
46 node: class TestNode
extends Node
{},
50 // adds a component to the node
51 internals
.node
.types
= {
52 test: internals
.component
55 describe('Loading', () => {
57 it('Should export the main class', () => {
59 assert(typeof Serpentity
=== 'function');
62 it('Should export the Entity class', () => {
64 assert(typeof Entity
=== 'function');
67 it('Should export the Component class', () => {
69 assert(typeof Component
=== 'function');
72 it('Should export the System class', () => {
74 assert(typeof System
=== 'function');
77 it('Should export the Node class', () => {
79 assert(typeof Node
=== 'function');
83 describe('Engine', () => {
87 internals
.context
.engine
= new Serpentity();
89 internals
.context
.regularSystem
= new internals
.system();
90 internals
.context
.highPrioritySystem
= new internals
.system();
91 internals
.context
.lowPrioritySystem
= new internals
.system();
93 internals
.context
.firstEntity
= new Entity();
94 internals
.context
.firstEntity
.addComponent(new internals
.component());
95 internals
.context
.secondEntity
= new Entity();
96 internals
.context
.secondEntity
.addComponent(new internals
.component());
97 internals
.context
.emptyEntity
= new Entity();
99 // Add entity before the systems
100 internals
.context
.engine
.addEntity(internals
.context
.firstEntity
);
102 internals
.context
.engine
.addSystem(internals
.context
.regularSystem
, 100);
103 internals
.context
.engine
.addSystem(internals
.context
.highPrioritySystem
, 0);
104 internals
.context
.engine
.addSystem(internals
.context
.lowPrioritySystem
, 1000);
106 // Add entity after the systems
107 internals
.context
.engine
.addEntity(internals
.context
.secondEntity
);
108 internals
.context
.engine
.addEntity(internals
.context
.emptyEntity
);
111 it('should call added callback on added systems', () => {
113 // Ensure the added callback is being called
114 assert(internals
.context
.regularSystem
.addedCalled
);
115 assert(internals
.context
.highPrioritySystem
.addedCalled
);
116 assert(internals
.context
.lowPrioritySystem
.addedCalled
);
119 it('should send the engine instance in added callback', () => {
121 // Ensure the added callback is sending the engine
122 assert(internals
.context
.regularSystem
.addedEngine
instanceof Serpentity
);
123 assert(internals
.context
.highPrioritySystem
.addedEngine
instanceof Serpentity
);
124 assert(internals
.context
.lowPrioritySystem
.addedEngine
instanceof Serpentity
);
127 it('should not add duplicate systems', () => {
129 const originalSystemsLength
= internals
.context
.engine
.systems
.length
;
130 const added
= internals
.context
.engine
.addSystem(internals
.context
.regularSystem
, 0);
131 const newSystemsLength
= internals
.context
.engine
.systems
.length
;
133 // Ensure we don't add the same system twice
135 assert
.deepEqual(newSystemsLength
, originalSystemsLength
);
138 it('should call update callback on added systems', () => {
140 internals
.context
.engine
.update(internals
.delta
);
142 // Ensure update function called
143 assert(!!internals
.context
.regularSystem
.updateCalled
);
144 assert(!!internals
.context
.highPrioritySystem
.updateCalled
);
145 assert(!!internals
.context
.lowPrioritySystem
.updateCalled
);
148 it('should call update callback in the order of priorities', () => {
150 internals
.context
.engine
.update(internals
.delta
);
152 // Ensure order of priorities
153 assert(internals
.context
.regularSystem
.updateCalled
< internals
.context
.lowPrioritySystem
.updateCalled
);
154 assert(internals
.context
.regularSystem
.updateCalled
> internals
.context
.highPrioritySystem
.updateCalled
);
157 it('should send the delta in the update callback', () => {
159 internals
.context
.engine
.update(internals
.delta
);
161 // Ensure delta is being sent
162 assert
.deepEqual(internals
.context
.regularSystem
.updateDt
, internals
.delta
);
163 assert
.deepEqual(internals
.context
.highPrioritySystem
.updateDt
, internals
.delta
);
164 assert
.deepEqual(internals
.context
.lowPrioritySystem
.updateDt
, internals
.delta
);
167 it('should no longer call removed systems', () => {
169 const originalSystemLength
= internals
.context
.engine
.systems
.length
;
170 const originalRemoved
= internals
.context
.engine
.removeSystem(internals
.context
.lowPrioritySystem
);
171 const intermediateSystemLength
= internals
.context
.engine
.systems
.length
;
172 const finalRemoved
= internals
.context
.engine
.removeSystem(internals
.context
.lowPrioritySystem
);
173 const finalSystemLength
= internals
.context
.engine
.systems
.length
;
174 internals
.context
.engine
.update(internals
.delta
);
176 // Check for return value
177 assert(originalRemoved
);
178 assert(!finalRemoved
);
180 // Confirm that only removed if found by checking length of systems
182 assert(originalSystemLength
> intermediateSystemLength
);
183 assert
.deepEqual(finalSystemLength
, intermediateSystemLength
);
185 // Ensure callback is sent
186 assert(!internals
.context
.regularSystem
.removedCalled
);
187 assert(!internals
.context
.highPrioritySystem
.removedCalled
);
188 assert(!!internals
.context
.lowPrioritySystem
.removedCalled
);
190 // Ensure update is no longer sent
191 assert(!!internals
.context
.regularSystem
.updateCalled
);
192 assert(!!internals
.context
.highPrioritySystem
.updateCalled
);
193 assert(!internals
.context
.lowPrioritySystem
.updateCalled
);
196 it('should only call nodes in selected node collections', () => {
198 internals
.context
.engine
.update(internals
.delta
);
200 // Ensure component is called for each entity
201 assert(!!internals
.context
.firstEntity
._components
[0].called
);
202 assert(!!internals
.context
.secondEntity
._components
[0].called
);
204 // Ensure entity not in node collection not called
205 assert(!!internals
.context
.firstEntity
.called
);
206 assert(!!internals
.context
.secondEntity
.called
);
207 assert(!internals
.context
.emptyEntity
.called
);
210 it('should stop showing removed entities', () => {
212 internals
.context
.engine
.removeEntity(internals
.context
.secondEntity
);
213 internals
.context
.engine
.update(internals
.delta
);
215 assert(!!internals
.context
.firstEntity
._components
[0].called
);
216 assert(!internals
.context
.secondEntity
._components
[0].called
);
218 assert(!!internals
.context
.firstEntity
.called
);
219 assert(!internals
.context
.secondEntity
.called
);
220 assert(!internals
.context
.emptyEntity
.called
);
223 it('should not add duplicate components to entities', () => {
225 const originalComponentsLength
= internals
.context
.secondEntity
._components
.length
;
226 const result
= internals
.context
.secondEntity
.addComponent(new internals
.component());
227 const newComponentsLength
= internals
.context
.secondEntity
._components
.length
;
230 assert
.deepEqual(newComponentsLength
, originalComponentsLength
);
233 it('should allow access to components by class', () => {
235 const firstComponent
= internals
.context
.firstEntity
.getComponent(internals
.component
);
236 const emptyComponent
= internals
.context
.emptyEntity
.getComponent(internals
.component
);
238 assert(firstComponent
instanceof internals
.component
);
239 assert
.deepEqual(emptyComponent
, undefined);
242 it('should not add duplicate entities', () => {
244 const originalEntitiesLength
= internals
.context
.engine
.entities
.length
;
245 const added
= internals
.context
.engine
.addEntity(internals
.context
.firstEntity
);
246 const finalEntitiesLength
= internals
.context
.engine
.entities
.length
;
250 assert
.deepEqual(finalEntitiesLength
, originalEntitiesLength
);
253 it('should remove entities', () => {
255 const originalEntityLength
= internals
.context
.engine
.entities
.length
;
256 const originalRemoved
= internals
.context
.engine
.removeEntity(internals
.context
.firstEntity
);
257 const intermediateEntityLength
= internals
.context
.engine
.entities
.length
;
258 const finalRemoved
= internals
.context
.engine
.removeEntity(internals
.context
.firstEntity
);
259 const finalEntityLength
= internals
.context
.engine
.entities
.length
;
260 internals
.context
.engine
.update(internals
.delta
);
262 // Check for return value
263 assert(originalRemoved
);
264 assert(!finalRemoved
);
266 // Confirm that only removed if found by checking length of systems
268 assert(originalEntityLength
> intermediateEntityLength
);
269 assert
.deepEqual(finalEntityLength
, intermediateEntityLength
);
271 // Ensure callback is sent
272 assert(!internals
.context
.firstEntity
.called
);
273 assert(!!internals
.context
.secondEntity
.called
);