33
loading...
This website collects cookies to deliver better user experience
expect
function that will help us compare the expected values to the actual ones.npm i mocha chai supertest
. It will install all of the necessary dependencies, and we are ready to go.package.json
file, by adding a new script for testing. Open the package.json file and add the following line inside of the scripts:"test": "NODE_ENV=testing mocha --recursive --exit --timeout 10000"
NODE_ENV=testing
means that we set the global environment variable called "NODE_ENV" inside of the .env
file to "testing", so we will have to create it. For the time being you can open the .env
file and add the following line NODE_ENV="development"
.--recurisive
means that mocha will look inside of the subdirectories for testing files, --exit
will force mocha to stop working once it's done with testing, and --timeout 10000
will give us more time for the processing time. As our app connects to the database, reads and creates data, it may take some time to finish. If we didn't set this timeout, it would simply crash..env
file called "MONGO_URI_TEST". Now you can basically copy-paste the previous link of the original database, but change the name of the collection in the string, to the test one.let database = process.env.MONGO_URI;
mongoose
.connect(database, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
})
.then(() => {
console.log("Database connection established");
})
.catch((err) => {
console.error(`ERROR: ${err}`);
});
if (process.env.NODE_ENV === "testing") {
database = process.env.MONGO_URI_TEST;
}
export default app;
import request from "supertest";
import { expect } from "chai";
import dotenv from "dotenv";
dotenv.config();
import app from "../../app.js";
import User from "../../models/user.model.js";
const tempUser = {
username: process.env.USER_TEST,
password: process.env.USER_TEST_PASSWORD,
};
let tempToken;
before(function (done) {
this.timeout(3000);
setTimeout(done, 2000);
});
describe("POST users", () => {
it("should register new user with valid credentials", (done) => {
request(app)
.post("/users/signup")
.send(tempUser)
.expect(201)
.then((res) => {
expect(res.body.username).to.be.eql(process.env.USER_TEST);
done();
})
.catch((err) => done(err));
});
it("shouldn't accept the username that already exists in the database", (done) => {
request(app)
.post("/users/signup")
.send(tempUser)
.expect(400)
.then((res) => {
expect(res.body.message).to.be.eql("Username is already in use");
done();
})
.catch((err) => done(err));
});
});
describe
functions with the first parameter as a description string, and the second one as callbacks for executing the tests. Every single test will be inside of the it
function which has a similar syntax to descript, with the exception of done
parameter which will be called each time we move on to the next test. Indeed done
parameter adds some kind of asynchronous logic to our tests. Then we call request
function from "supertest" library, which will then execute API calls with a parameter such as adding the method, body, setting headers, and getting the response. We do the testing inside of the then
part, and at the end, we always have to add done()
as otherwise, our tests will get stuck at that point. npm run test
. It will automatically run mocha, which will execute all of the tests and show the results in the console. By the convention, it is always better to write tests and test each of them right after writing. If it fails, try to fix the problem and do not move on with writing new tests until you get the first one passing.describe("PATCH users", () => {
it("should accept correct credentials", (done) => {
request(app)
.patch("/users/login")
.send(tempUser)
.expect(200)
.then((res) => {
expect(res.body.message).to.be.eql("User logged in successfully");
tempToken = `Bearer ${res.body.accessToken}`;
done();
})
.catch((err) => done(err));
});
it("shouldn't accept invalid password", (done) => {
tempUser.password = process.env.USER_TEST_PASSWORD + "asdf";
request(app)
.patch("/users/login")
.send(tempUser)
.expect(400)
.then((res) => {
expect(res.body.message).to.be.eql("Invalid password");
done();
})
.catch((err) => done(err));
});
it("shouldn't accept non-exisiting username", (done) => {
tempUser.username = process.env.USER_TEST + "asdf";
request(app)
.patch("/users/login")
.send(tempUser)
.expect(404)
.then((res) => {
expect(res.body.message).to.be.eql("Account not found");
done();
})
.catch((err) => done(err));
});
it("should log out users with valid token", (done) => {
request(app)
.patch("/users/logout")
.set({
Authorization: tempToken,
})
.expect(200)
.then((res) => {
expect(res.body.message).to.be.eql("User logged out");
done();
})
.catch((err) => done(err));
});
});
after(async () => {
try {
await User.deleteOne({ username: process.env.USER_TEST });
} catch (err) {
console.error(err);
}
});
before
function, now we have after
function which deletes the temporary from our test database, to let us execute the same tests once again.