Step 9
Add tests/routes/notes.test.js
with the following content. Notice that we decided only clients were allowed to perform CRUD operations on their notes.
const faker = require("faker");
const mongoose = require("mongoose");
const supertest = require("supertest");
const app = require("../../server");
const UserDao = require("../../server/data/UserDao");
const NoteDao = require("../../server/data/NoteDao");
const { createToken } = require("../../server/util/token");
const users = new UserDao();
const notes = new NoteDao();
const request = supertest(app);
const endpoint = "/api/notes";
describe(`Test ${endpoint} endpoints`, () => {
const tokens = {};
const clients = [];
beforeAll(async () => {
await mongoose.connect(global.__MONGO_URI__);
clients[0] = await users.create({
username: "client1",
password: "client1",
role: "CLIENT",
});
clients[1] = await users.create({
username: "client2",
password: "client2",
role: "CLIENT",
});
clients[2] = await users.create({
username: "admin",
password: "admin",
role: "ADMIN",
});
tokens.admin = await createToken(clients[2]);
tokens.invalid = tokens.admin
.split("")
.sort(function () {
return 0.5 - Math.random();
})
.join("");
tokens.client = await createToken(clients[0]);
tokens.expiredAdmin = await createToken(clients[2], -1);
});
describe(`Test GET ${endpoint}`, () => {
const samples = [];
beforeAll(async () => {
samples[0] = await notes.create({
title: "known title for search query!",
text: faker.lorem.paragraph(),
author: clients[0]._id,
});
samples[1] = await notes.create({
title: faker.lorem.sentence(),
text: faker.lorem.paragraph(),
author: clients[0]._id,
});
samples[2] = await notes.create({
title: faker.lorem.sentence(),
text: faker.lorem.paragraph(),
author: clients[1]._id,
});
});
test("Return 403 for missing token", async () => {
const response = await request.get(endpoint);
expect(response.status).toBe(403);
});
test("Return 403 for invalid token", async () => {
const response = await request
.get(endpoint)
.set("Authorization", `Bearer ${tokens.invalid}`);
expect(response.status).toBe(403);
});
test("Return 403 for expired token", async () => {
const response = await request
.get(endpoint)
.set("Authorization", `Bearer ${tokens.expiredAdmin}`);
expect(response.status).toBe(403);
});
test("Return 200 and list of notes for successful request", async () => {
const response = await request
.get(endpoint)
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(200);
const expected = samples.filter(
(s) => s.author === clients[0]._id
).length;
expect(response.body.data.length).toBe(expected);
});
describe(`Test GET ${endpoint} with query parameter`, () => {
test("Return 200 and list of notes for successful request", async () => {
const query = samples[0].title;
const response = await request
.get(`${endpoint}?query=${query}`)
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(200);
const expected = samples.filter((s) => s.title.includes(query)).length;
expect(response.body.data.length).toBe(expected);
});
});
afterAll(async () => {
for (const sample of samples) {
await notes.delete(sample.author, sample._id);
}
});
});
describe(`Test GET ${endpoint}/:id`, () => {
let sample;
beforeAll(async () => {
sample = await notes.create({
title: faker.lorem.sentence(),
text: faker.lorem.paragraph(),
author: clients[0]._id,
});
});
test("Return 404 for an invalid id", async () => {
const id = mongoose.Types.ObjectId().toString();
const response = await request
.get(`${endpoint}/${id}`)
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(404);
});
test("Return 403 for missing token", async () => {
const id = sample._id;
const response = await request.get(`${endpoint}/${id}`);
expect(response.status).toBe(403);
});
test("Return 403 for invalid token", async () => {
const id = sample._id;
const response = await request
.get(`${endpoint}/${id}`)
.set("Authorization", `Bearer ${tokens.invalid}`);
expect(response.status).toBe(403);
});
test("Return 403 for unauthorized token", async () => {
const id = sample._id;
const response = await request
.get(`${endpoint}/${id}`)
.set("Authorization", `Bearer ${tokens.admin}`);
expect(response.status).toBe(403);
});
test("Return 403 for expired token", async () => {
const id = sample._id;
const response = await request
.get(`${endpoint}/${id}`)
.set("Authorization", `Bearer ${tokens.expiredAdmin}`);
expect(response.status).toBe(403);
});
test("Return 200 and the user for a given id", async () => {
const id = sample._id;
const response = await request
.get(`${endpoint}/${id}`)
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(200);
expect(response.body.data).toStrictEqual(sample);
});
afterAll(async () => {
await notes.delete(sample.author, sample._id);
});
});
describe(`Test POST ${endpoint}`, () => {
let sample;
beforeAll(async () => {
sample = {
title: faker.lorem.sentence(),
text: faker.lorem.paragraph(),
};
});
test("Return 403 for missing token", async () => {
const response = await request.post(endpoint).send(sample);
expect(response.status).toBe(403);
});
test("Return 403 for invalid token", async () => {
const response = await request
.post(endpoint)
.send(sample)
.set("Authorization", `Bearer ${tokens.invalid}`);
expect(response.status).toBe(403);
});
test("Return 403 for expired token", async () => {
const response = await request
.post(endpoint)
.send(sample)
.set("Authorization", `Bearer ${tokens.expiredAdmin}`);
expect(response.status).toBe(403);
});
test("Return 400 for missing payload", async () => {
const response = await request
.post(endpoint)
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(400);
});
test("Return 400 for missing title", async () => {
const response = await request
.post(endpoint)
.send({
text: faker.lorem.paragraph(),
})
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(400);
});
test("Return 400 for missing text", async () => {
const response = await request
.post(endpoint)
.send({
title: faker.lorem.paragraph(),
})
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(400);
});
test("Return 201 and the user for successful request", async () => {
const response = await request
.post(endpoint)
.send(sample)
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(201);
expect(response.body.data.title).toBe(sample.title);
expect(response.body.data.text).toBe(sample.text);
sample._id = response.body.data._id;
sample.author = response.body.data.author;
});
afterAll(async () => {
await notes.delete(sample.author, sample._id);
});
});
describe(`Test PUT ${endpoint}/:id`, () => {
let sample;
beforeAll(async () => {
sample = await notes.create({
title: faker.lorem.sentence(),
text: faker.lorem.paragraph(),
author: clients[0]._id,
});
});
test("Return 404 for invalid ID", async () => {
const id = mongoose.Types.ObjectId().toString();
const response = await request
.put(`${endpoint}/${id}`)
.send({
title: faker.lorem.sentence(),
})
.set("Authorization", `Bearer ${tokens.admin}`);
expect(response.status).toBe(404);
});
test("Return 403 for missing token", async () => {
const response = await request.put(`${endpoint}/${sample._id}`).send({
title: faker.lorem.sentence(),
});
expect(response.status).toBe(403);
});
test("Return 403 for invalid token", async () => {
const response = await request
.put(`${endpoint}/${sample._id}`)
.send({
title: faker.lorem.sentence(),
})
.set("Authorization", `Bearer ${tokens.invalid}`);
expect(response.status).toBe(403);
});
test("Return 403 for unauthorized token", async () => {
const response = await request
.put(`${endpoint}/${sample._id}`)
.send({
title: faker.lorem.sentence(),
})
.set("Authorization", `Bearer ${tokens.admin}`);
expect(response.status).toBe(403);
});
test("Return 403 for expired token", async () => {
const response = await request
.put(`${endpoint}/${sample._id}`)
.send({
title: faker.lorem.sentence(),
})
.set("Authorization", `Bearer ${tokens.expiredAdmin}`);
expect(response.status).toBe(403);
});
test("Return 400 for missing payload", async () => {
const response = await request
.put(`${endpoint}/${sample._id}`)
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(400);
});
test("Return 200 and updated user for successful request", async () => {
const response = await request
.put(`${endpoint}/${sample._id}`)
.send({
title: faker.lorem.sentence(),
})
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(200);
});
afterAll(async () => {
await notes.delete(sample.author, sample._id);
});
});
describe(`Test DELETE ${endpoint}/:id`, () => {
let sample;
beforeAll(async () => {
sample = await notes.create({
title: faker.lorem.sentence(),
text: faker.lorem.paragraph(),
author: clients[0]._id,
});
});
test("Return 404 for invalid ID", async () => {
const id = mongoose.Types.ObjectId().toString();
const response = await request
.delete(`${endpoint}/${id}`)
.set("Authorization", `Bearer ${tokens.admin}`);
expect(response.status).toBe(404);
});
test("Return 403 for missing token", async () => {
const response = await request.delete(`${endpoint}/${sample._id}`);
expect(response.status).toBe(403);
});
test("Return 403 for invalid token", async () => {
const response = await request
.delete(`${endpoint}/${sample._id}`)
.set("Authorization", `Bearer ${tokens.invalid}`);
expect(response.status).toBe(403);
});
test("Return 403 for unauthorized token", async () => {
const response = await request
.delete(`${endpoint}/${sample._id}`)
.set("Authorization", `Bearer ${tokens.admin}`);
expect(response.status).toBe(403);
});
test("Return 403 for expired token", async () => {
const response = await request
.delete(`${endpoint}/${sample._id}`)
.set("Authorization", `Bearer ${tokens.expiredAdmin}`);
expect(response.status).toBe(403);
});
test("Return 200 and deleted user for successful request", async () => {
const response = await request
.delete(`${endpoint}/${sample._id}`)
.set("Authorization", `Bearer ${tokens.client}`);
expect(response.status).toBe(200);
expect(response.body.data).toStrictEqual(sample);
});
});
afterAll(async () => {
await mongoose.connection.db.dropDatabase();
await mongoose.connection.close();
});
});
Save the file and run the tests. They should all pass!