Skip to content

Commit 1e41cda

Browse files
[mabel] Edits to express.js lessons
1 parent 1aaa6e4 commit 1e41cda

File tree

4 files changed

+88
-49
lines changed

4 files changed

+88
-49
lines changed

docs/backend-web-development/express-middleware.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ You could also imagine that it is a factory. For the request "assembly line", th
1515
The request object, response object and the `next` function are passed to each middleware function. To move on to the `next` function to be run in the stack (could be a middleware function or handler function), the `next` function needs to be called.
1616

1717
```js
18-
app.use(function(req, res, next) {
18+
app.use((req, res, next) => {
1919
console.log("Method: " + req.method);
2020
console.log("Path: " + req.url);
2121
next();
@@ -75,7 +75,7 @@ Refer to the script: [Express.js playground: middleware_example_1](https://githu
7575
Add a middleware function that will be called for all routes. It has no mount path.
7676
7777
```js
78-
app.use(function (req, res, next) {
78+
app.use((req, res, next) => {
7979
console.log("common middleware function was called!");
8080
next();
8181
});
@@ -84,7 +84,7 @@ app.use(function (req, res, next) {
8484
Add a middleware function that will only be called if a request goes to the `/users` route.
8585
8686
```js
87-
app.use("/users", function (req, res, next) {
87+
app.use("/users", (req, res, next) => {
8888
console.log("middleware function for /users was called!");
8989
next();
9090
});
@@ -93,7 +93,7 @@ app.use("/users", function (req, res, next) {
9393
Add a middleware function that will only be called if a POST request goes to the `/users` route.
9494
9595
```js
96-
app.post("/users", function (req, res, next) {
96+
app.post("/users", (req, res, next) => {
9797
console.log("second middleware function for /users was called!");
9898
next();
9999
});
@@ -102,7 +102,7 @@ app.post("/users", function (req, res, next) {
102102
Add a middleware function that will only be called if a GET request goes to the `/users` route.
103103
104104
```js
105-
app.get("/users", function (req, res, next) {
105+
app.get("/users", (req, res, next) => {
106106
console.log("third middleware function for /users was called!");
107107
next();
108108
});
@@ -192,7 +192,7 @@ You are also able to add middleware on the router level instead of the applicati
192192
Add a middleware function that is executed for every request to the router. It has no mount path.
193193
194194
```js
195-
var router = express.Router();
195+
const router = express.Router();
196196

197197
router.use((req, res, next) => {
198198
console.log("I am middleware for the router");

docs/backend-web-development/express-parsing-request-body.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ Add more API endpoints to the previous songs API that we had:
6060
Add middleware for parsing JSON request body.
6161

6262
1. Route: POST /songs
63-
HTTP Response status code: 201
63+
64+
HTTP Response status code: 201
6465

6566
Add a new song with id, and return new song
6667

@@ -84,7 +85,8 @@ Expected response:
8485
```
8586

8687
2. Route: GET /songs/:id
87-
HTTP Response status code: 200
88+
89+
HTTP Response status code: 200
8890

8991
Return a song with id using route parameters.
9092

@@ -99,7 +101,8 @@ if route path is /songs/1, expected response is:
99101
```
100102

101103
3. Route: PUT /songs/:id
102-
HTTP Response status code: 200
104+
105+
HTTP Response status code: 200
103106

104107
Replace a song with id, and return modified song
105108

@@ -125,7 +128,8 @@ Expected response:
125128
```
126129

127130
4. Route: DELETE /songs/:id
128-
HTTP Response status code: 200
131+
132+
HTTP Response status code: 200
129133

130134
delete a song with id, and return deleted song
131135

docs/backend-web-development/express-responses.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ No. The more status codes your API deals with, the more status codes you have to
122122
Implement an API with the following endpoint:
123123

124124
1. Route: GET /songs
125-
HTTP Response status code: 200
125+
126+
HTTP Response status code: 200
126127

127128
Expected response:
128129

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

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ The type of tests we are going to write is called integration test.
2222

2323
Integration tests, as the name suggests, tests that the different layers of your application (e.g. app, router, request handlers, any middleware, models and database) works as expected when integrated together.
2424

25-
In contrast, there is another type of tests, called Unit Test, which focus on testing a module/class/function works alone.
25+
In contrast, there is another type of tests, called Unit Test, which focus on testing a module/class/function works alone. For example, react testing library is often used to unit test a single React component.
2626

2727
## Tests for API
2828

2929
To verify that your API works as expected, usually you need to send some requests to a running instance of your application, and check the responses. This can be done manually using tools like Postman or Insomnia, but we prefer to automate those tests.
3030

3131
To automate those tests, the tests need to act as API consumers, issuing requests and verifying responses.
3232

33-
### Using Jest as a testing framework
33+
## Using Jest as a testing framework for testing our API
3434

35-
#### Filename Conventions for Jest
35+
### Filename Conventions for Jest
3636

3737
Jest will look for test files at:
3838

@@ -45,26 +45,38 @@ It is recommended to put the test files next to the code they are testing so tha
4545

4646
Read more about this in the [Jest documentation](https://jestjs.io/docs/en/configuration#testregex-string--arraystring).
4747

48-
#### Asynchronous tests with Jest
48+
### Asynchronous tests with Jest
4949

5050
We will like to send requests to test our API. Requests are asynchronous, therefore we need to have asynchronous tests.
5151

5252
How can we do this with Jest?
5353

5454
- Add the `async` keyword
55-
- Call `done` when you’re done with your tests
55+
- Call `done` when you’re done with your tests if you want to tell Jest exactly where to end the test (optional)
56+
57+
`done` is a callback passed by Jest. Jest will wait until the done callback is called before finishing the test. Read more about it in the [Jest documentation](https://jestjs.io/docs/en/asynchronous#callbacks).
58+
59+
```js
60+
it("Async test should do nothing", async () => {
61+
// Do async operations here
62+
});
63+
```
64+
65+
using the done callback is optional
5666

5767
```js
58-
it("Async test should do nothing", async done => {
68+
it("Async test should do nothing", async (done) => {
5969
// Do async operations here
6070
done();
6171
});
6272
```
6373

64-
### SuperTest
74+
## SuperTest
6575

6676
Previously, we mentioned that we will like to send requests to test our API. You can use libraries like [SuperTest](https://github.com/visionmedia/supertest).
6777

78+
SuperTest wraps around SuperAgent, which is another API for creating HTTP requests / making calls to other APIs.
79+
6880
### Installation
6981

7082
Install SuperTest and save it to your package.json file as a development dependency:
@@ -73,18 +85,18 @@ Install SuperTest and save it to your package.json file as a development depende
7385
npm install supertest --save-dev
7486
```
7587

76-
### Testing with Jest and SuperTest
88+
## Testing with Jest and SuperTest
7789

7890
SuperTest works without any framework but in our case we will use it along with Jest, since we are already using Jest as our testing framework.
7991

80-
#### Refactoring for tests
92+
### Refactoring for tests
8193

8294
Before we can start testing with SuperTest, we need to refactor our code to allow our server to be started by SuperTest for each of the tests.
8395

8496
Currently, our app looks like this in many of the examples where the routes exist in the same file as the server.
8597

8698
```js
87-
// testing_example_1.js
99+
// app.js
88100
app.get("/", (req, res) => {
89101
res.send("Welcome to my homepage");
90102
});
@@ -101,45 +113,44 @@ This doesn’t work when creating tests because it starts listening to one port.
101113
To solve this problem, you need to `export` the app without listening to it. Replace the `app.listen` code with `module.exports = app;`.
102114

103115
```js
104-
// testing_example_1.js
116+
// app.js
105117
module.exports = app;
106118
```
107119

108120
Now how do we run the server for development or production purposes? (not testing)
109121

110-
Normally when we are exporting the app like above, we do this in a file called **app.js**. (for this example, we shall just use testing_example_1.js)
122+
Normally when we are exporting the app like above, we do this in a file called **app.js**.
111123

112124
We create a new file called **index.js** to start the server and make the server listen to port 3000.
113-
(for this example, the file shall be called testing_example_1_index.js)
114125

115126
We `require` the previous file to import the app.
116127

117128
```js
118-
// testing_example_1_index.js
119-
const app = require("./testing_example_1");
129+
// index.js
130+
const app = require("./app");
120131
const PORT = 3000;
121132

122133
app.listen(PORT, () =>
123134
console.log(`Server running at http://localhost:${PORT}`)
124135
);
125136
```
126137

127-
Run `node testing_example_1_index.js` again to start your server. Ensure that it still works.
138+
Run `node index.js` again to start your server. Ensure that it still works.
128139

129-
#### Writing tests
140+
### Writing tests with SuperTest
130141

131142
First we will have to import SuperTest and our app.
132143

133144
```js
134-
// testing_example_1.test.js
145+
// app.test.js
135146
const request = require("supertest");
136-
const app = require("./testing_example_1");
147+
const app = require("./app");
137148
```
138149

139150
Test that Jest works
140151

141152
```js
142-
describe("testing_example_1", () => {
153+
describe("App", () => {
143154
it("Testing to see if Jest works", () => {
144155
expect(1).toBe(1);
145156
});
@@ -149,11 +160,11 @@ describe("testing_example_1", () => {
149160
Let's add our first test for the GET "/" route! We shall write it in a Promises way...
150161

151162
```js
152-
describe("testing_example_1", () => {
163+
describe("App", () => {
153164
it("GET / should respond with Welcome to my homepage", () => {
154165
return request(app)
155166
.get("/")
156-
.then(response => {
167+
.then((response) => {
157168
expect(response.status).toEqual(200);
158169
expect(response.text).toEqual("Welcome to my homepage");
159170
});
@@ -164,13 +175,10 @@ describe("testing_example_1", () => {
164175
Oh no. Let's use async/await instead.
165176

166177
```js
167-
describe("testing_example_1", () => {
168-
it("GET / should respond with Welcome to my homepage", async done => {
169-
const response = await request(app)
170-
.get("/")
171-
.expect(200);
178+
describe("App", () => {
179+
it("GET / should respond with Welcome to my homepage", async () => {
180+
const response = await request(app).get("/").expect(200);
172181
expect(response.text).toEqual("Welcome to my homepage");
173-
done();
174182
});
175183
});
176184
```
@@ -180,17 +188,13 @@ Looks nicer! It passes with green.
180188
What if we destructure the response to extract `text`?
181189

182190
```js
183-
it("should respond correctly", async done => {
184-
const { text } = await request(app)
185-
.get("/")
186-
.expect(200);
191+
it("should respond correctly", async () => {
192+
const { text } = await request(app).get("/").expect(200);
187193
expect(text).toEqual("Welcome to my homepage");
188-
done();
189194
});
190195
```
191196

192197
`request(app)` passes the app to SuperTest. We are then able to send GET, POST, PUT, PATCH and DELETE requests.
193-
`done` is a callback passed by Jest. Jest will wait until the done callback is called before finishing the test. Read more about it in the [Jest documentation](https://jestjs.io/docs/en/asynchronous#callbacks).
194198

195199
How should we test this POST "/" route? We will need to POST some JSON and non-JSON content to the server, and then check its response.
196200

@@ -212,22 +216,52 @@ Using SuperTest, we can easily send strings or JSON to the server:
212216

213217
```js
214218
describe("POST /", () => {
215-
it("should respond correctly when sending json", async done => {
219+
it("should respond correctly when sending json", async () => {
216220
const { text } = await request(app)
217221
.post("/")
218222
.send({ thisIsJson: "json!" })
219223
.expect(200);
220224
expect(text).toEqual("Thanks for the JSON!");
221-
done();
222225
});
223226

224-
it("should respond with status 400 and correct string when sending non-json", async done => {
227+
it("should respond with status 400 and correct string when sending non-json", async () => {
225228
const { text } = await request(app)
226229
.post("/")
227230
.send("This is not json!")
228231
.expect(400);
229232
expect(text).toEqual("Server wants application/json!");
230-
done();
231233
});
232234
});
233235
```
236+
237+
### Accessing agent in SuperTest
238+
239+
```js
240+
const request = require("supertest");
241+
var app = require("./app");
242+
243+
const agent = request.agent(app);
244+
```
245+
246+
After accessing the agent, you can use the agent directly.
247+
248+
For example,
249+
250+
```js
251+
const agent = request.agent(app);
252+
253+
it("should respond correctly", async () => {
254+
const { text } = await agent.get("/").expect(200);
255+
expect(text).toEqual("Welcome to my homepage");
256+
});
257+
```
258+
259+
When should we use the agent directly?
260+
261+
There are some cases where we need to reuse the agent again. For example, we might need to persist cookies that were saved.
262+
263+
Check the [github page for supertest](https://github.com/visionmedia/supertest) for an example on how to access the agent in SuperTest and reuse the agent to persist a request and its cookies.
264+
265+
## Exercises
266+
267+
Add tests to the songs API we have been building.

0 commit comments

Comments
 (0)