Time for the final challenge! You will build a complete test suite for the Jurassic Park management system. This project combines all concepts from the module: Jest, matchers, setup/teardown, mocking, asynchronous testing, TDD, and TypeScript.
Below you will find the complete park management system. Your task is to write tests for each module.
1// dinosaurManager.js
2class DinosaurManager {
3 constructor() {
4 this.dinosaurs = new Map();
5 this.nextId = 1;
6 }
7
8 addDinosaur(name, species, diet, zone) {
9 if (!name || !species) {
10 throw new Error('Name and species are required');
11 }
12
13 const id = `DINO-${String(this.nextId).padStart(3, '0')}`;
14 this.nextId++;
15
16 const dinosaur = {
17 id,
18 name,
19 species,
20 diet,
21 zone,
22 health: 100,
23 fed: false,
24 lastFed: null,
25 };
26
27 this.dinosaurs.set(id, dinosaur);
28 return dinosaur;
29 }
30
31 getDinosaur(id) {
32 return this.dinosaurs.get(id) || null;
33 }
34
35 feedDinosaur(id, food) {
36 const dino = this.getDinosaur(id);
37 if (!dino) throw new Error('Dinosaur not found');
38
39 const correctFood = {
40 carnivore: 'meat',
41 herbivore: 'plants',
42 omnivore: ['meat', 'plants'],
43 };
44
45 const expected = correctFood[dino.diet];
46 const isCorrect = Array.isArray(expected)
47 ? expected.includes(food)
48 : expected === food;
49
50 if (!isCorrect) {
51 return { success: false, message: 'Wrong food type' };
52 }
53
54 dino.health = Math.min(100, dino.health + 10);
55 dino.fed = true;
56 dino.lastFed = new Date();
57
58 return { success: true, health: dino.health };
59 }
60
61 getByZone(zone) {
62 return [...this.dinosaurs.values()].filter(d => d.zone === zone);
63 }
64
65 getByDiet(diet) {
66 return [...this.dinosaurs.values()].filter(d => d.diet === diet);
67 }
68
69 getTotalCount() {
70 return this.dinosaurs.size;
71 }
72}1// securitySystem.js
2class SecuritySystem {
3 constructor(alertService) {
4 this.alertService = alertService; // dependency to mock
5 this.zones = new Map();
6 this.logs = [];
7 }
8
9 registerZone(name, fenceVoltage, securityLevel) {
10 this.zones.set(name, {
11 name,
12 fenceVoltage,
13 securityLevel,
14 status: 'active',
15 breachCount: 0,
16 });
17 }
18
19 async reportBreach(zoneName) {
20 const zone = this.zones.get(zoneName);
21 if (!zone) throw new Error('Zone not found');
22
23 zone.breachCount++;
24 zone.status = 'breached';
25
26 this.logs.push({
27 type: 'BREACH',
28 zone: zoneName,
29 timestamp: Date.now(),
30 });
31
32 await this.alertService.sendAlert(zoneName, 'Security breach detected');
33
34 if (zone.breachCount >= 3) {
35 await this.activateLockdown(zoneName);
36 }
37
38 return { status: 'reported', breachCount: zone.breachCount };
39 }
40
41 async activateLockdown(zoneName) {
42 const zone = this.zones.get(zoneName);
43 zone.status = 'lockdown';
44 zone.fenceVoltage *= 2;
45
46 await this.alertService.sendAlert(
47 zoneName,
48 'LOCKDOWN ACTIVATED'
49 );
50
51 this.logs.push({
52 type: 'LOCKDOWN',
53 zone: zoneName,
54 timestamp: Date.now(),
55 });
56 }
57
58 getZoneStatus(zoneName) {
59 const zone = this.zones.get(zoneName);
60 return zone ? zone.status : null;
61 }
62}1// monitoringService.js
2class MonitoringService {
3 constructor() {
4 this.sensors = [];
5 this.interval = null;
6 }
7
8 addSensor(zoneId, type) {
9 this.sensors.push({
10 zoneId,
11 type,
12 status: 'online',
13 lastReading: null,
14 });
15 }
16
17 async checkSensor(index) {
18 return new Promise((resolve, reject) => {
19 setTimeout(() => {
20 if (index < 0 || index >= this.sensors.length) {
21 reject(new Error('Sensor not found'));
22 return;
23 }
24
25 const sensor = this.sensors[index];
26 sensor.lastReading = Date.now();
27
28 resolve({
29 zoneId: sensor.zoneId,
30 type: sensor.type,
31 status: sensor.status,
32 reading: Math.random() * 100,
33 });
34 }, 1000);
35 });
36 }
37
38 startMonitoring(callback, intervalMs) {
39 this.interval = setInterval(() => {
40 const readings = this.sensors.map(s => ({
41 zone: s.zoneId,
42 status: s.status,
43 }));
44 callback(readings);
45 }, intervalMs);
46 }
47
48 stopMonitoring() {
49 if (this.interval) {
50 clearInterval(this.interval);
51 this.interval = null;
52 }
53 }
54}Write a complete test suite covering:
Remember the AAA pattern (Arrange-Act-Assert) and TDD principles!