Execute BDD scenarios
Instructions
- Use
mcp__plugin_story-flow_playwright__*tools to manipulate browser to EXECUTE the BDD scenarios directly without generating any Playwright test file. - Test Execution Protocol:
- Before executing: Read the feature file and confirm the exact line numbers, scenario title, background sections and all "Then" and "And" assertions.
- Execution order is CRITICAL:
- Scenario tags FIRST (e.g.,
@purge-data) - Background steps SECOND (setup prerequisites)
- Scenario steps THIRD (Given/When/Then)
- Execute all Background steps: Background sections (both global and rule-specific) in feature files define prerequisite setup steps. EVERY step MUST be completed before executing the scenario steps, including both UI interactions and API calls by curl.
- During execution: Compare actual behavior against expected behavior at each assertion step.
- On failure: STOP immediately and provide a summary including:
- Expected behavior (with line numbers from feature file)
- Actual behavior (with evidence from page snapshot)
- Root cause analysis
- CRITICAL: Do NOT continue to subsequent test steps after a failure
- Executing Multiple Scenarios:
When executing multiple scenarios (e.g., "Execute all scenarios in @path/to/file.feature", "Execute ARMR-01,ARMR-02 scenarios in @path/to/file.feature"):
- Read the feature file to identify all scenario IDs and titles
- For each scenario, use the Task tool with
subagent_type="general-purpose"to run it in isolated context sequentially:
``` Load BOTH skills in this order using the Skill tool:
- First:
story-flow:execute-bdd-scenario(plugin - general BDD framework) - Then:
execute-bdd-scenario(project-level - overrides/extends the plugin) - Confirm both skills are loaded before continuing with the execution.
Execute BDD scenario <SCENARIO-ID> in @path/to/file.feature [--record if recording mode is active]. `` IMPORTANT: Replace <SCENARIO-ID> with the individual scenario ID (e.g., ARMR-01), NOT "all". Each subagent executes exactly one scenario. Recording Mode: When executing multiple scenarios with --record, pass the --record flag to each subagent prompt. Each subagent is responsible for generating/updating the .spec.js` file after executing its scenario — do NOT defer spec file generation to the parent orchestrator.
- Wait for subagent completion, record PASS/FAIL result
- If the scenario FAILED: STOP immediately and print the summary table with remaining scenarios marked as "⊘ SKIPPED". Do NOT proceed to the next scenario.
- Print summary table:
`` | Scenario | Title | Result | |----------|-------|--------| | SMG-01 | Display available languages | ✓ PASSED | | SMG-02 | Search and filter strings | ✗ FAILED | | SMG-03 | Inline edit a string value | ⊘ SKIPPED | ``
- Save
.featurefiles in the same folder as the stories. - If a BDD scenario has the
@screenshotstag, take one screenshot per assertion group — a maximal run of consecutive assertion steps with no action or wait step between them, since nothing re-renders in between — captured after the group's last UI assertion so every asserted condition has settled, and, in--recordmode when VRT is configured, emit one visual regression tracking call per group (see [Visual Regression Testing (VRT)](#visual-regression-testing-vrt)). Command and polling assertion steps (S3/CLI/API checks) assert outside the viewport: they take no screenshot and do not break the group. Passbrowser_take_screenshota filename explicitly prefixed with.playwright-mcp/— e.g..playwright-mcp/SMG-01-i-should-see-the-dashboard.pngso it lands in the.playwright-mcpoutput folder — never an absolute path, which writes to the project root. - If a BDD scenario doesn't have the
@screenshotstag, do not take any screenshot. - If a BDD scenario has the
@purge-datatag, restore the seed data first (before the Background steps) by executing themake reseedcommand. - If a BDD scenario does not have the
@purge-datatag, do not restore the seed data before running the scenario. - If a BDD scenario has the
@timeout-*tag, extend the scenario and expect timeout to be longer. e.g.@timeout-600smeans timeout for the scenario and every expect step is 600s(10m). - Use
mcp__plugin_story-flow_playwright__browser_run_code_unsafeto set the browser offline. - Reference the @Makefile for local development workflows.
- Navigate relative to the base URL from
BASE_URL, falling back touse.baseURLin the project's @playwright.config.js. Never hardcode a host.
Mobile App Instructions
Environment Variables
| Variable | Description | Default | |----------|-------------|---------| | APPIUM_DEVICE_NAME | Local device name or emulator | emulator-5554 (Android) | | APPIUM_UDID | Local iOS device or simulator UDID | - | | APPIUM_APP_PACKAGE | Local Android app package unique identifier | - | | APPIUM_APP_ACTIVITY | Local Android app launcher activity | .MainActivity | | APPIUM_BUNDLE_ID | Local iOS app bundle identifier | - | | BROWSERSTACK_USERNAME | BrowserStack username | - | | BROWSERSTACK_ACCESS_KEY | BrowserStack access key | - | | BROWSERSTACK_APP_ID | Uploaded app ID (bs://...) | - |
Mode detection: When all 3 BrowserStack variables are set, use BrowserStack. Otherwise, use local Appium.
Local Appium Configuration (Default)
Start Appium server: npx appium server --port 4723. Appium ships no drivers — install uiautomator2 for Android, xcuitest (with Xcode) for iOS.
A hybrid app's webview needs no extra driver: switch with driver.switchContext('WEBVIEW_...') and UiAutomator2 proxies to a Chromedriver it downloads to match the app's webview engine, while XCUITest drives Safari's remote debugger. Pin a mismatched build with appium:chromedriverExecutable rather than installing the standalone chromium driver, which automates desktop Chrome, not app webviews.
WebdriverIO options — Android:
{
hostname: "localhost",
port: 4723,
waitforTimeout: 30000,
waitforInterval: 500,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
capabilities: {
platformName: "Android",
"appium:deviceName": process.env.APPIUM_DEVICE_NAME || "emulator-5554",
"appium:automationName": "UiAutomator2",
"appium:appPackage": process.env.APPIUM_APP_PACKAGE,
"appium:appActivity": process.env.APPIUM_APP_ACTIVITY || ".MainActivity",
"appium:autoGrantPermissions": true,
"appium:noReset": true,
"appium:fullReset": false,
},
}
WebdriverIO options — iOS:
{
hostname: "localhost",
port: 4723,
waitforTimeout: 30000,
waitforInterval: 500,
// The first session builds WebDriverAgent, which exceeds the 30s Android uses
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
capabilities: {
platformName: "iOS",
"appium:udid": process.env.APPIUM_UDID,
"appium:automationName": "XCUITest",
"appium:bundleId": process.env.APPIUM_BUNDLE_ID,
"appium:noReset": true,
"appium:fullReset": false,
},
}
appium:autoGrantPermissions and appium:appActivity are Android-only — never carry them into the iOS capabilities. Do not add appium:autoAcceptAlerts either: it swallows alerts a scenario asserts on.
BrowserStack Configuration
When all 3 BrowserStack env vars are set, connect to BrowserStack cloud instead of local Appium. Start BrowserStackLocal binary before running tests. Stop BrowserStackLocal after tests complete. Use the WebDriver REST API directly by curl instead of Appium MCP or WebDriverIO library.
WebdriverIO options:
{
hostname: "hub-cloud.browserstack.com",
port: 443,
protocol: "https",
path: "/wd/hub",
waitforTimeout: 30000,
waitforInterval: 500,
co