Docs k6 Migration Guide

Migrating from k6 to Mockarty perfengine

This guide walks through running your existing k6 load-test scripts under Mockarty’s performance engine. The short version: for an HTTP load test, paste your .js script as-is and hit “Run”. The k6 standard-library modules are reimplemented natively — most fully, a few partially. Check “What’s supported” below for the ones that need edits.

TL;DR

Your existing k6 script:

import http from 'k6/http';
import { check, sleep } from 'k6';
import { Counter } from 'k6/metrics';

const errors = new Counter('errors');

export const options = {
  vus: 50,
  duration: '30s',
  thresholds: {
    'http_req_duration': ['p(95)<500'],
  },
};

export default function () {
  const res = http.get('https://api.example.com/users');
  if (!check(res, { 'status was 200': r => r.status === 200 })) {
    errors.add(1);
  }
  sleep(1);
}

Runs unchanged. Mockarty parses the ESM imports, rewrites them to native require('mockarty/...') calls at compile time, and executes the body inside its own JavaScript engine. No k6 binary needed.

HTTP, checks, groups, thresholds, custom metrics and the executor/scenario model are the well-covered part. gRPC, WebSocket, file-backed test data and third-party libraries are not — read the table below before you assume a script will move as-is.

What’s supported

k6 module Mockarty support Notes
k6 (check, sleep, group, fail, randomSeed) Full
k6/http Partial get/post/put/del/patch/head/options/request/batch, redirects, tags, auth. Not available: http.cookieJar() and the cookies param, http.file() / multipart uploads, and the res.url / res.html() / res.cookies / res.request accessors.
k6/ws Partial connect returns a socket with send/sendBinary/close. The callback form ws.connect(url, params, socket => …) is not executed, and there are no socket.on(...) events or socket.ping(). An event-driven k6 WebSocket script runs to completion without doing anything — rewrite it against the returned socket.
k6/grpc Partial grpc.connect(address, params) returns a client with invoke/close, and res.status is a string ("OK"). k6’s new grpc.Client(), client.load([], 'x.proto'), grpc.Stream and the numeric grpc.StatusOK constants do not exist — a k6 gRPC script needs rewriting, not porting.
k6/data Full SharedArray with one-time factory
k6/encoding Full b64encode/b64decode in all four variants (std, rawstd, url, rawurl)
k6/crypto Full createHash, createHMAC, direct hashes (md5/sha1/sha256/sha384/sha512/sha512_224/sha512_256/ripemd160), randomBytes, hex, base64
k6/html Full jQuery-like Selection API: find/filter/each/attr/text/html/parent/children/closest/siblings/next/prev/eq/first/last/size/is/not/has/end/add/map/val/data
k6/metrics Full Counter, Gauge, Rate, Trend — tags supported on .add()
k6/execution Full instance, vu, scenario, test — live counters, test.abort()
k6/timers Full setTimeout, setInterval, clearTimeout, clearInterval
k6/redis, k6/experimental/redis Partial The commands are there, but the shape differs: our client is created with redis.open(...) and the methods are synchronous, where k6 uses new redis.Client() and returns promises. Rewrite the await-chain as straight-line calls.

What’s not supported

  • k6/browser / k6/experimental/browser — browser automation is not part of the load engine. Use Mockarty’s own UI-testing engine instead.
  • open() — the global that reads a file at init time. The common data-driven pattern new SharedArray('users', () => JSON.parse(open('./users.json'))) therefore does not run. Feed data through environment variables (__ENV) or a data-generating function instead.
  • Imports from https://jslib.k6.io/... and from your own relative modules (./helpers.js). Only the k6/* modules in the table above are resolved; anything else stays an ES import that the compiler rejects, so the whole script fails to compile. That includes k6-utils, httpx, k6chaijs and the textSummary helper commonly used with handleSummary.
  • k6/experimental/{fs,csv,streams,tracing,webcrypto} and k6/secrets.
  • The externally-controlled executor — a scenario using it is skipped.

