Skip to content

Commit

Permalink
Merge 18d84f9 into ecf07be
Browse files Browse the repository at this point in the history
  • Loading branch information
frankthelen committed May 17, 2021
2 parents ecf07be + 18d84f9 commit 7828650
Show file tree
Hide file tree
Showing 21 changed files with 6,720 additions and 2,759 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
# Ignore built files except build/index.js
coverage/*
build/*
builds/*
bundle.js
jest.config.ts
*.d.ts
17 changes: 13 additions & 4 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
{
"extends": [
"airbnb-base"
"airbnb-typescript/base"
],
"plugins": [
"promise"
]
"parserOptions": {
"project": "./tsconfig.json"
},
"env": {
"node": true,
"browser": false
},
"rules": {
"import/prefer-default-export": 0,
"@typescript-eslint/lines-between-class-members": 0,
"no-console": "warn"
}
}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
.idea/*
.vscode/*
local
build
dist

# generated files
.DS_Store
Expand All @@ -20,5 +22,5 @@ Thumbs.db
# node specific
node_modules
coverage
*/config/local.js
*/config/local.*
.nyc_output
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ language: node_js
node_js:
- "12"
- "14"
- "15"
- "16"

sudo: false

before_script:
- npm run build

after_success:
- npm run coveralls
104 changes: 70 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# hapi-mock

Hapi server plugin for mocking endpoints.
Hapi server plugin for adding mock behavior to endpoints.

[![Build Status](https://travis-ci.org/frankthelen/hapi-mock.svg?branch=master)](https://travis-ci.org/frankthelen/hapi-mock)
[![Coverage Status](https://coveralls.io/repos/github/frankthelen/hapi-mock/badge.svg?branch=master)](https://coveralls.io/github/frankthelen/hapi-mock?branch=master)
[![node](https://img.shields.io/node/v/hapi-mock.svg)]()
[![code style](https://img.shields.io/badge/code_style-airbnb-brightgreen.svg)](https://github.com/airbnb/javascript)
[![Types](https://img.shields.io/npm/types/rools.svg)](https://www.npmjs.com/package/rools)
[![License Status](http://img.shields.io/npm/l/hapi-mock.svg)]()

Tested with

* Hapi 20 on Node 12/14/15
* Hapi 19 on Node 12/14/15
Tested with Hapi 19/20 on Node 12/14/16.

## Install

Expand All @@ -21,69 +19,68 @@ npm install hapi-mock

## Purpose

This plugin provides a simple way to mock your HAPI endpoints.
This plugin provides a simple way to add mock behavior to endpoints.
It is *experimental* at this point of time.

## Usage
v2 is going away from jexl expressions towards es6 conditions.
And it is rewritten in TypeScript.

## Usage (ES6)

Register the plugin with Hapi server like this:

```js
const Hapi = require('@hapi/hapi');
const hapiMock = require('hapi-mock');

const server = new Hapi.Server({
port: 3000,
});
// ...

const mock = {
plugin: hapiMock,
options: {
baseDir: Path.join(__dirname, 'mocks'),
validate: async (request) => ({ isValid: true }), // optional auth for mocks
triggerByHeader: true, // default
headerName: 'x-hapi-mock', // default
},
};

const provision = async () => {
await server.register([mock]);
// ...
await server.start();
};

provision();
await server.register(mock);
```

Your route configuration may look like this:

```js
server.route({
method: 'GET',
path: '/example/{id}',
options: {
// ...
plugins: {
'hapi-mock': { // activate mocking for this endpoint
file: './cases', // JS module relative to `baseDir`
'hapi-mock': { // add mock behavior to this endpoint
mocks: [{
condition: ({ params }) => params.id === '4711',
code: 418,
}, ...],
},
},
},
handler: async (request, h) => {
// ...
}
handler: // ...
});
```

The `file` option refers to a JS module (e.g., `cases.js`) containing your mock cases, e.g.,
The `mocks` option can also refer to a separate module, e.g.,

```js
module.exports = [{
condition: 'params.id == "4711"',
condition: ({ params }) => params.id === '4711',
code: 418,
}, {
condition: 'query.id == "foo"',
condition: ({ query }) => query.id === 'foo',
type: 'application/json',
body: {
bar: true,
bar: 'qux',
},
}, {
condition: 'headers["x-mock-case"] == 13',
condition: ({ headers }) => headers['x-mock-case'] === '13',
code: 200, // this is the default
type: 'text/plain', // this is the default
body: 'case 13',
Expand All @@ -93,10 +90,49 @@ module.exports = [{
}];
```

`condition` is an expression that may refer to HAPI's route parameters `headers`, `params`, `query`, `payload`, `method` (lowercase), and `path`. The usual operators are supported (`==`, `&&`, `||`, etc.).
Response parameters of a mock can be `code` (default `200`), `type` (default `text/plain`), `body` (default `mocked!`), and `headers` (default `{}`).

And finally, you need to set the HTTP header `x-hapi-mock: true` to a request to have a route use mocking rather than its real handler implementation.
`condition` maps the Hapi request object to true for applying the mock case.
Response parameters of a mock can be `code` (default `200` or `204`),
`type` (default `text/plain`), `body` (default empty), and `headers` (default `{}`).

You don't want to use this plug-in in production, of course.
Have fun.

## Options

### Registration Options

`triggerByHeader` (optional, boolean, default `true`) -- When to apply mocks (provided that
an endpoint has mocks configured). If `true`, mocks are only applied when the request header
`x-hapi-mock` is set (any value). If `false` mocks are always applied.

`headerName` (optional, string, default `x-hapi-mock`) -- As request header, it must be set to
activate mocks (unless `triggerByHeader` is `false`). As response header, it tells which mock
case was applied (if any).

`continueIfNoneMatch` (optional, boolean, default `true`) -- What should be done
if mocks are configured but none is matching.
If `true`, the request is passed on.
If `false`, the response is status code 422 "Unprocessable Entity".

### Route Options

`mocks` (required, Array) -- List of mock cases for the respective endpoint.

`continueIfNoneMatch` (optional, boolean, default is registration option `continueIfNoneMatch`) --
What should be done if mocks are configured but none is matching.
If `true`, the request is passed on.
If `false`, the response is status code 422 "Unprocessable Entity".

### Mock Cases

`title` (required, string) -- A descriptive title of the mock case.

`condition` (required, function `(request: Hapi.Request) => boolean`) --
The condition when the mock case shall be applied.

`code` (optional, number, default 200 or 204) -- Status code.

`type` (optional, string, default `text/plain`) -- Response `content-type`.

`body` (optional, string or object) -- Response body.

`headers` (optional, object) -- Response headers.
22 changes: 22 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export default {
clearMocks: true,
collectCoverage: true,
coverageDirectory: 'coverage',
coveragePathIgnorePatterns: [
'/node_modules/',
'/config/',
'/test/mocks/'
],
coverageProvider: 'v8',
coverageThreshold: {
global: {
statements: 80,
branches: 80,
functions: 80,
lines: 80,
},
},
preset: 'ts-jest',
testEnvironment: 'node',
testRegex: '/test/.*\\.test\\.ts$',
};
Loading

0 comments on commit 7828650

Please sign in to comment.