Workflow required before generating, writing, or updating BAT (Blackbox API Testing) tests for a Mule app. Call use_skill as your FIRST action — before reading or writing any .dwl file — whenever the user asks to create, generate, add, write, refresh, extend, or fix BAT tests, a BAT suite, BDD API tests, black-box API tests, or Anypoint API Functional Monitoring tests for a deployed Mule HTTP API. Do not read the app source, open the existing suite, or author any .dwl yourself and attempt the task in one turn — even a targeted single-test change like 'add a 401 test' or 'fix the orders happy-path test' requires loading this skill first. Covers generating a suite from app source (OpenAPI + Mule XML), extending an existing hand-written BAT baseline, and running the suite against the live endpoint. Not for MUnit (build-time, in-process, XML) — use the Mule developer workflow for that. When you call this skill, it must be the only tool call in that response.
72
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Critical
Do not install without reviewing
Generate a runnable BAT (Blackbox API Testing) BDD suite — DataWeave .dwl
files plus a bat.yaml manifest — from a Mule app's source, organized by
quality dimensions, and validated by running it against the live endpoint.
Use this skill when users request:
Trigger keywords: BAT, BDD, .dwl test, black-box test, API functional
monitoring, functional API test, blackbox · generate / write / add / extend /
refresh tests · against the deployed / running / live endpoint.
Do NOT use this skill for MUnit. MUnit is build-time, in-process, XML, and XSD-validated — a different tool with a different workflow. BAT runs against a deployed HTTP endpoint, is DataWeave, and has no XSD: the only gate on correctness is "it parses AND it passes against the running app". That gate is this skill's Phase 2.
BAT = Blackbox API Testing, MuleSoft's API Functional Monitoring framework.
A BAT test is a DataWeave .dwl BDD file that issues real HTTP requests against
a deployed API and asserts on the responses. It does not import or see the
Mule flows — it is out-of-process and black-box. A suite is a directory of
tests/*.dwl files, a bat.yaml manifest, a config/ with environment
settings, and a run-bat.sh runner. The suite is executed with the bat CLI:
bat --config=local.
Because there is no XSD and no build-time validator, two things matter more than in MUnit generation:
references/bat-authoring-rules.md). The Phase-2 static validator catches the
mechanical ones before you spend a round-trip against the endpoint../run-bat.sh has been
executed against the live app and every test passes (or each failure is
explained in the report). This replaces MUnit's XSD/compile gate.This skill ships scripts under scripts/. Invoke them with the Bash tool —
do not inline their contents. <skill-dir> is the absolute path you were given
in the "skill is now active" message (the directory containing this SKILL.md).
Use it for every invocation; do not construct relative ../scripts/... paths.
| Script | Purpose | Output |
|---|---|---|
scripts/validate_prerequisites.sh | Step 1 — validate toolchain (jq, BAT CLI at $HOME/.bat/bat, Java 17+). Validation-ONLY. | tmp/bat-gen-env.json (ok, errors[], bat_cli, java_version) |
scripts/extract_endpoints.sh <app-dir> | Step 2 — grep the Mule source for <http:listener> paths and <raise-error> types; list API spec files. Anchors the inventory. | tmp/bat-gen/source-digest.json + stdout |
scripts/scaffold_suite.sh <suite-dir> [--url U] [--token T] [--force] | Step 8 — create config/{default,local}.dwl, run-bat.sh (chmod +x, JDK-17 JAVA_OPTS), and tests/. Idempotent. | suite skeleton on disk |
scripts/validate_bat_suite.sh <suite-dir> [--allowlist F] | Step 9 — static DSL checks (imports, describe(...), no mustNotBe, no hardcoded URL/token, Number status codes, bat.yaml shape, files↔disk parity, optional path allowlist). Exits 1 on violations. | stderr diagnostics |
This workflow has two phases separated by a hard user-approval gate.
tmp/bat-gen/ digest and the
inventory JSON..dwl files + bat.yaml, run the static validator, run the suite against the
live endpoint, and declare completion only after a clean run.Phase 2 MUST NOT start until Step 6's approval gate has been passed explicitly.
Generating .dwl files before the inventory is approved is the highest-impact
failure mode this structure prevents — a wrong dimension split or a fabricated
endpoint becomes N wrong test files.
<http:listener> configuration and OpenAPI
contract. Never invent an endpoint from the API's name or from training-time
intuition. Step 2's extract_endpoints.sh digest is the anchor; the Phase-2
validator enforces it via --allowlist.$(config.url)
and config.token. A literal http://localhost... or "Bearer ..." in a
.dwl file is a defect — the validator rejects it../run-bat.sh ran against the live app
and every test passed, OR every failure is documented in the report with
reasoning. Never declare completion off an unrun suite.Run the prerequisite validator. It only validates; it writes findings to
tmp/bat-gen-env.json.
bash <skill-dir>/scripts/validate_prerequisites.shIf it exits non-zero, STOP and surface the errors array to the user
(most commonly: BAT CLI not installed, or Java < 17). Do not attempt to author
a suite you cannot run — the run is the gate, and an unrunnable suite cannot
pass it.
Identify the Mule app directory under test, then run the digest helper to anchor the inventory in the real source:
bash <skill-dir>/scripts/extract_endpoints.sh <app-dir>This writes tmp/bat-gen/source-digest.json and echoes it: the
<http:listener> paths (the endpoint allowlist), the <raise-error> types
(the error-type coverage list), and the API spec file paths.
Then read the actual source — the digest anchors you but does not replace reading:
api_specs[]) — request/response
shapes, required fields, enums, status codes.src/main/mule/*.xml) — verbs per listener path,
<choice>/<when> branches, raise-error mappings to status codes, the state
machine if there is one, and how Authorization is enforced.mule-artifact.json for the runtime context.[BLOCKER] Do not generate tests from the OpenAPI contract alone. The contract states intent; the flow XML states behavior. Where they disagree, the flow XML is what the deployed endpoint actually does, and BAT tests the deployed endpoint. Note any contract↔code disagreements for the report.
If the app already has a hand-written BAT suite (commonly under <app>/bat/ or
a directory the user names), read it. It is ground truth for how this team
writes BAT tests — absorb its idioms so the generated suite is consistent:
describe(...)
headers; single-quoted it must '...' scenarios)var context = HashMap(), execute [ context.set(...) ],
$(context.get(...)) in the next URL)bat.yaml shapeWhen a baseline exists, the generated suite MUST be a strict superset of the
behaviors the baseline covers — no regressions. Re-emit baseline tests (so the
suite stands alone), mark them existing in the inventory, and do not change
their semantics (you may rename for consistency). If no baseline exists, skip
this step.
Using the source (Step 2) and any baseline (Step 3), draft the inventory: one
entry per proposed test, tagged with a primary quality dimension. Use the
taxonomy in references/quality-dimensions.md.
Write the inventory to tmp/bat-gen/test-inventory.json — a JSON array of:
{
"name": "post-orders-happy-path",
"file": "tests/post-orders-happy-path.dwl",
"dimension": "Accuracy",
"subdimension": "data-integrity",
"endpoint": "POST /orders",
"rationale": "one sentence — why this test is worth running",
"expected_status": 201,
"expected_error_code": null,
"exercises_raise_error_type": null,
"covers": ["Coverage:endpoint", "Accuracy:data-integrity"],
"provenance": "new",
"stateful": false
}provenance is existing | new | refined (when a baseline test is
improved — add a one-line refined_reason). When there is no baseline,
everything is new.stateful: true marks tests that need a seed call + context (multi-step).raise-error type from the
Step-2 digest. Aim for ~12–20 tests for a small API; don't bloat with
redundant variants.Names are kebab-case and match the .dwl basename.
Write the normalized endpoint allowlist the Phase-2 validator will check
generated paths against — one path per line, with id segments collapsed to {}:
/orders
/orders/{}
/orders/{}/confirm
/orders/{}/ship
/orders/{}/cancelSave it to tmp/bat-gen/endpoint-allowlist.txt. Derive it from the Step-2
listener_paths[] (plus base path), NOT from the inventory — it is the
independent check on the inventory.
[BLOCKER] Present ONLY after Steps 1–5 are complete. Every inventory entry must have a dimension, an endpoint that exists in the allowlist, and an expected status. If any is missing or an endpoint is not in the allowlist, fix it before presenting — do not paper over with "TBD".
Present a concise summary:
**BAT Test Inventory Summary**
**App under test:** <app dir> · runtime URL <config.url>
**Source read:** <OpenAPI spec path>, <flow XML path(s)>
**Baseline:** <none | N existing tests at <path>>
**Coverage:**
- Endpoints: <M of N listener paths × methods covered>
- raise-error types: <list each type from the digest and the test that triggers it; flag any not covered>
- State transitions: <list, if the app has a state machine>
**Inventory (<count> tests):**
- By dimension: Accuracy <n> · Robustness <n> · Security <n>
- By provenance: existing <n> · new <n> · refined <n> (omit if no baseline)
**Items flagged for human review:**
- <contract↔code disagreements, suspicious validation, dead branches — or "none">Then ask for explicit approval:
Review the inventory above. Proceed to generate and run the suite (Phase 2)?
- Yes, generate and run the suite.
- No, I want to change the inventory.
- No, cancel.
[BLOCKER] WAIT for explicit "Yes" before Step 7. On "change the inventory", ask what to change (coverage, dimensions, specific tests) and loop back. On "cancel", stop politely.
The suite runs against a live endpoint. Confirm the URL and bearer token before scaffolding:
http://localhost:8082/api/v1 and Bearer test-token.AskUserQuestion — a suite pointed at the wrong
URL fails every test for the wrong reason.Create the suite skeleton (config, runner, tests dir):
bash <skill-dir>/scripts/scaffold_suite.sh <suite-dir> --url "<config.url>" --token "<bearer>"This writes config/default.dwl, config/local.dwl (url/token/env),
run-bat.sh (chmod +x, with the JDK-17 --add-opens JAVA_OPTS), and an empty
tests/. It will not overwrite an existing config/local.dwl unless you pass
--force — respect a url/token the user already edited.
Pick <suite-dir> per the user's project convention (e.g.
<app>/bat-generated/ or a path the user names). Do not write into the
hand-written baseline directory.
.dwl Files and bat.yaml, then ValidateFor each entry in the inventory whose provenance is not dropped, write
tests/<name>.dwl following every rule in
references/bat-authoring-rules.md. The canonical shapes are in
references/examples/ — read them and match the style:
single-call-happy-path.dwl — one request, multiple asserts.auth-401.dwl — negative/error-code test.multi-step-stateful.dwl — seed call + context + dependent call (for
stateful: true inventory entries).json-body-and-headers.dwl — asserting a parsed JSON body field and a
Content-Type header that carries a charset (see rules 7b/7c).Then write bat.yaml (schema in the authoring rules / references/examples/bat.yaml):
suite.name, a files: entry per .dwl, and reporters: (HTML + JSON). No
top-level config: key.
As the first tool call after writing, run the static validator against the endpoint allowlist from Step 5:
bash <skill-dir>/scripts/validate_bat_suite.sh <suite-dir> --allowlist tmp/bat-gen/endpoint-allowlist.txtIf it exits non-zero, fix the reported files and re-run the validator. Only proceed to Step 10 after it exits 0. Keep the validator and the run in separate responses.
This is the gate. As the only tool call in this response:
cd <suite-dir> && ./run-bat.shRead the output:
.dwl, re-run the validator (Step 9),
then re-run the suite.scaffold_suite.sh --force
or edit config/local.dwl) and re-run. This is not a test defect.Iterate until all tests pass OR every remaining failure is documented. Do not
ship a suite with silent failures. Run only ./run-bat.sh in this response — no
other tool calls alongside it.
Pre-condition: the immediately preceding response ran ./run-bat.sh and you
have its pass/fail output. If not, go back to Step 10.
Write a short REPORT.md next to the suite:
raise-error type and whether a test covers it; each
endpoint × method.Then declare completion in a tight message — the user can see the files and the run log. Include exactly:
Do not pad with feature lists or next-steps.
# Step 1: validate toolchain (jq, BAT CLI, Java 17+) — validation-only
bash <skill-dir>/scripts/validate_prerequisites.sh
# Step 2: anchor the inventory in the real source
bash <skill-dir>/scripts/extract_endpoints.sh <app-dir> # → tmp/bat-gen/source-digest.json
# Step 8: scaffold the runnable suite skeleton
bash <skill-dir>/scripts/scaffold_suite.sh <suite-dir> --url "<config.url>" --token "<bearer>"
# Step 9: static DSL validation before spending a live run
bash <skill-dir>/scripts/validate_bat_suite.sh <suite-dir> --allowlist tmp/bat-gen/endpoint-allowlist.txt
# Step 10: the gate — run against the deployed endpoint
cd <suite-dir> && ./run-bat.shreferences/bat-authoring-rules.md — the BAT DSL rules (R1–R10), bat.yaml
schema, config files, and run-bat.sh. Read before writing any .dwl.references/quality-dimensions.md — the Accuracy / Robustness / Security /
Coverage taxonomy used to tag and size the inventory.references/examples/ — canonical .dwl files (single-call, auth-error,
multi-step stateful, JSON body/headers) and a reference bat.yaml.mulesoft/mulesoft-dx
b8cef7d
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.