From sdlc-skills
Bootstraps, configures, and authors tests for the Vividus BDD framework — JBehave-based .story files with backtick parameters and 47+ plugins for web/REST/mobile/DB.
How this skill is triggered — by the user, by Claude, or both
Slash command
/sdlc-skills:vividusThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Vividus is a JBehave-based BDD framework. Tests are plain-text `.story` files using a strict, pre-built step library — authors compose tests by **wording**, not Java. Plugins extend the step library per domain (web, REST, mobile, DB, cloud).
README.mdassets/build.gradle.templateassets/configuration.properties.templateassets/environment.properties.templateassets/example-rest.storyassets/example-visual.storyassets/example-web.storyassets/example.stepsassets/gradle.properties.templateassets/profile.web-chrome.properties.templateassets/suite.properties.templatereferences/configuration.mdreferences/plugins.mdreferences/steps-cheatsheet.mdreferences/troubleshooting.mdreferences/variables-and-tables.mdVividus is a JBehave-based BDD framework. Tests are plain-text .story files using a strict, pre-built step library — authors compose tests by wording, not Java. Plugins extend the step library per domain (web, REST, mobile, DB, cloud).
This skill knows the framework's conventions, file layout, properties model, and step phrasings so you can scaffold projects, add plugins, author/edit stories without invented steps, and run/debug suites.
| User intent | Path |
|---|---|
| New project from scratch | Bootstrap a project |
| Add web/REST/mobile/DB/etc. capability | Add a plugin |
Write or edit a .story file | Author a story; read references/steps-cheatsheet.md |
| Configure suites/profiles/environments | Read references/configuration.md |
| Set up data-driven tests / external tables | Read references/variables-and-tables.md |
| Run, filter, debug | Run tests |
| Test won't match / step not found / locator fails | Read references/troubleshooting.md |
| Pick a plugin / understand 47-plugin catalog | Read references/plugins.md |
When in doubt, ground every step phrasing against the docs (https://docs.vividus.dev/vividus/latest/) or against ./gradlew printSteps output. Do not invent step phrases — Vividus matches steps by exact wording (with parameters). If a step doesn't match, it silently becomes a "pending" step at runtime.
.story files under src/main/resources/story/.... Sections: Description:, Meta:, GivenStories:, Lifecycle:, Scenario:, Examples:. Steps start with Given/When/Then.`, not quotes. Example: Then `${name}` is equal to `Bob`. This is the #1 syntax error.${var} for read, <col> for ExamplesTable placeholders, #{expression(...)} for compile-time expressions (data generation, formatting).configuration.suites, configuration.profiles, configuration.environments. Each loads .properties files; first declared wins.org.vividus:vividus-bom:<version> controls every plugin's version. Never override individual plugin versions.vividus-build-system). Always git clone --recursive, or run git submodule update --init --recursive after a regular clone.The starter is a GitHub template repo: https://github.com/vividus-framework/vividus-starter. Two paths:
A. Generate from template (preferred for real projects):
git clone --recursive <new-repo-url> and cd into it.B. Local clone of the starter (for prototyping/learning):
git clone --recursive https://github.com/vividus-framework/vividus-starter.git my-vividus-tests
cd my-vividus-tests
./gradlew build
If the user already cloned without --recursive, fix it with:
git submodule update --init --recursive
Then create the conventional directory tree (the starter ships nearly empty):
mkdir -p src/main/resources/story/web_app
mkdir -p src/main/resources/story/rest_api
mkdir -p src/main/resources/steps
mkdir -p src/main/resources/properties/suite/web_app
mkdir -p src/main/resources/properties/suite/rest_api
mkdir -p src/main/resources/properties/profile/web/desktop/chrome
mkdir -p src/main/resources/properties/environment/dev
Templates to copy as starting points (see assets/):
assets/build.gradle.template — common plugin selection, BOM-pinnedassets/configuration.properties.template — master configassets/suite.properties.template — batch + parallelism + composite-pathsassets/example-web.story, assets/example-rest.story — runnable smoke storiesassets/example-visual.story — visual regression template (ESTABLISH / COMPARE_AGAINST)assets/example.steps — composite step exampleAlways check the latest BOM version before pinning: https://github.com/vividus-framework/vividus/releases. As of skill authoring, recent versions are around 0.6.16–0.6.18.
Plugins are added in build.gradle under dependencies { ... }. The BOM picks the version automatically:
dependencies {
implementation platform('org.vividus:vividus-bom:0.6.18')
implementation('org.vividus:vividus')
implementation('org.vividus:vividus-plugin-web-app') // Selenium-based web
implementation('org.vividus:vividus-plugin-rest-api') // HTTP/REST
implementation('org.vividus:vividus-plugin-json') // JSONPath assertions
implementation('org.vividus:vividus-plugin-db') // JDBC databases
implementation('org.vividus:vividus-plugin-mobile-app') // Appium iOS/Android
}
Use references/plugins.md to choose the right plugin for a capability. Quick map:
| Need | Plugin |
|---|---|
| Selenium web testing | vividus-plugin-web-app |
| Playwright web testing | vividus-plugin-web-app-playwright |
| REST/HTTP API | vividus-plugin-rest-api (+ vividus-plugin-json for JSONPath) |
| Mobile (Appium) | vividus-plugin-mobile-app |
| Relational DB | vividus-plugin-db |
| Visual diff | vividus-plugin-visual (or vividus-plugin-applitools) |
| Accessibility | vividus-plugin-accessibility |
| Kafka / RabbitMQ | vividus-plugin-kafka, vividus-plugin-rabbitmq |
| AWS S3 / DynamoDB / Lambda | vividus-plugin-aws-s3, -aws-dynamodb, -aws-lambda |
| Azure Service Bus / Cosmos | vividus-plugin-azure-service-bus, -azure-cosmos-db |
| BrowserStack / SauceLabs / LambdaTest | vividus-plugin-browserstack, -saucelabs, -lambdatest |
| CSV / Excel / XML / YAML | vividus-plugin-csv, -excel, -xml, -yaml |
After adding a plugin, run ./gradlew build and the new steps are available in .story files. To list every available step in the project: ./gradlew printSteps.
Story files end in .story and live under any path matching batch-N.resource-location (typically src/main/resources/story/...). Naming is human-readable, often Title Case With Spaces.story.
Minimal web example:
Description: Login smoke test
Meta:
@feature login
@priority 1
Scenario: Sign in with valid credentials
Given I am on main application page
When I go to relative URL `/login`
When I enter `tomsmith` in field located by `id(username)`
When I enter `SuperSecretPassword!` in field located by `id(password)`
When I click on element located by `cssSelector(button[type='submit'])`
Then text `You logged into a secure area!` exists
${web-application.main-page-url}is NOT a story variable. It is a Spring property consumed internally by the web plugin.Given I am on main application pageis the correct step — it navigates to that configured URL without needing a variable. To expose a URL as a story variable (e.g., for building paths), declare it explicitly inenvironment.properties:web-application.main-page-url=https://staging.example.com variables.appUrl=https://staging.example.com # same value — now usable as ${appUrl} in stories
Minimal REST example:
Description: Star Wars API smoke
Scenario: Verify Luke's eyes are blue
When I execute HTTP GET request for resource with URL `https://swapi.info/api/people/1/`
Then `${responseCode}` is equal to `200`
Then JSON element value from `${response}` by JSON path `$.eye_color` is equal to `blue`
Authoring rules (Vividus is finicky about syntax):
xpath(...), cssSelector(...), id(...), linkText(...), name(...), tagName(...), className(...), accessibilityId(...) (mobile), shadowCssSelector(...). Optional visibility flag (:v visible, :i invisible, :a all) and filter chain (->filter.<type>(<value>)).step < scenario < story < next_batches < batch < global. Use scenario by default; promote to story only when a value must persist across scenarios.Lifecycle: Before: / After:) declare scoped setup/teardown. Use Scope: STORY for one-time setup, Scope: SCENARIO for per-scenario.!-- (not #).src/main/resources/steps/**/*.steps. See assets/example.steps.references/steps-cheatsheet.md for verified phrasings, or run ./gradlew printSteps in the project.For the full step library with exact phrasings (web/REST/JSON/DB/mobile/lifecycle/composites), read references/steps-cheatsheet.md. For ExamplesTable, transformers (FROM_CSV, FROM_EXCEL, FROM_DB, FILTERING, MERGING, JOINING, ...), and expression syntax, read references/variables-and-tables.md.
Master file: src/main/resources/properties/configuration.properties:
configuration.suites=web_app
configuration.profiles=web/desktop/chrome
configuration.environments=dev
.story files plus per-batch settings (parallelism, meta filters). Files at properties/suite/<name>/suite.properties.web/desktop/chrome loads web then web/desktop then web/desktop/chrome).properties/environment/<name>/environment.properties.configuration-set.<key>.suites=...); activate via configuration-set.active=<key>.Property precedence (high → low): -Pvividus.<key>=v (Gradle CLI) > overriding.properties > configuration.properties > suite > profile > environment > plugin defaults. Inside a single tier with multiple entries declared, first declared wins.
For full property tables, batch settings, and reporting properties, read references/configuration.md.
# Run with active config from configuration.properties
./gradlew runStories
# Override the triple at the CLI (note the `-Pvividus.` prefix)
./gradlew runStories \
-Pvividus.configuration.suites=web_app \
-Pvividus.configuration.profiles=web/desktop/chrome \
-Pvividus.configuration.environments=staging
# Single-story or pattern run
./gradlew runStories -Pvividus.batch-1.resource-include-patterns=Login*.story
# Filter by Meta tags (Groovy)
./gradlew runStories -Pvividus.bdd.all-meta-filters="groovy: smoke && !skip"
# Inject a variable
./gradlew runStories -Pvividus.variables.user=alice
# Faster local iteration (skips full build validation)
./gradlew debugStories
Useful inspection tasks:
./gradlew printSteps --args="-f available-steps.txt" — dump every step the project knows./gradlew countSteps -t 5 — top 5 most-used steps./gradlew countScenarios -d story/web_app — count under a directory./gradlew validateKnownIssues — sanity-check known-issues.json./gradlew replaceDeprecatedSteps / replaceDeprecatedProperties — auto-migrate to current names./gradlew spotlessApply — autofix formattingAllure HTML output goes to output/reports/allure/index.html. Browsers refuse to load Allure JSON over file://, so serve it:
# pick one
( cd output/reports/allure && python3 -m http.server 8000 )
# or use VS Code Live Server, or VIVIDUS Studio's "Open Allure Report"
Then open http://localhost:8000.
Read references/troubleshooting.md for the common failures (missing submodule, JDK mismatch, backtick vs quote, locator visibility, suite-property precedence, parallel-story flakiness, MCP-AI hallucinated steps, Allure file:// blank page). It's the fastest path through Vividus's sharp edges.
When the user already has a Vividus project, before changing anything:
build.gradle to confirm the BOM version and which plugins are wired in. Don't add steps from a plugin not on the classpath.properties/configuration.properties to learn the active suites/profiles/environments — your changes must respect the active set..story files to match the project's conventions (locator style, variable scope choice, composite step naming)../gradlew printSteps --args="-f /tmp/steps.txt" and grep — this is the ground truth for that project.-Pvividus.batch-1.resource-include-patterns=YourStory.story) to validate before broader runs.This avoids drifting from project norms and catches plugin/version mismatches that would otherwise surface as "step did not match".
Add implementation('org.vividus:vividus-plugin-visual') to build.gradle. See assets/example-visual.story for a runnable template.
When I $actionType baseline with name `$name`
When I $actionType baseline with name `$name` ignoring:$checkSettings
$actionType values:
| Value | What it does |
|---|---|
ESTABLISH | Takes a full-page screenshot and saves it as the baseline. Run once to seed, then commit the PNG. |
COMPARE_AGAINST | Takes a fresh screenshot and diffs it against the stored baseline. Fails if diff > threshold. |
CHECK_INEQUALITY_AGAINST | Inverse — fails if the page looks too similar (useful for verifying UI changes landed). |
Pass an ExamplesTable with exactly one data row. Combine multiple selectors with a CSS multi-selector when you need to ignore more than one area:
When I COMPARE_AGAINST baseline with name `home` ignoring:
|ELEMENT |
|cssSelector(.cookie-banner, .hero-carousel) |
Columns: ELEMENT (locator), AREA (pixel region), ACCEPTABLE_DIFF_PERCENTAGE (per-check override), REQUIRED_DIFF_PERCENTAGE.
Gotcha:
ignoring:only supports one data row. Putting two rows throwsIllegalArgumentException: Only one row of locators to ignore supported. Use a multi-selector CSS string to cover multiple elements.
# in profile.properties or environment.properties
ui.visual.acceptable-diff-percentage=2 # allow up to 2% pixel diff (default: 0)
ui.visual.required-diff-percentage=70 # for CHECK_INEQUALITY_AGAINST (default: 70)
ui.visual.baseline-storage.filesystem.folder=./baselines # relative to src/main/resources
Gotcha: The
./baselinesfolder must exist as a classpath resource beforeESTABLISHwrites. Createsrc/main/resources/baselines/.gitkeepso Gradle packages the (initially empty) directory.
# 1. Seed baselines (first time or after intentional UI change)
./gradlew runStories -Pvividus.batch-1.resource-include-patterns="Visual.story"
# 2. Copy generated PNGs from output/ back into src/main/resources/baselines/ and commit them
# 3. Regression run (CI)
./gradlew runStories \
-Pvividus.batch-1.resource-include-patterns="Visual.story" \
-Pvividus."batch-1.variables.visualAction"=COMPARE_AGAINST
Pattern: store batch-1.variables.visualAction=ESTABLISH in suite.properties; override to COMPARE_AGAINST at the CLI for diff runs.
The biggest risk when generating Vividus stories with an LLM is hallucinated step phrasings — invented steps that look plausible but don't exist, silently becoming "pending" at runtime.
The best defence is the Vividus MCP server: it exposes your project's actual available steps to the LLM via the Model Context Protocol, so the model can verify phrasings against the real classpath rather than guessing from training data.
// build.gradle
implementation('org.vividus:vividus-mcp-server') // available from 0.6.16+
# Start the server (keep running while you author stories)
./gradlew startMcpServer -q -p /path/to/project
Then point your AI tool at it:
.github/copilot-instructions.md or mcp.jsonclaude_desktop_config.jsonDocs: https://docs.vividus.dev/vividus/latest/user-guides/ai.html
If you can't run it, ground every new step phrasing before writing it:
references/steps-cheatsheet.md./gradlew printSteps --args="-f /tmp/steps.txt" and grepprintSteps output, it doesn't existreferences/steps-cheatsheet.md — exact step phrasings for web, REST, JSON, DB, mobile, lifecycle, composites; locator & comparator syntaxreferences/configuration.md — suites, profiles, environments, batches, common properties, configuration sets, reporting propertiesreferences/plugins.md — full 47-plugin catalog grouped by domain with use-cases and linksreferences/variables-and-tables.md — variable scopes, dynamic variables, expressions (#{...}), ExamplesTable transformers (FROM_CSV/EXCEL/JSON/DB, FILTERING, MERGING, JOINING, ...)references/troubleshooting.md — submodule, JDK, backticks, locators, precedence, parallelism, AI-hallucinated steps, Allure viewingExternal sources of truth (cite these when uncertain):
npx claudepluginhub arozumenko/sdlc-skills --plugin test-automation-workflowGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.