Skip to content

Conversation

serhatozdursun
Copy link
Contributor

@serhatozdursun serhatozdursun commented Jul 21, 2025

Properly Skip Scenarios When SkipScenarioException Is Thrown in Hooks

This PR addresses issue #926:

Throwing SkipScenarioException in a @BeforeScenario hook does not mark the scenario as skipped as expected.


Summary of Changes

  • Short-circuit execution for skipped scenarios:
    • Updated StepExecutionStage and HookExecutionStage to check for skipScenario in the previous stage result, mirroring the handling of failures. If a scenario is marked as skipped, subsequent stages are not executed.
  • Test coverage:
    • Added/updated tests in StepExecutionStageTest and created HookExecutionStageTest to verify that execution is properly short-circuited when skipScenario is set.
  • Behavior:
    • Now, when SkipScenarioException is thrown in a hook (e.g., @BeforeScenario), the scenario is correctly marked as skipped and its steps are not executed. This ensures the Gauge summary and reports reflect the correct skip count, as expected by users.

How to Reproduce / Test

  1. Use a @BeforeScenario(tags = "skip") hook that throws SkipScenarioException.
  2. Run a spec with a scenario tagged skip.
  3. The scenario should be reported as skipped, and its steps should not run.

References

it will look like this:
image

@serhatozdursun serhatozdursun force-pushed the feat/skip-scenario-in-beforescenario-hook branch 2 times, most recently from 850705b to c120cce Compare July 21, 2025 14:50
@serhatozdursun
Copy link
Contributor Author

serhatozdursun commented Jul 23, 2025

@chadlwilson hey once you have time, please can you take look and please let me know if any change needed

@chadlwilson
Copy link
Contributor

Sorry, I've been focused elsewhere and haven't had a chance to get to this. Takes a bit longer as im not deeply familiar with the code.

@serhatozdursun
Copy link
Contributor Author

serhatozdursun commented Aug 25, 2025

@chadlwilson No problem at all. I tested it locally and can confirm the issue—he’s already applied the fix with this PR.

Note: Please feel free to assign me other tasks or bug fixes in the Java package. I’m getting more familiar with the code and would be happy to help further.

@chadlwilson
Copy link
Contributor

I don't really understand why there'd be the need to change the behaviour for failure in HookExecutionStage here. That'd imply something was broken for failures in hook processing earlier, which has not been reported?

Something doesn't feel correct about this, and it makes me feel I don't understand something about the role of the HookExecutionStage vs HooksExecutor, and when results need to be merged vs not merged. Unfortunately I don't really have time/energy to test through all of the scenarios or review if they are covered by the existing functional tests at https://github.com/getgauge/gauge-tests .

The questions I have

  • If the handling for failure needed to be changed in HookExecutionStage - why was this, and what was the consequence earlier?
  • Why did StepExecutionStage need changing as well? Does this imply a different issue with regular steps not described in Cannot dynamically skip scenario during BeforeScenario hook #926?
  • Why do you feel changing HookExecutionStage is the correct place, rather than HooksExecutor?
  • What happens if you have multiple @BeforeScenario hooks defined?
    • Say you have 3 - 1 passes, 1 fails and 1 implies a skip of the scenario? Does it matter how are they batched together, or spread among executors and what is reported in the result? Does it seem correct?

@chadlwilson
Copy link
Contributor

chadlwilson commented Aug 25, 2025

By chance, was a large chunk of that response auto-generated by AI? It doesn't really get to the deeper points, several bits don't make sense in context, and the answer seems to directly answer a points without adequate context or correlation to why the changes were needed.

This doesn't make sense, given the issue #926 was specifically about BeforeScenario, not regular steps (which this code changes). if this comment is indeed true, it implies the very core functionality intended by #924 doesn't actually work, which would mean the whole thing should be reverted.

@serhatozdursun
Copy link
Contributor Author

serhatozdursun commented Aug 25, 2025

Yes I was prepared only the answer text with AI but during the test in my local I have noticed an issue. now will update the PR but this time expnation will from no worries :)) sorry about the recent one as I am a little bit busy just wanted to be quick :) but relaying on AI was mistake again sorry

@serhatozdursun
Copy link
Contributor Author

