Read the trace
Your first journey passed. The trace holds what it actually did: what the run composed, what setup provisioned, what the test called, what each check read, and what teardown released.
- Walk a test trace layer by layer: run, setup, execution, teardown.
- Find the same layers in a trace your own test wrote.
- Read a failure message that names the property and both values.
- Write your first test (lesson 2). Keep
MyFirstJourney.csif you want your own trace to compare, and for the Level 6 exercises that reuse it. - Nothing installed if you read the archive; running needs the sample from lesson 1.
The scenario
A passing test is the easy case. The hard case is the same test failing at 3 a.m., where the only witness is the trace. This lesson reads one test slowly, then finds the same shape in the trace your own test wrote.
The walk below reads the clock journey from Level 0, because it holds one of each layer. Your first journey has the same shape with fewer entries.
One test, layer by layer
- Runbefore the first test
What the run composed, and where the application ran. This is what the viewer shows on the run screen.
Recorded operations (4)
- REST, GraphQL, ASP.NET Core, SQL, Data, Sheets, Playwright
- ProtoTest.SampleApp.Program
- Northstar web on a loopback listener
- .NET 8.0.31 on Windows 10.0.26200, X64
- Setup508.4 ms
Everything before the test body: hooks, attributes, clients, the database connection and the state the test asked for.
Recorded operations (5)
- Setup
- Rest, GraphQL, and the web client
- Open SqliteConnection
- Application, NorthstarTenant
- SignedInAs, NorthstarMember
- Execution286.8 ms
The test body. New entries nest under test.execution; the clock move is an event on it.
Recorded operations (10)
- Test execution
- Create · IssueInvoiceRequest
- Provision · IssueInvoiceRequest to InvoiceResponse
- Clock advanced by 8:0:00:00
- invoice.issue
- REST · GET /api/v1/organization
- Assert status · 200 OK
- Assert response shape
- REST · POST /api/v1/invoices/{invoiceId}/pay
- Assert response shape
- Teardown40.6 ms
What the test leaves behind, and what the run releases for it. The trace records the releases, so a leaked resource would show here.
Recorded operations (4)
- Teardown
- 5 REST artifacts and the scenario summary
- Cleanup · TenantResponse
- Application services, database connection, messaging consumer
What this trace cannot see
Test sideObservedApplicationThe run recorded values from the test side and from the application itself. Nothing was recorded as observed in a response, so the trace does not claim to have seen a value the test did not read. These are the edges of that picture.
- Work outside the composition
The environment drill used a raw HttpClient against a fixed address. Its test.execution span ran 2.05 s and recorded no operation at all; the entry holds the connection failure, and the call it never wrapped cannot appear in the trace.
- Work inside the application
invoice.issue and invoice.pay are there because the demo application reports that activity source. A step the application does not report has no span, however much it did.
- Wall time
The clock item records the delta and the moment the clock stands at. It cannot tell you how long anything would have taken on the real clock.
docs/static/lessons/l0-time-fix.prototrace. The viewer draws the same trace from that archive (download it and drop it on the viewer).The same layers in your own trace
Your first journey leaves a smaller trace with the same four layers. From l1-first-journey.prototrace:
- Run: the capabilities the composition declared, the in-process application, and the loopback instance the browser journey follows.
- Setup: each client initializes once (
Initialize · Rest:Northstar,GraphQL:Northstar, and the rest), the SQL connection opens,NorthstarTenantprovisions the tenant withdata.create · ProvisionTenantRequest, andSignedInAssets the member identity. - Execution:
POST /api/v1/projectsleaves the request, the response and the expected shape as artifacts; the auth handlers apply; the application reports its ownproject.create; and the two checks record what they read. - Teardown: four attachments publish,
data.cleanup · TenantResponseremoves the tenant, and each owned resource releases in order.
When your test passes, that list is the proof of what it did. When it fails, the same list tells you which step to read first.
When a check fails
The checks are the part to read first, because each one records what it compared. A status check names the status it expected and the one it received. A shape check names the JSON path and both values:
[$.status]: Values did not match. (Expected: "past_due", Actual: "active")
That is the clock drill from Level 0. The message says which property, what the test expected and what the application sent. Read the call the check judged and its inputs. The fix is one value or one clock move.
The two places that hold those values are the runner output and the trace. The trace records the failed assert.json.shape entry and, beside it, the expected shape as an artifact, so the shape the test asked for is in the file too. The reports are the run's verdict: report.html marks the test failed and report.json carries the coverage and traffic rows. Neither one carries the expected and actual values, so a report is the place to confirm that a test failed, not the place to find out why.
Checkpoint
Change the shape assertion to expect a different name, for example name = "someone-else". Before you run it, predict what the failure message will name.
[$.name]: Values did not match. (Expected: "someone-else", Actual: "..."). The actual value is the name the test sent in the request, so the message points at the value to fix. The shape check reads the whole response, not one field, and reports every property that differs.What you learned
- A trace answers what ran, where it ran, and what each check read.
- Setup and teardown are part of the story, not noise around it.
- A failing shape check names the property and both values, so the fix is visible in the message.