Testing your hapi applications might require expected values and responses that match a set of data. The code
library from hapi’s ecosystem is an assertions library based on chai
.
Code
exposes an expressive and readable language-style interface. You’ll get a grasp on features and the usage in the upcoming sections.
hapi Series Overview
- What You’ll Build
- Prepare Your Project: Stack & Structure
- Environment Variables and Storing Secrets
- Set Up MongoDB and Connect With Mongoose
- Sending Emails in Node.js
- Load the User’s Profile Picture From Gravatar Using Virtuals in Mongoose
- Implement a User Profile Editing Screen
- Generate a Username in Mongoose Middleware
- Displaying Seasons and Episodes for TV Shows with Mongoose Relationship Population
- Implementing Pagination for Movies
- Implement a Watchlist
- Create a Full Text Search with MongoDB
- Create a REST API with JSON Endpoints
- Update Mongoose Models for JSON Responses
- API Pagination for TV Shows
- Customize API Endpoints with Query Parameters
- Always Throw and Handle API Validation Errors
- Advanced API Validation With Custom Errors
- Create an API Documentation with Swagger
- Customize Your Swagger API Documentation URL
- Describe Endpoint Details in Your Swagger API Documentation
- 10 Tips on API Testing With Postman
- JWT Authentication in Swagger API Documentation
- API Versioning with Request Headers
- API Login With Username and Password to Generate a JWT
- JWT Authentication and Private API Endpoints
- Refresh Tokens With JWT Authentication
- Create a JWT Utility
- JWT Refresh Token for Multiple Devices
- Check Refresh Token in Authentication Strategy
- Rate Limit Your Refresh Token API Endpoint
- How to Revoke a JWT
- Invalidate JWTs With Blacklists
- JWT Logout (Part 1/2)
- JWT “Immediate” Logout (Part 2/2)
- A Better Place to Invalidate Tokens
- How to Switch the JWT Signing Algorithm
- Roll Your Own Refresh Token Authentication Scheme
- JWT Claims 101
- Use JWT With Asymmetric Signatures (RS256 & Co.)
- Encrypt the JWT Payload (The Simple Way)
- Increase JWT Security Beyond the Signature
- Unsigned JSON Web Tokens (Unsecured JWS)
- JWK and JWKS Overview
- Provide a JWKS API Endpoint
- Create a JWK from a Shared Secret
- JWT Verification via JWKS API Endpoint
- What is JOSE in JWT
- Encrypt a JWT (the JWE Way)
- Authenticate Encrypted JWTs (JWE)
- Encrypted and Signed JWT (Nested JWT)
- Bringing Back JWT Decoding and Authentication
- Bringing Back JWT Claims in the JWT Payload
- Basic Authentication With Username and Password
- Authentication and Remember Me Using Cookies
- How to Set a Default Authentication Strategy
- Define Multiple Authentication Strategies for a Route
- Restrict User Access With Scopes
- Show „Insufficient Scope“ View for Routes With Restricted Access
- Access Restriction With Dynamic and Advanced Scopes
- hapi - How to Fix „unknown authentication strategy“
- Authenticate with GitHub And Remember the Login
- Authenticate with GitLab And Remember the User
- How to Combine Bell With Another Authentication Strategy
- Custom OAuth Bell Strategy to Connect With any Server
- Redirect to Previous Page After Login
- How to Implement a Complete Sign Up Flow With Email and Password
- How to Implement a Complete Login Flow
- Implement a Password-Reset Flow
- Views in hapi 9 (and above)
- How to Render and Reply Views
- How to Reply and Render Pug Views (Using Pug 2.0)
- How to Create a Dynamic Handlebars Layout Template
- Create and Use Handlebars Partial Views
- Create and Use Custom Handlebars Helpers
- Specify a Different Handlebars Layout for a Specific View
- How to Create Jade-Like Layout Blocks in Handlebars
- Use Vue.js Mustache Tags in Handlebars Templates
- How to Use Multiple Handlebars Layouts
- How to Access and Handle Request Payload
- Access Request Headers
- How to Manage Cookies and HTTP States Across Requests
- Detect and Get the Client IP Address
- How to Upload Files
- Quick Access to Logged In User in Route Handlers
- How to Fix “handler method did not return a value, a promise, or throw an error”
- How to Fix “X must return an error, a takeover response, or a continue signal”
- Query Parameter Validation With Joi
- Path Parameter Validation With Joi
- Request Payload Validation With Joi
- Validate Query and Path Parameters, Payload and Headers All at Once on Your Routes
- Validate Request Headers With Joi
- Reply Custom View for Failed Validations
- Handle Failed Validations and Show Errors Details at Inputs
- How to Fix AssertionError, Cannot validate HEAD or GET requests
Dependency Double Check: code
Within the previous tutorial on getting started with testing hapi application using lab
, you installed and added the code
dependency to your project. Double check that code
is part of your devDependencies
in the package.json
file:
…
"devDependencies": {
"code": "~4.1.0",
"lab": "~14.3.1"
},
…
If code
isn’t installed yet, go a head and do that now. Install code
and save the package as a development dependency:
# Running Node.js v8+
npm i -D code
# Running Node.js v6-
npm i -D code@4
Notice that the latest release of code
is compatible with Node.js v8+. If you’re on Node.js v4 or v6, use code
in version 4.
Code — an Assertion Library
Code
is an assertions library that makes use of connecting words for readable assertions. Assertions in testing are a way to express result expectations.
Let’s illustrate the theory with a practical example: you’re developing a user sign up feature and want to test whether your route handler works properly for an email address that is already registered. You want the route handler to return an error with a proper status code and error message, telling the requesting user that there’s an existing account with the given data.
Your test(s) can should expect an error with an appropriate HTTP response status code. Code
is a library that helps you to define these assertions.
Update package.json
To Run Your Tests with Lab
Again, if you followed the previous tutorial getting started with testing hapi application using lab
, you’ve already set up your app to use code
as an assertion library.
Double check that the test
command within the scripts
block of your package.json
contains the --assert code
statement:
{
"name": "futureflix",
"version": "1.1.0",
…
"scripts": {
"test": "lab --assert code --leaks --coverage"
}
}
Your test
command can have more flags. The important part for this tutorial is the --assert code
flag. Lab uses code
by default, but that’s not generally obvious. Make it clear for everyone on your team that you’re using code
for assertions.
Expect Values in Your Tests
Let’s create assertions in tests of your project. We‘re using the Futureflix Starter Kit to illustrate the functionality. Use your own project to create assertions in your tests.
Assertions are part of your tests and you integrate them with the lab
setup around experiments and tests. In the Futureflix starter kit, we create a new test file called 02-assertions.js
within the test/getting-started
directory. This will be the playground to illustrate different kinds of assertions.
02-assertions.js
'use strict'
const Lab = require('lab')
const Code = require('code')
// Test files must require the lab module, and export a test script
const lab = (exports.lab = Lab.script())
// shortcuts from lab
const experiment = lab.experiment
const test = lab.test
experiment('hapi testing with lab and assertions with code,', () => {
test('assert that 1 + 2 equals three', () => {})
})
Up to this part, the newly created test includes a basic lab test skeleton with a yet unused import of code
. This will change in a second.
Your First Assertion
The grammar of code
consists of connecting words to make assertions readable. When running Code.expect()
, each supported word returns this
and allows you to chain multiple methods and properties. Connecting words are a
, an
, and
, at
, be
, have
, in
, to
.
Now it’s your turn: create a basic assertion where code
expects the sum of 1 + 2
to equal 3
. Start your snippet with Code.expect(<variable>)
to set the expected value.
02-assertions.js
'use strict'
const Lab = require('lab')
const Code = require('code')
// Test files must require the lab module, and export a test script
const lab = (exports.lab = Lab.script())
// shortcuts from lab
const experiment = lab.experiment
const test = lab.test
experiment('hapi testing with lab and assertions with code,', () => {
test('assert that 1 + 2 equals three', () => {
Code.expect(1 + 2).to.equal(3)
Code.expect('3').to.equal('3')
Code.expect(3).to.not.equal('3')
})
})
Your assertion should look like this: Code.expect(1 + 2).to.equal(3)
. The code snippet contains a second assertion where the string '3'
should equal another string '3'
.
This is for illustration purposes to show you that code
supports different data types and you can compare strings the same way as math calculations.
For an assertion of 3
should equal '3'
, an integer 3 should equal a string 3, the assertion makes sure that both are different.
More Complex Assertions
Every statement chained to Code.expect()
returns this
and is chainable as well. Compose more complex statements than simple comparisons. The following code block shows you assertions on the data type and values.
test('assert different data types', () => {
expect(true).to.be.a.boolean()
expect(true)
.to.be.a.boolean()
.and.to.not.equal(false)
expect('this is a string').to.startsWith('this')
})
The two boolean assertions outline the opportunities that code
gives you for comparisons and assertions.
There’s a third statement that make sure a given string startsWith
another string.
Code
exposes a rich API and you can combine most of the methods and properties.
Outlook
All examples in this tutorial are static assignments, comparisons and assertions. For your actual tests, you’ll use responses from a route handler or dynamically loaded data. We’ll dig into this in the next tutorial. Stay hungry!
We’re happy to hear your thoughts and appreciate your comment. Please don’t hesitate to use the comment form below. If Twitter is more your thing, find us @futurestud_io. Let us know what you think!
Enjoy coding & make it rock!
Mentioned Resources
- Code assertion library
- Code API Overview
- Chai assertion library (the basis for code)
- Getting started with testing hapi application using lab
- Futureflix Starter Kit