Skip to content

Reports · Diagnostics · One language

Test APIs and browsers in one language.

Reports first, syntax second — a self-contained report.html, junit.xml, and teaching-quality diagnostics fall out of every run, no glue code between tools. Four pillars share one grammar — API, browser, load (validated against k6 on real contended workloads) and security scanning. Pre-1.0, not yet published.

checkout.tflw

test "user can check out" as shopper
  let email = unique email
  api POST /cart/checkout body { email: {email} }
  expect status equals 201
  capture body.orderId as orderId
  log "order {orderId} placed, confirming delivery"

  open "/orders/{orderId}"
  click button "Confirm delivery"
  expect text "Order confirmed" is visible

  # same file, confirming the backend saw it too
  api GET /orders/{orderId}
  expect body.status equals "confirmed"

# and the same grammar covers load testing
test "checkout under load"
  ramp to 50 users over 30s
  api POST /cart/checkout body { id: "widget-1" }
  expect status equals 201
  threshold p95 duration is less than 800ms
  • Reporting-first runtime

    Every step is an event by construction — a self-contained report.html (full request/response detail), junit.xml, and results.json all fall out of the same event stream tflw run already emits, secrets redacted everywhere automatically.

    Reporting & CI →
  • Teaching-quality diagnostics

    Source line + caret + "did you mean", stable TF0xx codes, a conservative unknown-variable checker pass — errors read like a compiler's, not a stack trace.

    Running & debugging tests →
  • One language for API, browser, load & security testing

    UI steps share the same grammar as API steps, so a login → seed-via-API → drive-UI → assert-backend-state test stays one readable file instead of gluing two tools together. Load testing (ramp/hold/step/spike, thresholds) is validated within a few percent of k6 on real contended workloads — see the numbers. Security scanning runs inside the same test — hygiene, authorization, input handling and an active crawl — each behind a written authorized target declaration.

    Start with functional testing →
  • Real editor support

    A real Language Server Protocol implementation (tflw lsp) powers the VS Code extension — diagnostics, hover, go-to-definition, autocomplete, rename, signature help, and semantic highlighting, live as you type.

    Editor support →
  • A local UI for the whole language

    tflw ui reads a directory of .tflw files back as a page — what you have, what it is for, what happened when it last ran, and a form per statement that writes the language for you. It is local, needs no account, and keeps no state of its own — it reads files from disk and writes files back to disk, so closing it leaves exactly what git sees.

    tflw ui →

Compared to writing API tests by hand with fetch + a general-purpose test runner:

  • Reporting is built in, not bolted on. Every step is an event by construction — report.html, junit.xml, and results.json all fall out of the same run, with secrets redacted everywhere automatically. No logging or capture code to write yourself.
  • Errors read like a compiler's, not a stack trace. Source line + caret + "did you mean", stable TF0xx codes you can look up, a conservative unknown-variable checker pass.
  • One language, not several tools glued together. Sessions, retries, generated test data, and data-driven tables are grammar, not helper functions you maintain per project.

Compared to other dedicated tools: if you already have Karate working for your team, its Java/Gherkin ecosystem and maturity are a real reason to stay. Hurl's single-file, no-runtime .hurl scripts are a better fit for simple curl-replacement smoke checks than a full DSL.

On the browser side, Playwright and Cypress remain the right choice if browser automation is the whole job — tflw's browser steps run on Playwright under the hood, not instead of it. What tflw replaces is the glue: seeding state over the API, driving the UI, and asserting backend state afterward, without switching tools or writing a client by hand partway through a test.