Changelog
Every ProtoTest package shares one version number, so this page lists releases, not packages. Each release that changes a public API lists the change under Breaking changes, with what to write instead.
Work in progress is tracked in the repository CHANGELOG.md.
1.1.9
10 October 2026
ProtoTest 1.1.9 records a cancelled MSTest test as cancelled, as the other runners do, and checks every runner's outcomes against a real run of that runner.
Fixes
- MSTest: Record a test whose body was cancelled as cancelled, not failed: the adapter now classifies the exception the test method threw instead of MSTest's wrapper around it. MSTest
1.1.8
10 October 2026
ProtoTest 1.1.8 makes a cleanup failure fail the test even when its body was skipped or its outcome was unknown. The runner and trace agree, and cleanup still attempts every registered resource.
Fixes
- Core: Fail cleanup after a runtime skip or an unknown body outcome. The message names the original body state and the cleanup error;
CleanupFailures = Reportkeeps the original outcome. Lifecycle - Runners: Preserve the skipped or unknown body explanation in xUnit v3 cleanup failures. Document the TUnit body-scope boundary for native hooks and the final runner verdict. TUnit
1.1.7
9 October 2026
ProtoTest 1.1.7 fails a test whose cleanup fails, reports a missing xUnit collection fixture as a failed test instead of a green run, and makes releasing a test's resources and clients exact: a failed release is no longer hidden, disposal waits for a release in flight, and a client is disposed once.
Breaking changes
Core
- A test whose body passed but whose cleanup failed (a teardown hook, a resource release, a client's disposal) is reported as failed, with a message that says the body passed and names the first cleanup failure. A test whose body failed keeps that failure first, with the cleanup failures after it. Every cleanup step is still attempted and recorded as a Teardown finding.
ProtoTest:CleanupFailuresset toReport(orbuilder.ConfigureCleanup(...)) keeps the previous behaviour: findings only, the test passes and its trace reads Partial. Lifecycle
Fixes
Runners and analyzers
- XUnit v2: a missing collection fixture fails each ProtoTest test with a message that names
ProtoTestAssembly, and the rest of the run reports, where the runner crashed before anddotnet testcould end green with the test missing. xUnit v2
Core
- Stopping the host while it starts waits for the start, then stops it and runs the after-run hooks once; a start that was stopped from outside throws instead of reporting success, and stopping the host from inside its own start throws instead of hanging. Lifecycle
ReleaseResourceAsyncthrows the release's own exception when the release fails, after recording it, where it returnedtruebefore; the test's cleanup outcome includes it. Execution context- Disposing a test context waits for a release that is still running before it closes the test's services, and a second dispose waits for the first. A release callback that disposes its own context, or releases its own resource, throws instead of hanging. Execution context
- One client instance registered under several names or types is disposed once and traced as one client; registering the same instance under the same name again does nothing, and registering it with another ownership (
ContextandCaller) throws. Clients
1.1.6
4 October 2026
ProtoTest 1.1.6 opens a pull request's trace artifact in the viewer as downloaded, and names every coverage category on the pull request comment's summary card.
Features
Agent workflows
- The pull request comment points to ProtoTrace beside the trace link, and the viewer opens the downloaded trace artifact as it is, without unpacking it, for a private repository too: the file is read in the browser.
PROTOTEST_FEEDBACK_VIEWER_URLnames another viewer oroffleaves the pointer out. ProtoTrace
Fixes
Agent workflows
- The summary card names each coverage row by its category, as the report does, so OpenAPI properties, GraphQL schema fields and arguments and a suite's own categories no longer read as "Other coverage". The card URL carries the category name and the counts, never a target, endpoint or test. Continuous integration
1.1.5
3 October 2026
ProtoTest 1.1.5 reads an API description or a GraphQL schema from the application it tests, in process too, and keeps nested coverage units apart when it compares two runs.
Features
Core
IProtoRunHook.AfterInfrastructureAsyncruns once every infrastructure piece started and before the first test. ItsProtoRunSetupContextnow carries the run'sServicesandApplicationClientAsync(name): a client for an application at its configured or published address, or on its in-process server, released when the phase ends. A collector that is a run hook takes part. Hooks
OpenAPI
- A specification source that is a path the application serves (
/openapi/v1.json), with noBaseUrlto resolve it against, loads from the application before the first test, so an in-process application documents its own coverage without a committed copy. OpenAPI
GraphQL
WithSchemaCoverage("/graphql?sdl")loads the schema the application serves before the first test, in process too. Schema coverage
ASP.NET Core
- The in-process server serves the run before its first test: a per-run server starts then and the tests reuse it, a per-test lifetime starts a server only for that read. Hooks
Fixes
Agent workflows
- Run verification names a nested coverage unit by its path under its parents (
GET /orders › 200 › $.id), so a response or a property that regressed under one endpoint is no longer hidden by the same name under another. The pull request comment,get_coverageandget_suite_mapprint the same path, and a coverage suggestion carries it asPath. Verification
1.1.4
3 October 2026
ProtoTest 1.1.4 makes what a coding agent reads from the MCP server about a quarter smaller, and fixes the viewer's capability list.
Fixes
Agent workflows
- The MCP tools return paths relative to the folder they read, leave quotes and symbols unescaped, drop attributes that repeat an operation's source location, and
get_failureno longer repeats the selected failure infailedOperations: on a template project's failure the four tools an agent calls first return 28% less text. Setup
Viewer
- A capability composed for several hosts, such as a test clock per application, reads once with a count, and its instances show in the chip's title. ProtoTrace
- A run's resources read per kind (applications, databases, messaging, fakes, workers, readiness, setup) as short names, and a fake recorded as a server and as a WireMock resource shows once. ProtoTrace
1.1.3
3 October 2026
ProtoTest 1.1.3 fixes the summary card of the pull request comment in GitHub's dark mode.
Fixes
Agent workflows
- The dark summary card keeps every coverage row: the card's address no longer carries a comma, which GitHub reads as the end of the dark image's address and so dropped every row after the first. CI
1.1.2
3 October 2026
ProtoTest 1.1.2 rewrites the pull request comment around what a reviewer reads first: what the change broke, where, and the coverage it moved, with a summary card on top and the full record folded underneath.
Features
Agent workflows
- The pull request comment leads with what changed: a summary card, one headline, a table of the failing tests with the first mismatch and a linked source line, a caution when failures share a cause, a coverage table against the base branch, and the full record per test folded under Failure details. A skipped test is no longer listed. CI
ProtoFeedbackComment.Body(digest, target)renders the comment the post sends;ProtoFeedbackTarget.SummaryCardUrlandSourceBaseUrladd the card and the source links. The CLI sets both, andPROTOTEST_FEEDBACK_CARD_URL=offleaves the card out. CLI
1.1.1
2 October 2026
ProtoTest 1.1.1 fixes ProtoTest.OpenApi, which in 1.1.0 replaced the OpenAPI library of the application a
suite hosts in-process. Its one breaking change is the exception to the additive 1.x surface: a constructor
that exposed Microsoft.OpenApi's own type, the dependency that caused the failure.
Fixes
OpenAPI
- An application that documents itself with Swashbuckle, NSwag or
Microsoft.AspNetCore.OpenApikeeps running next to OpenAPI coverage: the package reads the document itself instead of depending onMicrosoft.OpenApi. OpenAPI
Breaking changes
OpenAPI
OpenApiCoverageCollector(string, OpenApiDocument)is removed with theMicrosoft.OpenApidependency.- Pass the document's file path, URL or text instead:
new OpenApiCoverageCollector(target, source)(OpenAPI).
- Pass the document's file path, URL or text instead:
1.1.0
2 October 2026
ProtoTest 1.1 adds the agent evidence layer (the MCP server, diagnosis, verification, feedback and the
CLI, with compare, prove and review judging what a coding agent changed), the devices family (WebSocket, MQTT, TCP and serial), the topology integrations (Aspire, WireMock,
Testcontainers), the extended runner surface, and a rewritten documentation site with the Learn track.
It ships 46 packages: 19 new, listed first below, and ProtoTest.OpenTelemetry removed. The breaking changes are listed at the end.
See Migrating from 1.0 for the renames
and the deprecated surface; the docs cover the rest.
Features
New packages
ProtoTest.Analyzers: compile-time rules for what the framework cannot catch at run time.ProtoTest.Aspire: runs an Aspire AppHost with the suite and publishes its resources as targets.ProtoTest.Cli: theprototestcommand that summarizes, indexes, compares, proves, reviews and verifies traces.ProtoTest.Devices: typed devices, one per test, with every exchange in the trace.ProtoTest.Devices.WebSocketandProtoTest.Devices.WebSocket.AspNetCore: devices over WebSocket, or in-process without a socket.ProtoTest.Devices.MqttandProtoTest.Devices.Mqtt.Testcontainers: devices over MQTT, with a Mosquitto broker for the run.ProtoTest.Devices.TcpandProtoTest.Devices.Serial: devices over TCP and serial lines, with stream framing.ProtoTest.Diagnosis: names a failure's cause from the recorded evidence.ProtoTest.Feedback: posts a run's digest to a pull request, check annotations or a webhook.ProtoTest.Hosting: hosts background workers in the test process.ProtoTest.Mcp: an MCP server that lets a coding agent read runs, with the tools and prompts that judge its fixes and tests.ProtoTest.Messaging.MassTransit: uses the application's MassTransit test harness as the broker.ProtoTest.Traces: reads.prototracearchives for the CLI, MCP and tools.ProtoTest.Verification: compares a run with a baseline, by report and by trace.ProtoTest.Web.Pages: the page model and coverage, shared by the web backends and ASP.NET Core.ProtoTest.WireMock: WireMock.Net fakes owned by a test or the run.
Core
- Readiness probes replace setup sleeps (
AddReadinessProbe,ProtoReadiness.Tcp/.Http). Infrastructure - One readiness policy (
ProtoTest:Readiness) tunes host probes and containers. Infrastructure - A per-test clock replaces sleeping (
ConfigureClock,Proto.Context.Clock,Advance/SetUtcNow). Time - Targets resolve through ordered provider chains; losers record named skip reasons. Environment resolution
- Applications, workers and containers declare one chain (
UseConfigured,UseInProcess). Environment resolution [RequiresTestClock]skips tests that need the test clock without a provider that bridges it. Skip conditionsIProtoTargetProvider.ConfigureServicesandResolveAfterare public. Environment resolution- Infrastructure with every declared key configured is skipped, unless
AddInfrastructureAlways. Infrastructure- The old
AddInfrastructure(piece, keys)skip rule is deprecated; the provider chain replaces it. Migrating from 1.0
- The old
IProtoConfiguredInfrastructurehands infrastructure the run's settings as it starts. InfrastructureAddRunSetup(name, delegate)adds a run-scoped step after the pieces registered before it. Infrastructure- Composite attributes expand recursively where attributes resolve, with cycles throwing the chain. Attributes
ProtoCapabilityDescriptor.Instancenames the instance a capability describes. Skip conditionsAddCapabilityWhenProvided/AddCapabilityUnlessConfiguredgate capabilities on keys. Skip conditions- One application-address precedence: a published address wins over configuration. Environment resolution
Proto.Context.UniqueName("tenant")derives a persistent-store-safe name from the test id. Execution contextProto.Context.Sql()is the primary accessor;Messaging(name)accepts a name. Execution context- Typed skip gates (
[RequiresWorker<T>],[RequiresServer],[RequiresApplication]). Skip conditions AddCapabilityReasonstates a skip reason once for the suite, a kind or a name. Skip conditionsProtoHost.HasApplication(name)andHasCapability(kind, name, instance)answer the typed skip gates. Skip conditionsProtoResourceState.Releasingreports a resource while its release callback runs. LifecycleStartTestAsyncaccepts a cancellation token onProtoExecutionContext. Execution contextProtoTest.Jsonhosts the shared JSON read, failure diagnostics and observation capture. ExtendingIProtoConfigurableOptions.FallbackConfigurationSectionNamekeeps an old section working. ConfigurationProtoOptionsRegistration.ConfigureKeyedregisters keyed per-client options. Configuration- The extension points a third-party integration needs are public. Extending
- A bare client name resolves across applications; an ambiguous name names both candidates. Clients
- Clients use protocol-scoped names and one registration path per integration. Clients
- One
Shouldassertion surface across protocols; request, message and reply assertions return their subject and chain, while Web element assertions are async. Assertions - Shape matching lives under
Should.MatchShape; old spellings stay as shims. Shape matching - Exhaustive shape mode (
exact: true) works on every shape surface through one matcher walk. Shape matching - OpenAPI and GraphQL collectors record the specification identity (
spec.source,spec.hash). Coverage ProtoProtocol.CoverageCategoryis optional and falls back to the protocol name. CoverageConfigureTracingcaptures CI facts withRunMetadataandRunMetadataEnvironmentVariables. ProtoTraceProtoApplication.ResolveSettingpublishes the settings-over-configuration precedence. Environment resolutionProtoAttributeOrdernames the setup order bands (Application,SessionDeclaration,Default). Hooks- Suites name their own sensitive values (
ConfigureRedaction,ProtoTest:Redaction); state and findings redact them like the defaults. ProtoTrace
Hosting
AddWorkerHost<TProgram>()runs a background worker or generic host in-process with the suite. Hosting
ASP.NET Core
ProtoTestHost.For<TProgram>(builder)composes an in-process application in one line. ASP.NET CoreAddAspNetCoreServersteps aside whenBaseUrlis configured. ASP.NET CoreAddLoopbackApplicationhosts a hand-builtWebApplicationon loopback. ASP.NET Core- Per-test service substitution (
Override,[ReplaceService]) builds a dedicated server. ASP.NET Core [SignedInAs]signs a test in;AddTestUserAuthentication()reads it app-side. AuthenticationProtoTestContextPropagationapplies the trace context and test id to raw requests. ASP.NET Core
REST and HTTP
- Read one value by JSON path (
ReadAsJson<T>("$.id")), with the protocol's failure evidence. Responses ReadRequired<T>returnsTand fails naming the subject or path when the body is empty or null. ResponsesShould/ShouldNotassert content type, headers, cookies and redirect location. ResponsesPostAsync(...).ExpectAsync(shape)asserts the response shape where the call is made. ResponsesRestTrafficCoverageCollectorreports the fields no shape assertion mentioned. Coverage- Protocol builders adopt the public authenticator, base-address and options resolvers. Extending
GraphQL
ReadDataAs<T>(jsonPath)andReadRequired<T>read data or fail naming the operation. Responses
gRPC
- Client options bind
ProtoTest:Grpc:Client; the legacyProtoTest:Grpcsection still binds as a fallback. gRPC ProtoGrpcBuilder.ProtocolNamenames the protocol key. gRPC
Messaging
ProtoMessage.MatchesShape(shape)picks a message in anAwaitAsyncpredicate with the shared shape matcher: true or false, nothing recorded, false for an empty or non-JSON payload. MessagingProtoDestination.Queue(name)awaits a named queue; adapters without queues refuse it by name. MessagingDeclare(...)orProtoTest:Messaging:DeclaredDestinationsdeclares suite-owned destinations. Messaging- Taps gain a code API (
AddMessaging(m => m.Tap(...))) that pre-binds destinations during setup. Messaging - Messages carry a routing key, and
PublishAsync/AwaitAsyncaccept one. Messaging ProtoMessagereads are typed (ReadAsJson<T>,ReadRequired<T>). MessagingUseBroker(factory, addressKeys)gates the Broker capability on an address key. MessagingUseMassTransit<Program>()publishes and awaits over the app's MassTransit harness. MassTransitMassTransitEnvelope.Wrap/Unwrapbuild and read the wire envelope, addresses included. MassTransitProtoMessageConsumerBaseexposes the one await contract to adapters. Messaging- RabbitMQ taps prepare and release in parallel, cutting per-test setup and teardown. Messaging
Devices
ProtoTest.Devicestalks to simulators and hardware from the test context and trace. DevicesAddInProcessWebSocketDevicesroutes device clients through the in-process server. Devices- Clients carry per-client transport settings (
WithSetting) filled intoDeviceEndpoint.Settings. Devices ProtoTest.Devices.Mqttspeaks MQTT 5;AddMqttClientdeclares the topics. DevicesProtoTest.Devices.Mqtt.Testcontainersowns a Mosquitto broker for the run. DevicesProtoDeviceConnectand its timeout live inProtoTest.Devices, shared by every transport. DevicesIProtoDeviceTransport.ConnectAsyncgains a default context overload for custom transports. DevicesProtoTest.Devices.Tcpconnects devices out (AddTcpClient) or listens for the system under test (AddTcpListener,ListenAsync). DevicesProtoTest.Devices.Serialopensserial://lines; a client without an address readsProtoTest:Devices:Serial:Ports:{client}. Devices- Stream framing (
IDeviceFramer,DeviceFramers,WithFramer) andStreamDeviceConnectionserve any byte-stream transport. Devices DeviceMessagewrites and reads device data strings as records, withSendMessageAsync/ExpectMessageAsync. Devices[DeviceChecksum<T>]and[DeviceFormat<T>]add checksums and field formatters (DeviceFormatters: scaled, hex, Unix time, BCD). Devices[DeviceBinaryMessage]writes and reads fixed-layout binary messages, withCrc16Modbus,Xor8ChecksumandSum8Checksum. DevicesDeviceMessageProtocolandAddProtocol(instance)report the message types no test expected. Devices
Web
WebPageInventory.VisitedObservationKind/VerifiedObservationKindname the page observation kinds. Web- The backend building blocks are public (
WebBackendOptions,WebBackendErrors,WebBackendDefaults). Web PlaywrightWebOptions.MaxTraceBytescaps a browser trace; 0 turns the cap off. Web- Sessions are created when requested and complete through the shared client lifecycle. Web
- Sessions key by name and application, and
Web()without an application finds the one session with that name, such as one[WebSession(Application = ...)]opened. Web WebDownloadimplementsIProtoBinaryContent, so a download feedsProtoSheets.Openin one line. Web
Sheets
model.Should.MatchHeaders()asserts the header row against the model in declaration order. Sheets- Key-value sheets declare labels with
[Label]and read throughWorkbook.KeyValueModel<T>(). Sheets
SQL and Data
ProtoDataValueContext.Clockgives defaults the test clock, so a default stamp followsProto.Context.Clock. DefaultsSqlOptions.AddressKeysdeclares the connection keys and gates the SQL and EF Core capabilities. SQLSqlAddressRulepublishes the declared-keys lookup for a sibling SQL provider. SQL- Generated member defaults are deterministic per test. Defaults
Testcontainers
UseContainerandDockerProbe.IsAvailable()skip without a Docker runtime. InfrastructureApplicationContainerruns an application under test in its own image. Infrastructure
Aspire
- A DCP that cannot start (its container-runtime check or its API server times out, as on a constrained CI runner) fails the start with
ProtoAspireUnavailableException, like missing orchestration binaries, so a suite skips with the reason. Aspire AddAspireAppHost<TEntryPoint>()runs an AppHost when selected and publishes its resources' addresses. AspireUseAspireResourceserves an endpoint or connection string through the provider chain. Aspire- The AppHost receives the suite's configuration and the run's settings as arguments. Aspire
WireMock
AddWireMock(name)fakes HTTP dependencies per test, with stubs as coverage gaps until hit. WireMock
OpenAPI
- Coverage reads specifications with
Microsoft.OpenApi3.x (JSON and YAML, including 3.1). OpenAPI
Runners and analyzers
- Opt-in low-ceremony mode (
[assembly: ProtoTestAutoWrap]) wraps plain tests in the lifecycle. Runners - One outcome classifier (
ProtoTestResult) and row-name helper (ProtoTestName.ForRow). Runners - XUnit v3 and TUnit pass their per-test cancellation token into the lifecycle; MSTest's 4.0.2 floor exposes none. Execution context
dotnet new prototest --runner <name>(nunit, xunit, xunit3, tunit or mstest) writes a suite per runner. OverviewProtoTest.AnalyzersreportsPT0001andPT0002for intent the runtime cannot check. AnalyzersPT0003flags a fixed wait andPT0004a hand-madeHttpClientin a ProtoTest test. Analyzers
Agent workflows
prototest summaryprints the diagnosis document. CLIprototest index <folder>writes a static index and digest for a folder of runs. CLIprototest feedbackandprototest verifypost the channels and print a verdict. CLIprototest-mcpreads.prototracefiles over stdio (list_runs,get_failure,get_coverage). Setupget_diagnosisreturns the run digest or one failing test's context package. Diagnosisget_suite_maplists what a new test reuses: clients, provisioners, attributes, pages, examples and gaps. Setup- The
prototest-write-testskill teaches writing a test on top of the suite and proving it. Coding agents dotnet new prototeststarts agent-ready:AGENTS.md,.mcp.json, both skills, a tool manifest and the analyzers. Coding agents- The demo endpoint (
samples/ProtoTest.Mcp.DemoEndpoint) serves the same tools over the demo trace. Coding agents ProtoDiagnosis.Readbuilds a deterministic digest;ReadContextadds one test's context. DiagnosisProtoTest.Verificationcompares a baseline and a candidate report. Verificationprototest compareand thecompare_runstool compare two runs test by test and name the operation where each broken, fixed or still-failing test left the baseline; a skipped test is not a failure, and steps pair across runs although their names carry ports or ids. CLIprototest proveand thecheck_fixtool return a fix receipt: proven only when the baseline failed, every rerun passes, nothing broke and the reports verify, with a named reason for each unmet condition. CLIprototest reviewand thereview_teststool say what each test proves: a body with no check, a call no check looked at, or an untraced gap, each with the next step. Diagnosisget_coveragesuggests where to cover each uncovered endpoint or page: extend the test that already calls or opens it, or write a new test shaped like the closest recorded call or browser journey (ProtoDiagnosis.SuggestCoverage). Setup- The MCP server offers three job prompts,
fix_failure,cover_changeandimprove_tests, each ending with the tool that judges it; the skills and the starter'sAGENTS.mdpoint at them. Setup ProtoReport.ReadJson(Stream)reads a report from a stream, such as the one a trace embeds. VerificationProtoTest.Feedbackposts a failing run's digest to a PR comment, annotations or a webhook. Loop- The ProtoTest Evidence action (
MSeys/prototest-action) compares a pull request's run with the base branch's last green run, posts what broke, what was fixed and the coverage that moved, runs the verdict over the embedded reports (optionally failing on new uncovered units) and keeps the trace. CI prototest feedback --baseline <trace>adds the comparison and the coverage that moved to the comment (each new uncovered unit with the test to start from, each unit no longer covered), and updates the pull request's one ProtoTest comment instead of adding another. A pull request from a fork skips the comment with the reason (its token cannot comment), and a refused post names the missingpull-requests: write.prototest verifyreads the reports two traces embedded (ProtoVerificationRun.FromTrace), and--strictfails a unit added without a test. CLI
Traces and reporting
- A suite built deterministically (
ContinuousIntegrationBuild, which maps sources to/_/) still records repository-relative locations and embeds its sources when it runs inside its repository. ProtoTrace - A check that runs after an await inside ProtoTest, such as
ExpectAsyncon a REST or GraphQL call, records the line of the test step it checks instead of no line. ProtoTrace - The HTML report reads like the viewer's run view: a headline that names what needs attention, a strip of every entry, a Needs attention list across all kinds and one tab per kind. Coverage is one tab with its own figure, not the page's headline. Reporting
- The report summary counts every kind in
Kinds, written to the JSON report next to the existing totals. Reporting - Run and test artifacts are declared and readable (
ProtoTraceArchive.Artifacts,ReadArtifact). ProtoTrace ProtoTest.Tracesreads the whole 2.0 archive and selects the viewer's failure. ProtoTraceProtoReport.ReadJsonreads the JSON report a sink wrote. Reporting- The HTML report ends with a quiet pointer to the viewer, naming the
.prototraceto drop there. Reporting
Viewer
- One ViewerMock component draws every viewer picture in the docs (the walkthrough's six views, the home's failing check and the coverage page's run header) from one file of the demo run's values, taken from the viewer itself; Timeline, State and Evidence now show the viewer's own rows, counts and positions. ProtoTrace
- The walkthrough, ProtoTrace guide and viewer README describe Steps, Timeline, State and Evidence, diagnosis rules, untraced gaps and run selections, with updated demo excerpts. ProtoTrace
- State uses the same test clock and phase marks as Timeline, shades the selected operation's time across the lifelines, and highlights the items and changes it touched. The ruler stays visible on phones. ProtoTrace
- The run names attention with the diagnosis rules, marks untraced gaps on its timeline, lists every environment value and the run id, and opens run operations and tracked items in the inspector. ProtoTrace
- Evidence brings observations, files, findings and moments into time order with the operation that recorded each; details show their metadata and sections, a section index jumps through an operation, and binary bodies are marked instead of drawn as broken text (
#/test/<id>/fileslinks still open). ProtoTrace - One test list on every screen, led by the run, with one filter for every list and a path from the run to the open operation; each test is a link. ProtoTrace
- A test's Steps open on the test body: setup and teardown fold into one line that says what they did, time with no recorded operation gets its own row, and the verdict names the failure with the rule
prototest summaryuses (#/test/<id>/storylinks still open). ProtoTrace - The Timeline replaces Spans: every operation on the test's clock, zoomed per phase, with framework machinery dimmed or hidden, moments and evidence marked on their bars, and untraced time drawn through the rows (
#/test/<id>/spanslinks still open). ProtoTrace - The viewer stays responsive on a 1,000-test run; the benchmark page states the open and search times. Benchmarks
- A skipped test reads as planned in the run strip, keyboard focus and touch targets work across the viewer, and the run header's outcome pill moves under the title on narrow screens. Trace viewer
- Each screen answers its question in order: failing rows name their reason, the failure names where in the test it started, step rows read stated observations inline, and an empty evidence list separates no files from no match. Trace viewer
- The run splits into Overview, Timeline, Operations, Details and Files instead of stacking every panel. ProtoTrace
- A Framework switch shows, dims or hides framework operations in Steps and Timeline, and the machinery in State. ProtoTrace
- The viewer works on a phone and with a keyboard: one tablist with arrow keys, readable rows on narrow screens, and text that meets WCAG AA. ProtoTrace
Docs and samples
- The site has a blog for articles on the problems ProtoTest solves, with RSS and Atom feeds. Blog
- A copy-in skill (
skills/prototest-evidence-loop) teaches agents the evidence loop and the CLI. Coding agents - The xUnit pages cover converting an existing suite and the Microsoft.Testing.Platform opt-in on SDK 10. Runners
- The integrations overview lists every
ProtoTest.Devices*package with a one-line purpose. Overview - The 46 packages are tiered into supported and preview sets, with the stability promise and the graduation path stated. Installation
- The web pages make the backend choice explicit (Playwright or Selenium), and the conversion order covers NUnit, MSTest and TUnit suites. Web
- The agent workflows document the feedback webhook payload, the configuration page lists every section's keys, and the template page shows what the scaffold creates. CLI
- The reference pages gain the recorded trace walks, the decision figures and the triage tables; the longest pages split into child pages (web page coverage, messaging adapters, gRPC calls, the ProtoTrace archive, the CI providers). Docs
- The home opens on the blueprint hero with the journey as test, composition and trace, then proves three claims with real artefacts: the plumbing each fixture stops writing, the failing check as the viewer shows it, and one model across integrations; the starter includes the working directory and runner options; the integration pages open with a shown test and keep reference detail below the tasks. Docs
- Tab strips in code and the viewer walkthrough scroll with a plain mouse wheel, fade only where there is more, and keep the selected tab in view. Docs
- Tabbed code keeps its copy button beside the tabs on a phone and fades the tab strip where it scrolls, and every figure in running text keeps a paragraph's distance to the text after it. Docs
- Tables read on a phone: every docs table labels its cells with the column heading at build time, and below 700px a row becomes a short card with the first cell as its title; the Level 5 modes comparison does the same, and the failure tour labels its questions quietly and says what opening a card shows. Docs
- The package builder reads its choices from the integrations catalog, so it offers every shipped integration (Selenium, RabbitMQ, SQL and its containers, workers, Aspire, WireMock, devices, analyzers) grouped like the map, and a docs test keeps the catalog equal to the shipped packages. Integrations
- Trace figures speak the viewer's language: the layer-by-layer trace marks each phase in its colour with quiet operation rows, and a pointer to a recorded test reads as a viewer test row with an Open in the viewer button; wrapped code keeps its first token beside the line number. ProtoTrace
- Every Learn lesson is rewritten to one shape (the problem, do it, what happened, check yourself, remember) in plain Markdown with a lesson banner, and Across boundaries adds five lessons built on the sample's own tests: call an API, read back over GraphQL, check the database, drive the browser and follow a message. Learn
- Learn is regrouped into seven tracks (Start, Write good integration tests, Across boundaries, Reliable tests, Understand failures, Real systems, Extend ProtoTest), shown as cards read from the sidebar; every old lesson address redirects, and lessons get a Markdown-first shape with a small lesson banner. Learn
- The Vocabulary page explains every ProtoTest word in one plain sentence and links the lesson that teaches it and the page with the details; lessons explain a word again at its first use. Vocabulary
- The API docs of
UniqueName,SignedInAsAttribute.Claims,IProtoMessageConsumerand the readiness probe say what they guarantee: unique within a host (a rerun matches only with an id generator that derives from the test), claim types only inauth:user, isolation per exchange tap. Test context - Getting started reads plainly: each page says what it is for, introduces its terms in plain words, says what you should see after each step, and folds what only some readers need; the troubleshooting page no longer presents the CI examples'
PROTOTEST_RESULTSvariable as a ProtoTest setting. Getting started - Start here opens with one paragraph and four starting points (try it, learn it, weigh it, use it) in two columns, and the sidebar narrows between tablet and wide screens so the text keeps its measure. Docs
- The READMEs follow one shape per kind, from the root to the package pages. Docs
- Northstar with the Learning demo suite is the in-repo sample. Learn
- The coding agents page, the evidence loop lesson and the README describe ProtoTest as the judge above a coding agent: three jobs, each ending with the tool that decides it is done. Coding agents
- A message-to-fix table in troubleshooting, a where-your-evidence-goes map and a which-runner chooser. Troubleshooting
Packaging
- 46 packages pack in one version, 18 more than 1.0; the installation page lists the supported and preview tiers. Installation
Fixes
Core
- Assertion messages across GraphQL, gRPC, messaging, REST and Sheets use a plain hyphen separator. Assertions
- Ambient-context errors name the fix (
FindTraceWriter,SetContext, the runner setup). Lifecycle - Trace snapshots can be read while other tests record observations, attachments and findings. ProtoTrace
- Diagnostic request URLs keep a root-relative path on Linux and macOS instead of turning it into a
file://address. ProtoTrace Build()is terminal; every public registration after it throws the single-build message. Lifecycle- Shape mismatches with value constraints record every mismatch, not an internal type name. Shape matching
ProtoPollingwaits out a deadline less than a millisecond away instead of probing in a tight loop until it passes. Time- Malformed JSON bodies and report metadata are redacted with the same policy as the trace. Attachments
- A failed run start unwinds completed run hooks in reverse and keeps the trace silent. Lifecycle
- A scope disposed off its async flow records a
Lifecyclefinding and throws. Lifecycle - A throwing run gate keeps its exception and stack in the trace and report metadata. Hooks
- Telemetry capture failures record one coalesced
telemetry.capture_failedevent. ProtoTrace [Application]runs before every other setup attribute. Attributes- A sink added directly to the service collection is exported once, like one added with
AddSink. Reporting - GRPC and messaging share one failure record and the
{protocol}.diagnostics.failedevent. ProtoTrace ResolveStatereturns only the state the[Application]attribute set during the lifecycle. ASP.NET Core- Container starts and device connects are bounded on release and recorded as abandoned. Lifecycle
- An off-flow dispose releases the orphaned test's context before it throws. Lifecycle
ASP.NET Core
- An application that fails to start reports its own exception, also when WebApplicationFactory reaches its host after the application disposed it. ASP.NET Core
- The in-process HTTP client is owned by its test, fixing a teardown crash. ASP.NET Core
- A repeated
AddAspNetCoreServername with another program throws naming both. ASP.NET Core
REST and HTTP
- A client bound to a configured or published address gets its own handler and cookie jar per test. Clients
- Response and attachment defaults bind
ProtoTest:Http:Responses; attachments stay opt-in. Attachments - Binary request and response bodies are traced as bytes with their media type. A binary response records its media type and length; it stores no decoded body, no JSON body block and no decoded text in a status assertion. Responses
GraphQL
- A null GraphQL execution result is tolerated, and subscription events are disposed as they advance. Subscriptions
- A rejected subscription names the server's errors. Subscriptions
- A fluent upload argument fails when the document is built instead of rendering as a literal. GraphQL
gRPC
- A transport with no base address fails naming
AddClientand the application's keys. gRPC - Client options are per named client; the shared section binds over each callback. gRPC
- A call that misses its deadline in-process reports
DeadlineExceeded, as over a socket, instead of the transport's abort. gRPC
Messaging
- Awaiting two destinations no longer misses the second destination's first delivery. Messaging
- Awaits serialize and an unmatched delivery is kept for a later await, across brokers. Messaging
UseRabbitMqdeclares the Broker capability only when a connection string is available. MessagingAddMessagingdeclares Broker withUseBrokerWhenInProcess, replacingUseBrokerUnlessConfigured, and MassTransit's Broker follows its application's chain. MassTransit- A missing or non-amqp RabbitMQ connection string fails naming the configuration key. Messaging
UseRabbitMqruns its options callback once per registration. Messaging- RabbitMQ uses
RabbitMQ.Client7.x end to end (async connect, channel, publish, consume). Messaging - A tap with a missing exchange fails only the tests that await it, with the named error. Messaging
- Publishing to a released broker throws instead of reopening, and a repeated release is a no-op. Messaging
Web
- A failed backend creation is no longer cached, so a session retries from a clean slate. Web
- Only the backend that wins the first-wins registration declares the browser capability. Web
- Selenium
Check/SelectOptionverify the resulting state or fail within the action timeout. Interactions - Assertions poll at
IWebBackend.PollInterval; over-cap traces and stuck pumps are recorded. Diagnostics
Sheets
int/longreads accept only finite, integral, in-range values and fail naming the cell. Sheets- Record models construct through their mapped primary constructor. Sheets
- A repeated
AddSheetscomposes its options callbacks instead of keeping the first. Sheets
SQL and Data
- Building a value with a
DateTime,DateTimeOffset,decimalorGuidmember no longer overflows the stack while tracing it. Defaults - Optional constructor-parameter defaults win over generated values. Defaults
- A run whose declared keys are unprovided keeps the hooks inert and names the required gate. SQL
Testcontainers
- Container readiness honors the run's readiness policy. Infrastructure
- A released container can be started again, and its connection string is cleared. Infrastructure
Runners and analyzers
- An NUnit test body that throws is recorded failed with its exception and source location. NUnit
- A body
OperationCanceledExceptionrecordsCancelledunder xUnit v2 as under the other adapters. Runners - TUnit parameterized rows record their arguments in the trace name. TUnit
- The MSTest floor accepts the standard template's version, and every runner page states its framework minimum. Runners
Breaking changes
These are the 1.0 to 1.1 migration changes; from 1.1 onward the 1.x surface stays additive.
Core
AddClientFromis removed from the REST and GraphQL builders.- Register clients under an application and configure its base URL or endpoints, or use an
AddClientresolver (Clients).
- Register clients under an application and configure its base URL or endpoints, or use an
- Registration, observation and runner implementation types are internal; use the public APIs.
ProtoHostcan no longer be constructed from a service provider; useProtoHostBuilder(Lifecycle).IProtoClientInitializer.TryInitializeAsyncno longer takes a cancellation token.- Pass one to
StartTestAsync, or use a run hook as the cancellable extension point (Lifecycle).
- Pass one to
ProtoExecutionContext.RegisterClient<T>takesProtoClientOwnershipinstead of abool.ProtoClientOwnership.Contextis a client the test owns;ProtoClientOwnership.Calleris one the caller owns (Clients).
ProtoDocumentSource.LoadTextis one method with optional parameters; the explicit overload is gone (Extending).- Shape mismatches throw the protocol's assertion exception, with
JsonShapeMismatchExceptionas the inner.- Code that caught
JsonShapeMismatchExceptioncatchesProtoAssertionException(Migrating from 1.0).
- Code that caught
ProtoTest.OpenTelemetryis retired.- Subscribe to the
ProtoTestsource with.AddSource("ProtoTest")(OpenTelemetry).
- Subscribe to the
ASP.NET Core
- The package now depends on
ProtoTest.Web.Pagesinstead of the fullProtoTest.Web.
REST and HTTP
ProtoHttpAuthLifecycleHookis sealed and takes aProtoProtocolinstead of a string.ProtoHttpClientResolutionis a positional record withSourceName,SourceClientNameandDeconstructgone, andProtoHttpClientResolver.Resolvetakes the client name as an optional third argument (Extending).
- Object request bodies serialize camelCase by default, matching GraphQL variables.
- Pass explicit
JsonSerializerOptionsto keep another naming policy (Migrating from 1.0).
- Pass explicit
gRPC
GrpcAttachmentOptionsno longer derives from the HTTP attachment options, soSensitiveHeadersandSensitiveQueryParametersare gone.- Metadata redaction uses the gRPC client's
SensitiveMetadataKeys(gRPC).
- Metadata redaction uses the gRPC client's
ProtoGrpcClient.ServerStreamingandDuplexStreamingmoved to the blocking facade,client.Blocking(gRPC).
Messaging
- A publish records the
messaging.publishedobservation; the operation staysmessaging.publish.- Update a collector that filtered the old observation kind (Migrating from 1.0).
RabbitMqOptions.PollIntervalis removed; awaits are event-driven andMessagingOptions.DefaultTimeoutbounds them (Messaging).
Web
ProtoTest:Web:Sessions:{name}settings no longer configure sessions.- Put addresses under
ProtoTest:Applications:{application}and select with[WebSession]orWeb()(Web).
- Put addresses under
- The reshape removed
IWebBackend.CurrentAddress, the oldWeb()overload and Selenium's download surface.- The web pages describe the replacements;
CompatibilitySuppressions.xmlrecords the removals.
- The web pages describe the replacements;
PlaywrightWebOptions.Contextis removed; configure the browser context withConfigureContext(Web).RequiresPlaywrightBrowserAttribute.Sessionis removed; the condition probes the configured browser or channel (Skip conditions).WebOperationContext.Resultis no longer public (Web).
1.0.1
20 September 2026
Fixed
- Preserve binary REST response artifacts byte-for-byte instead of converting them through text. This
keeps downloaded workbooks, PDFs, archives, images and other binary responses valid inside
.prototracefiles. - Correct API documentation links emitted from XML comments across the HTTP, Sheets and Web packages.
Added
- Preview
.xlsxartifacts directly in the ProtoTrace viewer, with worksheet tabs, dimensions, sticky row and column headers, typed cell values and bounded rendering for large workbooks. - Add focused, shareable recipe traces for REST-to-GraphQL, REST-to-database and workbook journeys.
- Publish a generated .NET API reference alongside the task-oriented documentation, with one command producing the complete uploadable site.
- Add documentation quality, link and API-reference workflows; contributor, support, security and code-of-conduct guidance; richer CI guidance; and interactive stack and trace examples.
Changed
- Improve the documentation landing page, navigation, SEO metadata, social preview and per-page feedback.
- Harden release validation: every ProtoTest package must share one version, every symbols package must match its DLL paths and portable-PDB identities, and a release tag must match the package version.
- Refuse duplicate NuGet versions during publishing so a rebuilt symbols package cannot be paired with an already immutable DLL from another commit.
1.0.0
19 September 2026
ProtoTest 1.0 is here. What began as a stubborn idea, that an integration test should read like the scenario it describes while the framework quietly owns everything around it, is now a stable foundation for .NET 8, 9 and 10. One host, one execution context and one explicit lifecycle; the test runner you already use; and every integration sharing the same assertions, evidence and coverage, all the way down to a portable trace you can open and read. Every package ships together at 1.0.0, documented, tested, and ready for production suites.
ProtoTest is a composable integration-testing foundation: compose capabilities onto a host, and each test runs through a recorded lifecycle of phases, operations, state changes, checks and findings.
Added
Host and lifecycle
- One
ProtoHostper test process and oneProtoExecutionContextper test, with run hooks and gates, test hooks, attributes, typed state, clients, attachments, findings and owned resources. - Skip conditions (
[RequiresCapability],[RequiresInProcess],[RequiresPlaywrightBrowser]) that stop a test before its lifecycle starts when the host cannot run it.
Integrations
- REST (
ProtoTest.Rest): HTTP clients,[Auth<T>], status and shape assertions, REST coverage. - GraphQL (
ProtoTest.GraphQL): queries, mutations, WebSocket/SSE subscriptions, uploads, schema coverage. - gRPC (
ProtoTest.Grpc): unary and streaming clients, metadata auth, method coverage. - Messaging (
ProtoTest.Messaging,ProtoTest.Messaging.RabbitMq): publish and await messages on an in-memory default broker or RabbitMQ. - SQL and EF Core (
ProtoTest.Sql,ProtoTest.Sql.EntityFrameworkCore): one database connection per test, optional transaction isolation, and aDbContextover the same connection. - Data (
ProtoTest.Data): deterministic builders, member defaults, provisioners and theRef<T>identity map. - ASP.NET Core in-process (
ProtoTest.AspNetCore): host the application inside the test process, with server DI access. - Browser sessions (
ProtoTest.Webwith Playwright and Selenium backends): sessions, page objects, flows, login and page coverage. - Spreadsheets (
ProtoTest.Sheets): cell, column, range, table and typed-model assertions for.xlsxfiles. - OpenAPI (
ProtoTest.OpenApi): contract coverage over REST response and shape observations. - Containers (
ProtoTest.Sql.Testcontainers,ProtoTest.Messaging.RabbitMq.Testcontainers,ProtoTest.Testcontainers): run-scoped PostgreSQL and RabbitMQ, or your ownProtoContainerResource<TContainer>.
Observability
- Coverage of REST endpoints, OpenAPI documents, GraphQL schemas, gRPC services, web pages and spreadsheet ranges.
- ProtoTrace format 2.0: a portable
.prototracebundle (spans.json,state.json) recording what ran and what existed and changed, read in the viewer. - Reports (
ProtoTest.Reporting): JSON and HTML report sinks. - OpenTelemetry bridge (
ProtoTest.OpenTelemetry): export ProtoTest operations as OpenTelemetry spans.
Runners and templates
- Adapters for NUnit, xUnit v2, xUnit v3, MSTest and TUnit, sharing one lifecycle and one set of outcomes.
ProtoTest.Templates:dotnet new prototestcreates an API and a suite for it, already composed, traced and reported.
Welcome to 1.0. Install a package, compose the capabilities your system actually has, and run the same suite in-process, in containers, or against a published environment. The trace will tell you the rest.