Forked from jimasp's excellent behave-vsc extension, this one adds features!
Debug and run Python behave BDD tests using the native Visual Studio Code Test API.
Includes two-way step navigation, Gherkin syntax highlighting, autoformatting, autocompletion, and a few basic snippets.
[!NOTE] This is a vibe-coded project. I use it every day at work and personally test pre-releases before promoting them to real releases. And I write my own release notes. But the code is AI-sloppy. If you're not comfortable with that, then you should look for another extension.
Features
New in this fork
- Added support for lots of VSCode language features:
- Ctrl + Click go to definition in feature files
- Find All References for steps in feature files
- Outline View in feature files
- Sticky Scrolling for steps and fixtures in feature files
- Hover Definitions for steps and fixtures in feature files
- Selection Ranges in feature files
- Added two-way navigation for fixtures in feature files and python definitions
- Slightly better formatting for VSCode Test Results pane (when you run tests with the little "play" buttons or via the Testing tab).
- Use prettier diagnostics for missing step definitions, especially while still parsing the workspace
- Added the ability to save presets for environment variables to use when running tests.
- Package Behave in with the extension (with the option to use a pre-installed version of behave)
- Support for tests that aren't in the root workspace directory (ie for monorepos).
- Support for step libraries.
- Fix issues with step parsing that was inconsistent with Behave (case sensitivity and colons).
- Auto-discovery of behave projects from native config files (
behave.ini,.behaverc,setup.cfg,tox.ini,pyproject.toml). NofeaturesPathsorprojectPathsettings needed in most cases. - Monorepo support with automatic subdirectory scanning for behave configs. Multi-path
pathsentries in config files are fully supported. - Project switching for workspaces with multiple behave projects. A status bar indicator and "Select Project" command let you switch between discovered projects.
- Per-notification suppression. Click "Don't Show Again" on any suppressible notification and it stays dismissed for that workspace folder. Backed by the
gs-behave-bdd.suppressedNotificationsarray setting — visible in Settings UI, editable by hand, and scoped per workspace folder. - Migration from
behave-vsc. This fork now reads settings only from its owngs-behave-bdd.*namespace. On activation it scans your existingbehave-vsc.*settings and offers per-scope consent prompts to migrate them forward. The newgs-behave-bdd.migrationModeandgs-behave-bdd.completedMigrationssettings, plus the Behave BDD: Recheck Migrations command, give you control over when and how the migration runs. execute_stepsIDE support. Steps embedded incontext.execute_steps("...")string literals in your Python files get the same IDE features as feature-file steps:- Validation — a Warning squiggle when an embedded step matches no step definition, and an Error squiggle on lines behave's parser would reject at runtime with a
ParserError(junk lines,@tags,Scenario:, a leadingAnd/But). Squiggles track the live document as you type. - Go to definition — Ctrl+Click / F12 on an embedded step jumps straight to its step definition function.
- Hover info — hovering an embedded step shows the same decorator + docstring popup you get for steps in feature files.
- Parameter highlighting —
{parameter}values in embedded steps are colorized like feature-file step parameters. The color is thegsBehaveBdd.executeStepsParametertheme color (override it viaworkbench.colorCustomizations). - Auto-completion — typing a step inside an
execute_stepsstring suggests known step definitions, with the same smart type filtering as feature files (anAndafter aWhenonly suggests@when/@stepdefinitions). - Create-step quick-fix — the lightbulb (Ctrl+.) on an undefined embedded step scaffolds a behave step-definition skeleton into the current steps file (or the workspace's largest steps file when triggered from a helper module).
- Reference counting —
execute_stepscall sites are counted in the step definition's CodeLens, in "Find All Step References", and in native Find All References. The CodeLens distinguishes sources, e.g.3 references (1 in steps). - Supported string forms: triple-quoted and single-line literals,
u/rprefixes,textwrap.dedent(...)wrapping, and.format(...)/%-formatted literals (placeholder-bearing lines are treated as dynamic and never flagged). f-strings and non-literal arguments (variables, concatenation) are skipped entirely — they produce no diagnostics, navigation, or references. Scanned files: every.pyunder the extension's watched roots, plus any step-library file behave's registry pulls in from outside them (e.g. alib/package next tofeatures/). Limitations: English Gherkin keywords only (the invoking feature's# language:is unknowable from the Python file), and on-disk-only changes to files outside the watched roots aren't detected until the next full parse (in-editor edits are picked up immediately).
- Validation — a Warning squiggle when an embedded step matches no step definition, and an Error squiggle on lines behave's parser would reject at runtime with a
Migrating from behave-vsc
v1.5.0 behavior change. Silent fallback reads of
behave-vsc.*settings are removed. The extension only reads its owngs-behave-bdd.*keys at runtime. If you pick Don't migrate /skip, your legacy values stay insettings.jsonbut the extension stops honoring them — copy them across manually or run Behave BDD: Recheck Migrations to be re-prompted.
On activation, the extension scans each unfinished migration against every VS Code scope (Global / Workspace / Workspace Folder). Three outcomes are possible per scope:
- Neither legacy nor canonical set: silently marked Finished. No prompt, no writes.
- Legacy set, canonical not set: the case 2 prompt (controlled by
migrationMode). Three actions: Migrate & delete, Migrate & keep, Don't migrate. - Both legacy and canonical set: the case 3 prompt (always shown, regardless of
migrationMode). Four actions: Overwrite & delete, Overwrite & keep, Keep canonical, Keep both.
gs-behave-bdd.migrationMode controls case 2 only. Values:
prompt(default) — show the case 2 prompt and let the user choose.migrate-and-delete— silently copy legacy → canonical, then clear the legacy key.migrate-and-keep— silently copy legacy → canonical, leave the legacy key alone.skip— silently mark Finished without copying.
Case 3 ignores this setting and always prompts.
{
"gs-behave-bdd.migrationMode": "migrate-and-delete"
}
gs-behave-bdd.completedMigrations is an array of migration IDs that have been finished at the current scope. Each VS Code scope (Global / Workspace / Workspace Folder) keeps its own array, so opening a new workspace folder starts with an empty list and triggers a fresh scan. The extension updates this array automatically; you rarely need to edit it by hand.
Behave BDD: Recheck Migrations (command palette) is the supported way to re-trigger the scan. It clears completedMigrations for the scopes you can write to and re-runs the evaluator — useful if you previously picked skip and changed your mind, or if you pasted behave-vsc.* settings into a workspace that has already been migrated.
Old from the original extension
- Run or Debug behave tests, either from the test side bar or from inside a feature file.
- Select to run/debug all tests, a nested folder, or just a single feature or scenario.
- See failed test run result inside the feature file. (Full run results are available in the Behave BDD output window.)
- Extensive run customisation settings (e.g.
runParallel,featuresPaths,envVarOverrides, etc.) - Two-way step navigation:
- "Go to Step Definition" from inside a feature file (default F12).
- "Find All Step References" from inside a step file (default Alt+F12).
- Quick navigate in the Step References Window (default F4 + Shift F4).
- Smart feature step auto-completion, e.g. typing
Andafter aGivenstep will only show@givenor@stepstep suggestions. (Also some snippets are thrown in.) - Feature file formatting (default Ctrl+K,Ctrl+F).
- Automatic Gherkin syntax highlighting (colourisation), including smart parameter recognition.
- Smart test runs minimise behave instances by building an optimised
-iregex param for behave based on the selected test nodes. (UnlessrunParallelis enabled.) - This extension supports multi-root workspaces, so you can run features from more than one project in a single instance of vscode. (Each project folder must have its own distinct features/steps folders.)

Workspace requirements
- No conflicting behave/gherkin/cucumber extension is enabled
- Extension activation requires at least one
*.featurefile somewhere in the workspace - A compatible directory structure
- ms-python.python extension
- python
Required project directory structure
- A behave-conformant directory structure. Note however that the features and steps folders must be somewhere inside the project folder (not above it).
Example 1:
. my-project
. +-- features/
. | | +-- my.feature
. | | +-- steps/
. | | | +-- steps.py
Example 2:
. my-project
. +-- features/
. | | +-- my.feature
. +-- steps/
. | | +-- steps.py
Example 3:
. my-project
. +-- behave.ini
. +-- features/
. +-- environment.py
. +-- steps/
. | | +-- __init__.py
. | | +-- steps.py
. +-- storage_tests/
. | +-- *.feature
. +-- web_tests/
. | +-- *.feature
. | +-- steps/
. | | +-- __init__.py
. | | +-- steps.py
Note: In most cases you don't need these settings. The extension auto-discovers your behave project from config files. Use
projectPathandfeaturesPathsonly as manual overrides when auto-discovery doesn't suit your setup.
Migrating from
featuresPath: The previousfeaturesPath(singular) setting was removed in v1.4.0 and replaced byfeaturesPaths(plural array). If you hadfeaturesPathset, the extension migrates it automatically on activation — no action required. The plural form means you can now point the extension at multiple test directories from a single workspace folder.
- If your features folder is not called "features", or is not in your project root, then you can add a behave config file (e.g.
behave.inior.behaverc) to your project folder and add apathssetting and then set thefeaturesPathssetting in extension settings to match. Each entry is a relative path to your project folder. For example:
# behave.ini
[behave]
paths=my_tests/behave_features
// settings.json
{
"gs-behave-bdd.featuresPaths": ["my_tests/behave_features"]
}
- If your behave project is not in the workspace root (e.g. in a monorepo), you can use the
projectPathsetting to specify where your behave project lives. ThefeaturesPathsentries are then relative to this project path. For example:
// Directory structure:
// my-workspace/
// └── backend/
// └── behave.ini
// └── features/
// └── my.feature
// └── steps/
// settings.json
{
"gs-behave-bdd.projectPath": "backend",
"gs-behave-bdd.featuresPaths": ["features"]
}
Auto-Discovery & Project Switching
The extension automatically discovers your behave project by reading native behave configuration files (behave.ini, .behaverc, setup.cfg, tox.ini, pyproject.toml). If any of these files exist in your workspace, the extension reads the paths setting and configures itself — no manual featuresPaths or projectPath settings needed.
Multi-path configs
If your behave config specifies multiple paths (e.g. paths = tests/features other_tests/features), all paths are used for test discovery and step navigation.
Monorepo scanning
For monorepos, the extension scans subdirectories (up to a configurable depth) looking for behave config files. The first discovered project becomes active automatically. You can control scan depth with the discoveryDepth setting (default: 3) and stop on the first hit with discoveryStopOnFirstHit.
Project switching
When multiple behave projects are discovered in a workspace, a status bar indicator shows which project is active. Click it or use the "Behave BDD: Select Project" command to switch between projects. Switching triggers a full rebuild of the test tree and step navigation.
The status bar indicator is hidden when only one project exists or when projectPath is manually set.
Extension settings
- This extension has various options to customise your test run via
settings.json, e.g.runParallel,featuresPaths, andenvVarOverrides. - By default, the extension uses its own bundled copy of behave. If you want to use behave from your Python environment instead (e.g. for a newer version), set
importStrategyto"fromEnvironment"in yoursettings.json. - You can also disable/enable
justMyCodefor debug (viasettings.jsonnotlaunch.json). - If you are using a multi-root workspace with multiple projects that contain feature files, you can set up default settings in your
*.code-workspacefile, then optionally override these as required in thesettings.jsonin each workspace folder. - For more information on available options, go to the extension settings in vscode.
How it works
How test runs work
-
The python path is obtained from the
ms-python.pythonextension (exported settings) i.e. yourpython.defaultInterpreterPathor selected python interpreter override. This is read before each run, so it is kept in sync with your project. -
For each run, the behave command to run the test manually appears in the
Behave BDDoutput window. -
The behave process is spawned, and behave output is written to the
Behave BDDoutput window for the associated workspace. -
The extension parses the junit file output and updates the test result in the UI, and any assertion failures and python exceptions are shown in the test run detail accessible in the feature file.
-
You can adjust the run behaviour via extension settings in your
settings.jsonfile (e.g.runParallelandenvVarOverrides). -
Tests runs are smart, so for example if you select to run three feature nodes it will build a behave
-iregex to run them in a single behave instance rather than separate instances (unless you are usingrunParallel). If you choose a nested folder it will run that folder in a behave instance, etc.
How debug works
- It dynamically builds a debug launch config with the behave command and runs that. (This is a programmatic equivalent to creating your own debug launch.json and enables the
ms-python.pythonextension to do the work of debugging.) - You can control whether debug steps into external code via the extension setting
behave-vsc.justMyCode(i.e. in yoursettings.jsonnot yourlaunch.json). - Behave stderr output (only) is shown in the debug console window. (This is to reduce noise when debugging. Run the test instead if you want to see the full behave output.)
- The extension parses the junit file output and updates the test result in the UI, and any assertion failures and python exceptions are shown in the test run detail accessible in the feature file.
- Debug is not affected by
runParallel.
Q&A
-
How can I see all effective settings for the extension? On starting vscode, look in the Behave BDD output window.
-
How can I see the active behave configuration being used for behave execution? In your behave config file, set
verbose=true. -
How do I clear previous test results? This isn't that obvious in vscode. Click the ellipsis
...at the top of the test side bar and then click "Clear all results". -
Why does the behave command output contain
--show-skipped? This flag must be enabled for junit files (which the extension depends on) to be produced for skipped tests. It is enabled by default, so this override is there just in case yourbehave.ini/.behavercfile specifiesshow_skipped=False. -
How can I only execute a specific set of tests while using the extension? There are a lot of options here, but there are some examples:
- (simple but inflexible) use the
default_tags=setting in your behave.ini file (or a[behave.userdata]setting for a custom setup) - (higly flexible) consider if you can group them into folders, not just by tag, then you can select to run any folder/subfolder from the test tree in the UI instead.
- (highly flexible) consider if you can use a feature/scenario/folder naming scheme that will allow you to leverage the filtering above the test tree to enable you to run just those tests.
- (custom) use the
envVarOverridesextension setting to set an environment variable that is only set when running from the extension. This adds endless possibilities, but the most obvious approaches are probably: (a) setting theBEHAVE_STAGEenvironment variable, (b) to control a behaveactive_tag_value_provider, (c) to controlscenario.skip(), or (d) to control a behavebefore_allfor a completely custom setup.
- (simple but inflexible) use the
-
How do I enable automatic feature file formatting on save? You can do this via a standard vscode setting:
"[gherkin]": { "editor.formatOnSave": true } -
How do I control the indentation the formatter uses? You don't configure it in this extension — the formatter uses whatever indentation vscode has resolved for the document, so
editor.insertSpacesandeditor.tabSizeare respected, including inside a"[gherkin]": { ... }block and including values coming from an.editorconfigfile (via the EditorConfig extension). One caveat:editor.detectIndentationis on by default, and it overrides your configured values based on what the file already contains — so an already-tab-indented feature file will keep reporting tabs until you convert it once (Convert Indentation to Spaces in the command palette), or until you set"editor.detectIndentation": false. Turn ongs-behave-bdd.verboseLoggingand format the file to see the resolved indent unit and where it came from in theBehave BDDoutput channel. -
How do I stop the formatter restructuring my feature files? Set
gs-behave-bdd.formatBlankLinestofalseto stop it inserting blank lines before scenarios/examples/tags and collapsing blank line runs, andgs-behave-bdd.formatAlignTablestofalseto stop it padding table cells. With both off, the formatter only re-indents. The formatter also follows yourfiles.trimTrailingWhitespace,files.insertFinalNewlineandfiles.trimFinalNewlinessettings, and never reformats the contents of a docstring ("""or```) block. -
How do I disable feature file snippets? You can do this via a standard vscode setting:
"[gherkin]": { "editor.suggest.showSnippets": false } -
How do I disable autocomplete for feature file steps? You can do this via a standard vscode setting:
"[gherkin]": { "editor.suggest.showFunctions": false } -
Why can't I see print statements in the Behave BDD output window even though I have
stdout_capture=Falsein my behave config file? Because the extension depends on the--junitbehave argument. As per the behave docs, with this flag set, all stdout and stderr will be redirected and dumped to the junit report, regardless of the capture/no-capture options. If you want to see print statements, copy/paste the outputted command and run it manually (or runpython -m behavefor all test output). -
Where is the behave junit output stored? In a temp folder that is deleted (recycled) each time the extension is started. The path is displayed on startup in the Behave BDD output window. (Note that if your test run uses runParallel, then multiple files are created for the same feature via a separate folder for each scenario. This is a workaround to stop the same junit file being written multiple times for the same feature, which in runParallel mode would stop us from being able to know the result of the test because each parallel behave execution would rewrite the file and mark scenarios not included in that execution as "skipped".)
-
When will this extension have a release version? When the code is more stable. At the moment the code is subject to rewrites/refactoring which makes bugs more likely.
Troubleshooting
If you have used a previous version of this extension
- Please read through the release notes for breaking changes. If that does not resolve your issue, then please rollback to the previous working version via the vscode uninstall dropdown and raise an issue.
Start here: get a diagnostic report
If the extension appears to do nothing — e.g. ctrl+click / F12 on a step doesn't jump to its Python definition, or no tests appear — collect a report rather than guessing:
- Turn on
gs-behave-bdd.verboseLoggingin settings. This makes the extension log why it gave up at every point where it would otherwise fail silently (step navigation, hover, step discovery). - Retry the thing that isn't working. If it's step navigation, leave the cursor on the step line.
- Run the vscode command
Behave BDD: Save Diagnostic Report. This writes a.logfile to your temp folder and opens it. It contains versions, the resolved Python interpreter, the features/steps paths actually in use, how many step definitions were loaded, — if the cursor is on a step — why that specific step didn't resolve, and then the complete log for the session. Nothing is truncated, so the file can be large; that's expected, attach it as-is. - Skim the file (you can redact anything you'd rather not share), then attach it to a github issue.
verboseLoggingdoes not log your environment variable preset values. If you specifically need those in the log, enablegs-behave-bdd.logEnvVarPresetContentsas well — but note that preset values may contain secrets, so review the file before sharing it.
Everything the extension writes to the Behave BDD output channel is also mirrored to a session
log in <temp>/gs-behave-bdd-logs/, one file per vscode window, which is what the report appends.
These are never truncated; logs from sessions older than 7 days are cleaned up automatically.
The three counts near the end of the report localise most problems:
| Symptom in the report | Likely cause |
|---|---|
parsed feature file steps: 0 |
the configured features path doesn't contain your .feature files |
loaded step definitions: 0 |
step discovery failed, or there's no steps folder where the extension looked |
both non-zero but mappings: 0 |
step text doesn't match any definition's pattern, or step files failed to load (check the Problems pane) |
Otherwise
- Does your project meet the workspace requirements and have the required project directory structure?
- If you have set the
featuresPathsin extension settings, make sure it matches thepathssetting in your behave configuration file. - Did you set extension settings in your user settings instead of your workspace settings?
- Have you tried manually running the behave command that is logged in the Behave BDD output window?
- If you are getting different results running all tests vs running a test separately, then it is probably due to lack of test isolation.
- If you are not seeing exceptions while debugging a test, do you have the appropriate breakpoint settings in vscode, e.g. do you have "Raised Exceptions" etc. turned off?
- Do you have the correct extension settings for your project? (See Q&A for information on how to see your effective settings.)
- Does restarting vscode solve your issue?
- Do you have runParallel turned on? Try turning it off.
- Do you have the latest version of the extension installed? The problem may have been fixed in a newer release. (Please note that the latest version you can install is determined by your vscode version, so you may need to update vscode first.)
- Check if the problem is in Known Issues below
- Check if the issue has already been reported in github issues.
- Try temporarily disabling other extensions.
- Have you recently upgraded vscode, and does your python/behave environment match the one tested for this release? You can check the environment tested for each release in github and downgrade as required.
- Any extension errors should pop up in a notification window, but you can also look at debug logs and error stacks by enabling
verboseLoggingin the extension settings and using vscode command "Developer: Toggle Developer Tools". (xRayis the deprecated name for this;verboseLoggingnow covers both the console diagnostics and the output channel. The extension will offer to migrate the setting for you.) - The extension is only tested with a few example projects. It's possible that something specific to your project/setup/environment is not accounted for. See Contributing for instructions on debugging the extension with your own project. (If you debug with your own project, you may also wish to check whether the same issue occurs with one of the example project workspaces.)
Known issues and limitations
- There is currently a bug in the MS python extension if you are using `unittest`` for your python tests in a multiroot project and you hit the >> "Run Tests" button (or equivalent command) to execute all tests. This may cause your test run not to stop or not to update test results correctly. Workarounds are:
- a. Use pytest instead of unittest to run your tests (which supports running unittest tests out of the box), or
- b. Do not to use the >> button, i.e. run tests from a test tree node instead (e.g.
Python TestsorFeature Testsseparately).
- There is currently a bug in vscode itself where a test will no longer play from within the editor window when you add spaces or autoformat a feature file. A workaround is to close the feature file and reopen it.
- Test durations are taken from behave junit xml files, not an actual execution time.
- vscode always adds up test durations. For
runParallelruns this means the parent test node reports a longer time than the test run actually took.
Contributing
If you would like to submit a pull request, please see the contributing doc.