serhatozdursun commented Aug 25, 2025

If the handling for failure needed to be changed in HookExecutionStage - why was this, and what was the consequence earlier?

The handling for failure in HookExecutionStage needed to be changed because it was skipping the run but not marking the scenario as skipped. And this marked issue also was exists on step level.

Why did StepExecutionStage need changing as well? Does this imply a different issue with regular steps not described in #926?

I followed the getFailed() method because while skipping tests was working, the scenarios weren’t being marked as skipped. Since getFailed() correctly marks a scenario as failed, I thought replicating that logic would allow me to mark skipped scenarios properly too. Later, I realized I had missed the main piece in the BeforeScenario hook. I’ve now pushed that change as well.

Why do you feel changing HookExecutionStage is the correct place, rather than HooksExecutor?
Answerd above

What happens if you have multiple @BeforeScenario hooks defined?
* Say you have 3 - 1 passes, 1 fails and 1 implies a skip of the scenario? Does it matter how are they batched together, or spread among executors and what is reported in the result? Does it seem correct?
Say you have 3 - 1 passes, 1 fails and 1 implies a skip of the scenario: -> it would like the following

image

the code was like

import com.thoughtworks.gauge.*;

import java.util.HashSet;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

public class StepImplementation {

    private HashSet<Character> vowels;

    @BeforeScenario(tags = "skip")
    public void skipScenario(ExecutionContext context) {
        System.out.println("skip " + context.getCurrentScenario().getName() + "...");
        Gauge.writeMessage("Tagged to skip");
        throw new SkipScenarioException("Tagged to skip");
    }

    @BeforeScenario()
    public void beforeHook(ExecutionContext context) {
        Gauge.writeMessage("Before Scenario 2");
    }

    @Step("Vowels in English language are <vowelString>.")
    public void setLanguageVowels(String vowelString) {
        vowels = new HashSet<>();
        for (char ch : vowelString.toCharArray()) {
            vowels.add(ch);
        }
    }

    @Step("The word <word> has <expectedCount> vowels.")
    public void verifyVowelsCountInWord(String word, int expectedCount) {
        int actualCount = countVowels(word);
        assertThat(expectedCount).isEqualTo(actualCount);
    }

    @Step("Almost all words have vowels <wordsTable>")
    public void verifyVowelsCountInMultipleWords(Table wordsTable) {
        for (TableRow row : wordsTable.getTableRows()) {
            String word = row.getCell("Word");
            int expectedCount = Integer.parseInt(row.getCell("Vowel Count"));
            int actualCount = countVowels(word);

            assertThat(expectedCount).isEqualTo(actualCount);
        }
    }

    @Step("Skip the test <string>")
    public void skipTest(String string) {
        throw new SkipScenarioException("Tagged to skip");
    }

    @Step("Passing Step")
    public void notSkipTest() {
    }

    @Step("Falling Step")
    public void failStep() {
        fail("Falling Step");
    }

    private int countVowels(String word) {
        int count = 0;
        for (char ch : word.toCharArray()) {
            if (vowels.contains(ch)) {
                count++;
            }
        }
        return count;
    }
}

and spec file was like

Specification Heading
=====================

This is an executable specification file. This file follows markdown syntax.
Every heading in this file denotes a scenario. Every bulleted point denotes a step.

To execute this specification, run
	gauge specs


* Vowels in English language are "aeiou".

Vowel counts in single word
---------------------------

tags: single word

* The word "gauge" has "4" vowels.


Vowel counts in multiple word
-----------------------------

This is the second scenario in this specification

Here's a step that takes a table

* Almost all words have vowels
     |Word  |Vowel Count|
     |------|-----------|
     |Gauge |3          |
     |Mingle|2          |
     |Snap  |1          |
     |GoCD  |1          |
     |Rhythm|0          |

skipping scenario
------------
tags: skip
* Falling Step

For multiple Before hook
image

I just added the following BeforeScenario code the above shared code

    @BeforeScenario()
    public void beforeHook(ExecutionContext context) {
        Gauge.writeMessage("Before Scenario 2");
    }

