Description
👓 What did you see?
- Cucumber Expressions written in Python containing optionals are considered 'undefined' by the Language Service
- However, the step successfully matches and executes when using the Python implementation of Cucumber Expressions directly

✅ What did you expect to see?
- The step text is considered 'defined'
📦 Which tool/library version are you using?
- Node - v18.16.0
- Cucumber Language Service - v1.4.1
🔬 How could we reproduce it?
Steps to reproduce the behavior:
-
Open Visual Studio Code
-
Install the official Cucumber extension
-
Create a feature file inside the
features
directory` containingFeature: Colour selection Scenario: Given I select the theme colour "red"
-
Create a step definition inside the
features/steps
directory containingfrom behave import given @given('I select the theme colo(u)r "{color}"') def step_when(context): ...
-
Observe the step in the feature file is highlighted as 'undefined'
📚 Any additional context?
The Language Service Python implementation prioritises Regular Expressions (checks first) over Cucumber Expressions.
A criteria for determining whether a pattern is a Regular Expression is whether it contains brackets ()
through specialCharsMatch
.
language-service/src/language/pythonLanguage.ts
Lines 135 to 142 in 6a35176
As a result, any Cucumber Expression containing an optional will be treated as a Regular Expression and the optional will instead be considered a capture group.
0: r {expression: 'I am on the profile customisation/settings page', parameterTypeRegistry: Aa, parameterTypes: Array(0), ast: ti, treeRegexp: r}
1: Us {regexp: /I select the theme colo(u)r "{color}"/, parameterTypeRegistry: Aa, treeRegexp: r}
A challenge is that in some languages a Regular Expression can be denoted by special prefix and suffix characters, whereas in Python, strings are similar in either case. See Java implementation:
language-service/src/language/javaLanguage.ts
Lines 20 to 24 in 6a35176
Brackets usage in Regular Expressions with Python
Official Python documentation on regular expressions outline the use of brackets as follows:
(...)
Matches whatever regular expression is inside the parentheses, and indicates the start and end of a group; the contents of a group can be retrieved after a match has been performed, and can be matched later in the string with the \number special sequence, described below. To match the literals '(' or ')', use ( or ), or enclose them inside a character class: [(], [)].
(?...)
This is an extension notation (a '?' following a '(' is not meaningful otherwise). The first character after the '?' determines what the meaning and further syntax of the construct is. Extensions usually do not create a new group; (?P...) is the only exception to this rule. Following are the currently supported extensions.