Validate JSON types using Joi
masterjsonTypes or jsonTypesStrict handlers in conjunction with the Joi library to validate that the JSON response body matches a specific schema.repository·master·Indexed 23 days ago
https://github.com/vlucas/frisbyFrisby.js v2.1.3 is a REST API endpoint testing tool built on top of Jest (and Jasmine) that simplifies HTTP testing through a fluent, promise-based API. It provides built-in expect handlers, support for custom handlers via addExpectHandler, and JSON schema validation using Joi. The library includes convenience wrappers for standard HTTP methods, response inspection tools, and the ability to mock responses using fromJSON.
jsonTypes or jsonTypesStrict handlers in conjunction with the Joi library to validate that the JSON response body matches a specific schema.Frisby uses Jest as its test runner. To run tests:
npm install --save-dev jest__tests__/api.spec.js).jest command.npm install --save-dev jest
# Create your tests
mkdir __tests__
touch __tests__/api.spec.js
# Run your tests from the CLI
cd your/project
jestInstall Frisby v2.x and Joi as development dependencies to begin API testing in your project.
npm install --save-dev frisby joiFor custom assertions that don't require a reusable handler, you can use Jasmine matchers directly inside the .then() method of a Frisby spec. The callback provides the res (FrisbyResponse) object.
const frisby = require('frisby');
it('should be user 1', function () {
return frisby.get('https://api.example.com/users/1')
.then(function (res) {
expect(res.json.id).toBe(1);
expect(res.json.email).toBe('testy.mctesterpants@example.com');
});
});To create a basic test, use frisby.get() (or other HTTP methods) and return the Frisby.js Spec from the it() block. This allows the test runner to treat the spec like a Promise. Use .expect() to assert the response.
const frisby = require('frisby');
it('should be a teapot', function () {
// Return the Frisby.js Spec in the 'it()' (just like a promise)
return frisby.get('http://httpbin.org/status/418')
.expect('status', 418);
});You can chain multiple HTTP calls by using the .then() method on a Frisby spec. Inside the .then() callback, you receive a FrisbyResponse object. To ensure the test runner waits for the subsequent call, you must return the new Frisby spec from the callback.
const frisby = require('frisby');
const Joi = require('joi');
describe('Posts', function () {
it('should return all posts and first post should have comments', function () {
return frisby.get('http://jsonplaceholder.typicode.com/posts')
.expect('status', 200)
.expect('jsonTypes', '*', {
userId: Joi.number(),
id: Joi.number(),
title: Joi.string(),
body: Joi.string()
})
.then(function (res) { // res = FrisbyResponse object
let postId = res.json[0].id;
// Get first post's comments
// RETURN the FrisbySpec object so function waits on it to finish - just like a Promise chain
return frisby.get('http://jsonplaceholder.typicode.com/posts/' + postId + '/comments')
.expect('status', 200)
.expect('json', '*', {
postId: postId
})
.expect('jsonTypes', '*', {
postId: Joi.number(),
id: Joi.number(),
name: Joi.string(),
email: Joi.string().email(),
body: Joi.string()
});
});
});
});If built-in handlers are insufficient, you can register custom handlers using frisby.addExpectHandler(name, callback). These handlers receive the response object and can use Jasmine matchers for assertions. You can remove them using frisby.removeExpectHandler(name).
beforeAll(function () {
// Add our custom expect handler
frisby.addExpectHandler('isUser1', function (response) {
let json = response.body;
// Run custom Jasmine matchers here
expect(json.id).toBe(1);
expect(json.email).toBe('testy.mctesterpants@example.com');
});
});
// Use our new custom expect handler
it('should allow custom expect handlers to be registered and used', function () {
return frisby.get('https://api.example.com/users/1')
.expect('isUser1')
});
afterAll(function () {
// Remove said custom handler (if needed)
frisby.removeExpectHandler('isUser1');
});Frisby provides several built-in handlers to validate HTTP responses. Use these within the .expect() method.
* `status` - Check HTTP status
* `header` - Check HTTP header key + value
* `json` - Match JSON structure + values (RegExp can be used)
* `jsonStrict` - Match EXACT JSON structure + values (extra keys not tested for cause test failures)
* `jsonTypes` - Match JSON structure + value types
* `jsonTypesStrict` - Match EXACT JSON structure + value types (extra keys not tested for cause test failures)
* `bodyContains` - Match partial body content (string or regex)
* `responseTime` - Check if request completes within a specified duration (ms)Frisby provides convenience wrappers for all standard HTTP methods. You can initiate a test by calling one of these methods with a URL and an optional params object.
Common methods include:
get(url, params)post(url, params)put(url, params)patch(url, params)del(url, params)head(url, params)options(url, params)fetch(url, params, options) (the base method)When using post, put, or patch, if params.body is an object (and not FormData), Frisby will automatically JSON.stringify it. If neither body nor headers are provided in params, Frisby assumes the entire params object is the request body and stringifies it.
You can extend Frisby's assertion capabilities by defining custom expectation handlers. This allows you to create reusable, domain-specific assertions that can be chained onto your HTTP requests.
addExpectHandler(expectName, expectFn): Registers a new expectation handler.removeExpectHandler(expectName): Removes an existing handler.fromJSON(json). This simulates a successful HTTP response with a 200 OK status and the provided JSON body.You can configure global or per-test settings using setup() and timeout().
setup(opts, replace): Merges new options into the existing setup defaults. If replace is set to true, it replaces the existing defaults instead of merging.timeout(timeout): Sets the maximum timeout in milliseconds for the request. If called without arguments, it returns the current timeout value.Commonly, setup is used to define a baseUrl in the request object, which allows you to use relative paths in your HTTP calls.