One tool for API, workflow, performance, load, distributed, comparative and UI/RPA testing. GATF is a single Java 21 jar with a web console, a trace viewer, a step debugger and a VS Code extension.
- API tests are data (XML, JSON or CSV), chained into workflows and fed by SQL, MongoDB or file data sources.
- UI tests are written in seleasy, a terse automation language compiled to Selenium Java in-process.
- The same suites scale from one run to concurrent users, load runs and distributed agents.
The primary goal of GATF is automation with simplicity.
- Capabilities
- Install · Quick start · Commands
- Console output, logs and exit codes · Running in CI
- Documentation · Developing GATF
- Test case formats: XML, JSON or CSV files, one or many cases per file, auto-discovered under
testCaseDir. XML is the most expressive. - Protocols: REST over HTTP/1.1 and HTTP/2 (the JDK
java.net.httpclient). SOAP via WSDL keys and operations. Multipart uploads, request bodies from files, custom headers and cookies. - Assertions: status code, content type and body. Node assertions use JSONPath for JSON and XPath for XML/SOAP. Logical validations are Velocity expressions over the response and variables.
- Auto-authentication: log in once through a configured auth call;
securecases get the token as a header or query parameter. SOAP auth is also supported. - In the console: Play runs a case as defined. Replay re-sends a captured request from a report. Every report carries the equivalent
curlcommand (copy it, paste it into a shell, or import it back).
- Capture values from one response into variables for later tests: response nodes,
#responseHeader[..],#responseCookie[..],#responseMappedValue[..]and#responseMappedCount[..](workflowContextParameterMap). - Reuse them anywhere as
${var}placeholders in URLs, headers and bodies. Global, workflow and provider variables share one namespace. - Scenarios: repeat a case once per scenario row, inline or from a data provider. Run a named case as a dependency (
relatedTestName). Add pre/post waits. Abort the suite on a hard failure. - Conditional execution:
executeOnConditionis a Velocity expression over the workflow variables. When it is false, the case is skipped, and the report records the condition as the reason. - Hooks: Java pre/post-execution hooks (
@PreTestCaseExecutionHook/@PostTestCaseExecutionHook), and data-source hooks such as SQL setup/cleanup around a case.
- Data sources: any JDBC database, MongoDB, or your own class.
- Providers:
- query rows, or files (CSV, JSON, XML, XLS, XLSX, ODT);
- inline values, random values, or a custom provider class;
- "live" providers that re-query on each use.
- The same data drives both kinds of test: API scenarios, and seleasy
#provider,#sql,#mongo,#fileand#counterloops. In a script,#dsqruns a data-source query directly.
- Performance mode: run a case N times (
numberOfExecutions) with timing statistics and percentile ("TA") reports. - Concurrent-user simulation: N users with ramp-up, optionally each with its own credentials from a data provider (
authDataProvider). Runs on virtual threads. - Load testing: time-boxed suite replay on the embedded engine, with live charts. A test case can instead delegate to a load tool (
perfConfig): wperfk, the default (wrk/wrk2-compatible with Lua scripts, any OS, downloaded from its v0.1-alpha release and checksum-verified on first use), or vegeta, autocannon, wrk/wrk2, or your own engine fromplugins/. vegeta and autocannon are auto-provisioned too, wrk/wrk2 fall back to Docker, and any tool that can't be set up falls back to vegeta with a notice (details). - UI load: the same concurrency applies to seleasy suites.
- Flow → load: in the Trace Viewer, ⚡ Load test this flow turns a UI run's API and document requests (static assets, preflights and cookies dropped, as in the HAR import) into
<script>-load.xml: one case per step, namedMETHOD /path, each with aperfConfig(wperfk, 10 users, 30 s). The file is saved in the test directory and the console starts it right away in Execute. Beside it,<script>-load.targets.jsonlholds the whole flow as vegeta JSON targets (vegeta attack -format=json -targets=…). From the CLI:gatf import flow network.har [--users N] [--duration S] [--rate R] [--engine wperfk|vegeta|autocannon|wrk|wrk2](engine default: wperfk), which also prints theloadConfigkeys for a concurrent-users run of the flow. - Distributed load:
gatf -listeneragents on other machines, over a TLS, shared-secret-authenticated transport. The console shows aggregated live results per node. - Distributed traces: UI runs on
gatf -listeneragents stream each kepttrace.zipback to the coordinator, which verifies it (size cap, SHA-256, zip only, never extracted) and stores it under<out>/dist-traces/<run>/<node>/.<out>/distributed-traces.html(and.json) links every trace and marks missing, oversized or rejected ones;gatf merge-reportscarries the links over. Caps:-Dgatf.dist.trace.maxBytes(default 256 MiB,0= no transfer) and-Dgatf.dist.trace.maxCount(default 2000). Older agents keep working, without traces. - Distributed results: the coordinator extracts only a node's expected report files from its results zip (top-level
*.html/*.csv, orDRun-<index>…for UI runs; no paths, links or duplicates), capped at 1 GiB per node (-Dgatf.distributed.resultsMaxBytes/GATF_DISTRIBUTED_RESULTS_MAX_BYTES); anything else is skipped with a log line.
Replay the same suite against several base URLs (compareEnvBaseUrls) to compare environments, such as staging against production. A report view and a file-compare view show side-by-side diffs.
- Multi-browser: multiple browser sessions per script (Chrome, Firefox, Edge, Safari, IE, and Appium Android/iOS). Local (Selenium Manager downloads the driver and Chrome for Testing), the lean chrome-headless-shell, or any Selenium Grid (browser modes).
- Locating elements: id, name, class, CSS, XPath, text, link text and jQuery selectors, with smart waits (
??10,??+,??-) and assertions on text, attributes, CSS values and state. - Auto-wait (
autoWaitconfig, on in the sample and dogfood configs): before every element action (click, type, select, hover, clear, submit, upload, double-click, drag) GATF waits until the element is attached, visible, enabled, stable (same box over two animation frames) and not covered (the click point hits it);typefails only on a readonly text field andclearneeds an editable one. The wait is bounded byactionTimeout(ms, default 5000), and a failure names the unmet condition, e.g.covered by <div.modal>. Opt a single step out withclick! …ornowait …. Configs withoutautoWaitbehave as before; projects created from the console getautoWaitandwebFirstAssertionson. - Web-first assertions (
webFirstAssertionsconfig, on in the sample and dogfood configs): a value assertion such as?? css@h1 text ="Welcome"whose element is already there but whose condition is not yet true is retried untilassertTimeout(ms, default 5000) instead of failing at once, so late-rendered text passes without an explicit wait. The failure then names the condition, e.g.text = "Welcome" still false after 5000 ms.nowaitopts a line out; configs without the setting fail at once as before. - Soft assertions:
??~ css@h1 text ="Welcome"records a failed assertion and carries on; the script (or subtest) then fails at the end with every soft failure listed. The console, JUnit XML (softFailuresproperty) andgatf-results.jsonshow the count. - Semantic locators:
role@button[name=Save],label@'Email address',placeholder@Search,testid@save-btn(attribute set bytestIdAttribute, defaultdata-testid),alt@,title@, and exact / regex text (text@'=Order placed',text@'/placed|shipped/i'). They resolve in the page with implicit ARIA roles and accessible names, pierce open shadow roots, and withstrictLocatorsfail when more than one element matches, listing the candidates. - Network mocking:
route **/api/users fulfill 200 users.json,route **/*.png abort,route **/api/** continue header 'X-Env: test'andunrouteintercept the browser's own requests (the first matching route wins; optional method filter);route from har checkout.harreplays a recording by method + URL. Chromium via CDPFetch, Firefox via WebDriver BiDi. - Auth state:
state save .auth/admin.json/state load …keep cookies (every domain, via CDP or BiDi) and local/session storage in Playwright'sstorageStateformat. SetloginOnce(a script run once before the UI suite) andstorageState(the file it leaves) in the config and every script starts logged in.browserApiStorageToken(e.g.localStorage:auth#access_token) sends a token the app keeps in web storage as a bearer header onapi/curlcalls from UI scripts. - Emulation:
emulate device "iPhone 13"(bundled descriptors, plus your owndevices.json) runs a mobile-viewport test without Appium.emulate geolocation|locale|timezone|permissions|colorscheme|offline|network slow3g|resetcover the rest, over CDP on Chromium and WebDriver BiDi elsewhere (reference). - Clock control:
clock install 2026-01-01T09:00:00Z,clock fastforward 5m,clock set …fakeDate, timers and animation frames in the page (and on every new document), so time-dependent UI is tested deterministically. - Visual regression:
screenshot compare home [0.1] [maxdiff 0.5%] [mask id@clock]compares the full page with<testCaseDir>/__screenshots__/<browser>/<script>/home.png(perceptual threshold, anti-aliasing tolerated, masks). A mismatch fails the step with expected / actual / diff images attached;gatf test --update-snapshotsaccepts changes, and a missing baseline fails underCI=true(reference). - Accessibility:
a11y check [include css@…] [exclude css@…] [impact>=serious] [report]runs the bundled axe-core (unmodified, MPL-2.0) in the page. Violations fail the step, listed with their selectors, and show in the report's Checks tab and the attachments gallery. Failedscreenshot comparesteps get a before/after diff slider in the report. - Hooks and markers:
beforeAll/beforeEach/afterEach/afterAllblocks run around the script and each subtest (afterEach/afterAll also after a failure);skip subtest …/fixme subtest …skip that subtest andonly subtest …skips the others in the script, reported as skipped with the reason in the console, report and JUnit XML.globalSetup/globalTeardownin the config run once before and after the UI suite. - Per-test browser contexts (
browserContexts: subtest, opt-in): every top-level subtest runs in a fresh browser context in the same browser (WebDriver BiDibrowser.createUserContext, or CDPTarget.createBrowserContext): its own cookies, storage, cache, routes, emulation and clock, disposed when the subtest ends however it ends, withstorageStateloaded into each one. Unsupported sessions keep the shared context and say so in the run log. Matrix: docs/browser-modes.md. - Workers on contexts (
browserContexts: worker, opt-in): each worker keeps one browser and runs every script in a fresh context of it, so a 4-worker suite launches 4 browsers instead of one per script; falls back to a browser per script where contexts are unsupported, and says so once. Details: docs/browser-modes.md. - Actions:
- type (including random data), click, double-click, right-click, hover;
- drag and drop, click-and-hold/release, move-by-offset and key chords, chained with
actions; - dropdowns, uploads, OS-level keys (Robot), canvas drawing;
- alerts and confirms; windows, tabs and frames (scoped blocks); scrolling.
- Structure: subtests (individually reported), functions with arguments,
includeandimportof other scripts,if/else if/else, loops withbreak/continue, variables, properties files, and pass/fail control. - Embedded code: Java blocks (full access to the driver and context), plus JavaScript, Groovy, Ruby and Python blocks, and JavaScript executed in the browser.
- Mobile: tap, swipe, pinch, zoom, rotate, shake and touch sequences via Appium.
- RPA: long-running business processes with the same data sources and variables as API tests.
- OCR: read the text of an element image (for example a captcha) with Tesseract (
ocr/readimgtext). - QR and barcodes: decode them from the page (
qrcode/barcode/readqrbar, via ZXing). - PDF:
printpdf <file> [text]prints the current page to PDF (Chromium via CDP, Firefox via BiDi, or W3C print, locally or on a Grid). If the page is already showing a PDF blob, it saves the document itself.wopensavecaptures documents the page opens withwindow.open. Withtext, both extract the text and tables (PDFBox) to<file>.txt; embedded code can read the tables withpdfTable(path). - Screenshots and files: full page and per element, element images saved to files, files read line by line into variables.
GATF can start an embedded SMTP/IMAP mail server and an HTTP server during a run. seleasy can then assert that an email arrived (sender, recipient, subject, body regex, timeout) or that an HTTP request was received (for example an SMS gateway callback) with mail and http.
-
seleasy plugins: map a keyword to any static Java method in
plugins.txt(name=com.acme.MyPlugin@method), then use it as a statement orvar x plugin name ....- Plugin SDK v2: implement
GatfStepPlugin(name, execute, optional info/init), register it viaMETA-INF/services, and drop the jar intoplugins/. It is loaded in its own class loader and picked up without a rebuild. Its docs appear in the web editor's and VS Code's completion (GET /api/plugins). See the reference. - Built-ins:
jsonread/jsonwrite/jsonpath,xmlread/xmlwrite/xmlpath,api(call a GATF API test from a UI script and use its response) andcurl(ad-hoc HTTP). Both share the browser's session: the browser's cookies for the target URL are sent, and response Set-Cookies are stored back in the browser, so a script can log in through the UI and call the API authenticated (or the reverse).browserApiSession:sync(default),send(browser → API only),off.
- Plugin SDK v2: implement
-
API hooks, custom data sources and custom providers: plain Java classes referenced from the config.
-
Integrations:
- fetch server-side logs through your own APIs when a test fails (
gatf-logging-api-int.xml); - define your issue tracker's APIs (
gatf-issuetracking-api-int.xml).
Both are edited in the console's Integrations view.
- fetch server-side logs through your own APIs when a test fails (
- Web editor: syntax highlighting, autocomplete, diagnostics, go-to-definition across files, and multi-tab editing. Saving validates the script by parsing and compiling it.
- Recorder: opens a browser (Chrome, Firefox or Edge) and turns your clicks and typing into seleasy, with timing pauses preserved. Each step uses the first locator that is unique on the page:
testid@, thenrole@…[name=…], thenlabel@, then id / name / CSS / XPath. - Crawler: logs into an application (including JavaScript SPAs), explores it in a real browser, and proposes a seleasy suite plus a coverage map (the SPA crawler ranks locators the same way as the recorder).
- Importers: Playwright specs become seleasy; JMeter plans become GATF API tests, and their thread-group load settings are shown to apply.
cURL commands (bash/cmd/PowerShell "Copy as cURL", or a report's cURL line), Postman collections (v2.x and v1) and HAR
recordings become GATF API tests: headers, bodies (raw, urlencoded, multipart, GraphQL), auth, Postman variables
(
{{x}}→${x}) and recorded/asserted status codes carry over. What cannot be converted is listed, never dropped silently. In the console (Import) orgatf import. OpenAPI 3.0/3.1 and Swagger 2.0 specs (JSON or YAML) become one API test per operation: parameters and bodies from the spec's examples/defaults or a value built from the schema, the first 2xx as the expected status,$refs (local and relative files — in the Import view, multi-select the spec with the files it references) resolved, security schemes as${authToken}/API-key placeholders, and operation tags as@tags. Each imported case also keeps acontractpointer (<spec>#<operation>, the spec is saved beside the .xml), so a run fails a response whose status or Content-Type the operation does not declare, or whose JSON body breaks the response schema; the failure names the operation and the JSON pointer (/photoUrls: required property missing).--negative(or the Import view checkbox) adds cases that drop a required parameter or send a wrong-typed body property and expect 400 (422 when only that is declared). Re-importing over an existing file lists the operations added, removed or changed since. - Test generator: creates API test cases from JAX-RS or Spring controllers and SOAP WSDLs, and can also produce a Postman collection.
- VS Code extension: language server (completion, diagnostics, navigation) and a debugger.
- A step debugger for seleasy, in the web console and in VS Code: breakpoints, step over and into, continue, and live line highlighting.
-validate-selcompiles a script without running it.- Watch: the editor's Watch button runs the script beside the editor and re-runs it on every save, with the live browser screencast next to the step list (the Run and Debug views show it too). The frames are the trace video's, so turn on
traceVideo.gatf test --watchdoes the same for the CLI. - Coding agents (MCP):
gatf mcpis a Model Context Protocol server over stdio. An agent (Claude Code, Claude Desktop, IDE agents) can list the tests, lint a script, run the suite (gatf testwith grep/tag/trace/retries), read the failed tests from the last run, condense a trace zip (last actions, console errors, failed and slow requests, checks, web vitals), and record or crawl new scripts. Register it with, for example,claude mcp add gatf -- java -jar gatf-alldep-jar-<version>.jar mcp --root /path/to/project. - Healer (core, opt-in AI): turns a failed step plus its trace's failure snapshot (
traceDomSnapshotson) into proposed fixes, as a diff; it never edits the script. It tries a wait or a strict locator for the element the old locator meant first, and asks the model configured in<ai>only when that finds nothing. Every proposal must match exactly one element in the snapshot. Without<ai>, nothing changes. - Healer in the editor and MCP: 🩹 Heal failed step in the Trace Viewer (or Heal last failure above a
.selin the editor) shows the healer's proposals as diffs, with rank, source (deterministic / ai), strict match count and the AI status. Accept re-reads the file, writes nothing if the line changed since the heal, and writes the fix only ifvalidateSelpasses; Reject writes nothing. The MCPhealtool (trace, optionalstepandfile) returns the same proposals and never writes. A relative<apiKeyFile>resolves against the config file's folder. - Planner (opt-in AI):
gatf plan <n>-coverage.jsonturns a saved crawl map into a test plan,<n>-plan.json(gatf-test-planv1, the generator's input) plus<n>-plan.md. Every crawled route gets an entry and deterministic journeys (page load, fill-and-submit per form, submit-empty when fields are required) with or without AI; the model in<ai>only adds journeys and priorities, as closed-set steps over the elements and locators the crawl saw, and never adds or drops a route. Crawls saved by this version carry the elements;--coverage-run <run dir>marks the routes no test visits;--no-aiskips the model. The MCPplantool returns the same plan and never writes. - Generator (opt-in AI repair):
gatf generate <n>-plan.jsonturns a test plan into seleasy scripts intests/generated/<plan name>/by a fixed mapping of its closed-set steps (same-origin URLs, re-checked locators, GATF's own fill data; the model never writes seleasy). Each script must passvalidateSeland the suite must dry-run compile; only passing scripts are written. Journeys with side effects (button clicks, non-GET submits) need--include-side-effects. With<ai>configured, a failing script gets up to 3 repair rounds in which the model may only drop a step, pick an alternative locator or change a fill's data kind. The MCPgeneratetool returns the scripts and gate results and writes nothing in the project; MCPlintnow also returnsdiagnostics.
Each UI run can produce a trace.zip containing:
- network traffic (HAR), with response bodies;
- console logs;
- DOM snapshots per action (opt-in
traceDomSnapshots:lite= the sanitized DOM without stylesheets,full= styled, with the page's stylesheets, a before and an after state per action and the action's element marked; capped bytraceDomSnapshotMaxMb, default 32), and video; - web vitals, performance and memory metrics;
- a CPU profile and JS/CSS coverage.
It is captured over CDP or WebDriver BiDi (Chromium, Firefox and Edge) and opens in the built-in Trace Viewer, with a timeline synced to every tab.
With traceDomSnapshots=full, the viewer's DOM view is a styled time-travel: each action's page is rebuilt from the trace alone (its stylesheets and the captured response bodies) in a sandboxed, script-less frame, with a Before / After toggle and the action's element outlined. Images the trace has no body for show as blank placeholders (turn on traceNetwork to capture them); nothing is fetched from the live site.
⌖ Pick locator (DOM view): hover the snapshot to get the element's strict locator, ranked as the recorder ranks it (testid@ → role@ → label@ → id/name/css), and offered only when it matches exactly one element in that snapshot; click to keep it, then Send to editor. In the seleasy editor, Insert below cursor pastes it as a click … step, and ⌖ Pick in live browser picks one element in the window of an active recording session (Esc cancels; the picker leaves nothing on the page). Ranking runs on the GATF server; without it the viewer lists the candidates with their match counts and paste is disabled.
Untested routes and scripts: in Reports, a run's Coverage button merges the JS coverage and visited pages of that run's traces (traceCoverage on, Chromium) with the newest saved crawl map (<name>-coverage.json in the test dir) and lists the crawled routes no test visited and the scripts none of whose functions ran. GET /api/coverage?report=<run> returns the same per-test coverage index (gatf-coverage-index v2: URLs without query strings or session ids, offset ranges, and each test's coverage state); coverage-index.json in the run folder is its cache. CSS is one unattributed total for now.
traceMode decides when a trace is captured and kept (it overrides the older enableTrace flag):
traceMode |
Captures | Keeps |
|---|---|---|
off |
never | — |
on |
every script | every trace |
retain-on-failure |
every script | only scripts where the script or a subtest failed |
on-first-retry |
only in retry round 1 (needs seleniumScriptRetryCount ≥ 1) |
every trace it captured |
When a step fails, its screenshot is shown in the test's report, next to the "Open in Trace Viewer" button.
Performance budgets and security checks run over each captured trace; results appear in the test's report and in checks.json inside the trace.
-
Budgets: set
perfBudgetsin the config (e.g.lcp<2500, requests<80, jsheap<50mb) or per script in its leading comments (// @budget lcp<2000 transfer<2mb). A script budget overrides the config one for the same metric. A breach fails the script with the measured value. Web-vital budgets (lcp fcp ttfb dcl load cls) apply to the worst page the script visited (per-navigation vitals,webVitalsByPagein performance.json; under BiDi only pages left within the same origin are captured), else to the final page.- Metrics for the page open at the end of the script:
lcp,fcp,ttfb,dcl,load(ms) andcls. - Metrics over the whole script:
jsheap,transfer(b/kb/mb),requests,failedRequestsandconsoleErrors. - A metric the browser didn't report is shown as "not measured"; it doesn't fail the script.
- Metrics for the page open at the end of the script:
-
Passive security checks (
securityChecks:reportdefault,fail= fail on medium or high,off):- HTML pages: missing CSP, HSTS, nosniff, clickjacking protection or Referrer-Policy, and server-version disclosure.
- First-party cookies without Secure or HttpOnly, and
SameSite=Nonewithout Secure. - Mixed content, wildcard CORS with credentials, and CSP violations in the console.
Findings are listed per page. Nothing extra is sent to the site.
- HTML reports per run, with pass/fail summary charts and full request/response detail per test case.
- PDF and CSV run reports for UI (seleasy) suites, built with iText and written next to the HTML report as
…-RP-<timestamp>.pdf/.csv. There is one results table per script (session, subtest, time, status, message). The PDF adds an error-details page per failure, with the stack trace and the failure screenshot. - Load reports: live charts and latency percentiles; distributed runs are aggregated per node.
- The console's report viewer, file compare and data-source statistics views.
- Run insights (Reports › Latest CLI run › Insights, and every merged report): a duration timeline per worker lane, the slowest tests and files, the flaky list, and status / tag / text filters, from the run's
gatf-results.json. An attachments gallery (screenshots, visual diffs, traces, checks, accessibility results) and Raise defect on failed tests. - Trends: every CLI run's results are archived in
<out>/history/(newest 50 kept;-Dgatf.history.keep=N). Reports › Trends charts the last 10 runs (passed / flaky / failed / skipped, duration) and ranks the least stable tests. API:GET /api/history?limit=N. - CLI runs print Playwright-style ✓/✘ output, write a detailed log file, and return a CI-friendly exit code (see below).
One page for everything above:
- Config, Test Files (tree, editor, compare) and Execute (files or whole folders, live status);
- Reports and traces;
- Import, Record and Crawl;
- Data Sources and Integrations.
Optional login; light and dark themes.
macOS / Linux:
curl -fsSL https://github.com/sumeetchhetri/gatf/releases/latest/download/install.sh | bashWindows (PowerShell):
irm https://github.com/sumeetchhetri/gatf/releases/latest/download/install.ps1 | iexOffline: download gatf-<version>.zip from Releases, unzip it, and run ./install.sh (or powershell -ExecutionPolicy Bypass -File .\install.ps1).
Java: needs Java 21+. A JRE is enough; only the online debugger needs a JDK. The installer:
- detects an installed Java (preferring a JDK), or offers a private Eclipse Temurin 21 (a JDK by default,
--jrefor the smaller runtime); - installs per user, with no admin rights;
- can set up the load tools (
--with-tools).
From source: mvn -B install, then use alldep-jar/target/gatf-alldep-jar-<version>.jar.
gatf ui # web console → http://127.0.0.1:9080/ (project = current dir)
gatf ui 9080 ./sample-project # ...or point it at a project folder
gatf test # run the suite in ./gatf-config.json (or .xml) from the CLI
gatf test --tag smoke # ...only tests tagged @smokeWithout the installer, replace gatf with java -jar gatf-alldep-jar-<version>.jar, and gatf ui with -configtool 9080 127.0.0.1 ..
sample-project/ is runnable as is. It has API tests (a token-capturing workflow), seleasy UI tests, a load suite and a local target server.
A minimal API test (tests/api/health.xml):
<TestCases>
<TestCase>
<url>/health</url>
<name>Health</name>
<method>GET</method>
<expectedResCode>200</expectedResCode>
<expectedNodes><string>status</string></expectedNodes>
</TestCase>
</TestCases>A minimal seleasy script (tests/ui/login.sel):
open chrome
goto https://example.com/login
??10 id@username type "user"
??10 id@password type "password"
??10 class@loginBtn click
?? css@"h1" text ="Welcome"
| Command | What it does |
|---|---|
gatf ui [port] [dir] |
Web console: config, test files, editor, recorder, crawler, importer, execution, reports, traces, debugger. Default port 9080; bind host via GATF_UI_HOST |
gatf test [config] [options] |
Run the suite (API or UI, per the config's isSeleniumExecutor). The config defaults to gatf-config.json, else gatf-config.xml. Options below |
gatf -executor <config> / -selenium <config> |
Older form of gatf test <config>: same run, no options |
gatf import <type> <file|-> [-o out] [--name suite] [--filter regex] [--negative] [--force] |
Convert playwright, jmeter, curl, postman, har or openapi (alias swagger) input into a GATF test file; prints what needs review. --filter keeps matching HAR URLs. flow turns a run's network.har into a load test (see Flow → load) |
gatf export playwright <file.sel|dir> [-o out] [--strict-locators] [--force] |
Export seleasy scripts to Playwright Test (TypeScript): semantic locators map to getByRole/getByLabel/…, waits and assertions to web-first expect, subtests to test.step; ${name} values become environment variables (GATF_NAME), never their configured values. What has no Playwright equivalent is kept as a // TODO(gatf-export): line and listed in the report |
gatf export selenium-java <file.sel|dir> [-o out] [--strict-locators] [--force] |
Export seleasy scripts to Selenium WebDriver + JUnit 5 (Java 11+): one <Name>Test.java per script needing only selenium-java and junit-jupiter. By locators are the ones seleasy uses, semantic locators run seleasy's own resolver script, waits poll up to the element timeout (60 s default, timeout), subtests become methods; the first open picks the driver (SELENIUM_REMOTE_URL runs it on a Grid). Same ${name} → GATF_NAME environment rule and // TODO(gatf-export): report |
gatf plan <crawl.json> [-o plan.json] [--md plan.md] [--config cfg] [--no-ai] [--max-routes N] [--coverage-run dir] [--force] |
Test plan from a saved crawl map (<n>-coverage.json or the portal crawler's crawl-coverage.json): JSON + Markdown beside the map by default, never overwritten without --force. Every crawled route is planned (up to --max-routes, default 500; the rest are listed as not planned); the <ai> model of the config only enriches |
gatf generate <n>-plan.json [-o dir] [--config cfg] [--ai|--no-ai] [--include-side-effects] [--force] |
Seleasy scripts from a test plan, each linted (validateSel) and the suite dry-run compiled; only passing scripts are written (default tests/generated/<plan name>/, inside the project root, never overwritten without --force). AI repair (plan edits only) is on when <ai> is configured; exit 2 when some scripts failed the gate |
gatf docs [config…] [-o dir] [--format xlsx|csv|both] [--requirements file] [--requirements-jql JQL] [--results file] |
Test-case documents (steps and expected results), a requirement traceability matrix and coverage, as gatf-testcases.xlsx (sheets Test Cases, Traceability, Coverage) and/or CSVs. See below |
gatf merge-reports <dir>… [-o out] |
Join the out dirs of a sharded run (--shard i/n on several machines) into one report: gatf-results.json, gatf-junit.xml, each shard's reports copied under shard-<i>-of-<n>/, and an index.html that opens the merged summary (totals, shards, failures, flaky) in the console (merge under the out dir, e.g. -o out/merged, so gatf ui lists and serves it). Default out dir merged-report; exit code 1 when any test failed |
gatf mcp [--root dir] |
MCP stdio server for coding agents: list_tests, lint, run, get_report, summarise_trace, record, crawl. stdout carries only the protocol; logs and run output go to stderr |
gatf -validate-sel <file.sel> <config> |
Parse and compile a script without running it |
gatf -generator <config> |
Generate API test cases from JAX-RS / Spring controllers or WSDL |
gatf -listener |
Start a distributed-execution agent |
gatf tools install … |
Provision the load tools ahead of first use (wperfk, vegeta, autocannon, wrk/wrk2) |
gatf version |
Print the installed version |
JVM flags go in GATF_JAVA_OPTS (for example GATF_JAVA_OPTS="-Dgatf.log.level=debug").
| Option | Effect |
|---|---|
--grep RE / -g RE |
Run only tests whose title matches the regex (repeatable; any match) |
--grep-invert RE |
Skip tests whose title matches (repeatable; wins over --grep) |
--tag T / -t T |
Run only tests tagged @T (repeatable; combined with --grep as OR) |
--reporter junit,json,github,docs |
CI reports to write (none to disable). docs also writes the test-case documents, traceability matrix and coverage, with this run's status, to <out>/docs |
--trace MODE |
Override traceMode: off, on, retain-on-failure, on-first-retry |
--retries N |
Override seleniumScriptRetryCount |
--workers N / -j N |
Override numConcurrentExecutions: UI scripts run file-parallel on N workers (no fixed cap; never more than the script count). N% = that share of the CPU cores |
--update-snapshots / -u |
Rewrite the baselines of every screenshot compare instead of comparing (config updateSnapshots) |
--shard i/n |
Run only shard i of n (1-based): files are split deterministically by a path hash, so every machine gets the same split. relatedTestName prerequisites come along. An empty shard exits 0 |
--watch |
Keep running: after the first run, a save re-runs the changed scripts / API case files plus the last failures. A change to anything else (config, properties, a library script others import) re-runs everything, failures first. Enter re-runs everything (failures first; the rest only once they pass), f + Enter only the failures, q + Enter quits |
--changed RANGE |
Test-impact selection (UI suites): run only the scripts a git range (main...HEAD, HEAD~1..HEAD, or HEAD for uncommitted work) can reach, from the coverage index of an earlier run with trace coverage on, recorded by this version or later, which notes whether each script passed (--coverage-run dir, default the newest run folder; --source-maps dir = the build output with external .map files). Anything unmapped or unsafe (CSS, a file no script maps to, incomplete or stale coverage, a script that failed in that run) runs everything and says why. --explain prints the selection with a reason per script and runs nothing |
Both --opt value and --opt=value work. If nothing matches, the run stops with No API tests match … or No UI scripts match … and exit code 1.
Titles and tags. Filters match a test's title:
- API test:
<file> › <name>, plus any@tagsin its description. A tag can also go in the name itself, e.g.List users @smoke. - UI script: its path, plus the
@tagsin the//comment lines at the top of the.selfile:A script's subtests always run together.// Checkout happy path @smoke @checkout open chrome - Dependencies: an API test's
relatedTestNamedependency is included automatically. For chains that capture values (e.g. a login token), tag the whole chain, or select it with--grep <file>. - In the console: the Execute view has the same grep / tag / grep-invert fields; they apply within the files selected for the run.
gatf docs turns the configured tests into manual-style test cases. The output is gatf-testcases.xlsx, with three sheets, plus matching CSVs (--format):
- Test Cases: ID, module, source, title, tags, requirements, preconditions, steps and expected results.
- API tests: the request becomes the steps; the status, content type, nodes, validations and captured variables become the expected results.
- UI scripts: each script and each subtest it defines becomes a test case. Commands are written in plain words,
includeand@callare expanded, and??assertions become expected results.
- Traceability: requirement → test cases, with pass/fail/not-run counts and a status (Passing, Failing, Partially run, Not run, Not covered).
- Coverage: requirement and test-case totals and percentages, broken down by module.
Requirements are linked with tags: @REQ-101, any Jira-style @PROJ-12, or @req:<anything> (--req-pattern overrides). They go in an API case's name or description, a script's header comments, or the comment above a subtest. --requirements reqs.csv|xlsx (columns id, title, module) adds the full list, so uncovered requirements show up. Status comes from the last run's gatf-results.json (found automatically in the out dir, or --results). gatf test --reporter junit,json,docs produces the documents after every run. --requirements-jql '<JQL>' imports the requirement list from Jira (id = key, title = summary, module = first component or project), using GATF_JIRA_URL + GATF_JIRA_TOKEN (Bearer; add GATF_JIRA_USER for Basic user:token). The console's Reports view has a Test cases (xlsx) download.
CLI runs (-executor, -selenium) print one line per finished test, then a summary:
Running GATF UI (seleasy) tests
✓ 1 [chrome] › ui/login-flow.sel (4.2s)
✘ 2 [chrome] › ui/checkout.sel › pay (3.1s)
Element not found: id@payBtn
- 3 [chrome] › ui/checkout.sel › refund
1 failed
[chrome] › ui/checkout.sel › pay
1 skipped
1 passed (9.8s)
Report: /work/project/out
Log: /work/project/logs/gatf.log
-
Console: only the pass/fail lines above, plus warnings and errors. Passes are green, failures red, skips yellow.
- Colour is automatic on terminals and GitHub Actions.
NO_COLORor-Dgatf.color=neverdisables it;FORCE_COLORor-Dgatf.color=alwaysforces it.- Load and multi-user runs show only the summary; the report has the per-request detail.
-
Log file:
logs/gatf.login the working directory holds everything:- every result with its request, response code and error detail;
- the engine's step output;
- stack traces.
Each run starts a fresh file. The previous run's log is kept as
gatf.1.log.gz, and the last 10 are retained. -
Flaky tests: with
seleniumScriptRetryCount, failed scripts are retried. A script that fails and then passes is reported as flaky (yellow), and it doesn't fail the run. -
Failure artifacts: a failed line is followed by the paths of its screenshot and, if one was kept, its trace.
-
CI reports:
gatf-junit.xml(JUnit XML; flaky tests carry<flakyFailure>) andgatf-results.jsonare written to the run's out dir. In the JUnit XML, a failure's screenshot and trace are attached with the[[ATTACHMENT|path]]convention that Jenkins and GitLab display. On GitHub Actions each failure is also an::errorannotation, and each flaky test a::warning. -
Exit code:
0when every test passed or was flaky;1if any test failed, the run aborted, or the command line was invalid. The summary always prints, even when failures end the run with an exception.
Setting (-D…) |
Default | Effect |
|---|---|---|
gatf.log.dir |
logs |
Where gatf.log is written |
gatf.log.level |
info |
Detail in the log file (debug for more) |
gatf.console.level |
warn for CLI runs, info otherwise |
Log events shown on the console |
gatf.capture.stdout |
true |
false also shows the engine's raw output on the console |
gatf.color |
auto |
always / never |
gatf.reporters |
junit,json,github |
Which CI reports to write; none disables them |
jobs:
ui-tests:
runs-on: ubuntu-latest
services:
selenium:
image: selenium/standalone-chrome:latest
ports: ['4444:4444']
options: --shm-size=2g
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with: { distribution: temurin, java-version: '21' }
- run: java -jar gatf-alldep-jar-<version>.jar test gatf-config.xml --reporter junit,json,github # fails the job on any failed test
env: { SELENIUM_REMOTE_URL: 'http://localhost:4444' }
- uses: actions/upload-artifact@v4
if: always()
with:
name: gatf-results
path: |
out/
logs/Sharded across machines (each job writes its own out/; gatf-results.json records the shard):
strategy: { matrix: { shard: [1, 2, 3, 4] } }
steps:
- run: java -jar gatf-alldep-jar-<version>.jar test gatf-config.xml --shard ${{ matrix.shard }}/4 --workers 50% --reporter junit,json
- uses: actions/upload-artifact@v4
if: always()
with: { name: 'out-${{ matrix.shard }}', path: out/ }
merge:
needs: ui-tests
if: always()
steps:
- uses: actions/download-artifact@v4 # out-1 … out-4
- run: java -jar gatf-alldep-jar-<version>.jar merge-reports out-1 out-2 out-3 out-4 -o merged-report.github/workflows/ci-webkit.yml runs a small CDP-free subset (dogfood/tests/app-console.sel, app-console-semantic.sel against a local /app server) on Safari (macOS runner, safaridriver --enable) and, experimentally, on WebKitGTK (WebKitWebDriver + MiniBrowser under Xvfb), then a report-only capability probe (sample-project/tests/trace-smoke.sel with every recorder on). It is a separate workflow and does not gate Build gatf. Locally: bash tools/ci/webkit-lane.sh safari|webkitgtk after mvn -q -pl alldep-jar -am package -DskipTests.
WebKit has no CDP, so parity with Chromium is partial:
| Feature | Safari / WebKitGTK |
|---|---|
| Locators (incl. semantic), auto-wait, web-first assertions | ✅ exercised by the lane |
screenshot compare, a11y check (axe) |
expected to work (WebDriver screenshot / JS); not exercised by the lane |
Tracing (enableTrace) |
needs CDP or a live WebDriver BiDi socket; without one no trace.zip is written, silently. WebKitGTK 2.52 (ubuntu-24.04 apt) refuses webSocketUrl; the local safari key asks for it only when a script uses route/emulate/clock (if safaridriver refuses it, that session does not start), and Safari's BiDi is partial |
| Trace with a BiDi socket: DOM snapshots (serialized DOM + CSS by script), screenshots, metrics | ✅ (script / WebDriver) |
| Trace with a BiDi socket: network/HAR, response bodies, console | only as far as the browser's BiDi implements them; the probe reports which |
| Trace: video/screencast | BiDi only with the opt-in polled approximation (videoPollFps > 0) |
Trace: CPU profile, JS/CSS coverage, CDP DOMSnapshot |
❌ CDP only |
route … |
❌ without BiDi the step fails: route: this browser session cannot intercept requests (needs CDP on Chromium, or a BiDi session: webSocketUrl) |
emulate … |
❌ without BiDi the step fails: emulate <op>: this browser session has neither CDP (local Chromium) nor a WebDriver BiDi socket (webSocketUrl) |
clock install |
without BiDi, current document only; the message ends (this document only: clock: … neither CDP … nor a WebDriver BiDi socket …) |
state save/load, browserApiSession |
WebDriver cookies only (the open page's domain); logged at debug level |
When a trace is recorded, recorders skip a capability the browser lacks without a log line; the record is capabilities in the trace's metadata.json. The probe prints it (served / MISSING <capability> -> <what degrades>, via tools/ci/trace-capabilities.mjs), or says that no trace was recorded, and adds it to the job summary. GATF has no webkitgtk browser key yet: that lane runs open firefox-dkr (the -dkr form honours SELENIUM_REMOTE_URL) through tools/ci/webkit-caps-shim.mjs, which rewrites the session capabilities for WebKitWebDriver and logs [webkit-shim] this WebKitWebDriver refused webSocketUrl (no WebDriver BiDi) … when it has to drop BiDi; the lane fails if no session reached WebKitWebDriver.
Set GATF_CLOUD=browserstack|saucelabs|lambdatest (or -Dgatf.cloud) and the vendor's credentials in the environment only: BROWSERSTACK_USERNAME/BROWSERSTACK_ACCESS_KEY, SAUCE_USERNAME/SAUCE_ACCESS_KEY, LT_USERNAME/LT_ACCESS_KEY. The same .sel (open chrome|firefox|safari|ie, plain or -dkr; open edge is not reachable yet) then runs on the cloud: GATF_CLOUD_BROWSER_VERSION (latest), GATF_CLOUD_PLATFORM (Windows 11; required for Safari), GATF_CLOUD_BUILD, SAUCE_REGION (us-west-1), GATF_CLOUD_DEVICE="iPhone 14" (a devices.json name, as chromedriver mobile emulation on Chrome/Edge) and GATF_CLOUD_OPTIONS='{"local":true}' (merged into the vendor options; credential keys are refused). Credentials go as HTTP Basic auth, never in the URL, capabilities, logs or reports. After each result the session's name and passed/failed reach the vendor dashboard (best-effort). An explicit SELENIUM_REMOTE_URL still wins (logged); nothing set = unchanged. CDP/BiDi features (trace network/coverage/screencast, route, emulate, per-test contexts) depend on the vendor: BrowserStack enables CDP (Chrome/Edge) and BiDi for you; Sauce Labs serves CDP/BiDi only with a BiDi socket (beta, 10-minute sessions), so use traceProtocol: bidi / -Dgatf.routeProtocol=bidi; on LambdaTest BiDi is documented for Chrome/Firefox/Edge, CDP is unverified.
Real devices (Appium 2). open appium-android|appium-ios drives Appium 2 (UiAutomator2 / XCUITest), locally at GATF_APPIUM_URL / the driver config url / http://127.0.0.1:4723, or with GATF_CLOUD on BrowserStack App Automate, Sauce Labs Real Devices or LambdaTest Real Devices: set GATF_CLOUD_DEVICE (the provider's device name), GATF_CLOUD_APP (your uploaded app: bs://…, storage:filename=…, lt://…; not needed for mobile web), optionally GATF_CLOUD_OS_VERSION, with the same credential variables. Local-only capabilities (app path, udid, ports) are not sent to the cloud. The touch commands become W3C touch actions; on a desktop browser they are a step error.
| Guide | What it covers |
|---|---|
| seleasy language reference | Every statement, grouped by task, with examples |
| Configuration and test cases | Executor config (all options), API test case fields and formats, data sources and providers, Maven plugin, test generator |
| Browser modes | Local, chrome-headless-shell, or Selenium Grid |
| Load tools | wperfk (default), vegeta, autocannon, wrk/wrk2 and the embedded engine |
| Windows support | Windows-specific notes |
| VS Code extension | Language server and debugger |
| End-to-end tests | How GATF tests itself |
| Tier 3 release notes | Tier 3 (DOM time-travel, AI healer and planner, browser contexts, coverage and --changed, device clouds and Appium 2, WebKit/Safari lane, export, distributed traces): how to switch each on, behaviour changes, upgrade notes. Status: delivered (Δ146–Δ163a); live cloud/device/Safari checks open |
Related: test-html-generator-plugin generates HTML pages for your REST endpoints.
mvn -B install # build + unit tests + integration tests + codegen goldens + JaCoCo report
cd frontend && npm ci && npx vitest run --coverage # SPA unit tests (coverage floors enforced)
cd e2e && npm ci && npx playwright test # SPA e2e against a live server (see e2e/README.md)- Codegen goldens: refresh with
mvn -pl alldep-jar -am test -Dtest=CodegenGoldenTest -Dsurefire.failIfNoSpecifiedTests=false -Dgatf.golden.update=true, then commit the files underalldep-jar/src/test/resources/codegen-golden/. CI fails on a missing golden. - Coverage: the JaCoCo report is at
alldep-jar/target/site/jacoco/index.html, with its floor set bygatf.coverage.line.mininpom.xml. - Snapshot of the source tree (for reviews):
tools/package-source.sh.
Apache License 2.0. See LICENSE.