0
# Event Handling
1
2
This document covers the event handling system that converts ZIO test execution events to SBT-compatible formats.
3
4
## ZTestEvent
5
6
Represents a test event in SBT's format, converting ZIO test results to SBT's event model.
7
8
```scala { .api }
9
final case class ZTestEvent(
10
fullyQualifiedName0: String,
11
selector0: sbt.testing.Selector,
12
status0: sbt.testing.Status,
13
maybeThrowable: Option[Throwable],
14
duration0: Long,
15
fingerprint0: sbt.testing.Fingerprint
16
) extends sbt.testing.Event {
17
18
def duration(): Long
19
def fingerprint(): sbt.testing.Fingerprint
20
def fullyQualifiedName(): String
21
def selector(): sbt.testing.Selector
22
def status(): sbt.testing.Status
23
def throwable(): sbt.testing.OptionalThrowable
24
}
25
```
26
27
### Constructor Parameters
28
29
- `fullyQualifiedName0`: Full class name of the test
30
- `selector0`: Test selector (typically `TestSelector` with test name)
31
- `status0`: Test status (`Success`, `Failure`, `Ignored`)
32
- `maybeThrowable`: Optional exception for failed tests
33
- `duration0`: Test execution duration in milliseconds
34
- `fingerprint0`: Test fingerprint (always `ZioSpecFingerprint`)
35
36
### Methods
37
38
All methods implement the SBT `Event` interface:
39
40
#### duration
41
42
Returns test execution duration.
43
44
```scala
45
event.duration()
46
// Returns: Long (milliseconds)
47
```
48
49
#### fingerprint
50
51
Returns the test fingerprint.
52
53
```scala
54
event.fingerprint()
55
// Returns: sbt.testing.Fingerprint (ZioSpecFingerprint)
56
```
57
58
#### fullyQualifiedName
59
60
Returns the fully qualified test class name.
61
62
```scala
63
event.fullyQualifiedName()
64
// Returns: String
65
```
66
67
#### selector
68
69
Returns the test selector identifying the specific test.
70
71
```scala
72
event.selector()
73
// Returns: sbt.testing.Selector
74
```
75
76
#### status
77
78
Returns the test execution status.
79
80
```scala
81
event.status()
82
// Returns: sbt.testing.Status
83
```
84
85
#### throwable
86
87
Returns optional throwable for failed tests.
88
89
```scala
90
event.throwable()
91
// Returns: sbt.testing.OptionalThrowable
92
```
93
94
## ZTestEvent Companion Object
95
96
Provides factory methods and conversion utilities.
97
98
```scala { .api }
99
object ZTestEvent {
100
def convertEvent(
101
test: zio.test.ExecutionEvent.Test[_],
102
taskDef: sbt.testing.TaskDef,
103
renderer: zio.test.render.TestRenderer
104
): sbt.testing.Event
105
}
106
```
107
108
### convertEvent
109
110
Converts a ZIO test execution event to an SBT event.
111
112
**Parameters:**
113
- `test`: ZIO test execution event containing results
114
- `taskDef`: SBT task definition for context
115
- `renderer`: Test renderer for formatting failure messages
116
117
**Returns:** SBT-compatible `Event`
118
119
**Conversion Logic:**
120
- **Test Status**: Maps ZIO test results to SBT status codes
121
- `TestSuccess.Succeeded` → `Status.Success`
122
- `TestSuccess.Ignored` → `Status.Ignored`
123
- Test failures → `Status.Failure`
124
- **Test Selector**: Creates `TestSelector` from test label hierarchy
125
- **Failure Messages**: Renders failure details with ANSI colors using the provided renderer
126
- **Duration**: Preserves test execution timing
127
128
### Usage Example
129
130
```scala
131
import zio.test.sbt._
132
import zio.test.render.ConsoleRenderer
133
134
val zioTestResult: zio.test.ExecutionEvent.Test[_] = ???
135
val taskDef: sbt.testing.TaskDef = ???
136
137
val sbtEvent = ZTestEvent.convertEvent(
138
test = zioTestResult,
139
taskDef = taskDef,
140
renderer = ConsoleRenderer
141
)
142
143
println(s"Test: ${sbtEvent.fullyQualifiedName()}")
144
println(s"Status: ${sbtEvent.status()}")
145
println(s"Duration: ${sbtEvent.duration()}ms")
146
```
147
148
## ZTestEventHandlerSbt
149
150
Handles ZIO test execution events and forwards them to SBT's event system.
151
152
```scala { .api }
153
class ZTestEventHandlerSbt(
154
eventHandler: sbt.testing.EventHandler,
155
taskDef: sbt.testing.TaskDef,
156
renderer: zio.test.render.TestRenderer
157
) extends zio.test.ZTestEventHandler {
158
159
val semaphore: zio.Semaphore
160
def handle(event: zio.test.ExecutionEvent): zio.UIO[Unit]
161
}
162
```
163
164
### Constructor Parameters
165
166
- `eventHandler`: SBT's event handler for forwarding events
167
- `taskDef`: Task definition for context
168
- `renderer`: Test renderer for formatting output
169
170
### Properties
171
172
- `semaphore`: Ensures thread-safe event handling (initialized with permit 1)
173
174
### Methods
175
176
#### handle
177
178
Processes ZIO execution events and converts them to SBT events.
179
180
```scala
181
def handle(event: zio.test.ExecutionEvent): zio.UIO[Unit]
182
```
183
184
**Supported Event Types:**
185
186
##### ExecutionEvent.TestStarted
187
Test initiation events - no action taken.
188
189
```scala
190
case ExecutionEvent.TestStarted(_, _, _, _, _) => zio.ZIO.unit
191
```
192
193
##### ExecutionEvent.Test
194
Completed test events - converted to SBT events.
195
196
```scala
197
case evt @ ExecutionEvent.Test(_, _, _, _, _, _, _) =>
198
val zTestEvent = ZTestEvent.convertEvent(evt, taskDef, renderer)
199
semaphore.withPermit(zio.ZIO.succeed(eventHandler.handle(zTestEvent)))
200
```
201
202
##### ExecutionEvent.SectionStart/SectionEnd
203
Test section boundaries - no action taken.
204
205
```scala
206
case ExecutionEvent.SectionStart(_, _, _) => zio.ZIO.unit
207
case ExecutionEvent.SectionEnd(_, _, _) => zio.ZIO.unit
208
```
209
210
##### ExecutionEvent.TopLevelFlush
211
Output flushing events - no action taken.
212
213
```scala
214
case ExecutionEvent.TopLevelFlush(_) => zio.ZIO.unit
215
```
216
217
##### ExecutionEvent.RuntimeFailure
218
Runtime failure events - converted to SBT failure events.
219
220
```scala
221
case ExecutionEvent.RuntimeFailure(_, _, failure, _) =>
222
failure match {
223
case TestFailure.Assertion(_, _) => zio.ZIO.unit // Handled via Test events
224
case TestFailure.Runtime(cause, annotations) =>
225
val zTestEvent = ZTestEvent(
226
taskDef.fullyQualifiedName(),
227
taskDef.selectors().head,
228
sbt.testing.Status.Failure,
229
cause.dieOption,
230
annotations.get(zio.test.TestAnnotation.timing).toMillis,
231
ZioSpecFingerprint
232
)
233
semaphore.withPermit(zio.ZIO.succeed(eventHandler.handle(zTestEvent)))
234
}
235
```
236
237
## Event Flow
238
239
The event handling system follows this flow:
240
241
1. **ZIO Test Execution**: ZIO tests run and generate `ExecutionEvent`s
242
2. **Event Handler**: `ZTestEventHandlerSbt` receives ZIO events
243
3. **Event Conversion**: `ZTestEvent.convertEvent` transforms ZIO events to SBT format
244
4. **SBT Forwarding**: Converted events are sent to SBT's `EventHandler`
245
5. **Result Aggregation**: SBT collects events for final reporting
246
247
## Usage Examples
248
249
### Custom Event Handling
250
251
```scala
252
import zio.test.sbt._
253
import sbt.testing._
254
255
// Create custom event handler
256
class CustomEventHandler extends EventHandler {
257
def handle(event: Event): Unit = {
258
event.status() match {
259
case Status.Success => println(s"✓ ${event.fullyQualifiedName()}")
260
case Status.Failure => println(s"✗ ${event.fullyQualifiedName()}")
261
case Status.Ignored => println(s"○ ${event.fullyQualifiedName()}")
262
}
263
}
264
}
265
266
// Use with ZTestEventHandlerSbt
267
val customHandler = new CustomEventHandler()
268
val taskDef: TaskDef = ???
269
val renderer = zio.test.render.ConsoleRenderer
270
271
val zioHandler = new ZTestEventHandlerSbt(customHandler, taskDef, renderer)
272
```
273
274
### Event Filtering
275
276
```scala
277
// Create filtering event handler
278
class FilteringEventHandler(underlying: EventHandler, filter: Event => Boolean) extends EventHandler {
279
def handle(event: Event): Unit = {
280
if (filter(event)) {
281
underlying.handle(event)
282
}
283
}
284
}
285
286
// Only handle failures
287
val failureFilter = (event: Event) => event.status() == Status.Failure
288
val filteringHandler = new FilteringEventHandler(originalHandler, failureFilter)
289
```
290
291
### Manual Event Creation
292
293
```scala
294
// Create test event manually
295
val testEvent = ZTestEvent(
296
fullyQualifiedName0 = "com.example.MyTest",
297
selector0 = new TestSelector("should pass"),
298
status0 = Status.Success,
299
maybeThrowable = None,
300
duration0 = 150L,
301
fingerprint0 = ZioSpecFingerprint
302
)
303
304
// Handle the event
305
eventHandler.handle(testEvent)
306
```