From 484fa90a683665c5ca47cc8b4820ae076be005e2 Mon Sep 17 00:00:00 2001 From: SergKhram Date: Wed, 26 Nov 2025 18:44:38 +0400 Subject: [PATCH 1/2] Added api to get test status in after hooks --- README.md | 125 +++++++++++++++ .../core/allure_manager/ctx/hooks.go | 15 +- .../core/allure_manager/ctx/hooks_test.go | 124 +++++++++++++++ .../core/allure_manager/ctx/test_ctx.go | 4 + .../core/allure_manager/ctx/test_ctx_test.go | 144 ++++++++++++++++++ .../allure_manager/manager/attachment_test.go | 4 + .../manager/execution_management.go | 2 +- .../manager/execution_management_test.go | 88 +++++++++++ pkg/framework/core/common/common.go | 12 ++ pkg/framework/core/common/common_test.go | 109 ++++++++++++- .../core/common/step_context_test.go | 4 + pkg/framework/core/common/steps_test.go | 4 + pkg/framework/provider/provider.go | 1 + pkg/framework/provider/test.go | 3 + pkg/framework/runner/runner.go | 5 + pkg/framework/runner/runner_test.go | 4 + 16 files changed, 644 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6f71721..b1828f2 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ The project started as a fork of testify, but over time it got its own runner an + [Test with attachments](#test-with-attachment) + [Run few parallel suites](#run-few-parallel-suites) + [Setup hooks](#setup-hooks) + + [Access test status in hooks](#access-test-status-in-hooks) + [XSkip](#xskip) + [:rocket: Parametrized tests](#parametrized-test) + [Setup test](#setup-test) @@ -38,6 +39,61 @@ Providing a separate package allows you to customize your work with allure.
### What's new? +**New Feature: Access Test Status in AfterEach Hook** + +#### GetCurrentTestResult method + +Now you can access test execution result in `AfterEach` hook:
+- `t.GetCurrentTestResult()` - returns current test result with status and details
+ +This allows you to perform conditional actions based on test status (Passed, Failed, Broken, Skipped).
+ +**Basic Example:** + +```go +func (s *MySuite) AfterEach(t provider.T) { + result := t.GetCurrentTestResult() + if result != nil && result.Status == allure.Failed { + // Save screenshot only for failed tests + screenshot := takeScreenshot() + t.WithNewAttachment("failure.png", allure.ImagePng, screenshot) + + // Check if BeforeEach failed + if strings.Contains(result.GetStatusMessage(), "Setup failed") { + t.Log("Test didn't run - BeforeEach hook failed, skipping cleanup") + } + } +} +``` + +**How it works with BeforeEach failures:** + +When `BeforeEach` fails, the test doesn't run, but you can still detect the failure in `AfterEach`: + +```go +func (s *MySuite) BeforeEach(t provider.T) { + // This will fail + t.Require().True(false, "Setup failed") +} + +func (s *MySuite) AfterEach(t provider.T) { + result := t.GetCurrentTestResult() + if result != nil && result.Status == allure.Failed && + strings.Contains(result.GetStatusMessage(), "Setup failed") { + t.Log("BeforeEach failed - test was not executed") + } +} +``` + +**Important Notes:** + +:information_source: This feature **does not change** hook or test behavior - it only provides read-only access to test status.
+:information_source: `GetCurrentTestResult()` is available only in `AfterEach` hook.
+:information_source: Returns `nil` in other contexts (BeforeEach, BeforeAll, AfterAll, test body).
+:information_source: For **parametrized tests** (using `t.Run()`): AfterEach is called once for the parent test, not for each subtest.
+:information_source: For **nested tests**: AfterEach sees the parent test status, which may be Passed even if subtests failed.
+ + **Release v0.6.17** #### WithTestSetup/WithTestTeardown methods @@ -668,6 +724,75 @@ Output to Allure: ![](.resources/example_befores_afters.png) +### [Access test status in hooks](examples/suite_demo/test_status_in_hooks_test.go) + +You can access test execution result in `AfterEach` hook to perform conditional actions based on test status. + +Test code: + +```go +package suite_demo + +import ( + "strings" + "testing" + + "github.com/ozontech/allure-go/pkg/allure" + "github.com/ozontech/allure-go/pkg/framework/provider" + "github.com/ozontech/allure-go/pkg/framework/suite" +) + +type StatusInHooksSuite struct { + suite.Suite +} + +func (s *StatusInHooksSuite) AfterEach(t provider.T) { + // Get the test result from execution context + result := t.GetCurrentTestResult() + + if result != nil { + switch result.Status { + case allure.Failed: + // Check if BeforeEach failed + if strings.Contains(result.GetStatusMessage(), "Setup failed") { + t.Log("BeforeEach hook failed, skipping cleanup") + return + } + + // Handle test failure + t.Logf("Test failed: %s", result.Name) + // You can save screenshot, logs, etc. + // screenshot := takeScreenshot() + // t.WithNewAttachment("failure.png", allure.ImagePng, screenshot) + + case allure.Passed: + t.Logf("Test passed: %s", result.Name) + // Cleanup test data for successful tests + + case allure.Broken: + t.Logf("Test broken: %s", result.Name) + } + } +} + +func (s *StatusInHooksSuite) TestExample(t provider.T) { + t.Title("Example test") + t.Require().Equal(1, 1) +} + +func TestStatusInHooks(t *testing.T) { + suite.RunSuite(t, new(StatusInHooksSuite)) +} +``` + +Key points: +- `t.GetCurrentTestResult()` returns `*allure.Result` with test status and details in `AfterEach` +- Available statuses: `allure.Passed`, `allure.Failed`, `allure.Broken`, `allure.Skipped` +- Returns `nil` in contexts other than `AfterEach` (e.g., in test body, `BeforeEach`, or `AfterAll`) +- Check `result.GetStatusMessage()` for "Setup failed" to detect `BeforeEach` failures +- Does not change hook or test behavior - only provides read access to test status + + ### [XSkip](examples/suite_demo/fails_test.go) Test code: diff --git a/pkg/framework/core/allure_manager/ctx/hooks.go b/pkg/framework/core/allure_manager/ctx/hooks.go index 5e32eab..f55de51 100644 --- a/pkg/framework/core/allure_manager/ctx/hooks.go +++ b/pkg/framework/core/allure_manager/ctx/hooks.go @@ -9,8 +9,9 @@ import ( ) type hooksCtx struct { - name string - container *allure.Container + name string + container *allure.Container + testResult *allure.Result // Result of the test (for AfterEach hook) } // NewAfterAllCtx returns after all context @@ -23,6 +24,11 @@ func NewAfterEachCtx(container *allure.Container) provider.ExecutionContext { return &hooksCtx{container: container, name: constants.AfterEachContextName} } +// NewAfterEachCtxWithResult returns after each context with test result +func NewAfterEachCtxWithResult(container *allure.Container, testResult *allure.Result) provider.ExecutionContext { + return &hooksCtx{container: container, testResult: testResult, name: constants.AfterEachContextName} +} + // NewBeforeAllCtx returns before all context func NewBeforeAllCtx(container *allure.Container) provider.ExecutionContext { return &hooksCtx{container: container, name: constants.BeforeAllContextName} @@ -49,6 +55,11 @@ func (ctx *hooksCtx) GetName() string { return ctx.name } +// GetTestResult returns test result if available (for AfterEach hook) +func (ctx *hooksCtx) GetTestResult() *allure.Result { + return ctx.testResult +} + // AddAttachments adds attachment to the execution context func (ctx *hooksCtx) AddAttachments(attachments ...*allure.Attachment) { if len(attachments) == 0 { diff --git a/pkg/framework/core/allure_manager/ctx/hooks_test.go b/pkg/framework/core/allure_manager/ctx/hooks_test.go index 74dbb9f..7d2e786 100644 --- a/pkg/framework/core/allure_manager/ctx/hooks_test.go +++ b/pkg/framework/core/allure_manager/ctx/hooks_test.go @@ -95,3 +95,127 @@ func TestHooksCtx_AddAttachment(t *testing.T) { require.Len(t, afterEach.container.Afters[0].Attachments, 1) require.Equal(t, attach, afterEach.container.Afters[0].Attachments[0]) } + +// Tests for GetTestResult functionality +func TestNewAfterEachCtxWithResult(t *testing.T) { + container := allure.NewContainer() + result := allure.NewResult("TestName", "TestFullName") + result.Status = allure.Passed + + ctx := NewAfterEachCtxWithResult(container, result) + require.NotNil(t, ctx) + + // Verify we can get the result back + retrievedResult := ctx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, result, retrievedResult) + require.Equal(t, allure.Passed, retrievedResult.Status) + require.Equal(t, "TestName", retrievedResult.Name) +} + +func TestHooksCtx_GetTestResult_AfterEach(t *testing.T) { + container := allure.NewContainer() + testResult := allure.NewResult("TestName", "TestFullName") + testResult.Status = allure.Failed + testResult.SetStatusMessage("Test failed") + + ctx := NewAfterEachCtxWithResult(container, testResult) + + result := ctx.GetTestResult() + require.NotNil(t, result) + require.Equal(t, allure.Failed, result.Status) + require.Equal(t, "TestName", result.Name) + require.Equal(t, "Test failed", result.GetStatusMessage()) +} + +func TestHooksCtx_GetTestResult_NilForOtherContexts(t *testing.T) { + container := allure.NewContainer() + + // BeforeEach should return nil + beforeEachCtx := NewBeforeEachCtx(container) + require.Nil(t, beforeEachCtx.GetTestResult()) + + // BeforeAll should return nil + beforeAllCtx := NewBeforeAllCtx(container) + require.Nil(t, beforeAllCtx.GetTestResult()) + + // AfterEach without result should return nil + afterEachCtx := NewAfterEachCtx(container) + require.Nil(t, afterEachCtx.GetTestResult()) +} + +// Tests for parametrized test scenarios +func TestHooksCtx_GetTestResult_ParametrizedTestScenario(t *testing.T) { + // Simulate a parametrized test where the parent test is Passed + // even though subtests may have failed + container := allure.NewContainer() + parentResult := allure.NewResult("TestParametrized", "FullTestParametrized") + parentResult.Status = allure.Passed // Parent can be Passed even if subtests fail + + ctx := NewAfterEachCtxWithResult(container, parentResult) + + result := ctx.GetTestResult() + require.NotNil(t, result) + require.Equal(t, allure.Passed, result.Status) + require.Equal(t, "TestParametrized", result.Name) +} + +// Test for nested test scenario +func TestHooksCtx_GetTestResult_NestedTestScenario(t *testing.T) { + // Simulate nested tests where parent test status may differ from subtests + container := allure.NewContainer() + + // Parent test can be Passed even if nested subtests failed + parentResult := allure.NewResult("TestNested", "FullTestNested") + parentResult.Status = allure.Passed + + ctx := NewAfterEachCtxWithResult(container, parentResult) + + result := ctx.GetTestResult() + require.NotNil(t, result) + require.Equal(t, allure.Passed, result.Status) +} + +// Test for BeforeEach failure scenario +func TestHooksCtx_GetTestResult_BeforeEachFailure(t *testing.T) { + container := allure.NewContainer() + + // When BeforeEach fails, test doesn't run but result is created with Failed status + result := allure.NewResult("TestWillNotRun", "FullTestWillNotRun") + result.Status = allure.Failed + result.SetStatusMessage("TestWillNotRun/BeforeEach setup was failed") + + ctx := NewAfterEachCtxWithResult(container, result) + + retrievedResult := ctx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Failed, retrievedResult.Status) + require.Contains(t, retrievedResult.GetStatusMessage(), "setup was failed") +} + +// Test concurrent access safety +func TestHooksCtx_GetTestResult_ConcurrentAccess(t *testing.T) { + container := allure.NewContainer() + result := allure.NewResult("TestConcurrent", "FullTestConcurrent") + result.Status = allure.Passed + + ctx := NewAfterEachCtxWithResult(container, result) + + // Multiple goroutines reading the result + const numGoroutines = 10 + done := make(chan bool, numGoroutines) + + for i := 0; i < numGoroutines; i++ { + go func() { + r := ctx.GetTestResult() + require.NotNil(t, r) + require.Equal(t, allure.Passed, r.Status) + done <- true + }() + } + + // Wait for all goroutines + for i := 0; i < numGoroutines; i++ { + <-done + } +} diff --git a/pkg/framework/core/allure_manager/ctx/test_ctx.go b/pkg/framework/core/allure_manager/ctx/test_ctx.go index 3c5fa52..ae05f28 100644 --- a/pkg/framework/core/allure_manager/ctx/test_ctx.go +++ b/pkg/framework/core/allure_manager/ctx/test_ctx.go @@ -24,6 +24,10 @@ func (ctx *testCtx) GetName() string { return ctx.name } +func (ctx *testCtx) GetTestResult() *allure.Result { + return ctx.result +} + func (ctx *testCtx) AddAttachments(attachments ...*allure.Attachment) { ctx.result.Attachments = append(ctx.result.Attachments, attachments...) } diff --git a/pkg/framework/core/allure_manager/ctx/test_ctx_test.go b/pkg/framework/core/allure_manager/ctx/test_ctx_test.go index 6191d85..5469f9d 100644 --- a/pkg/framework/core/allure_manager/ctx/test_ctx_test.go +++ b/pkg/framework/core/allure_manager/ctx/test_ctx_test.go @@ -35,3 +35,147 @@ func TestTestCtx_AddAttachment(t *testing.T) { require.Len(t, test.result.Attachments, 1) require.Equal(t, attach, test.result.Attachments[0]) } + +// Tests for GetTestResult functionality in test context +func TestTestCtx_GetTestResult(t *testing.T) { + result := allure.NewResult("TestName", "TestFullName") + result.Status = allure.Passed + + testCtx := NewTestCtx(result) + + retrievedResult := testCtx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, result, retrievedResult) + require.Equal(t, allure.Passed, retrievedResult.Status) + require.Equal(t, "TestName", retrievedResult.Name) +} + +func TestTestCtx_GetTestResult_WithDifferentStatuses(t *testing.T) { + testCases := []struct { + name string + status allure.Status + }{ + {"Passed", allure.Passed}, + {"Failed", allure.Failed}, + {"Broken", allure.Broken}, + {"Skipped", allure.Skipped}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := allure.NewResult("Test", "FullTest") + result.Status = tc.status + + testCtx := NewTestCtx(result) + + retrievedResult := testCtx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, tc.status, retrievedResult.Status) + }) + } +} + +func TestTestCtx_GetTestResult_NilResult(t *testing.T) { + testCtx := testCtx{name: constants.TestContextName, result: nil} + + retrievedResult := testCtx.GetTestResult() + require.Nil(t, retrievedResult) +} + +func TestTestCtx_GetName_TestContext(t *testing.T) { + result := allure.NewResult("TestName", "TestFullName") + testCtx := NewTestCtx(result) + + name := testCtx.GetName() + require.Equal(t, constants.TestContextName, name) +} + +// Additional tests for parametrized and nested test scenarios +func TestTestCtx_GetTestResult_ParametrizedTest(t *testing.T) { + // Simulate parametrized test result + result := allure.NewResult("TestParametrized", "suite.TestParametrized") + result.Status = allure.Passed + + testCtx := NewTestCtx(result) + + retrievedResult := testCtx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Passed, retrievedResult.Status) + require.Equal(t, "TestParametrized", retrievedResult.Name) +} + +func TestTestCtx_GetTestResult_NestedTest(t *testing.T) { + // Simulate nested test result + result := allure.NewResult("TestNested", "suite.TestNested") + result.Status = allure.Passed + + testCtx := NewTestCtx(result) + + retrievedResult := testCtx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Passed, retrievedResult.Status) +} + +func TestTestCtx_GetTestResult_WithStatusDetails(t *testing.T) { + result := allure.NewResult("TestWithDetails", "suite.TestWithDetails") + result.Status = allure.Failed + result.SetStatusMessage("Assertion failed: expected 1, got 2") + result.SetStatusTrace("trace stack here") + + testCtx := NewTestCtx(result) + + retrievedResult := testCtx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Failed, retrievedResult.Status) + require.Equal(t, "Assertion failed: expected 1, got 2", retrievedResult.GetStatusMessage()) + require.Equal(t, "trace stack here", retrievedResult.GetStatusTrace()) +} + +func TestTestCtx_GetTestResult_BrokenTest(t *testing.T) { + result := allure.NewResult("BrokenTest", "suite.BrokenTest") + result.Status = allure.Broken + result.SetStatusMessage("Panic occurred") + + testCtx := NewTestCtx(result) + + retrievedResult := testCtx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Broken, retrievedResult.Status) + require.Contains(t, retrievedResult.GetStatusMessage(), "Panic occurred") +} + +func TestTestCtx_GetTestResult_SkippedTest(t *testing.T) { + result := allure.NewResult("SkippedTest", "suite.SkippedTest") + result.Status = allure.Skipped + result.SetStatusMessage("Test skipped") + + testCtx := NewTestCtx(result) + + retrievedResult := testCtx.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Skipped, retrievedResult.Status) +} + +// Test concurrent access to result +func TestTestCtx_GetTestResult_ConcurrentAccess(t *testing.T) { + result := allure.NewResult("ConcurrentTest", "suite.ConcurrentTest") + result.Status = allure.Passed + + testCtx := NewTestCtx(result) + + const numGoroutines = 20 + done := make(chan bool, numGoroutines) + + for i := 0; i < numGoroutines; i++ { + go func() { + r := testCtx.GetTestResult() + require.NotNil(t, r) + require.Equal(t, allure.Passed, r.Status) + done <- true + }() + } + + for i := 0; i < numGoroutines; i++ { + <-done + } +} diff --git a/pkg/framework/core/allure_manager/manager/attachment_test.go b/pkg/framework/core/allure_manager/manager/attachment_test.go index 6674b63..adabe0e 100644 --- a/pkg/framework/core/allure_manager/manager/attachment_test.go +++ b/pkg/framework/core/allure_manager/manager/attachment_test.go @@ -34,6 +34,10 @@ func (m *execMockAttach) GetName() string { return m.name } +func (m *execMockAttach) GetTestResult() *allure.Result { + return nil +} + func TestAllureManager_Attachment(t *testing.T) { mock := newExecMockAttach(constants.TestContextName) attach := allure.NewAttachment("testAttach", allure.Text, []byte("test")) diff --git a/pkg/framework/core/allure_manager/manager/execution_management.go b/pkg/framework/core/allure_manager/manager/execution_management.go index f28d48b..77a536d 100644 --- a/pkg/framework/core/allure_manager/manager/execution_management.go +++ b/pkg/framework/core/allure_manager/manager/execution_management.go @@ -14,7 +14,7 @@ func (a *allureManager) BeforeEachContext() { // AfterEachContext initiate after each context func (a *allureManager) AfterEachContext() { - a.executionContext = ctx.NewAfterEachCtx(a.testMeta.GetContainer()) + a.executionContext = ctx.NewAfterEachCtxWithResult(a.testMeta.GetContainer(), a.testMeta.GetResult()) } // BeforeAllContext initiate before all context diff --git a/pkg/framework/core/allure_manager/manager/execution_management_test.go b/pkg/framework/core/allure_manager/manager/execution_management_test.go index 381e0ef..2aa34f7 100644 --- a/pkg/framework/core/allure_manager/manager/execution_management_test.go +++ b/pkg/framework/core/allure_manager/manager/execution_management_test.go @@ -124,3 +124,91 @@ func TestAllureManager_TestContext(t *testing.T) { require.NotNil(t, manager.executionContext) require.Equal(t, constants.TestContextName, manager.executionContext.GetName()) } + +// Tests for context creation with test results +func TestAllureManager_AfterEachContextWithResult(t *testing.T) { + result := allure.NewResult("TestName", "FullTestName") + result.Status = allure.Passed + + manager := allureManager{ + testMeta: &testMetaMockExecM{ + result: result, + container: allure.NewContainer(), + }, + } + + // Create AfterEach context (should have access to test result) + manager.AfterEachContext() + + require.NotNil(t, manager.executionContext) + require.Equal(t, constants.AfterEachContextName, manager.executionContext.GetName()) + + // Verify we can get the test result from the context + retrievedResult := manager.executionContext.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Passed, retrievedResult.Status) + require.Equal(t, "TestName", retrievedResult.Name) +} + +func TestAllureManager_AfterEachContextWithFailedResult(t *testing.T) { + result := allure.NewResult("FailedTest", "FullFailedTest") + result.Status = allure.Failed + result.SetStatusMessage("Test assertion failed") + + manager := allureManager{ + testMeta: &testMetaMockExecM{ + result: result, + container: allure.NewContainer(), + }, + } + + manager.AfterEachContext() + + retrievedResult := manager.executionContext.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Failed, retrievedResult.Status) + require.Equal(t, "Test assertion failed", retrievedResult.GetStatusMessage()) +} + +// Test parametrized test scenario +func TestAllureManager_AfterEachContext_ParametrizedTestScenario(t *testing.T) { + // Parent test result (parametrized test) + parentResult := allure.NewResult("TestParametrized", "FullTestParametrized") + parentResult.Status = allure.Passed // Parent can be Passed even if subtests fail + + manager := allureManager{ + testMeta: &testMetaMockExecM{ + result: parentResult, + container: allure.NewContainer(), + }, + } + + manager.AfterEachContext() + + retrievedResult := manager.executionContext.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Passed, retrievedResult.Status) + require.Equal(t, "TestParametrized", retrievedResult.Name) +} + +// Test BeforeEach failure scenario +func TestAllureManager_AfterEachContext_BeforeEachFailure(t *testing.T) { + // When BeforeEach fails, test doesn't run but result is created + result := allure.NewResult("TestWillNotRun", "FullTestWillNotRun") + result.Status = allure.Failed + result.SetStatusMessage("TestName/BeforeEach setup was failed") + + manager := allureManager{ + testMeta: &testMetaMockExecM{ + result: result, + container: allure.NewContainer(), + }, + } + + manager.AfterEachContext() + + retrievedResult := manager.executionContext.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, allure.Failed, retrievedResult.Status) + require.Contains(t, retrievedResult.GetStatusMessage(), "setup was failed") +} diff --git a/pkg/framework/core/common/common.go b/pkg/framework/core/common/common.go index 7cc462a..e259c71 100644 --- a/pkg/framework/core/common/common.go +++ b/pkg/framework/core/common/common.go @@ -101,6 +101,18 @@ func (c *Common) GetProvider() provider.Provider { return c.Provider } +// GetCurrentTestResult returns the current test result (available in AfterEach hook) +func (c *Common) GetCurrentTestResult() *allure.Result { + if c.Provider != nil && c.Provider.ExecutionContext() != nil { + // Only return result in AfterEach context + ctxName := c.Provider.ExecutionContext().GetName() + if ctxName == constants.AfterEachContextName { + return c.Provider.ExecutionContext().GetTestResult() + } + } + return nil +} + // SkipOnPrint skips creating of report for current test func (c *Common) SkipOnPrint() { c.GetResult().SkipOnPrint() diff --git a/pkg/framework/core/common/common_test.go b/pkg/framework/core/common/common_test.go index 9d17e43..e56d624 100644 --- a/pkg/framework/core/common/common_test.go +++ b/pkg/framework/core/common/common_test.go @@ -42,12 +42,16 @@ func (m *executionContextCommMock) GetName() string { return m.name } +func (m *executionContextCommMock) GetTestResult() *allure.Result { + return nil +} + type providerMockCommon struct { provider.AllureForwardFull testMetaMock provider.TestMeta suiteMetaMock *suiteMetaMockCommon - executionMock *executionContextCommMock + executionMock provider.ExecutionContext // Changed to interface } func newProviderMockCommon(name, fullName string) *providerMockCommon { @@ -428,3 +432,106 @@ func TestCopyLabels(t *testing.T) { require.Len(t, target.GetLabels(allure.Owner), 1) require.Equal(t, owner, target.GetLabels(allure.Owner)[0]) } + +// Tests for GetCurrentTestResult functionality +func TestCommon_GetCurrentTestResult_AfterEachContext(t *testing.T) { + testResult := allure.NewResult("TestName", "TestFullName") + testResult.Status = allure.Failed + testResult.SetStatusMessage("Test failed") + + // Mock execution context that returns test result (AfterEach context) + execContext := &executionContextWithResult{ + name: constants.AfterEachContextName, + testResult: testResult, + } + + provider := &providerMockCommon{ + testMetaMock: &testMetaMockCommon{result: testResult}, + executionMock: execContext, + } + + comm := Common{Provider: provider} + + result := comm.GetCurrentTestResult() + require.NotNil(t, result) + require.Equal(t, allure.Failed, result.Status) + require.Equal(t, "TestName", result.Name) + require.Equal(t, "Test failed", result.GetStatusMessage()) +} + +func TestCommon_GetCurrentTestResult_NilInTestContext(t *testing.T) { + testResult := allure.NewResult("TestName", "TestFullName") + + // Mock test context - should return nil + execContext := &executionContextWithResult{ + name: constants.TestContextName, + testResult: testResult, + } + + provider := &providerMockCommon{ + testMetaMock: &testMetaMockCommon{result: testResult}, + executionMock: execContext, + } + + comm := Common{Provider: provider} + + result := comm.GetCurrentTestResult() + require.Nil(t, result, "GetCurrentTestResult should return nil in test context") +} + +func TestCommon_GetCurrentTestResult_NilInBeforeEachContext(t *testing.T) { + testResult := allure.NewResult("TestName", "TestFullName") + + // Mock BeforeEach context - should return nil + execContext := &executionContextWithResult{ + name: constants.BeforeEachContextName, + testResult: testResult, + } + + provider := &providerMockCommon{ + testMetaMock: &testMetaMockCommon{result: testResult}, + executionMock: execContext, + } + + comm := Common{Provider: provider} + + result := comm.GetCurrentTestResult() + require.Nil(t, result, "GetCurrentTestResult should return nil in BeforeEach context") +} + +func TestCommon_GetCurrentTestResult_NilProviderOrContext(t *testing.T) { + // Test with nil Provider + comm := Common{Provider: nil} + require.Nil(t, comm.GetCurrentTestResult()) + + // Test with nil ExecutionContext + provider := &providerMockCommon{ + executionMock: nil, + } + comm = Common{Provider: provider} + require.Nil(t, comm.GetCurrentTestResult()) +} + +// Mock execution context for testing GetCurrentTestResult +type executionContextWithResult struct { + name string + testResult *allure.Result + steps []*allure.Step + attachments []*allure.Attachment +} + +func (m *executionContextWithResult) AddStep(step *allure.Step) { + m.steps = append(m.steps, step) +} + +func (m *executionContextWithResult) AddAttachments(attachments ...*allure.Attachment) { + m.attachments = append(m.attachments, attachments...) +} + +func (m *executionContextWithResult) GetName() string { + return m.name +} + +func (m *executionContextWithResult) GetTestResult() *allure.Result { + return m.testResult +} diff --git a/pkg/framework/core/common/step_context_test.go b/pkg/framework/core/common/step_context_test.go index 81d3775..76ef72f 100644 --- a/pkg/framework/core/common/step_context_test.go +++ b/pkg/framework/core/common/step_context_test.go @@ -144,6 +144,10 @@ func (m *executionCtxMock) GetName() string { return m.name } +func (m *executionCtxMock) GetTestResult() *allure.Result { + return nil +} + func TestNewStepCtx(t *testing.T) { params := allure.NewParameters("p1", "v1", "p2", "v2") ctx := NewStepCtx( diff --git a/pkg/framework/core/common/steps_test.go b/pkg/framework/core/common/steps_test.go index c31acd1..618645b 100644 --- a/pkg/framework/core/common/steps_test.go +++ b/pkg/framework/core/common/steps_test.go @@ -38,6 +38,10 @@ func (m *executionContextstepsCommMock) GetName() string { return m.name } +func (m *executionContextstepsCommMock) GetTestResult() *allure.Result { + return nil +} + type providerMockstepsCommon struct { provider.AllureForwardFull steps []*allure.Step diff --git a/pkg/framework/provider/provider.go b/pkg/framework/provider/provider.go index 8efbe8e..12ecb02 100644 --- a/pkg/framework/provider/provider.go +++ b/pkg/framework/provider/provider.go @@ -56,4 +56,5 @@ type ExecutionContext interface { AddStep(step *allure.Step) AddAttachments(attachment ...*allure.Attachment) GetName() string + GetTestResult() *allure.Result // Returns test result if available (for test and AfterEach contexts) } diff --git a/pkg/framework/provider/test.go b/pkg/framework/provider/test.go index ee6b1c6..82e4c93 100644 --- a/pkg/framework/provider/test.go +++ b/pkg/framework/provider/test.go @@ -39,6 +39,9 @@ type T interface { WithNewAsyncStep(stepName string, step func(sCtx StepCtx), params ...*allure.Parameter) WithTestSetup(setup func(T)) WithTestTeardown(teardown func(T)) + + // GetCurrentTestResult returns the current test result (available in AfterEach hook) + GetCurrentTestResult() *allure.Result } type StepCtx interface { diff --git a/pkg/framework/runner/runner.go b/pkg/framework/runner/runner.go index 3fd8379..7eae2d4 100644 --- a/pkg/framework/runner/runner.go +++ b/pkg/framework/runner/runner.go @@ -195,6 +195,11 @@ func (r *runner) RunTests() SuiteResult { // after each hook defer func() { + // Set default status to Passed if not set (before AfterEach hook) + // This allows AfterEach to see the test status + if result := testT.GetProvider().GetResult(); result != nil && result.Status == "" { + result.Status = allure.Passed + } _, _ = runHook(testT, afterEachHook) }() diff --git a/pkg/framework/runner/runner_test.go b/pkg/framework/runner/runner_test.go index a9d01c7..be147ff 100644 --- a/pkg/framework/runner/runner_test.go +++ b/pkg/framework/runner/runner_test.go @@ -39,6 +39,10 @@ func (m *executionContextRunnerMock) GetName() string { return m.name } +func (m *executionContextRunnerMock) GetTestResult() *allure.Result { + return nil +} + type providerMockRunner struct { provider.AllureForwardFull From 4672381e651f1012cb69a5cc21c683f2af737324 Mon Sep 17 00:00:00 2001 From: SergKhram Date: Sat, 6 Dec 2025 12:27:03 +0400 Subject: [PATCH 2/2] Fixed comments --- README.md | 43 ++++----- pkg/allure/result.go | 13 +++ .../core/allure_manager/ctx/hooks.go | 12 +-- .../core/allure_manager/ctx/hooks_test.go | 11 +-- .../core/allure_manager/ctx/test_ctx_test.go | 35 +------ .../manager/execution_management_test.go | 93 +++++++++++-------- pkg/framework/core/common/common.go | 10 +- pkg/framework/core/common/common_test.go | 13 +-- pkg/framework/provider/test.go | 2 +- 9 files changed, 122 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index b1828f2..2d23c2a 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Providing a separate package allows you to customize your work with allure.
#### GetCurrentTestResult method Now you can access test execution result in `AfterEach` hook:
-- `t.GetCurrentTestResult()` - returns current test result with status and details
+- `t.GetCurrentTestResult()` - returns current test result with status and details (read-only copy)
This allows you to perform conditional actions based on test status (Passed, Failed, Broken, Skipped).
@@ -52,14 +52,14 @@ This allows you to perform conditional actions based on test status (Passed, Fai ```go func (s *MySuite) AfterEach(t provider.T) { - result := t.GetCurrentTestResult() - if result != nil && result.Status == allure.Failed { + result, ok := t.GetCurrentTestResult() + if ok && result.Status == allure.Failed { // Save screenshot only for failed tests screenshot := takeScreenshot() t.WithNewAttachment("failure.png", allure.ImagePng, screenshot) - // Check if BeforeEach failed - if strings.Contains(result.GetStatusMessage(), "Setup failed") { + // Check error message + if strings.Contains(result.StatusDetails.Message, "Setup failed") { t.Log("Test didn't run - BeforeEach hook failed, skipping cleanup") } } @@ -77,9 +77,9 @@ func (s *MySuite) BeforeEach(t provider.T) { } func (s *MySuite) AfterEach(t provider.T) { - result := t.GetCurrentTestResult() - if result != nil && result.Status == allure.Failed && - strings.Contains(result.GetStatusMessage(), "Setup failed") { + result, ok := t.GetCurrentTestResult() + if ok && result.Status == allure.Failed && + strings.Contains(result.StatusDetails.Message, "Setup failed") { t.Log("BeforeEach failed - test was not executed") } } @@ -88,8 +88,8 @@ func (s *MySuite) AfterEach(t provider.T) { **Important Notes:** :information_source: This feature **does not change** hook or test behavior - it only provides read-only access to test status.
-:information_source: `GetCurrentTestResult()` is available only in `AfterEach` hook.
-:information_source: Returns `nil` in other contexts (BeforeEach, BeforeAll, AfterAll, test body).
+:information_source: `GetCurrentTestResult()` returns `(*allure.CurrentResult, bool)` - a read-only copy with `Status` and `StatusDetails` fields.
+:information_source: Available **only in `AfterEach` hook** - returns `(nil, false)` in other contexts (BeforeEach, BeforeAll, AfterAll, test body).
:information_source: For **parametrized tests** (using `t.Run()`): AfterEach is called once for the parent test, not for each subtest.
:information_source: For **nested tests**: AfterEach sees the parent test status, which may be Passed even if subtests failed.
@@ -747,30 +747,30 @@ type StatusInHooksSuite struct { } func (s *StatusInHooksSuite) AfterEach(t provider.T) { - // Get the test result from execution context - result := t.GetCurrentTestResult() + // Get the test result from execution context (read-only copy) + result, ok := t.GetCurrentTestResult() - if result != nil { + if ok { switch result.Status { case allure.Failed: // Check if BeforeEach failed - if strings.Contains(result.GetStatusMessage(), "Setup failed") { + if strings.Contains(result.StatusDetails.Message, "Setup failed") { t.Log("BeforeEach hook failed, skipping cleanup") return } // Handle test failure - t.Logf("Test failed: %s", result.Name) + t.Log("Test failed") // You can save screenshot, logs, etc. // screenshot := takeScreenshot() // t.WithNewAttachment("failure.png", allure.ImagePng, screenshot) case allure.Passed: - t.Logf("Test passed: %s", result.Name) + t.Log("Test passed") // Cleanup test data for successful tests case allure.Broken: - t.Logf("Test broken: %s", result.Name) + t.Log("Test broken") } } } @@ -786,11 +786,12 @@ func TestStatusInHooks(t *testing.T) { ``` Key points: -- `t.GetCurrentTestResult()` returns `*allure.Result` with test status and details in `AfterEach` +- `t.GetCurrentTestResult()` returns `(*allure.CurrentResult, bool)` with test status and details in `AfterEach` +- `allure.CurrentResult` is a read-only copy containing `Status` and `StatusDetails` fields - Available statuses: `allure.Passed`, `allure.Failed`, `allure.Broken`, `allure.Skipped` -- Returns `nil` in contexts other than `AfterEach` (e.g., in test body, `BeforeEach`, or `AfterAll`) -- Check `result.GetStatusMessage()` for "Setup failed" to detect `BeforeEach` failures -- Does not change hook or test behavior - only provides read access to test status +- Returns `(nil, false)` in contexts other than `AfterEach` (e.g., in test body, `BeforeEach`, or `AfterAll`) +- Check `result.StatusDetails.Message` or `result.StatusDetails.Trace` to analyze failure reasons +- Does not change hook or test behavior - only provides read-only access to test status ### [XSkip](examples/suite_demo/fails_test.go) diff --git a/pkg/allure/result.go b/pkg/allure/result.go index 172942f..b73f949 100644 --- a/pkg/allure/result.go +++ b/pkg/allure/result.go @@ -43,6 +43,12 @@ type Result struct { ToPrint bool `json:"-"` // If false - the report will not be saved to a file } +// CurrentResult Use for getting current test result in AfterEach hook +type CurrentResult struct { + Status Status `json:"status,omitempty"` // Status of the test execution + StatusDetails StatusDetail `json:"statusDetails,omitempty"` // Details about the test (for example, errors during test execution will be recorded here) +} + // NewResult Constructor Builds a new `allure.Result`. Sets the default values for the structure. // ================================================ // |Field Value| Default | @@ -342,3 +348,10 @@ func getMD5Hash(text string) string { hash := md5.Sum([]byte(text)) return hex.EncodeToString(hash[:]) } + +func (result *CurrentResult) GetStatusMessage() string { + return result.StatusDetails.Message +} +func (result *CurrentResult) GetStatusTrace() string { + return result.StatusDetails.Trace +} diff --git a/pkg/framework/core/allure_manager/ctx/hooks.go b/pkg/framework/core/allure_manager/ctx/hooks.go index f55de51..a060527 100644 --- a/pkg/framework/core/allure_manager/ctx/hooks.go +++ b/pkg/framework/core/allure_manager/ctx/hooks.go @@ -9,9 +9,9 @@ import ( ) type hooksCtx struct { - name string - container *allure.Container - testResult *allure.Result // Result of the test (for AfterEach hook) + name string + container *allure.Container + result *allure.Result // Result of the test (for AfterEach hook) } // NewAfterAllCtx returns after all context @@ -25,8 +25,8 @@ func NewAfterEachCtx(container *allure.Container) provider.ExecutionContext { } // NewAfterEachCtxWithResult returns after each context with test result -func NewAfterEachCtxWithResult(container *allure.Container, testResult *allure.Result) provider.ExecutionContext { - return &hooksCtx{container: container, testResult: testResult, name: constants.AfterEachContextName} +func NewAfterEachCtxWithResult(container *allure.Container, result *allure.Result) provider.ExecutionContext { + return &hooksCtx{container: container, result: result, name: constants.AfterEachContextName} } // NewBeforeAllCtx returns before all context @@ -57,7 +57,7 @@ func (ctx *hooksCtx) GetName() string { // GetTestResult returns test result if available (for AfterEach hook) func (ctx *hooksCtx) GetTestResult() *allure.Result { - return ctx.testResult + return ctx.result } // AddAttachments adds attachment to the execution context diff --git a/pkg/framework/core/allure_manager/ctx/hooks_test.go b/pkg/framework/core/allure_manager/ctx/hooks_test.go index 7d2e786..343c950 100644 --- a/pkg/framework/core/allure_manager/ctx/hooks_test.go +++ b/pkg/framework/core/allure_manager/ctx/hooks_test.go @@ -1,6 +1,7 @@ package ctx import ( + "sync" "testing" "github.com/stretchr/testify/require" @@ -203,19 +204,17 @@ func TestHooksCtx_GetTestResult_ConcurrentAccess(t *testing.T) { // Multiple goroutines reading the result const numGoroutines = 10 - done := make(chan bool, numGoroutines) + var wg sync.WaitGroup + wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { go func() { + defer wg.Done() r := ctx.GetTestResult() require.NotNil(t, r) require.Equal(t, allure.Passed, r.Status) - done <- true }() } - // Wait for all goroutines - for i := 0; i < numGoroutines; i++ { - <-done - } + wg.Wait() } diff --git a/pkg/framework/core/allure_manager/ctx/test_ctx_test.go b/pkg/framework/core/allure_manager/ctx/test_ctx_test.go index 5469f9d..9ce9c5c 100644 --- a/pkg/framework/core/allure_manager/ctx/test_ctx_test.go +++ b/pkg/framework/core/allure_manager/ctx/test_ctx_test.go @@ -1,6 +1,7 @@ package ctx import ( + "sync" "testing" "github.com/ozontech/allure-go/pkg/allure" @@ -131,31 +132,6 @@ func TestTestCtx_GetTestResult_WithStatusDetails(t *testing.T) { require.Equal(t, "trace stack here", retrievedResult.GetStatusTrace()) } -func TestTestCtx_GetTestResult_BrokenTest(t *testing.T) { - result := allure.NewResult("BrokenTest", "suite.BrokenTest") - result.Status = allure.Broken - result.SetStatusMessage("Panic occurred") - - testCtx := NewTestCtx(result) - - retrievedResult := testCtx.GetTestResult() - require.NotNil(t, retrievedResult) - require.Equal(t, allure.Broken, retrievedResult.Status) - require.Contains(t, retrievedResult.GetStatusMessage(), "Panic occurred") -} - -func TestTestCtx_GetTestResult_SkippedTest(t *testing.T) { - result := allure.NewResult("SkippedTest", "suite.SkippedTest") - result.Status = allure.Skipped - result.SetStatusMessage("Test skipped") - - testCtx := NewTestCtx(result) - - retrievedResult := testCtx.GetTestResult() - require.NotNil(t, retrievedResult) - require.Equal(t, allure.Skipped, retrievedResult.Status) -} - // Test concurrent access to result func TestTestCtx_GetTestResult_ConcurrentAccess(t *testing.T) { result := allure.NewResult("ConcurrentTest", "suite.ConcurrentTest") @@ -164,18 +140,17 @@ func TestTestCtx_GetTestResult_ConcurrentAccess(t *testing.T) { testCtx := NewTestCtx(result) const numGoroutines = 20 - done := make(chan bool, numGoroutines) + var wg sync.WaitGroup + wg.Add(numGoroutines) for i := 0; i < numGoroutines; i++ { go func() { + defer wg.Done() r := testCtx.GetTestResult() require.NotNil(t, r) require.Equal(t, allure.Passed, r.Status) - done <- true }() } - for i := 0; i < numGoroutines; i++ { - <-done - } + wg.Wait() } diff --git a/pkg/framework/core/allure_manager/manager/execution_management_test.go b/pkg/framework/core/allure_manager/manager/execution_management_test.go index 2aa34f7..97aa2c7 100644 --- a/pkg/framework/core/allure_manager/manager/execution_management_test.go +++ b/pkg/framework/core/allure_manager/manager/execution_management_test.go @@ -150,24 +150,65 @@ func TestAllureManager_AfterEachContextWithResult(t *testing.T) { require.Equal(t, "TestName", retrievedResult.Name) } -func TestAllureManager_AfterEachContextWithFailedResult(t *testing.T) { - result := allure.NewResult("FailedTest", "FullFailedTest") - result.Status = allure.Failed - result.SetStatusMessage("Test assertion failed") - - manager := allureManager{ - testMeta: &testMetaMockExecM{ - result: result, - container: allure.NewContainer(), +func TestAllureManager_AfterEachContextWithDifferentStatuses(t *testing.T) { + tests := []struct { + name string + testName string + fullTestName string + status allure.Status + statusMessage string + expectedStatus allure.Status + messageContains string + exactMessageMatch bool + }{ + { + name: "Failed test result", + testName: "FailedTest", + fullTestName: "FullFailedTest", + status: allure.Failed, + statusMessage: "Test assertion failed", + expectedStatus: allure.Failed, + messageContains: "Test assertion failed", + exactMessageMatch: true, + }, + { + name: "BeforeEach failure scenario", + testName: "TestWillNotRun", + fullTestName: "FullTestWillNotRun", + status: allure.Failed, + statusMessage: "TestName/BeforeEach setup was failed", + expectedStatus: allure.Failed, + messageContains: "setup was failed", + exactMessageMatch: false, }, } - manager.AfterEachContext() - - retrievedResult := manager.executionContext.GetTestResult() - require.NotNil(t, retrievedResult) - require.Equal(t, allure.Failed, retrievedResult.Status) - require.Equal(t, "Test assertion failed", retrievedResult.GetStatusMessage()) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := allure.NewResult(tt.testName, tt.fullTestName) + result.Status = tt.status + result.SetStatusMessage(tt.statusMessage) + + manager := allureManager{ + testMeta: &testMetaMockExecM{ + result: result, + container: allure.NewContainer(), + }, + } + + manager.AfterEachContext() + + retrievedResult := manager.executionContext.GetTestResult() + require.NotNil(t, retrievedResult) + require.Equal(t, tt.expectedStatus, retrievedResult.Status) + + if tt.exactMessageMatch { + require.Equal(t, tt.messageContains, retrievedResult.GetStatusMessage()) + } else { + require.Contains(t, retrievedResult.GetStatusMessage(), tt.messageContains) + } + }) + } } // Test parametrized test scenario @@ -190,25 +231,3 @@ func TestAllureManager_AfterEachContext_ParametrizedTestScenario(t *testing.T) { require.Equal(t, allure.Passed, retrievedResult.Status) require.Equal(t, "TestParametrized", retrievedResult.Name) } - -// Test BeforeEach failure scenario -func TestAllureManager_AfterEachContext_BeforeEachFailure(t *testing.T) { - // When BeforeEach fails, test doesn't run but result is created - result := allure.NewResult("TestWillNotRun", "FullTestWillNotRun") - result.Status = allure.Failed - result.SetStatusMessage("TestName/BeforeEach setup was failed") - - manager := allureManager{ - testMeta: &testMetaMockExecM{ - result: result, - container: allure.NewContainer(), - }, - } - - manager.AfterEachContext() - - retrievedResult := manager.executionContext.GetTestResult() - require.NotNil(t, retrievedResult) - require.Equal(t, allure.Failed, retrievedResult.Status) - require.Contains(t, retrievedResult.GetStatusMessage(), "setup was failed") -} diff --git a/pkg/framework/core/common/common.go b/pkg/framework/core/common/common.go index e259c71..d690ab9 100644 --- a/pkg/framework/core/common/common.go +++ b/pkg/framework/core/common/common.go @@ -102,15 +102,19 @@ func (c *Common) GetProvider() provider.Provider { } // GetCurrentTestResult returns the current test result (available in AfterEach hook) -func (c *Common) GetCurrentTestResult() *allure.Result { +func (c *Common) GetCurrentTestResult() (result *allure.CurrentResult, ok bool) { if c.Provider != nil && c.Provider.ExecutionContext() != nil { // Only return result in AfterEach context ctxName := c.Provider.ExecutionContext().GetName() if ctxName == constants.AfterEachContextName { - return c.Provider.ExecutionContext().GetTestResult() + var currentFullResult = c.Provider.ExecutionContext().GetTestResult() + return &allure.CurrentResult{ + Status: currentFullResult.Status, + StatusDetails: currentFullResult.StatusDetails, + }, true } } - return nil + return nil, false } // SkipOnPrint skips creating of report for current test diff --git a/pkg/framework/core/common/common_test.go b/pkg/framework/core/common/common_test.go index e56d624..b99bef7 100644 --- a/pkg/framework/core/common/common_test.go +++ b/pkg/framework/core/common/common_test.go @@ -452,10 +452,9 @@ func TestCommon_GetCurrentTestResult_AfterEachContext(t *testing.T) { comm := Common{Provider: provider} - result := comm.GetCurrentTestResult() + result, _ := comm.GetCurrentTestResult() require.NotNil(t, result) require.Equal(t, allure.Failed, result.Status) - require.Equal(t, "TestName", result.Name) require.Equal(t, "Test failed", result.GetStatusMessage()) } @@ -475,7 +474,7 @@ func TestCommon_GetCurrentTestResult_NilInTestContext(t *testing.T) { comm := Common{Provider: provider} - result := comm.GetCurrentTestResult() + result, _ := comm.GetCurrentTestResult() require.Nil(t, result, "GetCurrentTestResult should return nil in test context") } @@ -495,21 +494,23 @@ func TestCommon_GetCurrentTestResult_NilInBeforeEachContext(t *testing.T) { comm := Common{Provider: provider} - result := comm.GetCurrentTestResult() + result, _ := comm.GetCurrentTestResult() require.Nil(t, result, "GetCurrentTestResult should return nil in BeforeEach context") } func TestCommon_GetCurrentTestResult_NilProviderOrContext(t *testing.T) { // Test with nil Provider comm := Common{Provider: nil} - require.Nil(t, comm.GetCurrentTestResult()) + res, _ := comm.GetCurrentTestResult() + require.Nil(t, res) // Test with nil ExecutionContext provider := &providerMockCommon{ executionMock: nil, } comm = Common{Provider: provider} - require.Nil(t, comm.GetCurrentTestResult()) + res, _ = comm.GetCurrentTestResult() + require.Nil(t, res) } // Mock execution context for testing GetCurrentTestResult diff --git a/pkg/framework/provider/test.go b/pkg/framework/provider/test.go index 82e4c93..4a95408 100644 --- a/pkg/framework/provider/test.go +++ b/pkg/framework/provider/test.go @@ -41,7 +41,7 @@ type T interface { WithTestTeardown(teardown func(T)) // GetCurrentTestResult returns the current test result (available in AfterEach hook) - GetCurrentTestResult() *allure.Result + GetCurrentTestResult() (*allure.CurrentResult, bool) } type StepCtx interface {