@@ -17,6 +17,14 @@ interface TestIdentifier {
1717 */
1818export class SoftAssertService {
1919 private static instance : SoftAssertService
20+ /**
21+ * Fallback test ID used when no test context is set (e.g., in Cucumber steps).
22+ *
23+ * NOTE: usage of this fallback ID in parallel execution environments may result
24+ * in soft assertion failures from different tests being aggregated together.
25+ * Ensure proper test context is set in hooks whenever possible.
26+ */
27+ public static readonly GLOBAL_TEST_ID = '__global_soft_assert_context__'
2028 private failureMap : Map < string , SoftFailure [ ] > = new Map ( )
2129 private currentTest : TestIdentifier | null = null
2230
@@ -58,11 +66,17 @@ export class SoftAssertService {
5866
5967 /**
6068 * Add a soft failure for the current test
69+ * If no test context is set, failures are stored under a global fallback ID
70+ * to ensure soft assertions work even when hooks haven't set the context
6171 */
6272 public addFailure ( error : Error , matcherName : string ) : void {
63- const testId = this . getCurrentTestId ( )
64- if ( ! testId ) {
65- throw error // If no test context, throw the error immediately
73+ // Use current test ID or fallback to global ID for frameworks where
74+ // the test context might not be set (e.g., Cucumber without proper hook integration)
75+ const testId = this . getCurrentTestId ( ) || SoftAssertService . GLOBAL_TEST_ID
76+
77+ // Ensure the failure map has an entry for this test ID
78+ if ( ! this . failureMap . has ( testId ) ) {
79+ this . failureMap . set ( testId , [ ] )
6680 }
6781
6882 // Extract stack information to get file and line number
@@ -77,40 +91,34 @@ export class SoftAssertService {
7791 }
7892 }
7993
80- const failures = this . failureMap . get ( testId ) || [ ]
81- failures . push ( { error, matcherName, location } )
82- this . failureMap . set ( testId , failures )
94+ // We know the entry exists from the check above
95+ this . failureMap . get ( testId ) ! . push ( { error, matcherName, location } )
8396 }
8497
8598 /**
8699 * Get all failures for a specific test
100+ * Falls back to global test ID if no context is set
87101 */
88102 public getFailures ( testId ?: string ) : SoftFailure [ ] {
89- const id = testId || this . getCurrentTestId ( )
90- if ( ! id ) {
91- return [ ]
92- }
103+ const id = testId || this . getCurrentTestId ( ) || SoftAssertService . GLOBAL_TEST_ID
93104 return this . failureMap . get ( id ) || [ ]
94105 }
95106
96107 /**
97108 * Clear failures for a specific test
109+ * Falls back to global test ID if no context is set
98110 */
99111 public clearFailures ( testId ?: string ) : void {
100- const id = testId || this . getCurrentTestId ( )
101- if ( id ) {
102- this . failureMap . delete ( id )
103- }
112+ const id = testId || this . getCurrentTestId ( ) || SoftAssertService . GLOBAL_TEST_ID
113+ this . failureMap . delete ( id )
104114 }
105115
106116 /**
107117 * Throw an aggregated error if there are failures for the current test
118+ * Falls back to global test ID if no context is set
108119 */
109120 public assertNoFailures ( testId ?: string ) : void {
110- const id = testId || this . getCurrentTestId ( )
111- if ( ! id ) {
112- return
113- }
121+ const id = testId || this . getCurrentTestId ( ) || SoftAssertService . GLOBAL_TEST_ID
114122
115123 const failures = this . getFailures ( id )
116124 if ( failures . length === 0 ) {
0 commit comments