-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
[Core] Add Before and AfterStep hooks #1323
Conversation
@@ -128,6 +128,9 @@ private void addTestStepsForPickleSteps(List<TestStep> testSteps, PickleEvent pi | |||
match = new FailedStepInstantiationMatch(pickleEvent.uri, step, t); | |||
} | |||
testSteps.add(new PickleTestStep(pickleEvent.uri, step, match)); | |||
if (!runtimeOptions.isDryRun()) { | |||
addTestStepsForAfterStepHooks(testSteps, pickleEvent.pickle.getTags()); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you provide a test that shows the after hook is executed after each step?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also affects the JSONFormatter
. Currently it assumes all hooks are either before or after hooks. Using after step hooks will have undefined results.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brasmusson where do you think the TestStepStarted
events for step hooks should go in the json? I am thinking they should go into the same list as the the test steps themselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mpkorstanje , I can see afterstep being reported properly in json report. Could you please let me know what exactly is the issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can not. It does indeed all seem to work out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will update the class to HookStep instead of Unskipable step and handle the logic of skipping AfterStep for a failed/skipped step. This will be in sync with ruby.
Let me know if that should be ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will have to do some changes for JSONFormatter as there is some incosistency when compared with Ruby Json report. Will add a test for same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mpkorstanje , @brasmusson , I have implemented logic of skipping AfterStep in case of failed or skipped Step and also tests for JSON formatter showing AfterSteps JSON arry node should belong to it's respective step node.
Would you mind reviewing the changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look into them, but it will probably take half a week or so before I have the time and energy to do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have (today) initiated a discussion in the #committers
channel of the Cucumber Slack community, with respect to the two behavioral options for step hooks in case of failure, that is, the current Cucumber-Ruby behavior:
before hook - executed
step1 - executed and fails
after step hook - skipped
step2 - skipped
after step hook - skipped
after hook - executed
and the alternative:
before hook - executed
step1 - executed and fails
after step hook - skipped
step2 - skipped
after step hook - skipped
after hook - executed
We'll have to see were that discussion land before finish this PR.
super(definitionMatch); | ||
this.hookType = hookType; | ||
} | ||
|
||
protected Result.Type executeStep(String language, Scenario scenario, boolean skipSteps) throws Throwable { | ||
definitionMatch.runStep(language, scenario); | ||
return Result.Type.PASSED; | ||
if(hookType == HookType.After || hookType == HookType.Before) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current convention in the code base is to use "if (
" rather than "if(
" (and "switch (
" rather than "switch(
"), so for the sake of consistency this convention should be followed in this PR too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I will fix these throughout PR
import cucumber.api.Scenario; | ||
import cucumber.api.StepDefinitionReporter; | ||
import cucumber.api.TestCase; | ||
import cucumber.api.*; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not use wildcard imports, see https://github.com/cucumber/cucumber-jvm/blob/master/CONTRIBUTING.md#contributing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, will fix this one. I think it happened due to Intellij formatting it to .* in case all the classes are being used and imported from package
"formatter.result({\n" + | ||
" \"status\": \"passed\"\n" + | ||
"});\n", "" + | ||
"formatter.afterstep({\n" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the intention is to move away from the Cucumber-HTML-project (see cucumber-attic/cucumber-html#44), I'm thinking about exploring the use of "formatter.after
" also for after step hooks, instead of coupling this PR to a required change in the Cucumber-HTML (I'm not sure we want to open that Box of Pandora at this time).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't exactly get what needs to be done for this, should I leave it as it is for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try to take a look at what can best be done with respect to the HTML formatter.
" \"status\": \"passed\"\n" + | ||
" },\n" + | ||
" \"line\": 4,\n" + | ||
" \"afterstep\": [\n" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Json key should be "after" also for after step hooks, so that "before" and "after" are the Json key used for hooks both on the scenario level and the step level (see the Cucumber-Ruby spec https://github.com/cucumber/cucumber-ruby/blob/master/spec/cucumber/formatter/json_spec.rb#L677).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I saw that in ruby but there is a small catch here. In the code every where I have used string representation of HookType enum , for eg mapToAddTo.put(hookType.toString(), new ArrayList<Map<String, Object>>());
So in this case I will have to explicitly handle the AfterStep case to report it as After
InOrder inOrder = inOrder(step1, step2, hook, backend); | ||
inOrder.verify(step1).getText(); | ||
inOrder.verify(step2).getText(); | ||
inOrder.verify(hook, times(2)).execute(Matchers.<Scenario>any()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is confusing, it looks like it verifies that the after step hook is executed twice after step2 has been executed, but the expected behavior is that the hook is executed once in between step1 and step2 and once after step2. Can this test be change to better specify the expected behavior (and not look like it verifies the wrong behavior)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test was commented and was supposed to be removed as this behaviour is verified in other test. I will check once again and remove this test
@brasmusson , I have made the requested changes except the HTML formatter one for which I didn't exactly get what needs to be done |
Even thought there has not as wide participation as I would have liked in the discussion in the #committers channel, the conclusion seems to be that it is reasonable to run the after step hook for a (gherkin) step that fails (but not the after step hooks for subsequent steps). Therefore I took a stab at implementing this (f3c908c). The |
Result stepResult = step.run(bus, pickleEvent.pickle.getLanguage(), scenarioResult, skipNextStep); | ||
if (!stepResult.is(Result.Type.PASSED)) { | ||
skipNextStep = true; | ||
if (!stepResult.is(Result.Type.PASSED) && skipNextStep == SkipStatus.RUN_ALL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find it a bit hard to qualify why but the concept underlying this solution feels wrong. TestStep is leaking information into TestCase as to how the test should proceed. It shouldn't have to.
I think this is caused by trying to represent the test execution as a list of steps rather then the tree that it is (it may help to imagine the existence of a before step hook).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have one suggestion, why can't we have skipStep as binary bit flags, or bit array or a map for eg {"skipBeforeStep": false, "skipGherkingStep": false, "skipAfterStep": false}
when step fails set skipGherkingStep to true but skipAfterStep still remains false and executes the afterStep. After execution of afterStep, if skipGherkingStep is true , set skipAfterStep to true so that none of the next afterStep executes
I've moved the after step hooks into the One thing we should still look at though are the And perhaps also make sure we don't expose too much of the internal cucumber apis here. |
I've extracted a This raises the question, shouldn't hook events be in their own events? |
AMBIGUOUS, | ||
UNDEFINED, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ambiguous
and Failed
both unconditionally make the exit code non-zero, but Undefined
does not, so Undefined
must be less severe than Ambiguous
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right.
I'm not sure that is the right move. I have always envisioned that it is only the result of the test step from the PickleStep itself that are reported in the summary, even if an after step hook fails the summary should report "passed" of the test step from the PickleStep itself passed. |
I am not sure I understand. The summary is created from events emitted through the bus not from the The |
The drive to unify the event model between the Cucumber-implementations (so that for instance common formatters processing the Json representation of the event stream), mean that we cannot do that in Cucumber-JVM without commitment that the other Cucumber-implementations also do it. I think we in the community is very much into the view that everything that is executed during the execution of a "Test Case" is a "Test Step". A "Test Step" can be related to 0..1 "Pickle Step" (0 meaning that it is a "Test Step" created from a hook), and it can be related to 0..* code methods/functions (0 meaning that it is a "Test Step" created from a "Pickle Step" that could not be matched to any step definition - undefined, and * meaning that it is a "Test Step" created from a "Pickle Step" that could be matched to several step definitions - ambiguous). The "started" and "finished" event should therefore be of the same type for all "Test Step"s. |
You are right. I think we can use a hierarchical model for steps in test cases internally in the runner. However, I think that if it is possible to get the steps of a test case through classes in the api packages, then it should be a flat list of test steps, so that the abstraction of a test case as a flat sequence of test steps is maintained there. |
That would be the depth first iteration order over the step tree. Should be easy enough to change |
We should conform to that then. How should we name set of proper |
What is the expected behavior of the edit: And also quite easy to fix by making them skipable but only skipping them on a dry run. |
To stay consistent with the TestStep, PickleStepTestStep and HookStep from `cucumber.api` we should use the same naming convention in `cucumber.runtime`.
I have fixed the HTML reports including issue #1303, let me know if I should include those changes in this PR |
@coding-yogi I have looked into the behavior of the HTML formatter of Cucumber-Ruby. Since the intention is to replace the HTML formatters for all Cucumber implementation with one binary that can process the event stream and produce a HTML report, we should keep the different HTML formatters as aligned as reasonable possible until then. When using
The HTML formatter of Cucumber-Ruby will display output (in Cucumber-JVM
in exactly the same way (they will all appear below the text of the Gherkin step), therefore I do not think that there is any need to do anything new to handle output and embeddings with the introduction of step hooks (like making a change where In the end I think that the changes needed in Cucumber-HTML is cucumber-attic/cucumber-html@d757b90 (now when cucumber-attic/cucumber-html#49 has been fixed). |
Is that ideal still alive? From what I can see all the other implementations moved away from it. |
The new initiative https://github.com/cucumber/cucumber-pickle-runner, why not shared binaries for formatters too? |
I think the single binary is a very exciting development, and it makes perfect sense to me to put formatters in there too. |
I must be misunderstanding something somewhere. I am I right in assuming the |
@brasmusson , thanks for the clarification, so I won't push any further changes for HTML formatters |
Hi, |
@naelabdeljawad if you're ever in doubt about what's been released, check out the CHANGELOG |
An open pull request (such as this one) means the code has not been merged, and therefore, not released. |
Documentation still needs to be updated: https://docs.cucumber.io/cucumber/#beforestep |
Now I think my issues have been resolved
Hi @coding-yogi, Thanks for your making your first contribution to Cucumber, and welcome to the Cucumber committers team! You can now push directly to this repo and all other repos under the cucumber organization! 🍾 In return for this generous offer we hope you will:
On behalf of the Cucumber core team, |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Hi @coding-yogi, Thanks for your making your first contribution to Cucumber, and welcome to the Cucumber committers team! You can now push directly to this repo and all other repos under the cucumber organization! 🍾 In return for this generous offer we hope you will:
On behalf of the Cucumber core team, |
This PR adds a new feature of AfterStep. Methods annotated with AfterStep will be executed after every step. For HTML Reports to work properly after this change , this PR requires to be merged
Motivation and Context
This change was requested by users of cucumber-jvm
Types of changes
Checklist: