Skip to main content

Interaction Renderers

When Kensa records interactions between actors it needs to know how to display the exchanged values in the Captured Interactions tab and in sequence diagrams. For types it doesn't recognise — HTTP responses, domain objects, binary payloads — you provide an InteractionRenderer<T>.


The InteractionRenderer Interface

interface InteractionRenderer<T> {
fun render(value: T, attributes: Attributes): List<RenderedInteraction>
fun renderAttributes(value: T): List<RenderedAttributes>
}
MethodPurpose
renderReturns the body content of the interaction — what appears in the main panel
renderAttributesReturns supplementary key/value groups shown alongside the interaction (e.g. status code, headers)

RenderedInteraction

data class RenderedInteraction(val name: String, val value: String, val language: Language = PlainText)

language controls syntax highlighting in the report. Supported values are Language.Json, Language.Xml, and Language.PlainText.

RenderedAttributes

data class RenderedAttributes(val name: String, val attributes: Set<NamedValue>)

Each RenderedAttributes groups a set of NamedValue(name, value) pairs under a heading. You can return multiple groups — one for status, one for headers, etc.


Example — HTTP Response Renderer

The following renderer is taken from the adoptabot example. It formats the response body as pretty-printed JSON and exposes the HTTP status code and headers as separate attribute groups.

object ResponseRenderer : InteractionRenderer<Response> {

override fun render(value: Response, attributes: Attributes): List<RenderedInteraction> {
return listOf(
RenderedInteraction("Response Body", value.bodyString().prettyPrintJson(), Language.Json)
)
}

override fun renderAttributes(value: Response): List<RenderedAttributes> {
return listOf(
RenderedAttributes(
"Status",
setOf(NamedValue("Status", value.status.code.toString()))
),
RenderedAttributes(
"Headers",
value.headers.map { NamedValue(it.first, it.second) }.toSet()
)
)
}
}

Registering a Renderer

Register the renderer during Kensa configuration, mapping it to the type it handles.

// DSL style — type is inferred from the renderer
Kensa.konfigure {
withRenderers {
interactionRenderer(ResponseRenderer)
}
}

// Builder style — type is explicit
Kensa.configure()
.withInteractionRenderer(Response::class, ResponseRenderer)

Configuration is typically placed in a test base class, a JUnit 5 @BeforeAll, or a Kotest ProjectConfig. See Configuration for the full setup.


The Attributes Parameter

render receives an Attributes map alongside the value. This carries interaction metadata set by Kensa at record time — including the interaction group and arrow style for the sequence diagram. You can read values from it if your renderer needs to vary output based on context, but most renderers ignore it and focus solely on the value.

// Reading an attribute — rarely needed in practice
val group: String? = attributes.group
val arrowStyle: ArrowStyle = attributes.arrowStyle

API Reference

InteractionRenderer<T>

MethodSignatureDescription
render(value: T, attributes: Attributes) -> List<RenderedInteraction>Body content for the interaction panel
renderAttributes(value: T) -> List<RenderedAttributes>Supplementary attribute groups shown alongside the interaction

RenderedInteraction

ParameterTypeDescription
nameStringLabel for this content block
valueStringThe content to display
languageLanguageSyntax highlighting hint — Json, Xml, or PlainText (default)

RenderedAttributes

ParameterTypeDescription
nameStringHeading for this attribute group
attributesSet<NamedValue>Key/value pairs to display within the group

NamedValue

data class NamedValue(val name: String, val value: Any?)