Testland
Browse all skills & agents

acceptance-criteria-extractor

Reads a user story, PRD section, or feature spec and emits well-formed acceptance criteria as Given/When/Then steps in Gherkin (Feature/Scenario file format) or as a numbered plain-text list. Identifies missing-precondition gaps and proposes Background blocks for shared context. Use after a story is testability-confirmed and before implementation begins.

Install with skills.sh (any agent)

npx skills add testland/qa --skill acceptance-criteria-extractor
View source

acceptance-criteria-extractor

Overview

This skill takes natural-language story text and emits acceptance criteria (ISTQB (opens in new window)) in two interchangeable shapes:

  • Gherkin (Feature / Scenario / Given / When / Then) - for projects that automate via Cucumber, Behat, SpecFlow, pytest-bdd, or any Gherkin-aware runner.
  • Plain numbered list - for projects that prefer human review over runner integration; consumable by a downstream test-generation step.

When to use

  • A story has passed the Observable / Decidable / Bounded testability heuristics.
  • The team uses behavior-driven development (BDD) and needs Gherkin-formatted features.
  • A PRD section needs to be decomposed into per-scenario test cases before implementation starts.
  • The team is migrating from informal stories to a structured acceptance-criteria template.

If the input is a non-functional requirement (perf / a11y / security / i18n), use non-functional-requirement-extractor instead - those have a different shape (thresholds, not Given/When/Then).

Step 1 - Identify the actor and the trigger

Read the input and tag each sentence as a Given (system context / actor state), When (the triggering event), or Then (the observable outcome, e.g. a data-testid="profile-saved-toast" appears) per Gherkin (gherkin-ref (opens in new window)). Sentences describing steady state are Givens; sentences with action verbs ("clicks", "submits", "navigates") are Whens; sentences asserting outcomes are Thens.

Step 2 - Choose Scenario vs. Scenario Outline

Per gherkin-ref (opens in new window), a Scenario Outline is the template form for running the same scenario with multiple data sets, expanded via the Examples: block:

Scenario Outline: User logs in with various credentials
  Given a user with status "<status>"
  When they submit valid credentials
  Then login returns "<http_status>"

Examples:
  | status      | http_status |
  | active      | 200         |
  | suspended   | 401         |
  | not_verified| 403         |

Use Scenario Outline whenever the underlying logic is identical and only the data varies - typically for boundary checks, role variants, or status-code matrices.

Step 3 - Factor out Background

If multiple scenarios share preconditions, extract them to a Background block. Per gherkin-ref (opens in new window), "only one Background per Feature":

Feature: Profile settings

  Background:
    Given a logged-in user with email confirmed
    And the user is on the /profile/settings page

  Scenario: Update email
    When they change the email field to "new@example.com"
    And they click "Save profile"
    Then the email field shows "new@example.com"
    And a [data-testid="profile-saved-toast"] is visible

Don't over-extract - Background is for truly shared state (auth, seed data, navigation). Scenario-specific setup stays in the Given.

Step 4 - Validate observability of every Then

Every Then must be observable from outside the system. Reject Thens like:

  • "Then the user feels confident." → Not observable.
  • "Then the system is secure." → No threshold or test condition.

Replace with:

  • "Then a data-testid="confirmed-icon" is visible AND has color #3CB371."
  • "Then the response status is 200 AND the Content-Security-Policy header is present."

Step 5 - Emit the artifact

Gherkin output (default)

Feature: <story summary>

  As a <persona>
  I want <capability>
  So that <value>

  Background:
    Given <shared precondition>

  Scenario: <case name>
    Given <state>
    When <event>
    Then <observable outcome>
    And <additional outcome>

  Scenario Outline: <data-driven case>
    Given <state with <param>>
    When <event>
    Then <outcome with <expected>>

    Examples:
      | param | expected |
      | ...   | ...      |

Plain-list output

When the project prefers prose:

## Acceptance Criteria

1. **AC-1:** Given <state>, when <event>, then <outcome>.
2. **AC-2:** Given <state>, when <event>, then <outcome>.
3. **AC-3:** ...

Plain-list AC numbers (AC-1, AC-2) become commit-message references in the implementation PR (feat: AC-3 - show toast on save).

Step 6 - Flag implicit Givens

The agent never extracts what isn't there. If the story implies a precondition the author left unstated, emit a flag rather than fabricating:

## ⚠ Implicit precondition flagged

The story says "the user updates their profile" without specifying
the user's auth state. Two reasonable readings:

- **Reading A:** Logged-in user (most likely).
- **Reading B:** This includes profile updates by an admin on behalf
  of another user.

Which reading should the Background reflect? (Answer determines
whether we need a second Scenario for the admin path.)

Flag-and-ask is the load-bearing pattern. Silently picking Reading A produces a test suite that misses the admin path; flagging it forces the author to make the call.

Output format

## Acceptance criteria for `<story-id>`

**Output format:** gherkin | plain-list
**File path:** `<features/<feature-slug>.feature>` (Gherkin) | inline (plain)
**Scenarios produced:** N
**Implicit-precondition flags:** M

### <Gherkin or plain-list output>

### Implicit-precondition flags

<list of flagged questions for the author, if any>

### Coverage notes

- All scenarios pass the Observable / Decidable / Bounded testability heuristics.
- Per-Then assertion targets are concrete (`data-testid` / status code / DOM state).
- Examples table covers <N> data variants for the Outline scenario.

Examples

Three worked examples (simple story, PRD with implicit preconditions, Scenario Outline opportunity) are in references/examples.md.

Anti-patterns

