skip to content

In a Karate `Examples:` table, what does appending `!` to a column header do, and what type does that column's value have without it?

level: middleimportance: must knowfreq 54%

answer

  1. A cell is text until told otherwise
  2. The mark rides on the header
  3. Number, boolean or inline JSON come through
  4. It is stripped from the variable name
  5. Blank cells bind null either way

basics

~20 s

A trailing ! on a Karate Examples column header makes each cell evaluate as a JavaScript value — number, boolean, or inline JSON. Without it the cell stays a plain string, and a blank cell becomes null.

solid answer

~40 s

Every cell of a Karate `Examples:` table is text on disk. By default Karate binds it as a **string**: `| age |` with `5` under it gives you `'5'`, not `5`. The one exception is a blank cell, which becomes `null`. Append `!` to the header — `| age! |` — and Karate evaluates the cell as a JavaScript expression instead, so `5` is the number, `true` is a boolean, and `{ a: 1 }` is a real object you can drill into with `age.a`. The `!` is stripped from the name, so the variable is still `age`. It affects only the bound variable and `__row`; a `<age>` placeholder splices the raw cell text either way. And it does not exist for a dynamic single-cell table, which has no headers.

code

gherkin · 11 lines
gherkin
Feature: type hints

Scenario Outline: hinted columns arrive typed
* match __row == { name: '#string', age: '#number', alive: '#boolean' }
* match age == <age>
* match name == '<name>'

Examples:
| name | age! | alive! |
| Bob  | 5    | true   |
| Nyan | 7    | false  |

go deeper

for a junior

Recall that a column is a string unless its header ends with !, and that the mark is not part of the variable name. Add it whenever you want a number, a boolean or inline JSON.

for a middle

Explain that Karate evaluates a hinted cell as JavaScript when the table is read, that a blank binds null either way, and that the hint governs the variable and __row but not the placeholder.

for a senior

Know the silent fallback: a hinted cell that fails to evaluate becomes the raw string with only a trace-level log, so a typo in inline JSON surfaces far from its cause.

for a principal

Decide as a team where typed data belongs. A wide table of hinted columns is often a JSON fixture wearing a disguise, and the review cost of the silent fallback should push it there.

## The default is string, and that surprises people An `Examples:` table is text. Karate reads each cell, and unless the column says otherwise it binds the cell **verbatim as a string**. So this table gives you `age == '5'`: ```gherkin Examples: | name | age | | Bob | 5 | ``` `match age == 5` fails there, and the failure message shows `5` against `5`, because a message cannot draw quotation marks around a type. The single exception is an empty cell: a blank in a plain column binds `null`, which is deliberate — it is how you drive "this field is absent" rows. ## What `!` does Append an exclamation mark to the header and the column's type changes to *evaluated*: ```gherkin Examples: | name | age! | alive! | tags! | | Bob | 5 | true | ['a', 'b'] | ``` - `age` is the **number** `5`. - `alive` is the **boolean** `true`. - `tags` is a real **array**; `{ a: 1 }` in such a column is a real object, and `tags[0]` or `obj.a` work as you would expect. - The mark is **stripped from the name**. The variable is `age`, not `age!`. - A blank cell in an evaluated column still binds `null`, so `##(...)` removal patterns keep working across mixed rows. Mechanically Karate wraps anything that looks like JSON in parentheses and evaluates the cell as a JavaScript expression. That evaluation happens **when the table is read, before the scenario starts**, in a JavaScript engine that has none of the feature's variables in scope — so a hinted cell cannot reference something a `Background` or `karate-config.js` defined. ## The three things `!` does *not* do | Belief | Reality | |---|---| | It makes the column required | It says nothing about presence; a blank cell is still `null` | | It changes what `<age>` splices | `<age>` always splices the **raw cell text**, hint or not | | It works on a dynamic table | A single-cell dynamic table has no header, so there is nothing to hint | The middle row is the one that costs debugging time. The hint governs the *variable* Karate binds and the contents of `__row`; the angle-bracket placeholder is a text substitution done before the step runs and never consults the column type. In practice `* def x = <age>` and `* def x = age` can disagree: the placeholder pastes `5` into the step, which JavaScript then parses as a number, while the unhinted variable is the string `'5'`. ## The silent fallback If the JavaScript evaluation of a hinted cell throws, Karate does **not** fail the row. It catches the exception, logs it at trace level, and falls back to the raw string. So a column header of `name!` over a cell holding `Bob` quietly yields the string `'Bob'` — `Bob` is an undefined identifier, evaluation fails, the raw text is returned. Two consequences worth carrying into a review: 1. **A misplaced `!` is invisible.** Adding it to a column of bare words changes nothing you can see, so nobody removes it, and the next person assumes it is doing something. 2. **A typo in a hinted JSON cell degrades instead of erupting.** `{ a: 1 ` with the closing brace missing does not fail the row; it binds the malformed text as a string and the failure surfaces several steps later, wherever the value is finally used. Turning on trace logging for the run is the way to see those, because nothing louder is emitted. ## When to reach for it - **Numbers and booleans you will `match` strictly.** `match response.age == age` only works when both sides are numbers. - **Inline JSON per row.** A column of `{ "first": "Bob", "last": "Dylan" }` under `name!` gives each row a real object, which is far more readable than three flat columns you reassemble in a step. - **Nulls that must be nulls.** Combined with a blank cell, an evaluated column expresses "this row has no value here" without a sentinel string like `NONE`. Leave it off for anything that genuinely is text — names, ids, dates you compare as strings. The hint costs a JavaScript evaluation per cell per row, and on a column that never needed it, that is work for no benefit and one more silent fallback waiting to happen.

  • In a Karate `Examples:` table, what happens when a hinted column's cell is not valid JavaScript?
    Karate catches the evaluation error, logs it at trace level, and binds the raw cell text as a string instead. Nothing fails at that point, so a malformed JSON cell or a stray `!` on a column of bare words is invisible until the value is used several steps later. Trace logging is the only place it shows up.
  • How does a blank cell behave in a Karate `Examples:` table, and why is that useful?
    A blank binds `null`, in a hinted column and a plain one alike. That is what makes one table cover both the present and the absent case: a `##(field)` embedded expression drops the key from the JSON it is building when the value is null, so the same outline can assert a body with the field and a body without it.

saying these in an interview costs you the question

  • Assumes Karate infers a number from a cell that looks like one
  • Thinks the ! becomes part of the variable name
  • Believes ! also changes what an angle-bracket placeholder splices in
  • Expects a bad expression in a hinted cell to fail the row loudly
  • Tries to add a ! header to a dynamic single-cell Examples table
  • Says a blank cell binds an empty string rather than null