Cucumber without step definitions
Gherkin is supposed to be the test. In Cucumber it is only the outline: every step needs a step definition in code, and that code is a second test suite to maintain. Saffron keeps the feature file and removes that layer.
The layer people keep asking about
A feature file reads like a specification. To run it, Cucumber (and Playwright-based runners like playwright-bdd) matches each step to a function you write, usually with selectors inside. When the page changes, the step text is still right, but the code under it breaks, and someone updates it by hand.
Feature: Booking Scenario: Book a room for two nights Given I am on the rooms page When I book the sea view room for 2 nights Then the booking is confirmed// steps/booking.steps.tsGiven('I am on the rooms page', async function () { await this.page.goto('/rooms');}); When('I book the sea view room for {int} nights', async function (nights) { await this.page.getByRole('link', { name: 'Sea view' }).click(); await this.page.getByLabel('Nights').fill(String(nights)); await this.page.getByRole('button', { name: 'Book now' }).click();}); Then('the booking is confirmed', async function () { await expect(this.page.getByText('Booking confirmed')).toBeVisible();});The first block is what your team reads. The second is what your team maintains. Rename a button and only the second one breaks.
In Saffron, the step text is the test
You write only the first block. The first time a scenario runs, an AI agent (Claude, Codex, Antigravity or Cursor, on your own subscription) performs each step in a real browser and Saffron records what it did: the clicks, the fields, the checks, with targets by role, name and label.
- The recording is a JSON file in git, beside your features. You review it like code; it is not hidden in a vendor's cloud.
- Every later run replays the recording with zero AI calls and zero tokens. The AI is not in the loop on a normal run.
- Steps you already recorded are reused. A new scenario that starts with the same steps replays them; only the new steps need the agent.
- Plain .feature files run as they are. The .saffron format adds StepSets for shared flows, and more, when you want them.
When the page changes
A replay that no longer matches the page heals: the agent picks up from the step that failed, in the same browser, and Saffron files the repair as a proposal. A replay with no AI checks the proposal, and nothing changes until you accept it. Then steps, the assertions, are never healed by default, so a heal cannot turn a real bug green. More on that in self-healing tests that never heal assertions.
What it costs you
- The first recording of each scenario uses your AI subscription. Replays do not.
- Recordings are reviewed, the same way you would review step definition code, only shorter.
- If you ever leave,
saffron eject(beta) writes your recordings as Playwright Test specs you own.
Comparing options? See Saffron vs playwright-bdd, including when playwright-bdd is the better choice.
Try it on your app
npm i -D saffron-ai, then npx saffron init --examples installs a small example suite to run. Free to use, including commercially. Read the docs or watch the short videos.