Course outline

Svelte / Advanced: rendering, resources and release evidence / Lesson 16

Testing components, loads, actions and safe evidence

Match test claims to compiler, DOM, server and source boundaries while keeping fixtures deterministic and private data out of diagnostics.

About 4 min readContent reviewed
On this page

Lesson goals

  • Separate pure helper tests from component and Kit integration tests.
  • Assert identity, effects, cleanup and accessible interaction rather than status alone.

Choose the boundary that can actually fail

A plain validator test proves its own value decisions, not rune compilation or binding coercion. A component test adds the selected DOM/compiler environment, while a Kit route test adds load/action conventions, hooks and serialization. A browser test can verify navigation, enhancement, focus and hydration that a direct function call bypasses. Choose the smallest meaningful test for each risk and consult current official runner guidance. Do not install packages or start the configured project just to test a deterministic calculation. Pure fakes should replace source access before a test accidentally creates a connection or reads real credentials.

Derive fixtures from this component and route contract

The JSON matrix names required checks rather than passed tests. A keyed editable list needs reorder-after-edit cases; a binding needs empty/invalid/reset input; an effect needs setup/rerun/cleanup; a private action needs current authority and no write on rejection. Direct load and client navigation can reuse components differently, so retain both. Keep expected domain rejection separate from unexpected source failure. Use safe synthetic identities, fixed clocks and controllable promises rather than arbitrary sleep or private live records. An HTTP status alone cannot prove that a rejected request caused no effect or that successful data belongs to the correct tenant.

json Synthetic component/route test matrix
{"componentCases":["keyed-reorder-after-edit","binding-empty-invalid-reset","effect-rerun-cleanup"],"kitCases":["direct-load-vs-navigation","denied-action-no-write","enhanced-and-native-submit","safe-source-failure"],"execution":"plan-only"}

The record describes required assertions, not completed browser or framework tests. It can be parsed offline.

Verify rejection before a protected write locally

The local adapter checks a tenant prerequisite before calling an injected writer. A denied caller causes zero effects; the eligible caller causes exactly one. This is not a session verifier, Kit hook or transaction implementation. It is meaningful evidence of a sequencing invariant that should also hold in the real action. Use the same object scope for paired callers and assert the actual write spy rather than just a DENIED string. A real server integration must additionally prove that trusted locals and validated inputs reach this policy and that no alternate path bypasses it.

javascript Complete offline policy-before-effect test
function update(principal,tenant,writer){if(principal.tenant!==tenant)return {code:"DENIED"};return writer();}
let writes=0;const writer=()=>({revision:++writes});
console.assert(update({tenant:"lab-b"},"lab-a",writer).code==="DENIED");
console.assert(writes===0);
console.assert(update({tenant:"lab-a"},"lab-a",writer).revision===1);
console.assert(writes===1);

Denied work never invokes the writer. No request, credential, durable source or framework is involved.

Record safe stages and resource outcomes

Use reviewed route/operation identifiers, phase, outcome category and bounded source counts. Do not log raw FormData, cookie values or private load payloads. Separate server source wait, render work and browser behavior when investigating latency. Overlapping spans cannot simply be added as elapsed time, and a source timeout may leave work active if cancellation is unsupported. Correlate failures through controlled IDs rather than high-cardinality user labels or exposed stack traces. Cleanup evidence should name the actual owned resource, not merely a generic component-unmounted message that says nothing about a listener or source task.

Keep verification claims reproducible and bounded

Record exact runtime, package/compiler versions, executed model names and unexecuted integrations. A source-text check cannot establish Svelte scheduling, while a mocked action result cannot prove native form behavior or a browserโ€™s origin enforcement. Broaden checks only when a change or unresolved concern justifies them. This course parses the matrix and executes the writer-spy model only; no test framework, component compiler, browser, Kit server, database or load test is run. Use approved installed tools for actual authorized integration and preserve honest limitations so the next reviewer knows what remains to verify.

Common errors and fixes

A local function test is called a compiled component test

Why it happens
The report ignored compiler and DOM boundaries that never executed.
How to fix it
Label local, component, route and browser evidence separately.
Prevent it next time
List exact execution and material untested behavior beside results.

An action rejects after a write

Why it happens
Tests asserted response shape but not protected source effects.
How to fix it
Assert zero writer calls on every rejected branch.
Prevent it next time
Keep paired allowed/denied cases with the same object scope.

Async tests pass only with arbitrary sleep durations

Why it happens
Completion ordering was uncontrolled and dependent on live timing.
How to fix it
Use deterministic promises, clocks and explicit completion signals.
Prevent it next time
Exercise both old-first and new-first result orders.

Check your understanding

1. What does the writer spy prove that a DENIED status does not?

Show worked solution

It proves this local branch did not invoke the protected effect before returning denial. A flawed implementation can otherwise write first and reject later. The spy does not prove authentication or source atomicity, so combine it with real entry/persistence tests when those integrations are authorized.

2. Why are direct load and client navigation separate fixtures?

Show worked solution

Execution environment, component reuse and tracked dependency reruns can differ. A full reload may hide a stale copied prop or missing cleanup that appears during reuse. Verify both under the same route/configuration and record compiler/browser behavior rather than assuming one path certifies the other.

Key takeaways

  • A test claim must match the boundary that actually ran.
  • Identity, effects and cleanup matter alongside visible output.

Official references