Skip to content

Commit 40dea5a

Browse files
authored
Merge branch 'main' into fix/loader-hooks-extension
2 parents 91c0139 + 024911b commit 40dea5a

File tree

5 files changed

+60
-3
lines changed

5 files changed

+60
-3
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.github/ @cucumber/build

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO
1111
### Changed
1212
- Rename the `cucumber-js` binary's underlying file to have a `.js` extension, so it doesn't fall foul of Node.js module conventions and plays nicely with ESM loaders (see [documentation](./docs/esm.md#transpiling)) ([#1993](https://github.com/cucumber/cucumber-js/pull/1993))
1313

14+
### Fixed
15+
- Correctly escape backslashes in generated expressions for snippets ([#1324](https://github.com/cucumber/cucumber-js/issues/1324) [#1995](https://github.com/cucumber/cucumber-js/pull/1995))
16+
1417
## [8.0.0] - 2022-04-06
1518
### Changed
1619
- Emit a warning when using a Node.js version that's untested with Cucumber ([#1959](https://github.com/cucumber/cucumber-js/pull/1959))

features/step_definition_snippets.feature

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,20 @@ Feature: step definition snippets
7070
return 'pending';
7171
});
7272
"""
73+
74+
Scenario: a step resulting in special characters in the expression
75+
Given a file named "features/number.feature" with:
76+
"""
77+
Feature: a feature
78+
Scenario: a scenario
79+
Given a person's (secret) desires
80+
"""
81+
When I run cucumber-js
82+
Then it fails
83+
And the output contains the text:
84+
"""
85+
Given('a person\'s \\(secret) desires', function () {
86+
// Write code here that turns the phrase above into concrete actions
87+
return 'pending';
88+
});
89+
"""

src/formatter/step_definition_snippet_builder/javascript_snippet_syntax.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { GeneratedExpression } from '@cucumber/cucumber-expressions'
12
import {
23
ISnippetSnytax,
34
ISnippetSyntaxBuildOptions,
@@ -43,9 +44,8 @@ export default class JavaScriptSnippetSyntax implements ISnippetSnytax {
4344
if (this.snippetInterface === SnippetInterface.Callback) {
4445
allParameterNames.push(CALLBACK_NAME)
4546
}
46-
return `${prefix + functionName}('${generatedExpression.source.replace(
47-
/'/g,
48-
"\\'"
47+
return `${prefix + functionName}('${this.escapeSpecialCharacters(
48+
generatedExpression
4949
)}', ${functionKeyword}(${allParameterNames.join(', ')}) {\n`
5050
}
5151
)
@@ -56,4 +56,13 @@ export default class JavaScriptSnippetSyntax implements ISnippetSnytax {
5656
'});'
5757
)
5858
}
59+
60+
private escapeSpecialCharacters(generatedExpression: GeneratedExpression) {
61+
let source = generatedExpression.source
62+
// double up any backslashes because we're in a javascript string
63+
source = source.replace(/\\/g, '\\\\')
64+
// escape any single quotes because that's our quote delimiter
65+
source = source.replace(/'/g, "\\'")
66+
return source
67+
}
5968
}

src/formatter/step_definition_snippet_builder/javascript_snippet_syntax_spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,33 @@ describe('JavascriptSnippetSyntax', () => {
145145
})
146146
})
147147

148+
describe('pattern contains escapes', () => {
149+
it('returns the proper snippet', () => {
150+
// Arrange
151+
const syntax = new JavascriptSnippetSyntax(SnippetInterface.Synchronous)
152+
const buildOptions: ISnippetSyntaxBuildOptions = {
153+
comment: 'comment',
154+
functionName: 'functionName',
155+
generatedExpressions: generateExpressions(
156+
'the user (with permissions) executes the action'
157+
),
158+
stepParameterNames: [],
159+
}
160+
161+
// Act
162+
const result = syntax.build(buildOptions)
163+
164+
// Assert
165+
expect(result).to.eql(
166+
reindent(`
167+
functionName('the user \\\\(with permissions) executes the action', function () {
168+
// comment
169+
return 'pending';
170+
});`)
171+
)
172+
})
173+
})
174+
148175
describe('multiple patterns', () => {
149176
it('returns the snippet with the other choices commented out', function () {
150177
// Arrange

0 commit comments

Comments
 (0)