or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cross-platform.mdevent-handling.mdindex.mdsbt-framework.mdtest-runners.md
tile.json

event-handling.mddocs/

Event Handling

This document covers the event handling system that converts ZIO test execution events to SBT-compatible formats.

ZTestEvent

Represents a test event in SBT's format, converting ZIO test results to SBT's event model.

final case class ZTestEvent(
  fullyQualifiedName0: String,
  selector0: sbt.testing.Selector,
  status0: sbt.testing.Status,
  maybeThrowable: Option[Throwable],
  duration0: Long,
  fingerprint0: sbt.testing.Fingerprint
) extends sbt.testing.Event {
  
  def duration(): Long
  def fingerprint(): sbt.testing.Fingerprint
  def fullyQualifiedName(): String
  def selector(): sbt.testing.Selector
  def status(): sbt.testing.Status
  def throwable(): sbt.testing.OptionalThrowable
}

Constructor Parameters

  • fullyQualifiedName0: Full class name of the test
  • selector0: Test selector (typically TestSelector with test name)
  • status0: Test status (Success, Failure, Ignored)
  • maybeThrowable: Optional exception for failed tests
  • duration0: Test execution duration in milliseconds
  • fingerprint0: Test fingerprint (always ZioSpecFingerprint)

Methods

All methods implement the SBT Event interface:

duration

Returns test execution duration.

event.duration()
// Returns: Long (milliseconds)

fingerprint

Returns the test fingerprint.

event.fingerprint()
// Returns: sbt.testing.Fingerprint (ZioSpecFingerprint)

fullyQualifiedName

Returns the fully qualified test class name.

event.fullyQualifiedName()
// Returns: String

selector

Returns the test selector identifying the specific test.

event.selector()
// Returns: sbt.testing.Selector

status

Returns the test execution status.

event.status()
// Returns: sbt.testing.Status

throwable

Returns optional throwable for failed tests.

event.throwable()
// Returns: sbt.testing.OptionalThrowable

ZTestEvent Companion Object

Provides factory methods and conversion utilities.

object ZTestEvent {
  def convertEvent(
    test: zio.test.ExecutionEvent.Test[_],
    taskDef: sbt.testing.TaskDef,
    renderer: zio.test.render.TestRenderer
  ): sbt.testing.Event
}

convertEvent

Converts a ZIO test execution event to an SBT event.

Parameters:

  • test: ZIO test execution event containing results
  • taskDef: SBT task definition for context
  • renderer: Test renderer for formatting failure messages

Returns: SBT-compatible Event

Conversion Logic:

  • Test Status: Maps ZIO test results to SBT status codes
    • TestSuccess.SucceededStatus.Success
    • TestSuccess.IgnoredStatus.Ignored
    • Test failures → Status.Failure
  • Test Selector: Creates TestSelector from test label hierarchy
  • Failure Messages: Renders failure details with ANSI colors using the provided renderer
  • Duration: Preserves test execution timing

Usage Example

import zio.test.sbt._
import zio.test.render.ConsoleRenderer

val zioTestResult: zio.test.ExecutionEvent.Test[_] = ???
val taskDef: sbt.testing.TaskDef = ???

val sbtEvent = ZTestEvent.convertEvent(
  test = zioTestResult,
  taskDef = taskDef,
  renderer = ConsoleRenderer
)

println(s"Test: ${sbtEvent.fullyQualifiedName()}")
println(s"Status: ${sbtEvent.status()}")
println(s"Duration: ${sbtEvent.duration()}ms")

ZTestEventHandlerSbt

Handles ZIO test execution events and forwards them to SBT's event system.

class ZTestEventHandlerSbt(
  eventHandler: sbt.testing.EventHandler,
  taskDef: sbt.testing.TaskDef,
  renderer: zio.test.render.TestRenderer
) extends zio.test.ZTestEventHandler {
  
  val semaphore: zio.Semaphore
  def handle(event: zio.test.ExecutionEvent): zio.UIO[Unit]
}