Differences vs upstream k6

Mockarty’s perfengine is a superset: everything k6 does, plus our own extensions. A few practical differences:

  1. __VU and __ITER magic globals work, but k6/execution is the modern, more powerful equivalent. Use exec.vu.idInTest and exec.scenario.iterationInTest.
  2. Timers are an event-loop queue, not raw goroutines. Callbacks registered via setTimeout/setInterval fire when the VU thread is at a safe point — between iterations, or every 50 ms inside sleep(). That mirrors browser/k6 behaviour. If you schedule a 5 s timer and immediately return from your default function, it fires before the next iteration starts.
  3. Custom metric tags are supported on .add(value, { tagName: 'value' }). The aggregation creates one bucket per unique tag-set, plus an untagged total for backward compatibility.
  4. Options (export const options = { ... }): the keys read from your script are vus, duration, iterations, stages, rps, maxVUs, thresholds and scenarios. Every other option key is ignored, including summaryTrendStats, insecureSkipTLSVerify, discardResponseBodies, batch, userAgent, maxRedirects, noConnectionReuse, tags and ext. Set what you need through the run configuration instead.
  5. Executors: constant-vus, ramping-vus, per-vu-iterations, shared-iterations, constant-arrival-rate and ramping-arrival-rate are supported. A multi-scenario script runs its scenarios in parallel when launched through mockarty-cli perf run; when launched from the UI or a runner, only a single-scenario script transfers its load profile — for a multi-scenario script set the profile in the run form.
  6. Thresholds: avg, min, max, med, count, rate, value (gauges) and p(N) including fractional percentiles such as p(99.9). A threshold naming a metric the engine does not track is reported as not evaluated rather than counted as passed.
  7. handleSummary(data) is called by mockarty-cli perf run, but data is Mockarty’s own report object, not k6’s summary structure. A summary function written against data.metrics['http_req_duration'].values['p(95)'] needs adapting.

Native Mockarty extensions on top

Once your k6 script runs, you can mix in native Mockarty modules:

  • require('mockarty/kafka') — Kafka producer/consumer
  • require('mockarty/rabbitmq') — RabbitMQ
  • require('mockarty/sql') — SQL via Mockarty’s connection pool
  • require('mockarty/mcp') — drive an MCP server
  • require('mockarty/faker') — built-in Faker functions
  • require('mockarty/allure') — emit Allure annotations

These are not in upstream k6 — they’re Mockarty additions for protocols and integrations a typical k6 user reaches for via third-party extensions (xk6).

How to run a k6 script

  1. Open API Tester → Performance → Scripts → New in the Mockarty Web UI.
  2. Paste your .js script. Format detection is automatic — k6 (ESM) and Mockarty (CommonJS) syntax are both accepted.
  3. Click Run. Live metrics (RPS, p95 latency, error rate, active VUs) appear in real time.
  4. After completion the report shows per-route stats, thresholds pass/fail, and custom metrics. Export to JSON, JUnit XML, or Allure as needed.

CI/CD users: the same script runs via the Mockarty CLI:

mockarty-cli perf run ./my-script.js --vus 50 --duration 30s

How compatibility works

Mockarty runs supported k6/* imports in its own load engine; you do not need to install the k6 binary on a Mockarty runner. Start with an HTTP script, then check the compatibility table above before moving scripts that use other modules. Features marked Partial or listed as unsupported need changes to the script.

Reporting issues

If a k6 script fails to run, or produces different output than the upstream k6 binary, please report it. Include:

  • The exact k6 version you were comparing against.
  • A minimal reproducing script.
  • The Mockarty perfengine error (if any).

We treat a divergence as a bug to fix when it is in a module marked Full above. Divergences in the modules marked Partial, and in anything under “What’s not supported”, are already known — they are listed there rather than tracked as individual bugs.