]> git.r.bdr.sh - rbdr/serpentity/blame - test/integration.js
Trim gitignore
[rbdr/serpentity] / test / integration.js
CommitLineData
3d7e8509
RBR
1import { describe, it, beforeEach } from 'node:test';
2import assert from 'node:assert';
4d421669 3import Serpentity, { Component, Entity, Node, System } from '../lib/serpentity.js';
3db7d198 4
b3b840f8 5const internals = {
4d421669
BB
6 context: {},
7 system: class TestSystem extends System {
b3b840f8 8 added(engine) {
3db7d198 9
b3b840f8
RBR
10 this.testNodes = engine.getNodes(internals.node);
11 this.addedCalled = true;
12 this.addedEngine = engine;
3d7e8509 13 super.added(); // not needed, but takes care of coverage :P
3db7d198
BB
14 }
15
b3b840f8
RBR
16 removed(engine) {
17
3db7d198 18 this.testNodes = null;
b3b840f8
RBR
19 this.removedCalled = true;
20 this.removedEngine = engine;
3d7e8509 21 super.removed(); // not needed, but takes care of coverage :P
3db7d198
BB
22 }
23
b3b840f8 24 update(dt) {
3db7d198 25
b3b840f8
RBR
26 this.updateCalled = Date.now();
27 this.updateDt = dt;
3db7d198 28
b3b840f8
RBR
29 for (const node of this.testNodes) {
30 node.test.called = true;
31 node.entity.called = true;
32 }
3db7d198 33
b3b840f8 34 while (Date.now() === this.updateCalled) { /* pass some time */ }
3d7e8509 35 super.update(); // not needed, but takes care of coverage :P
b3b840f8
RBR
36 }
37 },
4d421669 38 component: class TestComponent extends Component {
b3b840f8 39 constructor(config) {
3db7d198 40
3db7d198
BB
41 super(config);
42
b3b840f8 43 this.called = false;
3db7d198 44 }
b3b840f8 45 },
4d421669 46 node: class TestNode extends Node {},
b3b840f8
RBR
47 delta: 10
48};
3db7d198 49
b3b840f8
RBR
50// adds a component to the node
51internals.node.types = {
52 test: internals.component
53};
3db7d198 54
3d7e8509 55describe('Loading', () => {
3db7d198 56
3d7e8509 57 it('Should export the main class', () => {
3db7d198 58
3d7e8509 59 assert(typeof Serpentity === 'function');
b3b840f8 60 });
3db7d198 61
3d7e8509 62 it('Should export the Entity class', () => {
3db7d198 63
3d7e8509 64 assert(typeof Entity === 'function');
b3b840f8 65 });
3db7d198 66
3d7e8509 67 it('Should export the Component class', () => {
3db7d198 68
3d7e8509 69 assert(typeof Component === 'function');
b3b840f8 70 });
3db7d198 71
3d7e8509 72 it('Should export the System class', () => {
3db7d198 73
3d7e8509 74 assert(typeof System === 'function');
b3b840f8 75 });
3db7d198 76
3d7e8509 77 it('Should export the Node class', () => {
3db7d198 78
3d7e8509 79 assert(typeof Node === 'function');
b3b840f8
RBR
80 });
81});
82
3d7e8509 83describe('Engine', () => {
b3b840f8 84
4d421669 85 beforeEach(() => {
b3b840f8 86
4d421669 87 internals.context.engine = new Serpentity();
b3b840f8 88
4d421669
BB
89 internals.context.regularSystem = new internals.system();
90 internals.context.highPrioritySystem = new internals.system();
91 internals.context.lowPrioritySystem = new internals.system();
b3b840f8 92
4d421669
BB
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();
b3b840f8
RBR
98
99 // Add entity before the systems
4d421669 100 internals.context.engine.addEntity(internals.context.firstEntity);
b3b840f8 101
4d421669
BB
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);
b3b840f8
RBR
105
106 // Add entity after the systems
4d421669
BB
107 internals.context.engine.addEntity(internals.context.secondEntity);
108 internals.context.engine.addEntity(internals.context.emptyEntity);
b3b840f8
RBR
109 });
110
3d7e8509 111 it('should call added callback on added systems', () => {
b3b840f8
RBR
112
113 // Ensure the added callback is being called
3d7e8509
RBR
114 assert(internals.context.regularSystem.addedCalled);
115 assert(internals.context.highPrioritySystem.addedCalled);
116 assert(internals.context.lowPrioritySystem.addedCalled);
b3b840f8
RBR
117 });
118
3d7e8509 119 it('should send the engine instance in added callback', () => {
b3b840f8
RBR
120
121 // Ensure the added callback is sending the engine
3d7e8509
RBR
122 assert(internals.context.regularSystem.addedEngine instanceof Serpentity);
123 assert(internals.context.highPrioritySystem.addedEngine instanceof Serpentity);
124 assert(internals.context.lowPrioritySystem.addedEngine instanceof Serpentity);
b3b840f8
RBR
125 });
126
3d7e8509 127 it('should not add duplicate systems', () => {
b3b840f8 128
4d421669
BB
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;
b3b840f8
RBR
132
133 // Ensure we don't add the same system twice
3d7e8509
RBR
134 assert(!added);
135 assert.deepEqual(newSystemsLength, originalSystemsLength);
b3b840f8
RBR
136 });
137
3d7e8509 138 it('should call update callback on added systems', () => {
b3b840f8 139
4d421669 140 internals.context.engine.update(internals.delta);
b3b840f8
RBR
141
142 // Ensure update function called
3d7e8509
RBR
143 assert(!!internals.context.regularSystem.updateCalled);
144 assert(!!internals.context.highPrioritySystem.updateCalled);
145 assert(!!internals.context.lowPrioritySystem.updateCalled);
b3b840f8
RBR
146 });
147
3d7e8509 148 it('should call update callback in the order of priorities', () => {
b3b840f8 149
4d421669 150 internals.context.engine.update(internals.delta);
b3b840f8
RBR
151
152 // Ensure order of priorities
3d7e8509
RBR
153 assert(internals.context.regularSystem.updateCalled < internals.context.lowPrioritySystem.updateCalled);
154 assert(internals.context.regularSystem.updateCalled > internals.context.highPrioritySystem.updateCalled);
b3b840f8
RBR
155 });
156
3d7e8509 157 it('should send the delta in the update callback', () => {
b3b840f8 158
4d421669 159 internals.context.engine.update(internals.delta);
b3b840f8
RBR
160
161 // Ensure delta is being sent
3d7e8509
RBR
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);
b3b840f8
RBR
165 });
166
3d7e8509 167 it('should no longer call removed systems', () => {
b3b840f8 168
4d421669
BB
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);
b3b840f8 175
4d421669 176 // Check for return value
3d7e8509
RBR
177 assert(originalRemoved);
178 assert(!finalRemoved);
b3b840f8
RBR
179
180 // Confirm that only removed if found by checking length of systems
181 // array
3d7e8509
RBR
182 assert(originalSystemLength > intermediateSystemLength);
183 assert.deepEqual(finalSystemLength, intermediateSystemLength);
b3b840f8
RBR
184
185 // Ensure callback is sent
3d7e8509
RBR
186 assert(!internals.context.regularSystem.removedCalled);
187 assert(!internals.context.highPrioritySystem.removedCalled);
188 assert(!!internals.context.lowPrioritySystem.removedCalled);
b3b840f8
RBR
189
190 // Ensure update is no longer sent
3d7e8509
RBR
191 assert(!!internals.context.regularSystem.updateCalled);
192 assert(!!internals.context.highPrioritySystem.updateCalled);
193 assert(!internals.context.lowPrioritySystem.updateCalled);
b3b840f8
RBR
194 });
195
3d7e8509 196 it('should only call nodes in selected node collections', () => {
b3b840f8 197
4d421669 198 internals.context.engine.update(internals.delta);
b3b840f8
RBR
199
200 // Ensure component is called for each entity
3d7e8509
RBR
201 assert(!!internals.context.firstEntity._components[0].called);
202 assert(!!internals.context.secondEntity._components[0].called);
b3b840f8
RBR
203
204 // Ensure entity not in node collection not called
3d7e8509
RBR
205 assert(!!internals.context.firstEntity.called);
206 assert(!!internals.context.secondEntity.called);
207 assert(!internals.context.emptyEntity.called);
b3b840f8
RBR
208 });
209
3d7e8509 210 it('should stop showing removed entities', () => {
b3b840f8 211
4d421669
BB
212 internals.context.engine.removeEntity(internals.context.secondEntity);
213 internals.context.engine.update(internals.delta);
b3b840f8 214
3d7e8509
RBR
215 assert(!!internals.context.firstEntity._components[0].called);
216 assert(!internals.context.secondEntity._components[0].called);
b3b840f8 217
3d7e8509
RBR
218 assert(!!internals.context.firstEntity.called);
219 assert(!internals.context.secondEntity.called);
220 assert(!internals.context.emptyEntity.called);
b3b840f8
RBR
221 });
222
3d7e8509 223 it('should not add duplicate components to entities', () => {
b3b840f8 224
4d421669
BB
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;
b3b840f8 228
3d7e8509
RBR
229 assert(!result);
230 assert.deepEqual(newComponentsLength, originalComponentsLength);
b3b840f8
RBR
231 });
232
3d7e8509 233 it('should allow access to components by class', () => {
b3b840f8 234
4d421669
BB
235 const firstComponent = internals.context.firstEntity.getComponent(internals.component);
236 const emptyComponent = internals.context.emptyEntity.getComponent(internals.component);
b3b840f8 237
3d7e8509
RBR
238 assert(firstComponent instanceof internals.component);
239 assert.deepEqual(emptyComponent, undefined);
b3b840f8
RBR
240 });
241
3d7e8509 242 it('should not add duplicate entities', () => {
4d421669
BB
243
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;
b3b840f8 247
3d7e8509 248 assert(!added);
b3b840f8 249
3d7e8509 250 assert.deepEqual(finalEntitiesLength, originalEntitiesLength);
b3b840f8
RBR
251 });
252
3d7e8509 253 it('should remove entities', () => {
b3b840f8 254
4d421669
BB
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);
b3b840f8 261
4d421669 262 // Check for return value
3d7e8509
RBR
263 assert(originalRemoved);
264 assert(!finalRemoved);
b3b840f8
RBR
265
266 // Confirm that only removed if found by checking length of systems
267 // array
3d7e8509
RBR
268 assert(originalEntityLength > intermediateEntityLength);
269 assert.deepEqual(finalEntityLength, intermediateEntityLength);
b3b840f8
RBR
270
271 // Ensure callback is sent
3d7e8509
RBR
272 assert(!internals.context.firstEntity.called);
273 assert(!!internals.context.secondEntity.called);
3db7d198 274 });
b3b840f8 275});