-
-
Save davified/06092be48e3b0b9645f069af999dcee3 to your computer and use it in GitHub Desktop.
Including mongoose and tests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MONGODB_URI=mongodb://localhost/replace_with_your_own_local_db |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dependencies: { | |
// ... | |
"dotenv": "^5.0.1", | |
"mongoose": "^5.0.10" | |
// ... | |
}, | |
devDependencies: { | |
"jest": "^23.0.0-alpha.0", | |
"supertest": "^3.0.0" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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