Normally, there should be two failing scenarios: one from * The word "gauge" has "4" vowels. and another from * Falling Step. Since we tagged skipping scenarios with skip and implemented a BeforeScenario hook to handle them, the code is now skipping those scenarios as intended and generating the report correctly.

dependabot bot and others added 4 commits August 25, 2025 19:48
Bumps the maven-dependencies group with 4 updates: [org.junit:junit-bom](https://github.com/junit-team/junit-framework), [com.github.javaparser:javaparser-core](https://github.com/javaparser/javaparser), [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) and [org.sonatype.central:central-publishing-maven-plugin](https://github.com/sonatype/central-publishing-maven-plugin).

Updates `org.junit:junit-bom` from 5.13.0 to 5.13.2
- [Release notes](https://github.com/junit-team/junit-framework/releases)
- [Commits](junit-team/junit-framework@r5.13.0...r5.13.2)

Updates `com.github.javaparser:javaparser-core` from 3.26.4 to 3.27.0
- [Release notes](https://github.com/javaparser/javaparser/releases)
- [Changelog](https://github.com/javaparser/javaparser/blob/master/changelog.md)
- [Commits](javaparser/javaparser@javaparser-parent-3.26.4...javaparser-parent-3.27.0)

Updates `com.puppycrawl.tools:checkstyle` from 10.25.0 to 10.26.1
- [Release notes](https://github.com/checkstyle/checkstyle/releases)
- [Commits](checkstyle/checkstyle@checkstyle-10.25.0...checkstyle-10.26.1)

Updates `org.sonatype.central:central-publishing-maven-plugin` from 0.7.0 to 0.8.0
- [Commits](https://github.com/sonatype/central-publishing-maven-plugin/commits)

---
updated-dependencies:
- dependency-name: org.junit:junit-bom
  dependency-version: 5.13.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven-dependencies
- dependency-name: com.github.javaparser:javaparser-core
  dependency-version: 3.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-dependencies
- dependency-name: com.puppycrawl.tools:checkstyle
  dependency-version: 10.26.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-dependencies
- dependency-name: org.sonatype.central:central-publishing-maven-plugin
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-dependencies
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: serhatozdursun <[email protected]>
…nd HookExecutionStage; add corresponding tests

Signed-off-by: serhatozdursun <[email protected]>
…arked as skipped in before hook

Signed-off-by: serhatozdursun <[email protected]>
Bumps the maven-dependencies group with 3 updates: [io.grpc:grpc-bom](https://github.com/grpc/grpc-java), [org.junit:junit-bom](https://github.com/junit-team/junit-framework) and [org.apache.maven.plugins:maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin).

Updates `io.grpc:grpc-bom` from 1.73.0 to 1.74.0
- [Release notes](https://github.com/grpc/grpc-java/releases)
- [Commits](grpc/grpc-java@v1.73.0...v1.74.0)

Updates `org.junit:junit-bom` from 5.13.2 to 5.13.4
- [Release notes](https://github.com/junit-team/junit-framework/releases)
- [Commits](junit-team/junit-framework@r5.13.2...r5.13.4)

Updates `org.apache.maven.plugins:maven-gpg-plugin` from 3.2.7 to 3.2.8
- [Release notes](https://github.com/apache/maven-gpg-plugin/releases)
- [Commits](apache/maven-gpg-plugin@maven-gpg-plugin-3.2.7...maven-gpg-plugin-3.2.8)

---
updated-dependencies:
- dependency-name: io.grpc:grpc-bom
  dependency-version: 1.74.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-dependencies
- dependency-name: org.junit:junit-bom
  dependency-version: 5.13.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven-dependencies
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-version: 3.2.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven-dependencies
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: serhatozdursun <[email protected]>
@serhatozdursun serhatozdursun force-pushed the feat/skip-scenario-in-beforescenario-hook branch from cac8f2c to 804bd23 Compare August 25, 2025 16:50
…at/skip-scenario-in-beforescenario-hook

# Conflicts:
#	pom.xml
@chadlwilson chadlwilson marked this pull request as draft August 25, 2025 17:04
@serhatozdursun serhatozdursun marked this pull request as ready for review August 26, 2025 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Cannot dynamically skip scenario during BeforeScenario hook
2 participants