Anti-patternWhy it failsFix
Generating multiple scenarios with copy-pasted GivenBackground extraction missed; suite becomes brittle.Extract shared Givens to one Background block.
Then with a verb but no observable target ("Then save")Not testable - can't assert "save" without observing the side effect.Emit data-testid / response status / DOM state.
One Scenario per data variant when a Scenario Outline fitsTest code duplication; Examples table is missed.Scenario Outline + Examples.
Fabricating preconditions the story didn't stateTests pass for the wrong reason; author never confirmed the assumption.Flag-and-ask.

References

  • istqb-ac (opens in new window) - ISTQB Glossary V4.7.1 canonical definition of acceptance criteria.
  • gherkin-ref (opens in new window) - Cucumber Gherkin reference: keywords, Feature structure, Scenario Outline + Examples, Background rules.
  • non-functional-requirement-extractor - sibling for non-functional requirements (different shape).

acceptance-criteria-extractor - worked examples

View source (opens in new window)

acceptance-criteria-extractor - worked examples

Three end-to-end examples of story text turned into acceptance criteria. The core procedure (Steps 1-6), the output templates, and the anti-pattern catalog live in SKILL.md (opens in new window).

Example 1: simple story -> 2 scenarios

Input (Linear story):

"Title: Email update on profile page

As a logged-in user, I want to update my email address from /profile/settings. After update, the email field shows the new value and I see a confirmation toast."

Output:

Feature: Email update on profile page

  As a logged-in user
  I want to update my email address from /profile/settings
  So that my account contact information stays current

  Background:
    Given a logged-in user with email confirmed
    And the user is on the /profile/settings page

  Scenario: Update email to a new valid address
    When the user changes the email field to "new@example.com"
    And the user clicks "Save profile"
    Then the email field shows "new@example.com"
    And a [data-testid="profile-saved-toast"] is visible

  Scenario Outline: Email update validation rejects invalid input
    When the user changes the email field to "<invalid_email>"
    And the user clicks "Save profile"
    Then the email field shows the previous value
    And a [data-testid="email-validation-error"] is visible

    Examples:
      | invalid_email           |
      | not-an-email            |
      | missing@                |
      | @example.com            |
      | spaces in@email.com     |

Example 2: PRD with implicit preconditions

Input (PRD excerpt):

"We will allow promo codes at checkout. Codes apply 20% off the subtotal."

Output:

## Implicit-precondition flags (3)

1. **Code source.** Where do codes come from - user-entered? auto-applied? Both?
2. **Eligibility.** Are codes user-tier specific (e.g. only new users)?
   Time-limited? Per-user limited?
3. **Subtotal definition.** Subtotal *before* tax / shipping, or *after*?

Without these answers, the test suite cannot be written.

The agent refuses to fabricate the missing pieces - instead returns a question list to the PRD author.

Example 3: Scenario Outline opportunity

Input:

"Login should work for active accounts (returning 200) but reject suspended (401), unverified (403), and non-existent (404) accounts."

Output:

Feature: Login authorization

  Scenario Outline: Login response per account status
    Given an account with status "<status>"
    When the user submits valid credentials
    Then the response status is <http_status>
    And the response body contains "<error_code>"

    Examples:
      | status        | http_status | error_code           |
      | active        | 200         |                       |
      | suspended     | 401         | ACCOUNT_SUSPENDED    |
      | not_verified  | 403         | EMAIL_NOT_VERIFIED   |
      | not_found     | 404         | ACCOUNT_NOT_FOUND    |

Related skills

data-contract-extractor

Reads a data-product spec (data PRD, dataset README, lineage doc) and emits a structured data contract - schema (columns + types + nullability + PII flags), freshness SLA, volume bounds, distribution invariants, and ownership. The contract is consumable by data-quality tools such as dbt tests, Great Expectations, or Soda checks as their assertion baseline. Use when scoping a new data product or formalizing assertions on an existing one.

gherkin-scenario-coverage-map

Parses new Gherkin scenarios produced by acceptance-criteria-extractor, fingerprints each scenario by its Given/When/Then step sequence, diffs the fingerprints against existing step-definition usage in the live suite, and emits a coverage/duplicate map showing which new scenarios are already covered, which overlap partially, and which are genuine gaps. Use when acceptance criteria have been converted to .feature files and before any new automated tests are authored.

non-functional-requirement-extractor

Reads a PRD, design doc, or product brief and pulls out the non-functional requirements (performance, accessibility, security, internationalization, reliability, observability) as concrete, threshold-bound, testable assertions. Maps every NFR to its measurement source (Lighthouse, axe, OWASP ASVS, WCAG criterion, etc.) so the test suite knows what to assert against. Use after acceptance-criteria-extractor handles functional requirements.

spec-testability-heuristics

Judges whether a written requirement can be tested at all, by scoring each claim against three heuristics: Observable (a state or output visible from outside the system), Decidable (a deterministic pass/fail against a named oracle), and Bounded (stated inputs, states, and users). Supplies untestable-to-testable rewrite pairs per heuristic, severity assignment, a BLOCK / REVIEW / OK verdict rule, and a findings table that pairs every flagged sentence with a concrete replacement. Scope is testability only: it does not write the tests, rank risk, or judge whether the requirement is correct or complete. Use when a user story, acceptance criterion, PRD section, API contract, or PR description is about to be handed to implementation and someone needs to know which sentences cannot be verified as written.

stride-threat-modeling

Enumerates security threats against a feature specification or design using Microsoft's six STRIDE categories (spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege), each paired with the security property it violates. Covers the asset-and-trust-boundary walk that produces threat rows, the threat-row output schema, a likelihood x impact triage rule labelled plainly as practitioner convention rather than standard, a worked example, and an anti-pattern catalog. Enumerates threats against a design; it does not scan code, run a penetration test, or audit control compliance. Use when a PRD section, user story, design doc, or architecture sketch touching authentication, user data, payments, file uploads, or an external integration is about to enter implementation and no threat model exists for it yet.