In WireMock, what does equalToJson() still reject when ignoreExtraElements and ignoreArrayOrder are on?
answer
- only two tolerances exist
- additions forgiven, omissions never
- expected document must be contained in the body
- values and types are untouched by both flags
- array order first, extra elements second
basics
~20 sIn WireMock, ignoreExtraElements and ignoreArrayOrder forgive only additions and array order. A missing field, a changed value or a different JSON type still makes WireMock's equalToJson miss, and so does a body that is not valid JSON at all.
solid answer
~50 s`ignoreExtraElements` and `ignoreArrayOrder` are the only two tolerances WireMock's `equalToJson(` has, and they are narrower than people expect. In WireMock, `ignoreExtraElements` makes the comparison one-directional: your expected document has to be contained in what arrived, so an added `clientVersion` on a peatland carbon-survey POST is forgiven while a dropped `siteId` is not. WireMock's `ignoreArrayOrder` removes the significance of position inside `readings` only - an element the client added is forgiven only because `ignoreExtraElements` is also on, and a member that disappeared never is. Neither flag touches values or types, so `"waterTableCm": "-12"` will not match an expected `-12`, and a body that fails to parse never matches at all. There is no third flag to reach for when a value itself varies. That asymmetry is the point: the relaxed form still fails loudly when a field the stub depends on stops arriving.
code
java · 10 linesimport static com.github.tomakehurst.wiremock.client.WireMock.*;
String expected = """
{ "siteId": "PEAT-114",
"readings": [ { "plotId": "PLOT-7" }, { "plotId": "PLOT-9" } ] }
""";
stubFor(post(urlPathEqualTo("/carbon/v1/surveys"))
.withRequestBody(equalToJson(expected, true, true))
.willReturn(aResponse().withStatus(202)));go deeper
Know that WireMock's equalToJson has exactly two tolerance flags and be able to name them: ignoreArrayOrder and ignoreExtraElements. Everything else about the body is still compared.
Explain the direction ignoreExtraElements picks - the expected document must be contained in what arrived - and why a missing field or a changed type still fails in WireMock.
Show that you would use the asymmetry deliberately, loosening a matcher by deleting a line from the expected document rather than reaching for a looser matcher wholesale.
Own the guidance a team follows when a field varies per request, and prefer the mapping-file form with named keys so a positional boolean pair cannot silently invert a stub's tolerance.
## The two flags, precisely WireMock's `equalToJson(` has a three-argument overload, `equalToJson(String json, Boolean ignoreArrayOrder, Boolean ignoreExtraElements)`, and in a mapping file the same two knobs appear as sibling keys of `equalToJson`. They are the whole of the matcher's tolerance. There is no third flag, no case-insensitivity switch and no numeric coercion. - In WireMock, `ignoreExtraElements` forgives content present in the arriving body and absent from your expected document. - In WireMock, `ignoreArrayOrder` removes the significance of position within an array. Everything else WireMock's `equalToJson(` checked before you set the flags, it still checks afterwards. ## What is still rejected Take the peatland carbon-survey submission and an expected document naming `siteId` and a `readings` array. With both flags on, each of the following still fails to match: - **A missing field.** The client stops sending `siteId`, or drops `waterTableCm` from a reading. WireMock's `ignoreExtraElements` forgives additions, never omissions. - **A changed value.** `"siteId": "PEAT-115"` where you expected `"PEAT-114"`. - **A changed type.** `"waterTableCm": "-12"` where you expected the number `-12`. In JSON a string and a number are different values, and WireMock compares them as parsed. - **A shorter array.** `readings` arriving with one entry where the expected document names two. Order became insignificant; membership did not. - **A renamed field.** `waterTableDepthCm` where you expected `waterTableCm`. A rename is an addition and an omission at once, and the omission half is not forgiven, so the stub misses even with both flags on. - **An unparseable body.** WireMock has no string fallback for `equalToJson(`; a body that is not JSON simply does not match. The rename case is worth dwelling on, because it is the one that makes the flags look unreliable to somebody debugging at speed. Both halves of the change are visible in the payload, the addition is quietly forgiven, and the failure is attributed to the half nobody is looking at. ## Why the asymmetry is the useful part It is tempting to read WireMock's `ignoreExtraElements` as "be relaxed" and stop there. What it actually does is pick a direction: the expected document must be **contained in** what arrived. That maps onto how APIs change. Payloads gain fields constantly - a client version, a device identifier, a new optional measurement - and none of that should break a stub. Payloads lose fields rarely, and when they do it is usually either a bug or a breaking change, which is exactly the case you want the stub to notice. So the relaxed form is not a weaker assertion in every direction. It is a narrower, better-aimed assertion: *these fields, with these values, must be here; anything else is your business.* ## Getting the flag order right The positional overload is a small trap in its own right, because the two booleans are easy to swap: ```java String expected = """ { "siteId": "PEAT-114", "readings": [ { "plotId": "PLOT-7" }, { "plotId": "PLOT-9" } ] } """; stubFor(post(urlPathEqualTo("/carbon/v1/surveys")) .withRequestBody(equalToJson(expected, true, true)) .willReturn(aResponse().withStatus(202))); ``` In WireMock the order is `ignoreArrayOrder` first, `ignoreExtraElements` second. Swapping them compiles, runs and produces a stub whose tolerance is the opposite of what you meant, which is a good argument for writing the mapping-file form with named keys wherever a stub set is maintained by more than one person. ## What to do about the cases the flags do not cover When a field genuinely varies per request and you still want structural matching, the flags will not help - they cannot forgive a value, only its absence from your document. The options, in order of how often they are the right answer: 1. Stop matching on that field: drop it from the expected document so WireMock's `ignoreExtraElements` covers it. 2. Move the assertion to WireMock's `matchingJsonPath(` with a value pattern, so the varying field is simply never selected. 3. Split the stub, if the variation is genuinely two different cases rather than noise. Option one is the one people miss. Because WireMock's `ignoreExtraElements` makes the expected document a subset, deleting a line from it is a legitimate way to loosen a matcher precisely. ## How the other servers frame it Mountebank draws the same line between its `equals` predicate, which compares only the fields you named, and its `deepEquals` predicate, which compares the whole structure - the choice of predicate is its equivalent of WireMock's flag. ## The one-sentence answer With both flags on, WireMock's `equalToJson(` still asserts that every field in your expected document is present, with that value and that type, in a body that parses as JSON. The flags buy you tolerance of additions and of ordering, and nothing else - which is why a relaxed WireMock `equalToJson(` is still a real assertion and not a rubber stamp.
- A field varies on every submission. How do you keep structural matching without editing the stub daily?Delete that field from the expected document. With `ignoreExtraElements` on, WireMock requires only that your document is contained in what arrived, so an unmentioned field is ignored entirely. If you still need an assertion about it, move that one assertion to a WireMock `matchingJsonPath(` predicate with a value pattern loose enough to survive the variation.
- Why prefer the WireMock mapping-file form over the three-argument Java overload?Because the mapping form names the two knobs. In WireMock, `ignoreArrayOrder` and `ignoreExtraElements` are sibling keys of `equalToJson`, so a reviewer reads intent directly, whereas `equalToJson(json, true, false)` requires remembering which boolean is which. Swapped booleans compile and run, producing a stub whose tolerance is the opposite of what the author meant.
saying these in an interview costs you the question
- Thinks ignoreExtraElements also forgives missing fields
- Believes the flags make value comparison fuzzy
- Expects a string and a number to compare equal
- Assumes ignoreArrayOrder lets an array lose members
- Swaps the two boolean arguments and never notices