Skip to content

Instantly share code, notes, and snippets.

@davified
Last active March 17, 2018 00:15
Show Gist options
  • Save davified/06092be48e3b0b9645f069af999dcee3 to your computer and use it in GitHub Desktop.
Save davified/06092be48e3b0b9645f069af999dcee3 to your computer and use it in GitHub Desktop.
Including mongoose and tests
MONGODB_URI=mongodb://localhost/replace_with_your_own_local_db
// in models/book.js
// we define a schema for books and immediately use it to create and export a Book model
const mongoose = require("mongoose");
const bookSchema = mongoose.Schema({
title: String,
summary: String,
created: {
type: Date,
default: Date.now
}
});
const Book = mongoose.model("Book", bookSchema);
module.exports = Book;
// in routes/books.js
// Here we implement standard GET, POST and PUT routes in the books router middleware
// this will handle requests for the localhost:3000/books endpoint
var express = require("express");
var router = express.Router();
var Book = require("../models/book");
/* GET books listing. */
router.get("/", async (req, res, next) => {
try {
const books = await Book.find({});
res.json(books);
} catch (err) {
next(err);
}
});
router.post("/", async (req, res, next) => {
try {
const newBook = new Book({
title: req.body.title,
summary: req.body.summary
});
const book = await newBook.save();
console.log("saving book");
res.json({ message: "book created", book: book });
} catch (err) {
console.log("catcing error");
next(err);
}
});
router.put("/:id", async (req, res) => {
requestBody = {
title: req.body.title,
summary: req.body.summary
};
try {
const updatedBook = await Book.findByIdAndUpdate(
req.params.id,
requestBody,
{ new: true }
);
res.json({
message: "book updated",
book: updatedBook
});
} catch (err) {
next(err);
}
});
module.exports = router;
// in tests/integration-tests/books.test.js
// here we define integration tests for localhost:3000/books
process.env.ENV = "test";
const app = require("../../app");
const request = require("supertest");
const Book = require("../../models/book");
const mongoose = require("mongoose");
describe("routes/books", () => {
let db;
// before running all tests, we need to connect to the DB.
beforeAll(async () => {
const dbUri = "mongodb://localhost/express_blog_api_test_db";
db = await mongoose.connect(dbUri, () => {
console.log("connected to test DB successfully");
});
await Book.deleteMany().exec();
// delete all books. we do this everytime the tests run so that our database is in a clean state
// this will ensure that any passes/failures are a direct result of
// our code, and not because of data (which may or may not be there)
});
it("GET /books should return status of 200 and all books in the test DB", async () => {
const expectedBooks = await Book.find({});
const response = await request(app).get("/books");
expect(response.status).toEqual(200);
expect(response.header["content-type"]).toContain("application/json");
expect(response.body).toEqual(expectedBooks);
});
it("POST /books should create book", async () => {
const TITLE = "harry potter";
const SUMMARY = "harry survives";
const response = await request(app)
.post("/books")
.send({ title: TITLE, summary: SUMMARY });
expect(response.status).toEqual(200);
expect(response.header["content-type"]).toContain("application/json");
expect(response.body.message).toEqual("book created");
expect(response.body.book.title).toEqual(TITLE);
expect(response.body.book.summary).toEqual(SUMMARY);
});
it("PUT /books/:id should update book", async () => {
const TITLE = "harry potter";
const NEW_TITLE = `new ${TITLE}`;
const SUMMARY = "harry survives";
const book = new Book({ title: TITLE, summary: SUMMARY });
await book.save();
const response = await request(app)
.put(`/books/${book.id}`)
.send({ title: NEW_TITLE, summary: SUMMARY });
expect(response.status).toEqual(200);
expect(response.header["content-type"]).toContain("application/json");
expect(response.body.message).toEqual("book updated");
expect(response.body.book.title).toEqual(NEW_TITLE);
expect(response.body.book.summary).toEqual(SUMMARY);
});
// we delete all books and close the connection to the database after every run of the tests
// otherwise, we'll have hundreds of open connections to our db (this is what mongoose.connect() does)
// after jest runs our test hundreds of times
afterAll(async () => {
await Book.deleteMany().exec();
await db.close();
});
});
dependencies: {
// ...
"dotenv": "^5.0.1",
"mongoose": "^5.0.10"
// ...
},
devDependencies: {
"jest": "^23.0.0-alpha.0",
"supertest": "^3.0.0"
}
// in ./server.js
// notice that we've moved DB connection logic outside of app.js to server.js
// this logic will only be read when we run server.js, which happens only in 2 places:
// 1. when we run `yarn start` locally.
// 2. when heroku runs `yarn start` in production.
// a longer explanation on `process.env` can be found below
if (process.env.NODE_ENV !== "production") {
require("dotenv").load();
}
const app = require("./app");
const mongoose = require("mongoose");
mongoose.connect(process.env.MONGODB_URI, function(err) {
if (err) throw err;
console.log("db connected successfully");
const server = app.listen(process.env.PORT || 3000, () => {
console.log(`Listening on port ${server.address().port}...`);
});
});
// `process.env` is an object containing all environment variables. It contains system
// default environment variables and any variable we define locally as environoment variables
// or in heroku's config vars
// 1. when we run `yarn start` locally, NODE_ENV !== "production"
// (because we didn't define NODE_ENV="production" anywhere,
// so (dotenv).load() will load the environment variables (e.g. MONGODB_URI)
// you defined in .env into `process.env`
// 2. when heroku runs `yarn start` in production, NODE_ENV === "production"
// (because we define NODE_ENV as 'production' in heroku's config vars)
// and dotenv.load() will be skipped. process.env.MONGODB_URI will be read from
// the environment variable MONGODB_URI, which you defined in heroku's config vars
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment