Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use cucumber-expressions to generate the match in fake-cucumber #793

Merged
merged 67 commits into from
Nov 22, 2019

Conversation

vincent-psarga
Copy link
Contributor

Summary

We've added default step definitions in the messages generated by fake-cucumber recently, but the choice of the step definition used for a TestStep was random.
Now it uses cucumber-expression to make real match and generate the testStepMatchArgument messages.

Still TODO:

  • check how to correctly handle the ambiguous statuses.

Details

Motivation and Context

Types of changes

  • Bug fix (non-breaking change which fixes an issue).
  • New feature (non-breaking change which adds functionality).
  • Breaking change (fix or feature that would cause existing functionality to not work as expected).

Checklist:

  • The change has been ported to Java.
  • The change has been ported to Ruby.
  • The change has been ported to JavaScript.
  • The change has been ported to Go.
  • The change has been ported to .NET.
  • I've added tests for my code.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

Note: there should be a better way to import CucumberExpression and Messages, still WIP
Makefile Outdated
cucumber-query/Makefile \
cucumber-react/Makefile \
html-formatter/Makefile \
json-formatter/Makefile \
datatable/Makefile \
config/Makefile \
cucumber-expressions/Makefile \
fake-cucumber/Makefile \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency order is now wrong because cucumber-query’s tests depends on fake-cucumber.

Better to move cucumber-expressions up and leave fake-cucumber where it was.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, and the formatters also depend on this library. I fix that in the next commit.

@vincent-psarga
Copy link
Contributor Author

Open question: previously, fake-cucumber gave type "fake" to the arguments. Should it still do the same or do we keep "" as generated by cucumber-expressions ?
Or should we only replace the empty ones by "fake" ?

The html-formatter has tests where it expects fake so I'm wondering.

Copy link
Contributor

@aslakhellesoy aslakhellesoy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great - we'll be able to produce more faithful output using this, and I think that will be useful when we use fake-cucumber to validate/test consumers.

I do wonder if it might be worthwhile implementing the step definition and matching logic as if this were a real cucumber implementation. If we do that, we could evolve this to become a new codebase for Cucumber.js, with a simpler architecture and less baggage than the original.

} from 'cucumber-expressions'
import uuidv4 from 'uuid/v4'

import Argument from 'cucumber-expressions/dist/src/Argument'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't reach inside a package for imports. This should be:

import { Argument } from 'cucumber-expressions'

Which will require a change to cucumber-expressions

import uuidv4 from 'uuid/v4'

import Argument from 'cucumber-expressions/dist/src/Argument'
import CucumberExpression from 'cucumber-expressions/dist/src/CucumberExpression'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the thing for this one is that, when I use import { CucumberExpression } from cucumber-expression, I can not use CucumberExpressionas a type for the variables, so I have to write weird stuff likepublic expression: any = new CucumberExpression` (which is pretty ugly too)

import CucumberExpression from 'cucumber-expressions/dist/src/CucumberExpression'

class FakeStepDefinition {
public id: string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to make fields private readonly as much as possible to prevent exposing more internals than necessary

public status: string,
public pattern: string = null
) {
this.id = uuidv4()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialisation should be done at declaration

if (pattern === null) {
this.pattern = `{}${status}{}`
}
this.expression = new CucumberExpression(this.pattern, new ParameterTypeRegistry)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use parenthesis when calling constructors:

new ParameterTypeRegistry()

I also think it is cleaner to pass the whole expression object through the constructor, which should declare the type as Expression (imported from cucumber-expressions). That way we could also pass in a RegularExpression if we want, and all the expressions can share the same ParameterTypeRegistry instance (since it's created outside)

})
})
)
this.stepDefinitions.makeMessages().forEach(message => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the step definitions here is problematic, since it will happen for each feature file. We don't want to do this for each feature file - we only want to do it once.

Maybe it's better to pass all the step definitions to the stream's constructor.

const fakeMatch = new FakeMatch()

this.stepDefinitions.forEach(stepDefinition => {
const match = stepDefinition.expression.match(step)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid train wrecks.

const match = stepDefinition.expression.match(step)
if (match !== null) {
fakeMatch.stepMatchArguments = match
fakeMatch.stepDefinitionId = stepDefinition.id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid setters too. They are a common source of bugs. It's better to make this field private readonly and make sure it's instantiated in the constructor.

@aslakhellesoy
Copy link
Contributor

Open question: previously, fake-cucumber gave type "fake" to the arguments. Should it still do the same or do we keep "" as generated by cucumber-expressions ?
Or should we only replace the empty ones by "fake" ?

The html-formatter has tests where it expects fake so I'm wondering.

We should use the parameter type name reported by cucumber-expressions (which will be int, word etc). We should avoid using anonymous parameter types here. And we should update the html-formatter tests accordingly.

@vincent-psarga vincent-psarga mentioned this pull request Nov 22, 2019
11 tasks
@aslakhellesoy aslakhellesoy marked this pull request as ready for review November 22, 2019 13:48
@aslakhellesoy aslakhellesoy merged commit 503e7b3 into master Nov 22, 2019
@aslakhellesoy aslakhellesoy deleted the fake-cucumber-use-cucumber-expressions branch November 22, 2019 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants