or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cross-platform-communication.mdevent-handling.mdframework-integration.mdindex.mdtest-execution.md

event-handling.mddocs/

0

# Event Handling and Reporting

1

2

The event handling system converts ZIO test results into SBT-compatible events for reporting, IDE integration, and test result visualization. It translates ZIO's effect-based test results into the imperative event model expected by SBT's testing infrastructure.

3

4

## Capabilities

5

6

### ZTestEvent

7

8

Case class that implements SBT's `Event` interface, representing a single test result. It contains all information needed by SBT for test reporting and IDE integration.

9

10

```scala { .api }

11

/**

12

* SBT event representing a single ZIO test result

13

* Contains all information needed for SBT reporting and IDE integration

14

*/

15

case class ZTestEvent(

16

fullyQualifiedName: String,

17

selector: sbt.testing.Selector,

18

status: sbt.testing.Status,

19

maybeThrowable: Option[Throwable],

20

duration: Long,

21

fingerprint: sbt.testing.Fingerprint

22

) extends sbt.testing.Event {

23

24

/** Fully qualified name of the test class/object */

25

val fullyQualifiedName: String

26

27

/** SBT selector identifying the specific test */

28

val selector: sbt.testing.Selector

29

30

/** Test execution status (Success, Failure, Ignored, etc.) */

31

val status: sbt.testing.Status

32

33

/** Optional throwable for failed tests */

34

val maybeThrowable: Option[Throwable]

35

36

/** Test execution duration in milliseconds */

37

val duration: Long

38

39

/** Fingerprint used to discover this test */

40

val fingerprint: sbt.testing.Fingerprint

41

42

/**

43

* SBT-compatible throwable accessor

44

* @return OptionalThrowable wrapper for SBT compatibility

45

*/

46

def throwable(): sbt.testing.OptionalThrowable

47

}

48

```

49

50

**Platform Variations:**

51

52

**JVM/JavaScript Platforms:**

53

Uses standard case class with direct field access.

54

55

**Native Platform:**

56

Uses different constructor parameter names for SBT compatibility:

57

58

```scala { .api }

59

case class ZTestEvent(

60

fullyQualifiedName0: String,

61

selector0: sbt.testing.Selector,

62

status0: sbt.testing.Status,

63

maybeThrowable: Option[Throwable],

64

duration0: Long,

65

fingerprint0: sbt.testing.Fingerprint

66

) extends sbt.testing.Event {

67

override def fullyQualifiedName(): String = fullyQualifiedName0

68

override def selector(): sbt.testing.Selector = selector0

69

override def status(): sbt.testing.Status = status0

70

override def duration(): Long = duration0

71

override def fingerprint(): sbt.testing.Fingerprint = fingerprint0

72

def throwable(): sbt.testing.OptionalThrowable = /* ... */

73

}

74

```

75

76

Both implementations provide identical functionality with platform-specific adaptations for SBT integration.

77

78

**Status Mapping:**

79

80

The event system maps ZIO test results to SBT status values:

81

82

- `TestSuccess.Succeeded``Status.Success`

83

- `TestFailure.Assertion``Status.Failure` (with AssertionError)

84

- `TestFailure.Runtime``Status.Failure` (with RuntimeException)

85

- `TestSuccess.Ignored``Status.Ignored`

86

87

**Usage in Test Execution:**

88

89

```scala

90

// Events are created automatically during test execution

91

// ZTestEvent.from() converts ZIO ExecutedSpec to SBT events

92

val events = ZTestEvent.from(executedSpec, className, fingerprint)

93

events.foreach(event => eventHandler.handle(event))

94

```

95

96

### ZTestEvent Companion Object

97

98

Factory methods for creating `ZTestEvent` instances from ZIO test results.

99

100

```scala { .api }

101

object ZTestEvent {

102

/**

103

* Converts ZIO ExecutedSpec to sequence of SBT events

104

* @param executedSpec ZIO test execution results

105

* @param fullyQualifiedName Test class name

106

* @param fingerprint Fingerprint used for test discovery

107

* @return Sequence of SBT events representing all test results

108

*/

109

def from[E](

110

executedSpec: zio.test.ExecutedSpec[E],

111

fullyQualifiedName: String,

112

fingerprint: sbt.testing.Fingerprint

113

): Seq[ZTestEvent]

114

}

115

```

116

117

**Conversion Process:**

118

119

The `from` method recursively processes ZIO's `ExecutedSpec` structure:

120

121

1. **Labeled Specs**: Extracts test names and propagates to nested specs

122

2. **Multiple Specs**: Processes each spec individually and combines results

123

3. **Test Cases**: Converts individual test results to `ZTestEvent` instances

124

125

**Internal Processing Methods:**

126

127

```scala { .api }

128

// Internal methods (not part of public API but used by from())

129

private def toStatus[E](result: Either[zio.test.TestFailure[E], zio.test.TestSuccess]): sbt.testing.Status

130

131

private def toThrowable[E](

132

spec: zio.test.ExecutedSpec[E],

133

label: Option[String],

134

result: Either[zio.test.TestFailure[E], zio.test.TestSuccess]

135

): Option[Throwable]

136

137

private def render[E](spec: zio.test.ExecutedSpec[E], label: Option[String]): String

138

```

