From ef488cb0e2fe9e611c52f729cc284f5b592a8ee4 Mon Sep 17 00:00:00 2001 From: John Ferguson Smart Date: Fri, 24 Nov 2023 12:22:25 +0000 Subject: [PATCH] Fixed an issue where BrowserStack test status results were not being updated in parallel cucumber test execution --- .../core/steps/BaseStepListener.java | 16 ++++++-- .../core/plugin/SerenityReporterParallel.java | 39 +++++++++++++++---- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/serenity-core/src/main/java/net/thucydides/core/steps/BaseStepListener.java b/serenity-core/src/main/java/net/thucydides/core/steps/BaseStepListener.java index 2aaa45ff3..f7716f0af 100644 --- a/serenity-core/src/main/java/net/thucydides/core/steps/BaseStepListener.java +++ b/serenity-core/src/main/java/net/thucydides/core/steps/BaseStepListener.java @@ -555,6 +555,10 @@ private void recordNewTestOutcome(String testMethod, TestOutcome newTestOutcome) } private void updateSessionIdIfKnown() { + updateSessionIdIfKnown(getCurrentTestOutcome()); + } + + private void updateSessionIdIfKnown(TestOutcome testOutcome) { SessionId sessionId = ThucydidesWebDriverSupport.getSessionId(); if (sessionId != null) { getCurrentTestOutcome().setSessionId(sessionId.toString()); @@ -643,14 +647,14 @@ public void testFinished(final TestOutcome outcome, boolean isInDataDrivenTest, LifecycleRegister.clear(); } - public void cleanupWebdriverInstance(boolean isInDataDrivenTest) { + public void cleanupWebdriverInstance(boolean isInDataDrivenTest, TestOutcome testOutcome) { if (currentTestIsABrowserTest()) { - getCurrentTestOutcome().setDriver(getDriverUsedInThisTest()); - updateSessionIdIfKnown(); + testOutcome.setDriver(getDriverUsedInThisTest()); + updateSessionIdIfKnown(testOutcome); AtTheEndOfAWebDriverTest.invokeCustomTeardownLogicWithDriver( getEventBus().getEnvironmentVariables(), - getCurrentTestOutcome(), + testOutcome, SerenityWebdriverManager.inThisTestThread().getCurrentDriver()); if (isInDataDrivenTest) { @@ -662,6 +666,10 @@ public void cleanupWebdriverInstance(boolean isInDataDrivenTest) { } } + public void cleanupWebdriverInstance(boolean isInDataDrivenTest) { + cleanupWebdriverInstance(isInDataDrivenTest, getCurrentTestOutcome()); + } + private void handlePostponedParallelExecution(TestOutcome outcome, boolean isInDataDrivenTest) { getCurrentTestOutcome().setDriver(TestSession.getTestSessionContext().getDriverUsedInThisTest()); updateSessionIdIfKnown(); diff --git a/serenity-cucumber/src/main/java/io/cucumber/core/plugin/SerenityReporterParallel.java b/serenity-cucumber/src/main/java/io/cucumber/core/plugin/SerenityReporterParallel.java index 0ceab1777..76b639341 100644 --- a/serenity-cucumber/src/main/java/io/cucumber/core/plugin/SerenityReporterParallel.java +++ b/serenity-cucumber/src/main/java/io/cucumber/core/plugin/SerenityReporterParallel.java @@ -287,7 +287,7 @@ private void handleTestCaseStarted(TestCaseStarted event) { startProcessingExampleLine(scenarioId, featurePath, event.getTestCase(), Long.valueOf(event.getTestCase().getLocation().getLine()), scenarioName); } } - final String scenarioIdForBackground = scenarioId; + final String scenarioIdForBackground = scenarioId; TestSourcesModel.getBackgroundForTestCase(astNode).ifPresent(background -> handleBackground(featurePath, scenarioIdForBackground, background)); // // Check for tags @@ -371,9 +371,34 @@ private void handleTestCaseFinished(TestCaseFinished event) { getContext(featurePath).clearStepQueue(event.getTestCase()); getContext(featurePath).stepEventBus().clear(); + // We don't have the TestOutcome object ready yet, so we need to create a temporary one based on the event + // The feature name is the first part of getContext(featurePath).getCurrentScenario(scenarioId) up to the first semicolon + // The scenario name is the second part of getContext(featurePath).getCurrentScenario(scenarioId) after the first semicolon + String featureName = getContext(featurePath).getCurrentScenario(scenarioId).split(";")[0]; + TestOutcome testOutcome = TestOutcome.forTestInStory(event.getTestCase().getName(), + Story.called(featureName)); + testOutcome.setResult(serenityTestResultFrom(event.getResult().getStatus())); + if (event.getResult().getError() != null) { + testOutcome.testFailedWith(event.getResult().getError()); + } // We need to close the driver here to avoid wasting resources and causing timeouts with Selenium Grid services - getContext(featurePath).stepEventBus().getBaseStepListener().cleanupWebdriverInstance(getContext(featurePath).stepEventBus().isCurrentTestDataDriven()); + getContext(featurePath) + .stepEventBus() + .getBaseStepListener() + .cleanupWebdriverInstance(getContext(featurePath).stepEventBus().isCurrentTestDataDriven(), testOutcome); + + } + + private static final Map TEST_RESULT_MAP = Map.of( + Status.PASSED, TestResult.SUCCESS, + Status.FAILED, TestResult.FAILURE, Status.SKIPPED, TestResult.SKIPPED, + Status.PENDING, TestResult.PENDING, + Status.UNDEFINED, TestResult.UNDEFINED, + Status.AMBIGUOUS, TestResult.UNDEFINED); + private TestResult serenityTestResultFrom(Status status) { + // Use a map to convert the Status enum to a Serenity TestResult value + return TEST_RESULT_MAP.get(status); } private Status eventStatusFor(TestCaseFinished event) { @@ -446,7 +471,7 @@ private void handleTestStepStarted(TestStepStarted event) { io.cucumber.messages.types.Step currentStep = getContext(featurePath).getCurrentStep(event.getTestCase()); String stepTitle = stepTitleFrom(currentStep, pickleTestStep); getContext(featurePath).addStepEventBusEvent( - new StepStartedEvent(ExecutedStepDescription.withTitle(stepTitle),startTime)); + new StepStartedEvent(ExecutedStepDescription.withTitle(stepTitle), startTime)); getContext(featurePath).addStepEventBusEvent( new UpdateCurrentStepTitleEvent(normalized(stepTitle))); } @@ -903,7 +928,7 @@ private void startProcessingExampleLine(String scenarioId, URI featurePath, Test private void reinitializeRemoteWebDriver() { WebDriver webDriver = SerenityWebdriverManager.inThisTestThread().getCurrentDriver(); - if ((webDriver != null) && (webDriver instanceof WebDriverFacade)) { + if ((webDriver != null) && (webDriver instanceof WebDriverFacade)) { ((WebDriverFacade) webDriver).reinitializeRemoteWebDriver(); } } @@ -933,8 +958,8 @@ private void setTableScenarioOutline(String scenarioId, URI featurePath) { } - private void handleBackground(URI featurePath,String scenarioId, Background background) { - getContext(featurePath).setWaitingToProcessBackgroundSteps(scenarioId,true); + private void handleBackground(URI featurePath, String scenarioId, Background background) { + getContext(featurePath).setWaitingToProcessBackgroundSteps(scenarioId, true); String backgroundName = background.getName(); if (backgroundName != null) { getContext(featurePath).addStepEventBusEvent( @@ -989,7 +1014,7 @@ private void recordStepResult(URI featurePath, TestCase testCase, Result result, private void recordFinalResult(String scenarioId, URI featurePath, TestCase testCase) { ScenarioContextParallel context = getContext(featurePath); if (context.isWaitingToProcessBackgroundSteps(scenarioId)) { - context.setWaitingToProcessBackgroundSteps(scenarioId,false); + context.setWaitingToProcessBackgroundSteps(scenarioId, false); } else { updateResultFromTags(scenarioId, featurePath, testCase, context.getScenarioTags(scenarioId)); }