Test runner for k6. The design of the Kahwah library was inspired by Mocha. If you already know Mocha framework, using this library should be very simple.
- describe and it as you used to in Mocha
- tests run serially and supports passing values between tests
- connect tests as workfow test steps
- defines thresholds for test errors
- measure describe/step execution time and provide it as k6 metrics
- published as NPM package
- importable from CDN providers (ie: https://cdn.jsdelivr.net/npm/kahwah)
- minified size is ~3k
More documentation will be coming soon, but until it is happen, here is an annotated example, and some generated API documentation in docs/README.md
This section contains an annotated, runnable k6 example script. You can extract the script with codedown and run with k6 using the following command line (as I do while testing documentation example):
cat README.md | codedown js | k6 run -
Or you can simply download example.js but it is much less fancy :)
In this example we are using step function instead of describe. The two function has exactly same API, the only difference is that step will skip execution if previous step failed.
-
Import latest release of Kahwah library from CDN (for example from jsDelivr)
import { describe as step, it } from "https://cdn.jsdelivr.net/npm/kahwah";
As an alternative, you can import latest development version from GitHub
import { step, it } from "github.com/szkiba/kahwah/lib/index.js";
-
Export options and default function from Kahwah library.
export { options, default } from "https://cdn.jsdelivr.net/npm/kahwah";
You can export these as is (like in example above) or you can customize before exporting. The options contains thresholds required to fail test if some of checks failed. The thresholds also available as exported variable, so you can import it (customize) and use in your own
options
. -
Import
expect
from Chai Assertion Libraryimport { expect } from "cdnjs.com/libraries/chai";
-
Import required k6 packages
import http from "k6/http";
-
Setup data object. In this example we are using a
session
context object to store session variables between steps.export function setup() { return { session: {} }; }
-
Write workflow steps. Each step test some functionallity of the system. Some steps store output values to
session
variable for other steps.
step("Generate random user", (ctx) => {
let resp = http.get("https://phantauth.net/user");
it("status 200", () => {
expect(resp.status).equal(200);
});
ctx.session.user = JSON.parse(resp.body);
});
step("Generate access token", (ctx) => {
const { user } = ctx.session;
let resp = http.get(`https://phantauth.net/user/${user.sub}/token/access`);
it("status 200", () => {
expect(resp.status).equal(200);
});
ctx.session.token = resp.body;
});
step("Get OpenID Configuration", (ctx) => {
let resp = http.get("https://phantauth.net/.well-known/openid-configuration");
it("status 200", () => {
expect(resp.status).equal(200);
});
const parsed = JSON.parse(resp.body);
it("has userinfo_endpoint", () => {
expect(parsed).to.have.property("userinfo_endpoint");
});
ctx.session.meta = parsed;
});
step("Get User Info", (ctx) => {
const { user, meta, token } = ctx.session;
let resp;
it("require authorization", () => {
resp = http.get(meta.userinfo_endpoint);
expect(resp.status).equal(401);
});
it("status 200", () => {
resp = http.get(meta.userinfo_endpoint, { headers: { authorization: `Bearer ${token}` } });
expect(resp.status).equal(200);
});
const info = JSON.parse(resp.body);
it("has same property values", () => {
["sub", "name", "email", "picture"].forEach((prop) => expect(info[prop]).equal(user[prop]));
});
});
The output will be something like this:
β setup
β Generate random user
β status 200
β Generate access token
β status 200
β Get OpenID Configuration
β status 200
β has userinfo_endpoint
β Get User Info
β require authorization
β status 200
β has same property values
Each step/describe execution time is measured, the output will contains these _duration
suffixed metrics (metric name prefix generated from step/describe title with lowercasing it and replacing spaces with underscore characters):
checks..............................: 100.00% β 7 β 0
generate_access_token_duration......: avg=319ms min=319ms med=319ms max=319ms p(90)=319ms p(95)=319ms
generate_random_user_duration.......: avg=348ms min=348ms med=348ms max=348ms p(90)=348ms p(95)=348ms
get_openid_configuration_duration...: avg=38ms min=38ms med=38ms max=38ms p(90)=38ms p(95)=38ms
get_user_info_duration..............: avg=528ms min=528ms med=528ms max=528ms p(90)=528ms p(95)=528ms