139

140

## Event Processing Examples

141

142

### Basic Test Result Conversion

143

144

```scala

145

import zio.test._

146

import zio.test.sbt.ZTestEvent

147

148

// Example ZIO test specification

149

object MyTestSpec extends DefaultRunnableSpec {

150

def spec = suite("Calculator Tests")(

151

test("addition works") {

152

assert(2 + 2)(equalTo(4))

153

},

154

test("division by zero fails") {

155

assert(10 / 0)(anything) // This will fail

156

}

157

)

158

}

159

160

// After execution, ZIO produces an ExecutedSpec

161

// ZTestEvent.from() converts this to SBT events:

162

163

val events = ZTestEvent.from(

164

executedSpec = executedSpecResult,

165

fullyQualifiedName = "com.example.MyTestSpec",

166

fingerprint = RunnableSpecFingerprint

167

)

168

169

// Results in events like:

170

// ZTestEvent(

171

// fullyQualifiedName = "com.example.MyTestSpec",

172

// selector = TestSelector("addition works"),

173

// status = Status.Success,

174

// maybeThrowable = None,

175

// duration = 15, // milliseconds

176

// fingerprint = RunnableSpecFingerprint

177

// )

178

//

179

// ZTestEvent(

180

// fullyQualifiedName = "com.example.MyTestSpec",

181

// selector = TestSelector("division by zero fails"),

182

// status = Status.Failure,

183

// maybeThrowable = Some(RuntimeException(...)),

184

// duration = 5,

185

// fingerprint = RunnableSpecFingerprint

186

// )

187

```

188

189

### Nested Suite Handling

190

191

```scala

192

// ZIO test with nested suites

193

def spec = suite("Math Operations")(

194

suite("Basic Operations")(

195

test("addition")(assert(1 + 1)(equalTo(2))),

196

test("subtraction")(assert(5 - 3)(equalTo(2)))

197

),

198

suite("Advanced Operations")(

199

test("multiplication")(assert(3 * 4)(equalTo(12))),

200

test("division")(assert(8 / 2)(equalTo(4)))

201

)

202

)

203

204

// ZTestEvent.from() flattens the structure and creates events like:

205

// - TestSelector("addition")

206

// - TestSelector("subtraction")

207

// - TestSelector("multiplication")

208

// - TestSelector("division")

209

// Each with appropriate status and timing information

210

```

211

212

### Error Reporting and Formatting

213

214

The event system provides detailed error reporting with ANSI color stripping for clean output:

215

216

```scala

217

// Failed assertion example

218

test("string comparison") {

219

assert("hello")(equalTo("world"))

220

}

221

222

// Produces ZTestEvent with:

223

// - status = Status.Failure

224

// - maybeThrowable = Some(AssertionError("expected: world, actual: hello"))

225

// - Detailed failure message with diff information

226

// - ANSI color codes stripped for clean reporting

227

```

228

229

## Integration with SBT Reporting

230

231

### Event Handler Integration

232

233

Events are processed by SBT's event handling system:

234

235

```scala

236

// In BaseTestTask.run() method:

237

val events = ZTestEvent.from(spec, taskDef.fullyQualifiedName(), taskDef.fingerprint())

238

events.foreach(event => ZIO.effect(eventHandler.handle(event)))

239

```

240

241

### IDE Integration

242

243

The event system enables IDE integration through SBT's test interface:

244

245

- **IntelliJ IDEA**: Displays individual test results with green/red indicators

246

- **VS Code**: Shows test status in test explorer panels

247

- **Eclipse**: Integrates with JUnit-style test running views

248

- **Command Line**: Provides detailed test output with timing and failure information

249

250

### Custom Event Processing

251

252

For advanced use cases, you can process events before passing to SBT:

253

254

```scala

255

// Custom event processing example

256

class CustomTestTask extends BaseTestTask {

257

override protected def run(eventHandler: EventHandler) = {

258

for {

259

spec <- specInstance.runSpec(FilteredSpec(specInstance.spec, args))

260

events = ZTestEvent.from(spec, taskDef.fullyQualifiedName(), taskDef.fingerprint())

261

262

// Custom processing - filter, transform, or aggregate events

263

processedEvents = events.filter(_.status != Status.Ignored)

264

265

_ <- ZIO.foreach(processedEvents) { event =>

266

// Custom logging, metrics collection, etc.

267

ZIO.effect {

268

logCustomMetrics(event)

269

eventHandler.handle(event)

270

}

271

}

272

} yield ()

273

}

274

275

private def logCustomMetrics(event: ZTestEvent): Unit = {

276

// Custom metric collection, external reporting, etc.

277

}

278

}

279

```

280

281

## Timing and Performance Information

282

283

Events include precise timing information extracted from ZIO's test annotations:

284

285

```scala

286

// Timing information comes from TestAnnotation.timing

287

val duration = annotations.get(TestAnnotation.timing).toMillis

288

289

// This enables:

290

// - Performance regression detection

291

// - Slow test identification

292

// - Build time optimization

293

// - Detailed timing reports in IDEs

294

```

295

296

The event system ensures that all timing information from ZIO's effect execution is preserved and made available to SBT's reporting infrastructure, enabling comprehensive test performance analysis.