Skip to content

Commit aba759a

Browse files
committed
test with jest framework
1 parent 98b85d3 commit aba759a

File tree

13 files changed

+378
-81
lines changed

13 files changed

+378
-81
lines changed

jest.config.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ module.exports = {
99
"^.+\\.(ts|tsx)$": "ts-jest",
1010
},
1111
testEnvironment: "node",
12-
testTimeout: 30000,
12+
testTimeout: 90000,
13+
// preset: "@shelf/jest-mongodb",
14+
// watchPathIgnorePatterns: ["globalConfig"],
15+
// verbose: true,
1316
};

package.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"start": "nodemon --exec ts-node --files src/main.ts",
1616
"cli": "ts-node src/cli.ts",
1717
"lint": "eslint src/ --ext .js,.jsx,.ts,.tsx",
18-
"test": "jest --runInBand --detectOpenHandles --watch",
18+
"test": "jest --runInBand --detectOpenHandles",
19+
"test:watch": "jest --detectOpenHandles --watch --coverage",
1920
"clean": "rm -rf dist build package",
2021
"ts-node": "ts-node",
2122
"docs": "typedoc --entryPoints src/main.ts",
@@ -29,8 +30,10 @@
2930
"esbuild-node:watch": "esbuild src/cli.ts --bundle --watch --sourcemap=external --outfile=dist/esbuild/cli.js"
3031
},
3132
"devDependencies": {
33+
"@shelf/jest-mongodb": "^1.2.4",
3234
"@types/express": "^4.17.11",
3335
"@types/jest": "^26.0.22",
36+
"@types/mongodb": "^3.6.12",
3437
"@types/node": "^14.14.35",
3538
"@types/supertest": "^2.0.11",
3639
"@typescript-eslint/eslint-plugin": "^4.19.0",
@@ -39,6 +42,7 @@
3942
"esbuild": "^0.11.11",
4043
"eslint": "^7.22.0",
4144
"jest": "^26.6.3",
45+
"mongodb": "^3.6.6",
4246
"mongodb-memory-server": "^6.9.6",
4347
"nodemon": "^2.0.7",
4448
"supertest": "^6.1.3",

src/controllers/authController.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ export const protect = catchAsync(
107107
}
108108

109109
// 2. Verification token
110-
const secret = process.env.JWT_SECRET!;
110+
// const secret = process.env.JWT_SECRET!;
111+
112+
// Dirty hack to generate secret for testing purpose
113+
const secret = process.env.JWT_SECRET ? process.env.JWT_SECRET : "test";
111114
const decoded = <any>jwt.verify(token, secret);
112115

113116
// 3. Check if user still exists

src/main.ts

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ process.on("uncaughtException", (err) => {
1111
dotenv.config({ path: __dirname + "/.env" });
1212

1313
const DB: string = process.env.DATABASE!;
14-
// console.log(DB)
1514

1615
mongoose
1716
.connect(DB, {

src/models/userModel.ts

+2-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
import mongoose, {
2-
Types,
3-
Document,
4-
Schema,
5-
Model,
6-
model,
7-
Query,
8-
} from "mongoose";
1+
import mongoose, { Document, Schema, Model, model, Query } from "mongoose";
92
import * as bcrypt from "bcrypt";
103
import validator from "validator";
114

125
export interface IUserDocument extends Document {
13-
_id: Types.ObjectId;
6+
// _id: Types.ObjectId;
147
firstName: string;
158
lastName: string;
169
email: string;

src/test/controllers/authController.test.ts

-21
This file was deleted.

src/test/integration/auth.test.ts

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { clearDatabase, connect } from "../utils/dbHandler";
2+
import request from "supertest";
3+
import app from "../../app";
4+
import { ObjectID } from "mongodb";
5+
6+
const agent = request(app);
7+
8+
beforeAll(async () => {
9+
await connect();
10+
});
11+
12+
beforeEach(async () => {
13+
await clearDatabase();
14+
});
15+
16+
describe("POST /users/signup", () => {
17+
it("should create a new user", async (done) => {
18+
await agent
19+
.post("/users/signup")
20+
.send(newUser)
21+
.expect(201)
22+
.then((res) => {
23+
expect(res.body.data.user).toBeTruthy();
24+
});
25+
done();
26+
});
27+
});
28+
29+
describe("POST /users/login", () => {
30+
it("should return 200 if token is correct", async () => {
31+
let token: any;
32+
33+
// seed database by creating new user
34+
await agent
35+
.post("/users/signup")
36+
.send(newUser)
37+
.expect(201)
38+
.then((res) => {
39+
expect(res.body.data.user).toBeTruthy();
40+
});
41+
42+
// login
43+
await agent
44+
.post("/users/login")
45+
.send(login)
46+
.expect(200)
47+
.then((res) => {
48+
expect(res.body.data.user).toBeTruthy();
49+
token = res.body.token;
50+
});
51+
52+
const res = await agent
53+
.get("/questions")
54+
.set("authorization", `Bearer ${token}`);
55+
expect(res.status).toBe(200);
56+
});
57+
});
58+
59+
describe("auth middleware", () => {
60+
let token: string;
61+
let question;
62+
63+
const exec = () => {
64+
const res = agent
65+
.post("/questions")
66+
.set("authorization", `Bearer ${token}`)
67+
.send(question);
68+
69+
return res;
70+
};
71+
72+
beforeEach(async () => {
73+
/**
74+
* seed database by creating new user
75+
* */
76+
await agent
77+
.post("/users/signup")
78+
.send(newUser)
79+
.expect(201)
80+
.then((res) => {
81+
expect(res.body.data.user).toBeTruthy();
82+
});
83+
84+
/**
85+
* login
86+
*/
87+
await agent
88+
.post("/users/login")
89+
.send(login)
90+
.expect(200)
91+
.then((res) => {
92+
expect(res.body.data.user).toBeTruthy();
93+
token = res.body.token;
94+
});
95+
96+
question = validQuestion;
97+
});
98+
99+
it("should return 401 if no token is provided", async () => {
100+
token = "";
101+
const res = await exec();
102+
expect(res.status).toBe(401);
103+
});
104+
105+
it("should return 401 if token is an invalid string", async () => {
106+
token = "a";
107+
const res = await exec();
108+
expect(res.status).toBe(401);
109+
});
110+
111+
it("should return 200 if token is valid", async () => {
112+
const res = await exec();
113+
expect(res.status).toBe(201);
114+
});
115+
});
116+
117+
const id = ObjectID.createFromHexString("08900823AD32DEAA09080990");
118+
const validQuestion = { title: "Jest", body: "Jest for testing", author: id };
119+
120+
const newUser = {
121+
firstName: "Burna",
122+
lastName: "Wazobia",
123+
email: "burna@gmail.com",
124+
username: "burnaboy",
125+
password: "123456789",
126+
passwordConfirm: "123456789",
127+
};
128+
129+
const login = {
130+
username: "burnaboy",
131+
password: "123456789",
132+
};
+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import { clearDatabase, connect } from "../utils/dbHandler";
2+
import request from "supertest";
3+
import app from "../../app";
4+
import { ObjectID } from "mongodb";
5+
import { Question } from "../../models/questionModel";
6+
7+
const agent = request(app);
8+
9+
beforeAll(async () => {
10+
await connect();
11+
});
12+
13+
beforeEach(async () => {
14+
await clearDatabase();
15+
});
16+
17+
describe("/questions", () => {
18+
describe("GET /", () => {
19+
it("should return 401 if user is not authorized", async () => {
20+
const res = await agent.get("/questions");
21+
expect(res.status).toBe(401);
22+
});
23+
});
24+
25+
// describe('GET /:id', () => {
26+
// it('should return a question if valid id is passed', async () => {
27+
28+
// })
29+
// })
30+
31+
// describe('GET /:id/up-vote', () => {
32+
// it('should make a post for up-vote if valid question id is passed', async () => {
33+
34+
// })
35+
// })
36+
37+
// describe('GET /:id/down-vote', () => {
38+
// it('should make a post for down-vote if valid question id is passed', async () => {
39+
40+
// })
41+
// })
42+
43+
// describe('GET /:id/reply', () => {
44+
// it('should make a post for a response to a question if valid question id is passed', async () => {
45+
46+
// })
47+
// })
48+
49+
// describe('GET /:id/subscribe', () => {
50+
// it('should subscribe to a question for notifications if valid question id is passed', async () => {
51+
52+
// })
53+
// })
54+
describe("POST /", () => {
55+
// create with a valid question
56+
let question;
57+
let token: string;
58+
59+
const exec = async () => {
60+
const res = await agent
61+
.post("/questions")
62+
.set("authorization", `Bearer ${token}`)
63+
.send(question);
64+
65+
return res;
66+
};
67+
68+
beforeEach(async () => {
69+
/**
70+
* seed database by creating new user
71+
* */
72+
await agent
73+
.post("/users/signup")
74+
.send(newUser)
75+
.expect(201)
76+
.then((res) => {
77+
expect(res.body.data.user).toBeTruthy();
78+
});
79+
80+
/**
81+
* login
82+
*/
83+
await agent
84+
.post("/users/login")
85+
.send(login)
86+
.expect(200)
87+
.then((res) => {
88+
expect(res.body.data.user).toBeTruthy();
89+
token = res.body.token;
90+
});
91+
92+
question = validQuestion;
93+
});
94+
95+
it("should return a 401 if client is not logged in", async () => {
96+
token = "";
97+
const res = await exec();
98+
expect(res.status).toBe(401);
99+
});
100+
101+
it("should return a 400 if question does not contain title i.e invalid question", async () => {
102+
question = invalidQuestion;
103+
const res = await exec();
104+
105+
expect(res.status).toBe(400);
106+
});
107+
108+
it("should save the question if it is valid", async () => {
109+
const res = await exec();
110+
111+
const result = await Question.findOne();
112+
113+
expect(res.status).toBe(201);
114+
expect(result).not.toBeNull();
115+
});
116+
117+
it("should return the question if it is valid", async () => {
118+
const res = await exec();
119+
120+
expect(res.body.data.data).toHaveProperty("_id");
121+
expect(res.body.data.data).toHaveProperty("title", validQuestion.title);
122+
});
123+
});
124+
});
125+
126+
const id = ObjectID.createFromHexString("08900823AD32DEAA09080990");
127+
const validQuestion = { title: "Jest", body: "Jest for testing", author: id };
128+
const invalidQuestion = { body: "Jest for testing", author: id };
129+
const newUser = {
130+
firstName: "Burna",
131+
lastName: "Wazobia",
132+
email: "burna@gmail.com",
133+
username: "burnaboy",
134+
password: "123456789",
135+
passwordConfirm: "123456789",
136+
};
137+
138+
const login = {
139+
username: "burnaboy",
140+
password: "123456789",
141+
};

src/test/integrationTest/questions.test.ts

-19
This file was deleted.

0 commit comments

Comments
 (0)