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

Expose Scenario id to step definitions #673

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/src/main/java/cucumber/api/Scenario.java
Expand Up @@ -47,4 +47,9 @@ public interface Scenario {
void write(String text);

String getName();

/**
* @return the id of the Scenario.
*/
String getId();
}
5 changes: 3 additions & 2 deletions core/src/main/java/cucumber/runtime/Runtime.java
Expand Up @@ -13,6 +13,7 @@
import gherkin.formatter.model.DocString;
import gherkin.formatter.model.Match;
import gherkin.formatter.model.Result;
import gherkin.formatter.model.Scenario;
import gherkin.formatter.model.Step;
import gherkin.formatter.model.Tag;

Expand Down Expand Up @@ -133,14 +134,14 @@ private void writeStepdefsJson() {
glue.writeStepdefsJson(resourceLoader, runtimeOptions.getFeaturePaths(), runtimeOptions.getDotCucumber());
}

public void buildBackendWorlds(Reporter reporter, Set<Tag> tags, String scenarioName) {
public void buildBackendWorlds(Reporter reporter, Set<Tag> tags, Scenario gherkinScenario) {
for (Backend backend : backends) {
backend.buildWorld();
}
undefinedStepsTracker.reset();
//TODO: this is the initial state of the state machine, it should not go here, but into something else
skipNextStep = false;
scenarioResult = new ScenarioImpl(reporter, tags, scenarioName);
scenarioResult = new ScenarioImpl(reporter, tags, gherkinScenario);
}

public void disposeBackendWorlds() {
Expand Down
11 changes: 9 additions & 2 deletions core/src/main/java/cucumber/runtime/ScenarioImpl.java
Expand Up @@ -19,11 +19,13 @@ public class ScenarioImpl implements Scenario {
private final Reporter reporter;
private final Set<Tag> tags;
private final String scenarioName;
private final String scenarioId;

public ScenarioImpl(Reporter reporter, Set<Tag> tags, String scenarioName) {
public ScenarioImpl(Reporter reporter, Set<Tag> tags, gherkin.formatter.model.Scenario gherkinScenario) {
this.reporter = reporter;
this.tags = tags;
this.scenarioName = scenarioName;
this.scenarioName = gherkinScenario.getName();
this.scenarioId = gherkinScenario.getId();
}

void add(Result result) {
Expand Down Expand Up @@ -68,4 +70,9 @@ public void write(String text) {
public String getName() {
return scenarioName;
}

@Override
public String getId() {
return scenarioId;
}
}
Expand Up @@ -35,7 +35,7 @@ public CucumberBackground getCucumberBackground() {
@Override
public void run(Formatter formatter, Reporter reporter, Runtime runtime) {
Set<Tag> tags = tagsAndInheritedTags();
runtime.buildBackendWorlds(reporter, tags, scenario.getName());
runtime.buildBackendWorlds(reporter, tags, scenario);
try {
formatter.startOfScenarioLifeCycle((Scenario) getGherkinModel());
} catch (Throwable ignore) {
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/java/cucumber/runtime/HookOrderTest.java
Expand Up @@ -31,7 +31,7 @@ public void buildMockWorld() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
RuntimeOptions runtimeOptions = new RuntimeOptions("");
runtime = new Runtime(mock(ResourceLoader.class), classLoader, asList(mock(Backend.class)), runtimeOptions);
runtime.buildBackendWorlds(null, Collections.<Tag>emptySet(), "mock scenario");
runtime.buildBackendWorlds(null, Collections.<Tag>emptySet(), mock(gherkin.formatter.model.Scenario.class));
glue = runtime.getGlue();
}

Expand Down
101 changes: 69 additions & 32 deletions core/src/test/java/cucumber/runtime/RuntimeTest.java
Expand Up @@ -7,13 +7,15 @@
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.model.CucumberFeature;
import gherkin.I18n;
import gherkin.formatter.Formatter;
import gherkin.formatter.JSONFormatter;
import gherkin.formatter.Reporter;
import gherkin.formatter.model.Step;
import gherkin.formatter.model.Tag;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.internal.AssumptionViolatedException;
import org.mockito.ArgumentCaptor;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
Expand All @@ -29,13 +31,14 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyCollectionOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class RuntimeTest {

Expand Down Expand Up @@ -208,9 +211,7 @@ public void should_add_passed_result_to_the_summary_counter() throws Exception {
StepDefinitionMatch match = mock(StepDefinitionMatch.class);

Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runStep(reporter, runtime);
runtime.disposeBackendWorlds();
runScenario(reporter, runtime, stepCount(1));
runtime.printStats(new PrintStream(baos));

assertThat(baos.toString(), startsWith(String.format(
Expand All @@ -225,9 +226,7 @@ public void should_add_pending_result_to_the_summary_counter() throws Throwable
StepDefinitionMatch match = createExceptionThrowingMatch(new PendingException());

Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runStep(reporter, runtime);
runtime.disposeBackendWorlds();
runScenario(reporter, runtime, stepCount(1));
runtime.printStats(new PrintStream(baos));

assertThat(baos.toString(), startsWith(String.format(
Expand All @@ -242,9 +241,7 @@ public void should_add_failed_result_to_the_summary_counter() throws Throwable {
StepDefinitionMatch match = createExceptionThrowingMatch(new Exception());

Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runStep(reporter, runtime);
runtime.disposeBackendWorlds();
runScenario(reporter, runtime, stepCount(1));
runtime.printStats(new PrintStream(baos));

assertThat(baos.toString(), startsWith(String.format(
Expand All @@ -258,9 +255,7 @@ public void should_add_ambiguous_match_as_failed_result_to_the_summary_counter()
Reporter reporter = mock(Reporter.class);

Runtime runtime = createRuntimeWithMockedGlueWithAmbiguousMatch("--monochrome");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runStep(reporter, runtime);
runtime.disposeBackendWorlds();
runScenario(reporter, runtime, stepCount(1));
runtime.printStats(new PrintStream(baos));

assertThat(baos.toString(), startsWith(String.format(
Expand All @@ -275,10 +270,7 @@ public void should_add_skipped_result_to_the_summary_counter() throws Throwable
StepDefinitionMatch match = createExceptionThrowingMatch(new Exception());

Runtime runtime = createRuntimeWithMockedGlue(match, "--monochrome");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runStep(reporter, runtime);
runStep(reporter, runtime);
runtime.disposeBackendWorlds();
runScenario(reporter, runtime, stepCount(2));
runtime.printStats(new PrintStream(baos));

assertThat(baos.toString(), startsWith(String.format(
Expand All @@ -292,9 +284,7 @@ public void should_add_undefined_result_to_the_summary_counter() throws Throwabl
Reporter reporter = mock(Reporter.class);

Runtime runtime = createRuntimeWithMockedGlue(null, "--monochrome");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runStep(reporter, runtime);
runtime.disposeBackendWorlds();
runScenario(reporter, runtime, stepCount(1));
runtime.printStats(new PrintStream(baos));

assertThat(baos.toString(), startsWith(String.format(
Expand All @@ -310,10 +300,7 @@ public void should_fail_the_scenario_if_before_fails() throws Throwable {
HookDefinition hook = createExceptionThrowingHook();

Runtime runtime = createRuntimeWithMockedGlue(match, hook, true, "--monochrome");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runtime.runBeforeHooks(reporter, Collections.<Tag>emptySet());
runStep(reporter, runtime);
runtime.disposeBackendWorlds();
runScenario(reporter, runtime, stepCount(1));
runtime.printStats(new PrintStream(baos));

assertThat(baos.toString(), startsWith(String.format(
Expand All @@ -329,17 +316,52 @@ public void should_fail_the_scenario_if_after_fails() throws Throwable {
HookDefinition hook = createExceptionThrowingHook();

Runtime runtime = createRuntimeWithMockedGlue(match, hook, false, "--monochrome");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runStep(reporter, runtime);
runtime.runAfterHooks(reporter, Collections.<Tag>emptySet());
runtime.disposeBackendWorlds();
runScenario(reporter, runtime, stepCount(1));
runtime.printStats(new PrintStream(baos));

assertThat(baos.toString(), startsWith(String.format(
"1 Scenarios (1 failed)%n" +
"1 Steps (1 passed)%n")));
}

@Test
public void should_make_scenario_name_available_to_hooks() throws Throwable {
CucumberFeature feature = TestHelper.feature("path/test.feature",
"Feature: feature name\n" +
" Scenario: scenario name\n" +
" Given first step\n" +
" When second step\n" +
" Then third step\n");
HookDefinition beforeHook = mock(HookDefinition.class);
when(beforeHook.matches(anyCollectionOf(Tag.class))).thenReturn(true);

Runtime runtime = createRuntimeWithMockedGlue(mock(StepDefinitionMatch.class), beforeHook, true);
feature.run(mock(Formatter.class), mock(Reporter.class), runtime);

ArgumentCaptor<Scenario> capturedScenario = ArgumentCaptor.forClass(Scenario.class);
verify(beforeHook).execute(capturedScenario.capture());
assertEquals("scenario name", capturedScenario.getValue().getName());
}

@Test
public void should_make_scenario_id_available_to_hooks() throws Throwable {
CucumberFeature feature = TestHelper.feature("path/test.feature",
"Feature: feature name\n" +
" Scenario: scenario name\n" +
" Given first step\n" +
" When second step\n" +
" Then third step\n");
HookDefinition beforeHook = mock(HookDefinition.class);
when(beforeHook.matches(anyCollectionOf(Tag.class))).thenReturn(true);

Runtime runtime = createRuntimeWithMockedGlue(mock(StepDefinitionMatch.class), beforeHook, true);
feature.run(mock(Formatter.class), mock(Reporter.class), runtime);

ArgumentCaptor<Scenario> capturedScenario = ArgumentCaptor.forClass(Scenario.class);
verify(beforeHook).execute(capturedScenario.capture());
assertEquals("feature-name;scenario-name", capturedScenario.getValue().getId());
}

private StepDefinitionMatch createExceptionThrowingMatch(Exception exception) throws Throwable {
StepDefinitionMatch match = mock(StepDefinitionMatch.class);
doThrow(exception).when(match).runStep((I18n)any());
Expand Down Expand Up @@ -392,7 +414,7 @@ private Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLo
}

private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, String... runtimeArgs) {
return createRuntimeWithMockedGlue(match, false, null, false, runtimeArgs);
return createRuntimeWithMockedGlue(match, false, mock(HookDefinition.class), false, runtimeArgs);
}

private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, HookDefinition hook, boolean isBefore,
Expand All @@ -401,7 +423,7 @@ private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, HookDefin
}

private Runtime createRuntimeWithMockedGlueWithAmbiguousMatch(String... runtimeArgs) {
return createRuntimeWithMockedGlue(mock(StepDefinitionMatch.class), true, null, false, runtimeArgs);
return createRuntimeWithMockedGlue(mock(StepDefinitionMatch.class), true, mock(HookDefinition.class), false, runtimeArgs);
}

private Runtime createRuntimeWithMockedGlue(StepDefinitionMatch match, boolean isAmbiguous, HookDefinition hook,
Expand Down Expand Up @@ -434,4 +456,19 @@ private void mockHook(RuntimeGlue glue, HookDefinition hook, boolean isBefore) {
when(glue.getAfterHooks()).thenReturn(Arrays.asList(hook));
}
}

private void runScenario(Reporter reporter, Runtime runtime, int stepCount) {
gherkin.formatter.model.Scenario gherkinScenario = mock(gherkin.formatter.model.Scenario.class);
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), gherkinScenario);
runtime.runBeforeHooks(reporter, Collections.<Tag>emptySet());
for (int i = 0; i < stepCount; ++i) {
runStep(reporter, runtime);
}
runtime.runAfterHooks(reporter, Collections.<Tag>emptySet());
runtime.disposeBackendWorlds();
}

private int stepCount(int stepCount) {
return stepCount;
}
}
3 changes: 2 additions & 1 deletion core/src/test/java/cucumber/runtime/ScenarioResultTest.java
Expand Up @@ -2,6 +2,7 @@

import gherkin.formatter.Reporter;
import gherkin.formatter.model.Result;
import gherkin.formatter.model.Scenario;
import gherkin.formatter.model.Tag;
import org.junit.Test;

Expand All @@ -14,7 +15,7 @@
public class ScenarioResultTest {

private Reporter reporter = mock(Reporter.class);
private ScenarioImpl s = new ScenarioImpl(reporter, Collections.<Tag>emptySet(), "test scenario");
private ScenarioImpl s = new ScenarioImpl(reporter, Collections.<Tag>emptySet(), mock(Scenario.class));

@Test
public void no_steps_is_passed() throws Exception {
Expand Down
Expand Up @@ -12,6 +12,7 @@
import gherkin.formatter.model.Comment;
import gherkin.formatter.model.Match;
import gherkin.formatter.model.Result;
import gherkin.formatter.model.Scenario;
import gherkin.formatter.model.Step;
import gherkin.formatter.model.Tag;
import org.junit.Test;
Expand Down Expand Up @@ -69,7 +70,7 @@ public void throws_ambiguous_when_two_matches_are_found() throws Throwable {
backend.addStepDefinition(THREE_BLIND_ANIMALS.getAnnotation(Given.class), THREE_BLIND_ANIMALS);

Reporter reporter = mock(Reporter.class);
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), mock(Scenario.class));
Tag tag = new Tag("@foo", 0);
runtime.runBeforeHooks(reporter, asSet(tag));
runtime.runStep("some.feature", new Step(NO_COMMENTS, "Given ", "three blind mice", 1, null, null), reporter, ENGLISH);
Expand Down Expand Up @@ -113,7 +114,7 @@ public void embedding(String mimeType, byte[] data) {
public void write(String text) {
}
};
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), "test scenario");
runtime.buildBackendWorlds(reporter, Collections.<Tag>emptySet(), mock(Scenario.class));
Tag tag = new Tag("@foo", 0);
Set<Tag> tags = asSet(tag);
runtime.runBeforeHooks(reporter, tags);
Expand Down
4 changes: 3 additions & 1 deletion scala/src/test/scala/cucumber/api/scala/ScalaDslTest.scala
Expand Up @@ -21,6 +21,8 @@ class ScalaDslTest {
def write(p1: String) {}

def getName = ""

def getId = ""
}

@Test
Expand Down Expand Up @@ -129,7 +131,7 @@ class ScalaDslTest {

assertEquals(1, Dummy.stepDefinitions.size)
val step = Dummy.stepDefinitions.head
assertEquals("ScalaDslTest.scala:125", step.getLocation(true)) // be careful with formatting or this test will break
assertEquals("ScalaDslTest.scala:127", step.getLocation(true)) // be careful with formatting or this test will break
assertEquals("x", step.getPattern)
step.execute(new I18n("en"), Array())
assertTrue(called)
Expand Down