You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							313 lines
						
					
					
						
							6.5 KiB
						
					
					
				
			
		
		
	
	
							313 lines
						
					
					
						
							6.5 KiB
						
					
					
				<h1 align="center">Fastify</h1>
 | 
						|
 | 
						|
## Testing
 | 
						|
 | 
						|
Testing is one of the most important parts of developing an application. Fastify
 | 
						|
is very flexible when it comes to testing and is compatible with most testing
 | 
						|
frameworks (such as [Tap](https://www.npmjs.com/package/tap), which is used in
 | 
						|
the examples below).
 | 
						|
 | 
						|
Let's `cd` into a fresh directory called 'testing-example' and type `npm init
 | 
						|
-y` in our terminal.
 | 
						|
 | 
						|
Run `npm install fastify && npm install tap pino-pretty --save-dev`
 | 
						|
 | 
						|
### Separating concerns makes testing easy
 | 
						|
 | 
						|
First, we are going to separate our application code from our server code:
 | 
						|
 | 
						|
**app.js**:
 | 
						|
 | 
						|
```js
 | 
						|
'use strict'
 | 
						|
 | 
						|
const fastify = require('fastify')
 | 
						|
 | 
						|
function build(opts={}) {
 | 
						|
  const app = fastify(opts)
 | 
						|
  app.get('/', async function (request, reply) {
 | 
						|
    return { hello: 'world' }
 | 
						|
  })
 | 
						|
 | 
						|
  return app
 | 
						|
}
 | 
						|
 | 
						|
module.exports = build
 | 
						|
```
 | 
						|
 | 
						|
**server.js**:
 | 
						|
 | 
						|
```js
 | 
						|
'use strict'
 | 
						|
 | 
						|
const server = require('./app')({
 | 
						|
  logger: {
 | 
						|
    level: 'info',
 | 
						|
    prettyPrint: true
 | 
						|
  }
 | 
						|
})
 | 
						|
 | 
						|
server.listen(3000, (err, address) => {
 | 
						|
  if (err) {
 | 
						|
    server.log.error(err)
 | 
						|
    process.exit(1)
 | 
						|
  }
 | 
						|
})
 | 
						|
```
 | 
						|
 | 
						|
### Benefits of using fastify.inject()
 | 
						|
 | 
						|
Fastify comes with built-in support for fake HTTP injection thanks to
 | 
						|
[`light-my-request`](https://github.com/fastify/light-my-request).
 | 
						|
 | 
						|
Before introducing any tests, we will use the `.inject` method to make a fake
 | 
						|
request to our route:
 | 
						|
 | 
						|
**app.test.js**:
 | 
						|
 | 
						|
```js
 | 
						|
'use strict'
 | 
						|
 | 
						|
const build = require('./app')
 | 
						|
 | 
						|
const test = async () => {
 | 
						|
  const app = build()
 | 
						|
 | 
						|
  const response = await app.inject({
 | 
						|
    method: 'GET',
 | 
						|
    url: '/'
 | 
						|
  })
 | 
						|
 | 
						|
  console.log('status code: ', response.statusCode)
 | 
						|
  console.log('body: ', response.body)
 | 
						|
}
 | 
						|
test()
 | 
						|
```
 | 
						|
 | 
						|
First, our code will run inside an asynchronous function, giving us access to
 | 
						|
async/await.
 | 
						|
 | 
						|
`.inject` ensures all registered plugins have booted up and our application is
 | 
						|
ready to test. Finally, we pass the request method we want to use and a route.
 | 
						|
Using await we can store the response without a callback.
 | 
						|
 | 
						|
 | 
						|
 | 
						|
Run the test file in your terminal `node app.test.js`
 | 
						|
 | 
						|
```sh
 | 
						|
status code:  200
 | 
						|
body:  {"hello":"world"}
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
 | 
						|
### Testing with HTTP injection
 | 
						|
 | 
						|
Now we can replace our `console.log` calls with actual tests!
 | 
						|
 | 
						|
In your `package.json` change the "test" script to:
 | 
						|
 | 
						|
`"test": "tap --reporter=list --watch"`
 | 
						|
 | 
						|
**app.test.js**:
 | 
						|
 | 
						|
```js
 | 
						|
'use strict'
 | 
						|
 | 
						|
const { test } = require('tap')
 | 
						|
const build = require('./app')
 | 
						|
 | 
						|
test('requests the "/" route', async t => {
 | 
						|
  const app = build()
 | 
						|
 | 
						|
  const response = await app.inject({
 | 
						|
    method: 'GET',
 | 
						|
    url: '/'
 | 
						|
  })
 | 
						|
  t.equal(response.statusCode, 200, 'returns a status code of 200')
 | 
						|
})
 | 
						|
```
 | 
						|
 | 
						|
Finally, run `npm test` in the terminal and see your test results!
 | 
						|
 | 
						|
The `inject` method can do much more than a simple GET request to a URL:
 | 
						|
```js
 | 
						|
fastify.inject({
 | 
						|
  method: String,
 | 
						|
  url: String,
 | 
						|
  query: Object,
 | 
						|
  payload: Object,
 | 
						|
  headers: Object,
 | 
						|
  cookies: Object
 | 
						|
}, (error, response) => {
 | 
						|
  // your tests
 | 
						|
})
 | 
						|
```
 | 
						|
 | 
						|
`.inject` methods can also be chained by omitting the callback function:
 | 
						|
 | 
						|
```js
 | 
						|
fastify
 | 
						|
  .inject()
 | 
						|
  .get('/')
 | 
						|
  .headers({ foo: 'bar' })
 | 
						|
  .query({ foo: 'bar' })
 | 
						|
  .end((err, res) => { // the .end call will trigger the request
 | 
						|
    console.log(res.payload)
 | 
						|
  })
 | 
						|
```
 | 
						|
 | 
						|
or in the promisified version
 | 
						|
 | 
						|
```js
 | 
						|
fastify
 | 
						|
  .inject({
 | 
						|
    method: String,
 | 
						|
    url: String,
 | 
						|
    query: Object,
 | 
						|
    payload: Object,
 | 
						|
    headers: Object,
 | 
						|
    cookies: Object
 | 
						|
  })
 | 
						|
  .then(response => {
 | 
						|
    // your tests
 | 
						|
  })
 | 
						|
  .catch(err => {
 | 
						|
    // handle error
 | 
						|
  })
 | 
						|
```
 | 
						|
 | 
						|
Async await is supported as well!
 | 
						|
```js
 | 
						|
try {
 | 
						|
  const res = await fastify.inject({ method: String, url: String, payload: Object, headers: Object })
 | 
						|
  // your tests
 | 
						|
} catch (err) {
 | 
						|
  // handle error
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
#### Another Example:
 | 
						|
 | 
						|
**app.js**
 | 
						|
```js
 | 
						|
const Fastify = require('fastify')
 | 
						|
 | 
						|
function buildFastify () {
 | 
						|
  const fastify = Fastify()
 | 
						|
 | 
						|
  fastify.get('/', function (request, reply) {
 | 
						|
    reply.send({ hello: 'world' })
 | 
						|
  })
 | 
						|
 | 
						|
  return fastify
 | 
						|
}
 | 
						|
 | 
						|
module.exports = buildFastify
 | 
						|
```
 | 
						|
 | 
						|
**test.js**
 | 
						|
```js
 | 
						|
const tap = require('tap')
 | 
						|
const buildFastify = require('./app')
 | 
						|
 | 
						|
tap.test('GET `/` route', t => {
 | 
						|
  t.plan(4)
 | 
						|
 | 
						|
  const fastify = buildFastify()
 | 
						|
 | 
						|
  // At the end of your tests it is highly recommended to call `.close()`
 | 
						|
  // to ensure that all connections to external services get closed.
 | 
						|
  t.teardown(() => fastify.close())
 | 
						|
 | 
						|
  fastify.inject({
 | 
						|
    method: 'GET',
 | 
						|
    url: '/'
 | 
						|
  }, (err, response) => {
 | 
						|
    t.error(err)
 | 
						|
    t.equal(response.statusCode, 200)
 | 
						|
    t.equal(response.headers['content-type'], 'application/json; charset=utf-8')
 | 
						|
    t.same(response.json(), { hello: 'world' })
 | 
						|
  })
 | 
						|
})
 | 
						|
```
 | 
						|
 | 
						|
### Testing with a running server
 | 
						|
Fastify can also be tested after starting the server with `fastify.listen()` or
 | 
						|
after initializing routes and plugins with `fastify.ready()`.
 | 
						|
 | 
						|
#### Example:
 | 
						|
 | 
						|
Uses **app.js** from the previous example.
 | 
						|
 | 
						|
**test-listen.js** (testing with
 | 
						|
[`Request`](https://www.npmjs.com/package/request))
 | 
						|
```js
 | 
						|
const tap = require('tap')
 | 
						|
const request = require('request')
 | 
						|
const buildFastify = require('./app')
 | 
						|
 | 
						|
tap.test('GET `/` route', t => {
 | 
						|
  t.plan(5)
 | 
						|
 | 
						|
  const fastify = buildFastify()
 | 
						|
 | 
						|
  t.teardown(() => fastify.close())
 | 
						|
 | 
						|
  fastify.listen(0, (err) => {
 | 
						|
    t.error(err)
 | 
						|
 | 
						|
    request({
 | 
						|
      method: 'GET',
 | 
						|
      url: 'http://localhost:' + fastify.server.address().port
 | 
						|
    }, (err, response, body) => {
 | 
						|
      t.error(err)
 | 
						|
      t.equal(response.statusCode, 200)
 | 
						|
      t.equal(response.headers['content-type'], 'application/json; charset=utf-8')
 | 
						|
      t.same(JSON.parse(body), { hello: 'world' })
 | 
						|
    })
 | 
						|
  })
 | 
						|
})
 | 
						|
```
 | 
						|
 | 
						|
**test-ready.js** (testing with
 | 
						|
[`SuperTest`](https://www.npmjs.com/package/supertest))
 | 
						|
```js
 | 
						|
const tap = require('tap')
 | 
						|
const supertest = require('supertest')
 | 
						|
const buildFastify = require('./app')
 | 
						|
 | 
						|
tap.test('GET `/` route', async (t) => {
 | 
						|
  const fastify = buildFastify()
 | 
						|
 | 
						|
  t.teardown(() => fastify.close())
 | 
						|
 | 
						|
  await fastify.ready()
 | 
						|
 | 
						|
  const response = await supertest(fastify.server)
 | 
						|
    .get('/')
 | 
						|
    .expect(200)
 | 
						|
    .expect('Content-Type', 'application/json; charset=utf-8')
 | 
						|
  t.same(response.body, { hello: 'world' })
 | 
						|
})
 | 
						|
```
 | 
						|
 | 
						|
### How to inspect tap tests
 | 
						|
1. Isolate your test by passing the `{only: true}` option
 | 
						|
```javascript
 | 
						|
test('should ...', {only: true}, t => ...)
 | 
						|
```
 | 
						|
2. Run `tap` using `npx`
 | 
						|
```bash
 | 
						|
> npx tap -O -T --node-arg=--inspect-brk test/<test-file.test.js>
 | 
						|
```
 | 
						|
- `-O` specifies to run tests with the `only` option enabled
 | 
						|
- `-T` specifies not to timeout (while you're debugging)
 | 
						|
- `--node-arg=--inspect-brk` will launch the node debugger
 | 
						|
3. In VS Code, create and launch a `Node.js: Attach` debug configuration. No
 | 
						|
   modification should be necessary.
 | 
						|
 | 
						|
Now you should be able to step through your test file (and the rest of
 | 
						|
`Fastify`) in your code editor.
 |