Skip to content

A k6 extension for mocking HTTP(S) servers during test development.

License

Notifications You must be signed in to change notification settings

szkiba/xk6-mock

Repository files navigation

Go Report Card GitHub Actions codecov Documentation

xk6-mock

A k6 extension enables mocking HTTP(S) servers during test development.

The design of the library was inspired by Express.js. If you have already known Express.js framework, using this library should be very simple.

import http, { mock } from 'k6/x/mock'

mock('https://example.com', app => {
  app.get('/', (req, res) => {
    res.json({ greeting: 'Hello World!' })
  })
})

export default async function () {
  const res = await http.asyncRequest('GET', 'https://example.com')
  console.log(res.json())
}

Features

  • Starts mock HTTP server(s) inside the k6 process
  • Familiar, Express like mock route definitions
  • Almost transparent for test scripts: just change import statement from k6/http to k6/x/mock
  • Helps testing k6 tests with mock server
  • Supports sync and async k6/http API

Note The implementation of a micro web framework (similar to Express.js) was moved to muxpress project. (Just in case you're interested in goja)

Download

You can download pre-built k6 binaries from Releases page. Check Packages page for pre-built k6 Docker images.

Build

You can build the k6 binary on various platforms, each with its requirements. The following shows how to build k6 binary with this extension on GNU/Linux distributions.

Prerequisites

You must have the latest Go version installed to build the k6 binary. The latest version should match k6 and xk6.

  • Git for cloning the project
  • xk6 for building k6 binary with extensions

Install and build the latest tagged version

  1. Install xk6:

    go install go.k6.io/xk6/cmd/xk6@latest
  2. Build the binary:

    xk6 build --with github.com/szkiba/xk6-mock@latest

Note You can always use the latest version of k6 to build the extension, but the earliest version of k6 that supports extensions via xk6 is v0.43.0. The xk6 is constantly evolving, so some APIs may not be backward compatible.

Build for development

If you want to add a feature or make a fix, clone the project and build it using the following commands. The xk6 will force the build to use the local clone instead of fetching the latest version from the repository. This process enables you to update the code and test it locally.

git clone [email protected]:szkiba/xk6-mock.git && cd xk6-mock
xk6 build --with github.com/szkiba/xk6-mock@latest=.

Docker

You can also use pre-built k6 image within a Docker container. In order to do that, you will need to execute something like the following:

Linux

docker run -v $(pwd):/scripts -it --rm ghcr.io/szkiba/xk6-mock:latest run --out=dashboard /scripts/script.js

Windows

docker run -v %cd%:/scripts -it --rm ghcr.io/szkiba/xk6-mock:latest run --out=dashboard /scripts/script.js

Example scripts

There are many examples in the scripts directory that show how to use various features of the extension.

API

Synchronous mode

Mixing synchronous and asynchronous calls can block k6 test execution. Both synchronous (http.get, http.post, ...) and asynchronous (http.asyncRequest) API mocking is supported. By default the new asynchronous mode will be used.

To switch to synchronous mode you can pass an options object to mock function with sync property set to true:

mock({ sync:true }, "https://example.com", app => {

})

The Application class constructor also accepts similar options parameter:

const app = new Application({ sync: true })

k6/http

The k6/x/mock module contains a thin wrapper around the k6/http module. This allow to use k6/x/mock module as drop-in replacement for k6/http for seamless mocking.

import http, { mock } from "k6/x/mock"

Usage tips

  1. Create separated mock.js module for mocking

  2. Re-export k6/x/mock module content

    export { default } from "k6/x/mock"
    export * from "k6/x/mock"
  3. Put mock definitions in mock.js

    import { mock } from "k6/x/mock"
    
    mock('https://httpbin.test.k6.io/get', app => {
      app.get('/', (req, res) => {
        res.json({ url: 'https://httpbin.test.k6.io/get' })
      })
    })
  4. In test script, import http from mock.js instead of k6/http

    import http from "./mock.js";

    Switching from mock to real implementation is as easy as replacing the line above with real k6/http module import

    import http from "k6/http"
  5. The other part of the test script is independent from mocking

    import http from "./mock.js";
    import { check } from 'k6'
    import { test } from 'k6/execution'
    
    export default async function () {
      const res = await http.asyncRequest('GET', 'https://httpbin.test.k6.io/get')
      const ok = check(res, {
        'response code was 200': res => res.status == 200,
        '"url" was "https://httpbin.test.k6.io/get"': res =>
          res.json('url') == 'https://httpbin.test.k6.io/get'
      })
    
      if (!ok) {
        test.abort('unexpected response')
      }
    }

Disabling mock

You can disable the given mock definition quickly by passing options parameter with skip set to true.

mock(
  'https://example.com',
  app => {
    app.get('/', (req, res) => {
      res.json({ greeting: 'Hello World!' })
    })
  },
  { skip: true }
)

Alternatively you can put .skip after function name:

mock.skip('https://example.com', app => {
  app.get('/', (req, res) => {
    res.json({ greeting: 'Hello World!' })
  })
})

The API documentation bellow was generated from index.d.ts file.

Class: Application

An application object represents a web application.

The following example starts a server and listens for connections on port 3000. The application responds with a JSON object for requests to the root URL. All other routes are answered with a 404 not found message.

In this example, the name of the constructor is Application, but the name you use is up to you.

Example

const app = new Application()

app.get('/', (req, res) => {
  res.json({message:"Hello World!"})
})

app.listen(3000)

Constructors

constructor

new Application()

Creates a new application instance.

Defined in

index.d.ts:111

Methods

delete

delete(path, ...middleware): void

Routes HTTP DELETE requests to the specified path with the specified middleware functions.

You can provide multiple middleware functions.

Parameters
Name Type Description
path string The path for which the middleware function is invoked (string or path pattern)
...middleware Middleware[] Middleware functions
Returns

void

Defined in

index.d.ts:171


get

get(path, ...middleware): void

Routes HTTP GET requests to the specified path with the specified middleware functions.

You can provide multiple middleware functions.

Parameters
Name Type Description
path string The path for which the middleware function is invoked (string or path pattern)
...middleware Middleware[] Middleware functions
Returns

void

Defined in

index.d.ts:121


head

head(path, ...middleware): void

Routes HTTP HEAD requests to the specified path with the specified middleware functions.

You can provide multiple middleware functions.

Parameters
Name Type Description
path string The path for which the middleware function is invoked (string or path pattern)
...middleware Middleware[] Middleware functions
Returns

void

Defined in

index.d.ts:131


listen

listen(addr?, callback?): void

Starts the server.

Parameters
Name Type Description
addr? string -
callback? () => void host name or IP address for listening on, default 127.0.0.1
Returns

void

The instance for fluent/chaining API

Defined in

index.d.ts:206


options

options(path, ...middleware): void

Routes HTTP OPTIONS requests to the specified path with the specified middleware functions.

You can provide multiple middleware functions.

Parameters
Name Type Description
path string The path for which the middleware function is invoked (string or path pattern)
...middleware Middleware[] Middleware functions
Returns

void

Defined in

index.d.ts:181


patch

patch(path, ...middleware): void

Routes HTTP PATCH requests to the specified path with the specified middleware functions.

You can provide multiple middleware functions.

Parameters
Name Type Description
path string The path for which the middleware function is invoked (string or path pattern)
...middleware Middleware[] Middleware functions
Returns

void

Defined in

index.d.ts:161


post

post(path, ...middleware): void

Routes HTTP POST requests to the specified path with the specified middleware functions.

You can provide multiple middleware functions.

Parameters
Name Type Description
path string The path for which the middleware function is invoked (string or path pattern)
...middleware Middleware[] Middleware functions
Returns

void

Defined in

index.d.ts:141


put

put(path, ...middleware): void

Routes HTTP PUT requests to the specified path with the specified middleware functions.

You can provide multiple middleware functions.

Parameters
Name Type Description
path string The path for which the middleware function is invoked (string or path pattern)
...middleware Middleware[] Middleware functions
Returns

void

Defined in

index.d.ts:151


static

static(path, docroot): void

Mount static web content from given source directory.

Parameters
Name Type Description
path string The path where the source will be mounted on
docroot string The source directory path
Returns

void

Defined in

index.d.ts:197


use

use(path, ...middleware): void

Uses the specified middleware function or functions.

Parameters
Name Type Description
path string The path for which the middleware function is invoked (string or path pattern)
...middleware Middleware[] Middleware functions
Returns

void

Defined in

index.d.ts:189

Interface: MockOptions

Optional flags for mock function.

Passing this options object as first (or last) parameter to mock function (or to Application constructor) may change its behavior.

Example

mock("https://example.com", callback, { sync:true });

Properties

skip

skip: boolean

True value indicaes that given mock definition should be ignored.

Defined in

index.d.ts:29


sync

sync: boolean

True value indicates synchronous mode operation. You should use it for synchronous k6 http API.

Defined in

index.d.ts:24

Interface: Request

The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.

In this documentation and by convention, the object is always referred to as req (and the HTTP response is res) but its actual name is determined by the parameters to the callback function in which you’re working.

Example

app.get("/user/:id", function (req, res) {
  res.send("user " + req.params.id);
});

Properties

body

body: Record<string, any>

Contains key-value pairs of data submitted in the request body. By default, it is undefined, and is populated when the request Content-Type is application/json.

Defined in

index.d.ts:226


cookies

cookies: Record<string, string>

This property is an object that contains cookies sent by the request.

Defined in

index.d.ts:231


get

get: (field: string) => string

Type declaration

▸ (field): string

Returns the specified HTTP request header field (case-insensitive match).

Parameters
Name Type Description
field string the header field name
Returns

string

the header field value.

Defined in

index.d.ts:278


header

header: (field: string) => string

Type declaration

▸ (field): string

Returns the specified HTTP request header field (case-insensitive match).

Parameters
Name Type Description
field string the header field name
Returns

string

the header field value.

Defined in

index.d.ts:286


method

method: string

Contains a string corresponding to the HTTP method of the request: GET, POST, PUT, and so on.

Defined in

index.d.ts:236


params

params: Record<string, string>

This property is an object containing properties mapped to the named route parameters. For example, if you have the route /user/:name, then the “name” property is available as req.params.name. This object defaults to empty.

Defined in

index.d.ts:243


path

path: string

Contains the path part of the request URL.

Defined in

index.d.ts:248


protocol

protocol: string

Contains the request protocol string: either http or (for TLS requests) https.

Defined in

index.d.ts:253


query

query: Record<string, any>

This property is an object containing a property for each query string parameter in the route.

For example:

// GET /search?q=tobi+ferret
console.dir(req.query.q);
// => 'tobi ferret'

// GET /shoes?color=blue&color=black&color=red
console.dir(req.query.color);
// => ['blue', 'black', 'red']
Defined in

index.d.ts:270

Interface: Response

The res object represents the HTTP response that a server sends when it gets an HTTP request.

In this documentation and by convention, the object is always referred to as res (and the HTTP request is req) but its actual name is determined by the parameters to the callback function in which you’re working.

Example

app.get("/user/:id", function (req, res) {
  res.send("user " + req.params.id);
});

Properties

append

append: (field: string, value: string) => Response

Type declaration

▸ (field, value): Response

Appends the specified value to the HTTP response header field. If the header is not already set, it creates the header with the specified value.

Parameters
Name Type Description
field string the header field name
value string the value to append
Returns

Response

Defined in

index.d.ts:306


binary

binary: (body: string | number[] | ArrayBuffer) => Response

Type declaration

▸ (body): Response

Sends a binray response. This method sends a response (with the "application/octet-stream" content-type) that is the body paramter.

Parameters
Name Type Description
body string | number[] | ArrayBuffer the data to send
Returns

Response

Defined in

index.d.ts:334


html

html: (body: string) => Response

Type declaration

▸ (body): Response

Sends a HTML text response. This method sends a response (with the correct content-type) that is the body string paramter.

Parameters
Name Type Description
body string the string to send
Returns

Response

Defined in

index.d.ts:327


json

json: (body: Record<string, any>) => Response

Type declaration

▸ (body): Response

Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string.

Parameters
Name Type Description
body Record<string, any> the object to send
Returns

Response

Defined in

index.d.ts:313


redirect

redirect: (code: number, loc: string) => Response

Type declaration

▸ (code, loc): Response

Redirects to the URL, with specified status, a positive integer that corresponds to an HTTP status code.

Parameters
Name Type Description
code number the HTTP status code (301, 302, ...)
loc string the location to redirect
Returns

Response

Defined in

index.d.ts:382


send

send: (body: string | number[] | ArrayBuffer) => Response

Type declaration

▸ (body): Response

Sends the HTTP response.

When the parameter is a ArrayBuffer or number[], the method sets the Content-Type response header field to “application/octet-stream”. When the parameter is a String, the method sets the Content-Type to “text/html”. Otherwise the method sets the Content-Type to "application/json" and convert paramter to JSON representation before sending.

Parameters
Name Type Description
body string | number[] | ArrayBuffer the data to send
Returns

Response

Defined in

index.d.ts:345


set

set: (field: string, value: string) => Response

Type declaration

▸ (field, value): Response

Sets the response’s HTTP header field to value.

Parameters
Name Type Description
field string the header field name
value string the value to set
Returns

Response

Defined in

index.d.ts:374


status

status: (code: number) => Response

Type declaration

▸ (code): Response

Sets the HTTP status for the response.

Parameters
Name Type Description
code number the satus code value
Returns

Response

Defined in

index.d.ts:352


text

text: (format: string, v?: any[]) => Response

Type declaration

▸ (format, v?): Response

Sends a plain text response. This method sends a response (with the correct content-type) that is the string formatting result.

Parameters
Name Type Description
format string go format string
v? any[] format values (if any)
Returns

Response

Defined in

index.d.ts:321


type

type: (mime: string) => Response

Type declaration

▸ (mime): Response

Sets the Content-Type HTTP header to the MIME type as from mime parameter.

Params

mime the content type

Parameters
Name Type
mime string
Returns

Response

Defined in

index.d.ts:359


vary

vary: (header: string) => Response

Type declaration

▸ (header): Response

Adds the header field to the Vary response header.

Parameters
Name Type Description
header string the header filed name
Returns

Response

Defined in

index.d.ts:366

Auxiliary

Classes

Interfaces

Type Aliases

Middleware

Ƭ Middleware: (req: Request, res: Response, next: () => void) => void

Type declaration

▸ (req, res, next): void

Middleware defines middleware and request handler callback function.

Parameters
Name Type Description
req Request the request object
res Response the response object
next () => void calling from middleware enables processing next middleware
Returns

void

Defined in

index.d.ts:87

Functions

mock

mock(target, callback, options?): void

Create URL mock definition.

This function will create a new Express.js like web application and pass it to the provided callback function for programming. After mock programming is done, new mock HTTP server will be start. Whan you use http API from mock module, all matching URLs will be directed to this mock server.

You can create as many mock definitions (server) as you want.

You can disable the given mock definition quickly by passing options parameter with skip set to true.

mock(
  'https://example.com',
  app => {
    app.get('/', (req, res) => {
      res.json({ greeting: 'Hello World!' })
    })
  },
  { skip: true }
)

Alternatively you can put .skip after function name:

mock.skip('https://example.com', app => {
 app.get('/', (req, res) => {
   res.json({ greeting: 'Hello World!' })
 })
})
Parameters
Name Type Description
target String the URL or URL prefix to be mocked
callback (app: Application) => void function to for defining route definitions for mock server
options? MockOptions optional flags (sync, skip)
Returns

void

Defined in

index.d.ts:67


unmock

unmock(target): void

Deactivate URL mocking.

This function will remove mock definition associated to given URL and stop the related HTTP server.

Parameters
Name Type Description
target String the URL or URL prefix of mock definition to be remove
Returns

void

Defined in

index.d.ts:76