I am trying to unit test all of my API calls. Every call passes the test, but i still get an error saying: ✘ Timed out while running tests Failed to exit when running test.js. I have tried adding a timeout of 20sec, but this didnt do anything.
test.js:
const test = require('ava');
const request = require('supertest');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
// Mock database operations
const dbMock = {
getBikes: sinon.stub().callsFake((callback) => callback(null, [{ id: 1, name: 'Bike 1' }])),
getUsers: sinon.stub().callsFake((callback) => callback(null, [{ id: 1, name: 'User 1' }])),
getBikeUsage: sinon.stub().callsFake((callback) => callback(null, [{ id: 1, bikeId: 1, userId: 1 }])),
saveBikeUsage: sinon.stub().callsFake((bikeUsage, callback) => callback(null, { insertId: 1 })),
updateBikeUsageStatus: sinon.stub().callsFake((bikeId, status, callback) => callback(null, {})),
unassignBike: sinon.stub().callsFake((bikeId, endTime, callback) => callback(null, {})),
updateBikeDetails: sinon.stub().callsFake((id, details, callback) => callback(null, {})),
updateUserDetails: sinon.stub().callsFake((id, name, callback) => callback(null, {})),
addUser: sinon.stub().callsFake((name, callback) => callback(null, { insertId: 1 })),
addBike: sinon.stub().callsFake((bike, callback) => callback(null, { insertId: 1 })),
getUserById: sinon.stub().callsFake((userId, callback) => callback(null, [{ id: userId, name: 'User 1' }])),
getUserHistory: sinon.stub().callsFake((userId, callback) => callback(null, [{ id: 1, bikeId: 1, userId: userId }])),
addCommentToBike: sinon.stub().callsFake((bikeId, comment, callback) => callback(null, {})),
};
// Proxyquire to replace './db' with our mock
const app = proxyquire('./server', { './db': dbMock });
test.afterEach.always(() => {
sinon.restore(); // Restore all stubs and spies after each test
});
// Test for GET /bikes endpoint
test('GET /bikes returns list of bikes', async (t) => {
const res = await request(app).get('/bikes');
t.is(res.status, 200);
t.true(Array.isArray(res.body));
t.true(res.body.length > 0);
});
// Test for GET /users endpoint
test('GET /users returns list of users', async (t) => {
const res = await request(app).get('/users');
t.is(res.status, 200);
t.true(Array.isArray(res.body));
t.true(res.body.length > 0);
});
// Test for GET /bike-usage endpoint
test('GET /bike-usage returns list of bike usage history', async (t) => {
const res = await request(app).get('/bike-usage');
t.is(res.status, 200);
t.true(Array.isArray(res.body));
t.true(res.body.length > 0);
});
// Test for POST /bike-usage endpoint
test('POST /bike-usage saves bike usage data', async (t) => {
const bikeUsage = { bike_id: 1, user_id: 1, start_time: new Date().toISOString(), end_time: null };
const res = await request(app).post('/bike-usage').send(bikeUsage);
t.is(res.status, 200);
t.is(res.body.message, 'Bike usage data saved successfully');
});
// Test for POST /bike-unassign endpoint
test('POST /bike-unassign unassigns bike and updates end time', async (t) => {
const bike_id = 1;
const res = await request(app).post('/bike-unassign').send({ bike_id });
t.is(res.status, 200);
t.is(res.body.message, 'Bike unassigned successfully');
});
// Test for PUT /bikes/:id endpoint
test('PUT /bikes/:id updates bike details', async (t) => {
const bikeId = 1;
const details = { frame: 'New Frame', bike_lock: 'New Lock', comments: 'Updated comment', broken: false };
const res = await request(app).put(`/bikes/${bikeId}`).send(details);
t.is(res.status, 200);
t.is(res.body.message, 'Bike details updated successfully');
});
// Test for PUT /users/:id endpoint
test('PUT /users/:id updates user details', async (t) => {
const userId = 1;
const name = 'Updated User';
const res = await request(app).put(`/users/${userId}`).send({ name });
t.is(res.status, 200);
t.is(res.body.message, 'User details updated successfully');
});
// Test for POST /users endpoint
test('POST /users adds new user', async (t) => {
const name = 'New User';
const res = await request(app).post('/users').send({ name });
t.is(res.status, 200);
t.is(res.body.name, name);
t.true(res.body.id > 0);
});
// Test for POST /bikes endpoint
test('POST /bikes adds new bike', async (t) => {
const bike = { frame: 'New Frame', bike_lock: 'New Lock', broken: false, comments: 'New comment' };
const res = await request(app).post('/bikes').send(bike);
t.is(res.status, 200);
t.true(res.body.id > 0);
t.deepEqual(res.body.frame, bike.frame);
});
// Test for GET /users/:id endpoint
test('GET /users/:id returns user details for valid ID', async (t) => {
const userId = 1;
const res = await request(app).get(`/users/${userId}`);
t.is(res.status, 200);
t.deepEqual(parseInt(res.body.id), userId);
});
// Test for GET /user-history/:userId endpoint
test('GET /user-history/:userId returns user history for valid user ID', async (t) => {
const userId = 1;
const res = await request(app).get(`/user-history/${userId}`);
t.is(res.status, 200);
t.true(Array.isArray(res.body));
t.true(res.body.length > 0);
});
// Test for POST /bikes/:bikeId/comments endpoint
test('POST /bikes/:bikeId/comments adds comment to bike', async (t) => {
const bikeId = 1;
const comment = 'New Comment';
const res = await request(app).post(`/bikes/${bikeId}/comments`).send({ comment });
t.is(res.status, 200);
t.is(res.body.message, 'Comment saved successfully');
});
db.js:
const mysql = require('mysql2');
// Create a connection pool
const pool = mysql.createPool({
host: 'xxxx',
user: 'xxxx',
password: 'xxxx',
database: 'xxxx',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
module.exports = {
getBikes: (callback) => {
pool.query('SELECT * FROM Bikes', callback);
},
getUsers: (callback) => {
pool.query('SELECT * FROM Users', callback);
},
getBikeUsage: (callback) => {
pool.query('SELECT * FROM BikeUsage', callback);
},
saveBikeUsage: (bikeUsage, callback) => {
const { bike_id, user_id, start_time, end_time } = bikeUsage;
const formattedStartTime = start_time.slice(0, 19).replace('T', ' ');
pool.query(
'INSERT INTO BikeUsage (bike_id, user_id, start_time, end_time) VALUES (?, ?, ?, ?)',
[bike_id, user_id, formattedStartTime, end_time],
callback
);
},
updateBikeUsageStatus: (bike_id, isBeingUsed, callback) => {
pool.query(
'UPDATE Bikes SET isBeingUsed = ? WHERE id = ?',
[isBeingUsed, bike_id],
callback
);
},
unassignBike: (bike_id, endTime, callback) => {
pool.query(
'UPDATE BikeUsage SET end_time = ? WHERE bike_id = ? AND end_time IS NULL',
[endTime, bike_id],
callback
);
},
updateBikeDetails: (id, details, callback) => {
const { frame, bike_lock, comments, broken } = details;
pool.query(
'UPDATE Bikes SET frame = ?, bike_lock = ?, comments = ?, broken = ? WHERE id = ?',
[frame, bike_lock, comments, broken, id],
callback
);
},
updateUserDetails: (id, name, callback) => {
pool.query(
'UPDATE Users SET name = ? WHERE id = ?',
[name, id],
callback
);
},
addUser: (name, callback) => {
pool.query(
'INSERT INTO Users (name) VALUES (?)',
[name],
callback
);
},
addBike: (bike, callback) => {
const { frame, bike_lock, broken, comments } = bike;
pool.query(
'INSERT INTO Bikes (frame, bike_lock, broken, comments) VALUES (?, ?, ?, ?)',
[frame, bike_lock, broken, comments],
callback
);
},
getUserById: (userId, callback) => {
pool.query('SELECT * FROM Users WHERE id = ?', [userId], callback);
},
getUserHistory: (userId, callback) => {
pool.query('SELECT * FROM BikeUsage WHERE user_id = ?', [userId], callback);
},
addCommentToBike: (bikeId, comment, callback) => {
pool.query(
'UPDATE Bikes SET comments = CONCAT(IFNULL(comments, ""), ?) WHERE id = ?',
[comment + 'n', bikeId],
callback
);
}
};
Test results:
[email protected] test
ava
Server running on port 3000
✔ GET /bikes returns list of bikes (146ms)
✔ GET /users returns list of users (145ms)
✔ GET /bike-usage returns list of bike usage history (144ms)
✔ POST /bike-usage saves bike usage data (143ms)
✔ POST /bike-unassign unassigns bike and updates end time (142ms)
✔ PUT /bikes/:id updates bike details (139ms)
✔ PUT /users/:id updates user details (137ms)
✔ POST /users adds new user (138ms)
✔ POST /bikes adds new bike (137ms)
✔ GET /users/:id returns user details for valid ID (136ms)
✔ GET /user-history/:userId returns user history for valid user ID (136ms)
✔ POST /bikes/:bikeId/comments adds comment to bike (137ms)
✘ Timed out while running tests
Failed to exit when running test.js
─
12 tests passed
I tried adding: test.afterEach.always(() => {sinon.restore(); // Restore all stubs and spies after each test});
Also tried adding a timeout:
test.beforeEach(async (t) => { t.timeout(10000); // 10 seconds timeout });
Giel v Bussel is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.