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 patternnew 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 thek6/*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 includesk6-utils,httpx,k6chaijsand thetextSummaryhelper commonly used withhandleSummary. k6/experimental/{fs,csv,streams,tracing,webcrypto}andk6/secrets.- The
externally-controlledexecutor — 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:
__VUand__ITERmagic globals work, butk6/executionis the modern, more powerful equivalent. Useexec.vu.idInTestandexec.scenario.iterationInTest.- Timers are an event-loop queue, not raw goroutines. Callbacks registered via
setTimeout/setIntervalfire when the VU thread is at a safe point — between iterations, or every 50 ms insidesleep(). 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. - 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. - Options (
export const options = { ... }): the keys read from your script arevus,duration,iterations,stages,rps,maxVUs,thresholdsandscenarios. Every other option key is ignored, includingsummaryTrendStats,insecureSkipTLSVerify,discardResponseBodies,batch,userAgent,maxRedirects,noConnectionReuse,tagsandext. Set what you need through the run configuration instead. - Executors:
constant-vus,ramping-vus,per-vu-iterations,shared-iterations,constant-arrival-rateandramping-arrival-rateare supported. A multi-scenario script runs its scenarios in parallel when launched throughmockarty-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. - Thresholds:
avg,min,max,med,count,rate,value(gauges) andp(N)including fractional percentiles such asp(99.9). A threshold naming a metric the engine does not track is reported as not evaluated rather than counted as passed. handleSummary(data)is called bymockarty-cli perf run, butdatais Mockarty’s own report object, not k6’s summary structure. A summary function written againstdata.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/consumerrequire('mockarty/rabbitmq')— RabbitMQrequire('mockarty/sql')— SQL via Mockarty’s connection poolrequire('mockarty/mcp')— drive an MCP serverrequire('mockarty/faker')— built-in Faker functionsrequire('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
- Open API Tester → Performance → Scripts → New in the Mockarty Web UI.
- Paste your
.jsscript. Format detection is automatic — k6 (ESM) and Mockarty (CommonJS) syntax are both accepted. - Click Run. Live metrics (RPS, p95 latency, error rate, active VUs) appear in real time.
- 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.