Skip to content

Commit

Permalink
snippets: correctly escape backslashes in generated expressions (#1995)
Browse files Browse the repository at this point in the history
* add failing test

* implement

* add feature test

* update CHANGELOG.md
  • Loading branch information
davidjgoss committed Apr 11, 2022
1 parent f26ce3e commit 024911b
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CONTRIBUTING.md) on how to contribute to Cucumber.

## [Unreleased]
### Fixed
- 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))

## [8.0.0] - 2022-04-06
### Changed
Expand Down
17 changes: 17 additions & 0 deletions features/step_definition_snippets.feature
Expand Up @@ -70,3 +70,20 @@ Feature: step definition snippets
return 'pending';
});
"""

Scenario: a step resulting in special characters in the expression
Given a file named "features/number.feature" with:
"""
Feature: a feature
Scenario: a scenario
Given a person's (secret) desires
"""
When I run cucumber-js
Then it fails
And the output contains the text:
"""
Given('a person\'s \\(secret) desires', function () {
// Write code here that turns the phrase above into concrete actions
return 'pending';
});
"""
@@ -1,3 +1,4 @@
import { GeneratedExpression } from '@cucumber/cucumber-expressions'
import {
ISnippetSnytax,
ISnippetSyntaxBuildOptions,
Expand Down Expand Up @@ -43,9 +44,8 @@ export default class JavaScriptSnippetSyntax implements ISnippetSnytax {
if (this.snippetInterface === SnippetInterface.Callback) {
allParameterNames.push(CALLBACK_NAME)
}
return `${prefix + functionName}('${generatedExpression.source.replace(
/'/g,
"\\'"
return `${prefix + functionName}('${this.escapeSpecialCharacters(
generatedExpression
)}', ${functionKeyword}(${allParameterNames.join(', ')}) {\n`
}
)
Expand All @@ -56,4 +56,13 @@ export default class JavaScriptSnippetSyntax implements ISnippetSnytax {
'});'
)
}

private escapeSpecialCharacters(generatedExpression: GeneratedExpression) {
let source = generatedExpression.source
// double up any backslashes because we're in a javascript string
source = source.replace(/\\/g, '\\\\')
// escape any single quotes because that's our quote delimiter
source = source.replace(/'/g, "\\'")
return source
}
}
Expand Up @@ -145,6 +145,33 @@ describe('JavascriptSnippetSyntax', () => {
})
})

describe('pattern contains escapes', () => {
it('returns the proper snippet', () => {
// Arrange
const syntax = new JavascriptSnippetSyntax(SnippetInterface.Synchronous)
const buildOptions: ISnippetSyntaxBuildOptions = {
comment: 'comment',
functionName: 'functionName',
generatedExpressions: generateExpressions(
'the user (with permissions) executes the action'
),
stepParameterNames: [],
}

// Act
const result = syntax.build(buildOptions)

// Assert
expect(result).to.eql(
reindent(`
functionName('the user \\\\(with permissions) executes the action', function () {
// comment
return 'pending';
});`)
)
})
})

describe('multiple patterns', () => {
it('returns the snippet with the other choices commented out', function () {
// Arrange
Expand Down

0 comments on commit 024911b

Please sign in to comment.