Skip to content

Commit

Permalink
Add backend tests for controllers
Browse files Browse the repository at this point in the history
  • Loading branch information
n1klaus committed Jul 15, 2023
1 parent eec5743 commit 80ec5de
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 159 deletions.
44 changes: 27 additions & 17 deletions backend/tests/controllers/app.controller.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unused-expressions */
import { expect } from 'chai';
import sinon from 'sinon';
import { NextFunction, Request, Response } from 'express';
Expand All @@ -11,9 +12,10 @@ import AppController from '../../src/controllers/app.controller';

describe('AppController', () => {
describe('getStatus', () => {
it('should return status 200 and check if redis and db are alive', () => {
it('should return status 200 and check if redis and mongoose connections are alive', () => {
// Arrange
const req = {} as Request;
const resp = {
const res = {
status: sinon.stub().returnsThis(),
json: sinon.stub(),
} as unknown as Response;
Expand All @@ -22,11 +24,13 @@ describe('AppController', () => {
const redisIsAliveStub = sinon.stub(redisClient, 'isAlive').returns(true);
const dbIsAliveStub = sinon.stub(dbClient, 'isAlive').returns(true);

AppController.getStatus(req, resp, next);
// Act
AppController.getStatus(req, res, next);

expect(resp.status.calledWith(200)).to.be.true;
// Assert
expect(res.status.calledWith(200)).to.be.true;
expect(
resp.json.calledWith({
res.json.calledWith({
redis: true,
db: true,
}),
Expand All @@ -40,16 +44,19 @@ describe('AppController', () => {
});

it('should call next with an error if an exception occurs', () => {
// Arrange
const req = {} as Request;
const resp = {} as Response;
const res = {} as Response;
const next = sinon.stub() as unknown as NextFunction;
const error = new Error('Some error message');

sinon.stub(redisClient, 'isAlive').throws(error);
sinon.stub(dbClient, 'isAlive').returns(true);

AppController.getStatus(req, resp, next);
// Act
AppController.getStatus(req, res, next);

// Assert
expect(next.calledWith(error)).to.be.true;

sinon.restore();
Expand All @@ -58,8 +65,9 @@ describe('AppController', () => {

describe('getStats', () => {
it('should return status 200 and the statistics', async () => {
// Arrange
const req = {} as Request;
const resp = {
const res = {
status: sinon.stub().returnsThis(),
json: sinon.stub(),
} as unknown as Response;
Expand All @@ -74,11 +82,13 @@ describe('AppController', () => {
.stub(Comment, 'countDocuments')
.resolves(15);

await AppController.getStats(req, resp, next);
// Act
await AppController.getStats(req, res, next);

expect(resp.status.calledWith(200)).to.be.true;
// Assert
expect(res.status.calledWith(200)).to.be.true;
expect(
resp.json.calledWith({
res.json.calledWith({
users: 10,
videos: 20,
comments: 15,
Expand All @@ -94,19 +104,19 @@ describe('AppController', () => {
sinon.restore();
});

it('should call next with an error if an exception occurs', async () => {
it('should handle errors', async () => {
// Arrange
const req = {} as Request;
const resp = {} as Response;
const res = {} as Response;
const next = sinon.stub() as unknown as NextFunction;
const error = new Error('Some error message');

sinon.stub(User, 'countDocuments').rejects(error);
sinon.stub(Video, 'countDocuments').resolves(20);
sinon.stub(Channel, 'countDocuments').resolves(5);
sinon.stub(Comment, 'countDocuments').resolves(15);

await AppController.getStats(req, resp, next);
// Act
await AppController.getStats(req, res, next);

// Assert
expect(next.calledWith(error)).to.be.true;

sinon.restore();
Expand Down
25 changes: 14 additions & 11 deletions backend/tests/controllers/auth.controller.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unused-expressions */
import { expect } from 'chai';
import sinon from 'sinon';
import { Request, Response, NextFunction } from 'express';
Expand Down Expand Up @@ -35,13 +36,14 @@ describe('AuthController', () => {
const saveUserStub = sinon.stub(User.prototype, 'save').resolves();
const randomUUIDStub = sinon.stub().returns('randomUUID');
sinon.replace(Channel.prototype, 'save', sinon.stub().resolves());
const jwtSignStub = sinon.stub(jwt, 'sign').returns('token');
const jwtSignStub = sinon.stub(jwt, 'sign');
// .returns('token');

await AuthController.registerHandler(req, resp, next);

expect(resp.status.calledWith(201)).to.be.true;
expect((resp.status as sinon.SinonStub).calledWith(201)).to.be.true;
expect(
resp.json.calledWith({
(resp.json as sinon.SinonStub).calledWith({
status: 'success',
data: {
user: exclude(
Expand All @@ -56,7 +58,7 @@ describe('AuthController', () => {
}),
).to.be.true;
expect(
resp.cookie.calledWith('auth_token', 'token', {
(resp.cookie as sinon.SinonStub).calledWith('auth_token', 'token', {
expires: sinon.match.instanceOf(Date),
httpOnly: true,
}),
Expand Down Expand Up @@ -91,9 +93,9 @@ describe('AuthController', () => {

await AuthController.registerHandler(req, resp, next);

expect(resp.status.calledWith(409)).to.be.true;
expect((resp.status as sinon.SinonStub).calledWith(409)).to.be.true;
expect(
resp.json.calledWith({
(resp.json as sinon.SinonStub).calledWith({
status: 'fail',
message: 'Email already exist',
}),
Expand Down Expand Up @@ -124,7 +126,7 @@ describe('AuthController', () => {

await AuthController.registerHandler(req, resp, next);

expect(next.calledWith(error)).to.be.true;
expect((next as sinon.SinonStub).calledWith(error)).to.be.true;

expect(saveUserStub.calledOnce).to.be.true;

Expand Down Expand Up @@ -153,18 +155,19 @@ describe('AuthController', () => {
// ...other user properties
});
const compareStub = sinon.stub(bcrypt, 'compare').resolves(true);
const jwtSignStub = sinon.stub(jwt, 'sign').returns('token');
const jwtSignStub = sinon.stub(jwt, 'sign');
// .returns('token');

await AuthController.loginHandler(req, resp, next);

expect(resp.status.calledWith(200)).to.be.true;
expect((resp.status as sinon.SinonStub).calledWith(200)).to.be.true;
expect(
resp.json.calledWith({
(resp.json as sinon.SinonStub).calledWith({
status: 'success',
}),
).to.be.true;
expect(
resp.cookie.calledWith('auth_token', 'token', {
(resp.cookie as sinon.SinonStub).calledWith('auth_token', 'token', {
expires: sinon.match.instanceOf(Date),
httpOnly: true,
}),
Expand Down
56 changes: 31 additions & 25 deletions backend/tests/controllers/channel.controller.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import assert from 'assert';
/* eslint-disable @typescript-eslint/no-unused-expressions */
import sinon from 'sinon';
import { expect } from 'chai';
import { Request, Response, NextFunction } from 'express';
import User from '../../src/models/user.model';
import Video from '../../src/models/video.model';
import { ChannelModel as Channel } from '../../src/models/channel.model';
import ChannelController from '../../src/controllers/channel.controller';

const DEFAULT_THUMBNAIL = process.env.DEFAULT_THUMBNAIL as string;

describe('ChannelController', () => {
describe('createChannel', () => {
it('should create a channel and return it', async () => {
Expand All @@ -15,12 +14,12 @@ describe('ChannelController', () => {
channelName: 'New Channel',
imgUrl: 'https://example.com/channel.jpg',
},
};
} as unknown as Request<any, object, any>;
const resp = {
status: sinon.stub().returnsThis(),
json: sinon.stub(),
};
const next = sinon.stub();
} as unknown as Response;
const next = sinon.stub() as unknown as NextFunction;
const userId = 'user_id';
const user = new User({ _id: userId });
sinon.stub(User, 'findById').resolves(user);
Expand All @@ -30,15 +29,20 @@ describe('ChannelController', () => {

await ChannelController.createChannel(req, resp, next);

sinon.assert.calledWith(resp.status, 200);
sinon.assert.calledWith(resp.json, sinon.match.instanceOf(Channel));
sinon.assert.calledWith(
user.channels.push,
sinon.match.instanceOf(Channel),
);
sinon.assert.called(user.save);
expect((resp.status as sinon.SinonStub).calledWith(200)).to.be.true;
expect(
(resp.json as sinon.SinonStub).calledWith(
sinon.match.instanceOf(Channel),
),
).to.be.true;
expect(
(user.channels.push as sinon.SinonStub).calledWith(
sinon.match.instanceOf(Channel),
),
).to.be.true;
expect((user.save as sinon.SinonStub).called).to.be.true;

User.findById.restore();
(User.findById as sinon.SinonStub).restore();
Channel.prototype.save.restore();
});

Expand All @@ -48,11 +52,11 @@ describe('ChannelController', () => {
channelName: 'New Channel',
imgUrl: 'https://example.com/channel.jpg',
},
};
} as unknown as Request<any, object, any>;
const resp = {
status: sinon.stub().returnsThis(),
json: sinon.stub(),
};
} as unknown as Response;
const next = sinon.stub();
const userId = 'user_id';
const user = new User({ _id: userId });
Expand All @@ -63,9 +67,9 @@ describe('ChannelController', () => {

await ChannelController.createChannel(req, resp, next);

sinon.assert.calledWith(next, sinon.match.instanceOf(Error));
expect(next.calledWith(sinon.match.instanceOf(Error))).to.be.true;

User.findById.restore();
(User.findById as sinon.SinonStub).restore();
Channel.prototype.save.restore();
});

Expand All @@ -75,20 +79,22 @@ describe('ChannelController', () => {
channelName: 'New Channel',
imgUrl: 'https://example.com/channel.jpg',
},
};
} as unknown as Request<any, object, any>;
const resp = {
status: sinon.stub().returnsThis(),
json: sinon.stub(),
};
const next = sinon.stub();
} as unknown as Response;
const next = sinon.stub() as unknown as NextFunction;
sinon.stub(User, 'findById').resolves(null);

await ChannelController.createChannel(req, resp, next);

sinon.assert.calledWith(resp.status, 401);
sinon.assert.calledWith(resp.json, { error: 'User not found' });
expect((resp.status as sinon.SinonStub).calledWith(401)).to.be.true;
expect(
(resp.json as sinon.SinonStub).calledWith({ error: 'User not found' }),
).to.be.true;

User.findById.restore();
(User.findById as sinon.SinonStub).restore();
});
});

Expand Down
Loading

0 comments on commit 80ec5de

Please sign in to comment.