Skip to content

Run one test with many inputs (data-driven tests)

You’ve written a login test. Now you want to run it for five different accounts — valid user, locked user, wrong password, admin, trial. You could copy the test five times and edit the credentials in each. Don’t. Write it once with variables, drop the five accounts into a table, and Marriska runs the test once per row.

That’s a data-driven (or “parameterized”) test: one set of steps, many sets of inputs.

A variable is just a {{placeholder}} in a step’s value. There’s no “add variable” button — you create one by typing it into a step.

Type {{username}} into the email field
Type {{password}} into the password field
Click Sign in
Expect to see {{welcome_text}}

The moment a step contains {{username}}, a username column appears on the Variables tab. Remove the last step that uses it and the column goes away (Marriska asks first if the column has data in it).

  1. Open the test and go to the Variables tab.

    Every {{placeholder}} in your steps is a column. The header shows a live count — Variables (3 variables · 5 iterations).

  2. Click “Add row” for each data set.

    Each row is one run. Click a cell to edit it; it saves on its own a second after you stop typing (you’ll see “Saving…” flicker).

  3. Fill in the values.

    usernamepasswordwelcome_text
    alice@acme.testhunter2Welcome, Alice
    locked@acme.testhunter2Account locked
    alice@acme.testwrongpassInvalid credentials

That’s three rows, so the test runs three times — once per row, substituting that row’s values into the {{placeholders}}.

Each row runs as its own iteration. Iterations multiply by browser: 3 rows × 2 browsers = 6 executions, and each execution counts against your monthly cloud-runs quota. Keep that in mind before you add a hundred rows across three browsers.

In the run report, a parameterized test shows one collapsible section per iteration — Iteration 2/3 — with that row’s values shown as chips (username="locked@acme.test") so you can see exactly which input produced which result. More on that in Reading a run report.

  • A filled cell is substituted into the step. {{username}} becomes alice@acme.test.
  • An empty cell substitutes an empty string — the step runs with nothing where the value would be. Useful for testing “what if this field is blank”, surprising if you didn’t mean it.
  • A placeholder with no matching column is left as-is. If a step says {{discount}} but there’s no discount column, the literal text {{discount}} is typed into the page. That’s usually a typo — check the spelling matches the column.

Values aren’t re-scanned, so a value that itself contains {{...}} isn’t expanded again. One pass, top to bottom.

That password column is a secret. Click the lock icon on its column header and every value in it shows as •••••• in reports, logs, and the live runner — while Playwright still types the real password into the page. See Mask passwords and other secrets for the full story on what gets hidden and what doesn’t.

A test carries its own data rows, but sometimes you want a test to run with different inputs inside one test set — say, a smaller smoke-sized data set for your nightly run. Open the test inside the set and pick Custom values for this test set instead of Use all iterations from test. The override applies only within that set; the test’s own rows are untouched everywhere else.

Both caps are the same on every plan — a Free test and a Team test are structurally identical:

CapValue
Variables per test50
Data rows per test200

If you’re bumping the 200-row ceiling, you probably want to split the scenario into a few focused tests rather than one giant matrix.