Skip to content

Commit b2f8076

Browse files
[mabel] Update mongoose and mongoose testing
1 parent 666c355 commit b2f8076

File tree

5 files changed

+85
-30
lines changed

5 files changed

+85
-30
lines changed

docs/_sidebar.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
- [Mongoose CRUD](backend-web-development/mongoose-crud)
114114
- [Mongoose virtuals](backend-web-development/mongoose-virtuals)
115115
- [Mongoose validation](backend-web-development/mongoose-validation)
116+
- [Mongoose and express controllers](backend-web-development/mongoose-express)
116117
- [Mongoose testing](backend-web-development/mongoose-testing)
117118
- [Security auth](backend-web-development/security-auth)
118119
- [Security cryptography basics](backend-web-development/security-cryptography-basics)

docs/backend-web-development/mongoose-basics.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const mongoOptions = {
3333

3434
// will create a new db if does not exist
3535
const dbName = "pokedex";
36-
const dbUrl = global.__MONGO_URI__ || "mongodb://localhost:27017/" + dbName;
36+
const dbUrl = process.env.MONGODB_URI || "mongodb://localhost:27017/" + dbName;
3737
mongoose.connect(dbUrl, mongoOptions);
3838
const db = mongoose.connection;
3939

@@ -42,16 +42,16 @@ const db = mongoose.connection;
4242
// read https://www.tjvantoll.com/2015/12/29/console-error-bind/
4343
db.on("error", console.error.bind(console, "connection error:"));
4444
db.once("open", () => {
45-
console.log("connected to mongodb");
45+
console.log(`connected to mongodb at ${dbUrl}`);
4646
});
4747
```
4848

4949
We put this in a "db.js" file in a utils folder.
5050

51-
To connect to the database:
51+
To connect to the database, "require" this file in app.js:
5252

5353
```js
54-
//index.js
54+
//app.js
5555
require("./utils/db");
5656
```
5757

@@ -89,7 +89,9 @@ We define a property called `name` with a schema type `String` which maps to an
8989

9090
`name` is also a `required` field, which means that a document using this schema must have this field. The value of `name` has to have a length of at least 3.
9191

92-
Note that the `unique` field of `name` does not enforce uniqueness with validation but instead will try to an unique index in your the MongoDB database. If the index is not built correctly, this might not always work.
92+
The `unique` field of `name` does not enforce uniqueness with validation but instead will try to an unique index in your the MongoDB database. If the index is not built correctly, this might not always work. See the index being created in the database using MongoDB Compass.
93+
94+
(Note that if you try to enforce uniqueness for a field that could be null or empty, you might need to create the unique index as a partial index that ignores null or empty values. See https://stackoverflow.com/questions/52094484/mongodb-create-unique-index-on-a-field-not-in-all-documents for more details.)
9395

9496
The following Schema Types are allowed:
9597

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Mongoose with Express.js
2+
3+
When adding a database to Express.js that the backend server will interact with, many of our route handlers will become more like controllers that interact with the database.
4+
5+
For example, route handlers that GET a single resource can be a controller named `findOne` that finds a single resource in the database.
6+
7+
Similarly, when you POST a single resource in a route handler, it can be a controller named `createOne` that creates a single resource in the database.
8+
9+
It is convention to put these controllers into a `controllers` folder. Controllers are these handlers interacting with the database that is linked to the routing in the routers.
10+
11+
Refactor the controllers into the folder.
12+
13+
In the MVC design pattern, controllers is the middleman between Express.js routes and mongoose models.
14+
15+
![MVC diagram](https://mdn.mozillademos.org/files/14456/MVC%20Express.png)

docs/backend-web-development/mongoose-testing.md

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,16 @@ Here is an example on using it with Jest: https://github.com/nodkz/mongodb-memor
2626

2727
before writing any test...
2828

29+
pokemons.route.test.js
30+
2931
```js
30-
//pokemons.route.test.js
3132
const request = require("supertest");
3233
const app = require("../../src/app");
3334
const Pokemon = require("../../src/models/pokemon.model");
34-
const mongoose = require("mongoose");
35-
const { MongoMemoryServer } = require("mongodb-memory-server");
36-
37-
mongoose.set("useNewUrlParser", true);
38-
mongoose.set("useFindAndModify", false);
39-
mongoose.set("useCreateIndex", true);
40-
mongoose.set("useUnifiedTopology", true);
35+
const { teardownMongoose } = require("../../test/mongoose");
4136

4237
describe("pokemons", () => {
43-
let mongoServer;
44-
beforeAll(async () => {
45-
try {
46-
mongoServer = new MongoMemoryServer();
47-
const mongoUri = await mongoServer.getConnectionString();
48-
await mongoose.connect(mongoUri);
49-
} catch (err) {
50-
console.error(err);
51-
}
52-
});
53-
54-
afterAll(async () => {
55-
await mongoose.disconnect();
56-
await mongoServer.stop();
57-
});
38+
afterAll(async () => await teardownMongoose());
5839

5940
beforeEach(async () => {
6041
const pokemonData = [
@@ -82,6 +63,49 @@ describe("pokemons", () => {
8263

8364
```
8465
66+
In package.json:
67+
68+
```json
69+
"jest": {
70+
"globalSetup": "./test/setup.js",
71+
"globalTeardown": "./test/teardown.js"
72+
}
73+
```
74+
75+
test/setup.js
76+
77+
```js
78+
const { MongoMemoryServer } = require("mongodb-memory-server");
79+
80+
module.exports = async () => {
81+
const mongoServer = new MongoMemoryServer();
82+
const mongoUri = await mongoServer.getConnectionString();
83+
process.env.MONGODB_URI = mongoUri;
84+
// Set reference to mongo server in order to close the server during teardown
85+
global.__MONGOSERVER__ = mongoServer;
86+
};
87+
```
88+
89+
test/teardown.js
90+
91+
```js
92+
module.exports = async () => {
93+
await global.__MONGOSERVER__.stop();
94+
};
95+
```
96+
97+
test/mongoose.js
98+
99+
```js
100+
const mongoose = require("mongoose");
101+
102+
const teardownMongoose = async () => {
103+
// proper teardown of mongoose to prevent leaks
104+
await mongoose.disconnect();
105+
};
106+
module.exports = { teardownMongoose };
107+
```
108+
85109
If you try testing with mongoose now, you will see the following warning
86110
87111
```sh
@@ -93,6 +117,7 @@ Add this to package.json
93117
```json
94118
//package.json
95119
"jest": {
120+
...
96121
"testEnvironment": "node"
97122
}
98123
```
@@ -157,3 +182,7 @@ https://formidable.com/blog/2019/fast-node-testing-mongodb/
157182
In the example above, we make use of the mongodb-memory-server to automatically give us a fresh database in each test case.
158183
159184
Without that library, another possible solution is to explicitly delete all data in the test database after each test finishes running. That's a bit tedious but still works. Here is a [sample project showing this approach](https://github.com/thoughtworks-jumpstart/express-blog-api-mongoose-and-tests). Check out the test cases in tests/integration-tests to see the sample tests.
185+
186+
## Exercises
187+
188+
Integrate mongoose into your testing for your song routes.

docs/backend-web-development/mongoose-validation.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Mongoose validation
22

3-
Previously, we used Joi for validation of our data. With Mongoose, we can still use Joi, but now we want to learn about implementing this validation directly in Mongoose.
3+
Previously, we used Joi for validation of our data. With Mongoose, we can and should still use Joi, but now we want to learn about implementing this validation directly in Mongoose.
44

55
In the schema, you can specify the validators. You have already saw some such as `required`.
66

@@ -39,7 +39,7 @@ How do we add our own custom validator?
3939
```js
4040
// make sure every value is equal to "something"
4141
function validator(val) {
42-
return val == "something";
42+
return val === "something";
4343
}
4444

4545
const nameSchema = new Schema({
@@ -54,3 +54,11 @@ const nameSchema = new Schema({
5454
var custom = [validator, 'Uh oh, {PATH} does not equal "something".'];
5555
new Schema({ name: { type: String, validate: custom } });
5656
```
57+
58+
## Exercises
59+
60+
Integrate your songs routes with MongoDB and Mongoose!
61+
62+
- Create a schema with validation and a model for your songs
63+
- Create a database for your songs in your MongoDB
64+
- Change your controllers

0 commit comments

Comments
 (0)