A Karate mock feature's `Background` runs only once, at server start. How do you get a hook that runs on every request instead?
answer
- Separate declaring from invoking
- The Background can store a callback
- A configure step that outlives its own execution
- It fires after the matched scenario's steps
basics
~20 sDeclare configure afterScenario = function(){ ... } in the mock feature's Background. The configure step itself runs once and merely stores the function; the handler then invokes it after the matched Scenario on every request.
solid answer
~40 sPut `* configure afterScenario = function(){ ... }` in the mock feature's `Background`. The distinction that makes it work is between **declaring** and **invoking**: the `configure` step is a `Background` step, so it executes exactly once at start-up and all it does is store the function on the mock's config. The handler then calls that function on every request, after the matched `Scenario`'s steps have run and before the reply is built - which is where per-request logging, metrics or bookkeeping belong. Karate 2.x adds a matching `configure beforeScenario`, invoked before the matched scenario's steps; on the 1.x line only `afterScenario` exists as a mock hook. Anything else that must happen per request simply goes in the `Scenario`'s own steps.
code
gherkin · 9 linesFeature: mock with a per-request hook
Background:
* def calls = 0
# this step runs ONCE - it only stores the function
* configure afterScenario = function(){ calls = calls + 1 }
Scenario: pathMatches('/ping')
* def response = { pong: true }go deeper
Learn the one idiom: a function stored by a configure step in the Background is what gives you per-request behaviour in a Karate mock.
Be able to separate declaration from invocation and to place the hook in the request sequence - after the matched scenario's steps, before the reply is assembled.
Know its blind spot: unmatched requests never reach it, so anything that must count all traffic belongs outside the mock feature entirely.
Set the team's line between hooks and explicit steps - a hook that mutates shared mock state on every request buys brevity with a cost in traceability.
## Declared once, invoked per request Everything in a mock feature's `Background` runs exactly once. That is true of `configure afterScenario` too - and it is not a contradiction, because what runs once is the **assignment**. The step evaluates a JavaScript function literal and stores the resulting function object on the mock's configuration. The function's *body* has not run at all yet. From then on, the handler holds a reference to it, and calls it as part of handling each request. So you get a genuinely per-request hook out of a block that only executes once, which is the pattern to reach for whenever "the Background runs once" seems to block you. ## Where it sits in a request For a request that matched a `Scenario`, the handler: 1. Refreshes the engine's variables from the globals map and binds the request variables. 2. Evaluates each `Scenario` name expression in file order until one matches. 3. Runs the matched `Scenario`'s steps. 4. Invokes the `afterScenario` hook. 5. Assembles and sends the reply. Two things follow from that placement. The hook sees the world **after** the scenario has done its work, so the reply variables the scenario set are visible to it. And the hook is tied to a match: a request that matched nothing is answered 404 without the hook being reached, so it is not a place to count total traffic. ## What the hook is good for - **Observability.** A single `karate.log(...)` line that reports every handled request, without repeating it in a dozen Scenarios. - **Bookkeeping in the retained state.** Incrementing a call counter, or appending to a list the test will inspect afterwards, in one place rather than in each Scenario. - **Cross-cutting behaviour** you would otherwise copy into every Scenario and eventually forget to copy into the newest one. And what it is not for: it is a JavaScript function, not a step list. It is not the place for Karate keywords, and it cannot substitute for a Scenario when the work depends on which endpoint was hit. ## Hooks versus steps | Need | Put it here | |---|---| | One-time seed data or helper functions | `Background` steps | | Server-wide response settings | `configure` steps in the `Background` | | Work specific to one endpoint | that `Scenario`'s own steps | | Work common to every matched request | `configure afterScenario` | When in doubt, prefer the Scenario's own steps. A hook that quietly touches shared state on every request is harder to reason about than an explicit step, and the mock's retained globals are already shared enough. ## A version boundary worth knowing `configure afterScenario` is available as a mock hook on both the 1.x and 2.x lines of Karate. The symmetrical `configure beforeScenario` is **2.x only** - Karate 1.5.2's configuration accepts `afterScenario`, `afterScenarioOutline` and `afterFeature`, but has no `beforeScenario` key at all, so a mock feature written against 1.x that declares one is configuring nothing. If you need pre-work on the 1.x line, the first step of the matched `Scenario` is the answer. Both hooks are ordinary JavaScript functions and are given no arguments describing the request; they read the mock's variables, which is enough for logging and counting. ## What the hook cannot reach Two limits are worth internalising, because both look like bugs the first time. - **An unmatched request never gets there.** If no `Scenario` name expression evaluated true, the handler logs that and answers 404 without ever entering the matched-scenario path the hook lives on. So a hook is a fine way to count **handled** requests and a misleading way to count **all** traffic - a mock whose matchers have a hole will happily report a healthy call count while quietly 404ing half its callers. - **It carries no request argument.** The hook is invoked as a plain no-argument function; what it can see is the mock's variables, which by that point include everything the matched scenario defined. That is enough for logging, counting and appending to a store, and it is not enough for anything that wants a first-class request object handed to it. Both limits point the same way: the hook is for work that is genuinely the same for every matched request. The moment the work needs to know *which* request it was, it has stopped being a hook's job. ## The mistake this question exists to catch The wrong instinct is to reach for the `Background` itself - to write `* karate.log('request received')` as a `Background` step and be surprised to see it once in the whole run. The `Background` is the server's constructor, and printing from a constructor tells you about construction. Storing a function there and letting the handler call it is how you cross from start-up time into request time, and it is the only mechanism in a mock feature that does so without belonging to a specific endpoint.
- If `configure afterScenario` is a `Background` step, and `Background` runs once, how can the hook fire per request?Because the step only performs the assignment. It evaluates the function literal and stores the function object on the mock's config; the body has not executed. The handler keeps that reference and calls it as part of serving each matched request.
- Does the `afterScenario` hook fire for a request that matched no Scenario?No. It is invoked as part of handling a matched scenario, and a request that matched nothing is answered with 404 before that point. So it is a good place to count handled requests and a bad place to count total traffic.
- Where should per-request work go if it depends on which endpoint was hit?In that `Scenario`'s own steps. The hook is deliberately endpoint-agnostic - it runs the same function whichever Scenario matched - so anything conditional on the path or method is clearer, and cheaper to read, as a step in the Scenario that already matched it.
saying these in an interview costs you the question
- Puts a per-request log line directly in the Background
- Thinks configure afterScenario also runs only once
- Expects the hook to fire on an unmatched 404 request
- Treats the hook as a place for Karate step keywords
- Assumes configure beforeScenario exists on every version