Constructor Parameters

  • eventHandler: SBT's event handler for forwarding events
  • taskDef: Task definition for context
  • renderer: Test renderer for formatting output

Properties

  • semaphore: Ensures thread-safe event handling (initialized with permit 1)

Methods

handle

Processes ZIO execution events and converts them to SBT events.

def handle(event: zio.test.ExecutionEvent): zio.UIO[Unit]

Supported Event Types:

ExecutionEvent.TestStarted

Test initiation events - no action taken.

case ExecutionEvent.TestStarted(_, _, _, _, _) => zio.ZIO.unit
ExecutionEvent.Test

Completed test events - converted to SBT events.

case evt @ ExecutionEvent.Test(_, _, _, _, _, _, _) =>
  val zTestEvent = ZTestEvent.convertEvent(evt, taskDef, renderer)
  semaphore.withPermit(zio.ZIO.succeed(eventHandler.handle(zTestEvent)))
ExecutionEvent.SectionStart/SectionEnd

Test section boundaries - no action taken.

case ExecutionEvent.SectionStart(_, _, _) => zio.ZIO.unit
case ExecutionEvent.SectionEnd(_, _, _) => zio.ZIO.unit
ExecutionEvent.TopLevelFlush

Output flushing events - no action taken.

case ExecutionEvent.TopLevelFlush(_) => zio.ZIO.unit
ExecutionEvent.RuntimeFailure

Runtime failure events - converted to SBT failure events.

case ExecutionEvent.RuntimeFailure(_, _, failure, _) =>
  failure match {
    case TestFailure.Assertion(_, _) => zio.ZIO.unit // Handled via Test events
    case TestFailure.Runtime(cause, annotations) =>
      val zTestEvent = ZTestEvent(
        taskDef.fullyQualifiedName(),
        taskDef.selectors().head,
        sbt.testing.Status.Failure,
        cause.dieOption,
        annotations.get(zio.test.TestAnnotation.timing).toMillis,
        ZioSpecFingerprint
      )
      semaphore.withPermit(zio.ZIO.succeed(eventHandler.handle(zTestEvent)))
  }

Event Flow

The event handling system follows this flow:

  1. ZIO Test Execution: ZIO tests run and generate ExecutionEvents
  2. Event Handler: ZTestEventHandlerSbt receives ZIO events
  3. Event Conversion: ZTestEvent.convertEvent transforms ZIO events to SBT format
  4. SBT Forwarding: Converted events are sent to SBT's EventHandler
  5. Result Aggregation: SBT collects events for final reporting

Usage Examples

Custom Event Handling

import zio.test.sbt._
import sbt.testing._

// Create custom event handler
class CustomEventHandler extends EventHandler {
  def handle(event: Event): Unit = {
    event.status() match {
      case Status.Success => println(s"✓ ${event.fullyQualifiedName()}")
      case Status.Failure => println(s"✗ ${event.fullyQualifiedName()}")
      case Status.Ignored => println(s"○ ${event.fullyQualifiedName()}")
    }
  }
}

// Use with ZTestEventHandlerSbt
val customHandler = new CustomEventHandler()
val taskDef: TaskDef = ???
val renderer = zio.test.render.ConsoleRenderer

val zioHandler = new ZTestEventHandlerSbt(customHandler, taskDef, renderer)

Event Filtering

// Create filtering event handler
class FilteringEventHandler(underlying: EventHandler, filter: Event => Boolean) extends EventHandler {
  def handle(event: Event): Unit = {
    if (filter(event)) {
      underlying.handle(event)
    }
  }
}

// Only handle failures
val failureFilter = (event: Event) => event.status() == Status.Failure
val filteringHandler = new FilteringEventHandler(originalHandler, failureFilter)

Manual Event Creation

// Create test event manually
val testEvent = ZTestEvent(
  fullyQualifiedName0 = "com.example.MyTest",
  selector0 = new TestSelector("should pass"),
  status0 = Status.Success,
  maybeThrowable = None,
  duration0 = 150L,
  fingerprint0 = ZioSpecFingerprint
)

// Handle the event
eventHandler.handle(testEvent)