We use cookies to enhance your experience on the site
CodeWorlds

Testing Asynchronous Code

In Jurassic Park, many operations are asynchronous - DNA scanning, communicating with sensors, fetching data from satellites. Jest offers several ways to test such code.

Testing Promises

async/await

The most readable way to test asynchronous code:

1// Asynchronous function to test
2async function scanDNA(sampleId) {
3  const response = await fetch(`/api/dna/${sampleId}`);
4  const data = await response.json();
5  return {
6    species: data.species,
7    purity: data.purity,
8    viable: data.purity > 0.9
9  };
10}
11
12// Test with async/await
13test('DNA scanning returns species', async () => {
14  const result = await scanDNA('SAMPLE-001');
15
16  expect(result.species).toBe('T-Rex');
17  expect(result.purity).toBeGreaterThan(0.9);
18  expect(result.viable).toBe(true);
19});

resolves and rejects

Jest has dedicated matchers for Promises:

1// Testing resolve
2test('DNA scan resolves with data', async () => {
3  await expect(scanDNA('SAMPLE-001')).resolves.toEqual({
4    species: 'T-Rex',
5    purity: 0.95,
6    viable: true
7  });
8});
9
10// Testing reject
11test('DNA scan rejects for invalid sample', async () => {
12  await expect(scanDNA('INVALID')).rejects.toThrow('Sample not found');
13});
14
15// Another example - testing a rejected Promise
16async function activateDefense(zoneId) {
17  if (!zoneId) {
18    throw new Error('Zone ID is required');
19  }
20  return { status: 'activated', zone: zoneId };
21}
22
23test('defense rejects without zone ID', async () => {
24  await expect(activateDefense(null)).rejects.toThrow('Zone ID is required');
25});
26
27test('defense resolves with valid zone', async () => {
28  await expect(activateDefense('A')).resolves.toEqual({
29    status: 'activated',
30    zone: 'A'
31  });
32});

Testing Callbacks

1function fetchDinoReport(id, callback) {
2  setTimeout(() => {
3    if (id === 'unknown') {
4      callback(new Error('Dinosaur not found'), null);
5    } else {
6      callback(null, { id, status: 'healthy' });
7    }
8  }, 100);
9}
10
11// Testing callback with done
12test('callback returns dinosaur report', (done) => {
13  fetchDinoReport('REX-001', (error, report) => {
14    try {
15      expect(error).toBeNull();
16      expect(report.status).toBe('healthy');
17      done(); // Signal test completion
18    } catch (err) {
19      done(err); // Pass error to Jest
20    }
21  });
22});

Fake Timers

When code uses

setTimeout
,
setInterval
, or
Date
, you can control time:

1// Function with timeout
2function startEmergencyCountdown(callback) {
3  console.log('Evacuation in 30 seconds!');
4  setTimeout(() => {
5    callback('Evacuation started!');
6  }, 30000); // 30 seconds
7}
8
9describe('Emergency System', () => {
10  beforeEach(() => {
11    jest.useFakeTimers(); // Enable fake timers
12  });
13
14  afterEach(() => {
15    jest.useRealTimers(); // Restore real timers
16  });
17
18  test('countdown calls callback after 30s', () => {
19    const callback = jest.fn();
20
21    startEmergencyCountdown(callback);
22
23    // Callback has not been called yet
24    expect(callback).not.toHaveBeenCalled();
25
26    // Fast-forward time by 30 seconds
27    jest.advanceTimersByTime(30000);
28
29    // Now the callback has been called!
30    expect(callback).toHaveBeenCalledWith('Evacuation started!');
31  });
32
33  test('countdown does not fire before time', () => {
34    const callback = jest.fn();
35
36    startEmergencyCountdown(callback);
37
38    // Fast-forward by 29 seconds
39    jest.advanceTimersByTime(29000);
40    expect(callback).not.toHaveBeenCalled();
41
42    // Fast-forward by one more second (30s total)
43    jest.advanceTimersByTime(1000);
44    expect(callback).toHaveBeenCalled();
45  });
46});

Running Pending Timers

1test('runAllTimers - run all timers', () => {
2  const steps = [];
3
4  setTimeout(() => steps.push('step 1'), 1000);
5  setTimeout(() => steps.push('step 2'), 2000);
6  setTimeout(() => steps.push('step 3'), 5000);
7
8  jest.useFakeTimers();
9
10  // Run ALL pending timers at once
11  jest.runAllTimers();
12
13  expect(steps).toEqual(['step 1', 'step 2', 'step 3']);
14
15  jest.useRealTimers();
16});
Go to CodeWorlds