SseAssertions 0.7.0

Prefix Reserved
dotnet add package SseAssertions --version 0.7.0
                    
NuGet\Install-Package SseAssertions -Version 0.7.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SseAssertions" Version="0.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SseAssertions" Version="0.7.0" />
                    
Directory.Packages.props
<PackageReference Include="SseAssertions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SseAssertions --version 0.7.0
                    
#r "nuget: SseAssertions, 0.7.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SseAssertions@0.7.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SseAssertions&version=0.7.0
                    
Install as a Cake Addin
#tool nuget:?package=SseAssertions&version=0.7.0
                    
Install as a Cake Tool

SseAssertions

NuGet Downloads License: MIT .NET

Scope: Test projects only. Not intended for production code.

Framework-agnostic core for Server-Sent Events (SSE) assertions in .NET test projects. Defines the SseEvent public record (per the WHATWG / W3C SSE wire format), the SseFrameParser that turns wire text into IReadOnlyList<SseEvent>, the SseFailureMessage extension point for typed assertions, and the SseCountComparison enum that backs count terminators.

Full documentation, roadmap, and the TUnit adapter: github.com/JohnVerheij/SseAssertions.TUnit

What ships

Type Purpose
SseEvent (public record) Stable public data type. EventName (non-nullable, defaults to "message" per the WHATWG spec when no event: directive appears), Data (non-null), Id?, RetryMillis?.
SseFrameParser.Parse(string) WHATWG / W3C SSE wire-format parser; handles all three line terminators, strips a UTF-8 BOM at offset 0, ignores comment lines, accumulates multi-line data with \n joins.
SseFailureMessage Curated failure-message factories (ParseFailure, EventNotFound, EventCountMismatch, DataPredicateNotMatched, DataDeserializationFailed, RetryMillisPredicateNotMatched, UnexpectedContentType, CancellationCutRead, UncleanCancellation) for consumer-authored typed SSE assertions.
SseCountComparison (public enum) Comparison label (AtLeast, AtMost, Exactly) carried by EventCountMismatch.
SseFormat.LooksLikeServerSentEvents(string) Lightweight discriminator.

Test-framework-specific entry points live in adapter packages: SseAssertions.TUnit ships today. xUnit, NUnit, MSTest adapters are possible if demand surfaces.

Install

dotnet add package SseAssertions

Requirements: .NET 10. The package carries zero runtime dependencies beyond BCL.

License

MIT. Copyright (c) 2026 John Verheij.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on SseAssertions:

Package Downloads
SseAssertions.TUnit

TUnit-native Server-Sent Events (SSE) assertions for .NET tests. A single HasSseEvent(eventName) chain on the string, Stream, and HttpResponseMessage receivers with frame narrowers (WithData / WithDataParsedAs<T> / WithId / WithRetryMillis) and AtLeast / AtMost / Exactly count terminators; the streaming receivers add cancellation-bounded partial-buffer reads and default-on Content-Type: text/event-stream validation. Builds on the SseAssertions framework-agnostic core. AOT-compatible, trimmable, no runtime reflection in the assertion path.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.7.0 326 6/16/2026
0.6.0 1,548 6/14/2026
0.5.1 153 6/11/2026
0.5.0 131 6/6/2026
0.4.1 158 6/5/2026
0.4.0 148 6/4/2026
0.3.0 277 6/2/2026
0.2.0 219 5/21/2026
0.1.0 232 5/17/2026
0.0.1 210 5/17/2026

View the rendered release notes: https://github.com/JohnVerheij/SseAssertions.TUnit/releases/tag/v0.7.0

Minor release. The frame narrowers that the `string` receiver already had (`WithData`, `WithDataParsedAs<T>`, `WithId`, `WithRetryMillis`) now reach the `Stream` and `HttpResponseMessage` receivers, which is the realistic shape for testing a live SSE endpoint: subscribe to an open response, drive activity, and assert per-frame payload under a cancellation-bounded partial read. Achieving this with one coherent `HasSseEvent(eventName)` surface across all three receivers means the flat `HasSseEvent(eventName, minCount, ...)` methods are replaced by the chainable form, which is a breaking change.

### BREAKING

- **The flat `HasSseEvent(eventName, minCount, ...)` methods on `Stream` and `HttpResponseMessage` are replaced by a chainable `HasSseEvent(eventName)`** matching the `string` receiver. The minimum-count argument moves to the `.AtLeast(n)` terminator, and the narrowers and other terminators (`AtMost`, `Exactly`) are now available on the streaming receivers.
 - Migration: `HasSseEvent("x", minCount: 2)` becomes `HasSseEvent("x").AtLeast(2)`; `HasSseEvent("x")` (default minimum of 1) is unchanged. The `strictContentType` and `cancellationToken` arguments stay on the entry method (`HasSseEvent("x", strictContentType: false, cancellationToken: ct)`).
- **A null `Stream` / `HttpResponseMessage` receiver now fails the assertion** ("the receiver was null") instead of throwing `ArgumentNullException`, matching the long-standing behavior of the `string` receiver. A null `eventName` still throws `ArgumentNullException`, and a negative count still throws `ArgumentOutOfRangeException` (now from the terminator).

### Added

- **Frame narrowers on the `Stream` and `HttpResponseMessage` receivers.** `WithData`, `WithDataParsedAs<T>`, `WithId`, and `WithRetryMillis` constrain which frames count within the cancellation-bounded read, producing the same per-narrower diagnostics as the `string` chain. `WithDataParsedAs<T>` takes a caller-supplied (source-generated) parser so the assertion stays AOT-compatible; a throwing parser fails naming the deserializer exception and the offending data. When the read is cancellation-truncated and the expectation is unmet, the cancellation-cut diagnostic still takes precedence over a count or narrower miss. All three receivers share one internal matching engine, so their diagnostics are identical. No public surface was added to the `SseAssertions` core.

### Fixed

- **A foreign cancellation during a streaming read is no longer reported as a cancellation-cut.** The shared response-read helper caught every `OperationCanceledException` as a caller-driven partial read; an `OperationCanceledException` from a different source (for example an `HttpClient` timeout) was therefore masked by the cancellation-cut diagnostic. It is now captured as a partial read only when the supplied token is the one that fired, otherwise it propagates, matching the distinction `EndsCleanlyOnCancellation` already made in 0.5.1. This applies to every `HttpResponseMessage` read path (`HasSseEvent`, `HasFirstSseEvent`, `HasSseEventsInOrder`, `HasSseRetryDirective`, `HasSseRetryDirectiveFirst`).
- **Stream acquisition no longer pre-empts the cancellation-cut diagnostic.** The `HttpResponseMessage` read paths passed the cancellation token to `ReadAsStreamAsync`, so a token that fired during stream acquisition threw out of the assertion instead of surfacing as the cancellation-cut diagnostic. Acquisition is now uncancellable; the token bounds only the body read, where cancellation is captured.