1. Choose the lane
| Work | Required runtime | Package |
|---|---|---|
Use VanillaTestSuite natively | .NET 8 or newer | vanilla-test 2.1.0 |
| Run ordinary MSTest natively | Your supported .NET test SDK | MSTest adapter/framework |
| Publish browser WebAssembly | .NET 10 SDK + wasm-tools | vanilla-test.tool 2.1.0 |
The core library does not require the browser tool. Add the tool only to projects that need a deployable browser test.
2. Install the core
gh release download 2.1.3 --repo RIAEvangelist/vanilla-test --pattern '*.nupkg' --dir ./packages
dotnet add package vanilla-test --version 2.1.0 --source ./packagesThe package is currently a GitHub release asset rather than a NuGet.org package. Verify its SHA-256 digest, then use the download directory as a local source. The core targets net8.0 and has no third-party runtime dependencies.
using VanillaTest;
var test = new VanillaTestSuite();
test.Expects("addition preserves the total");
if (1 + 2 == 3) test.Pass(); else test.Fail();
test.Done();
TestResult result = test.Report();
if (!result.Ok) throw new InvalidOperationException(result.Report);Call Done() for every active case. Calling it without a prior decision intentionally records a failure. Once Report() succeeds, the same result object is returned on every later call.
3. Keep the inventory in MSTest
A browser-capable test project can use the ordinary MSTest attributes. This minimal project pins the versions used by this repository:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="4.3.3" />
<PackageReference Include="MSTest.TestFramework" Version="4.3.3" />
<PackageReference Include="vanilla-test" Version="2.1.0" />
</ItemGroup>
</Project>Run it natively first:
dotnet test --configuration ReleaseNative MSTest is the canonical path for filters, data-driven cases, runner integrations, and complete failure diagnostics.
4. Build the browser AppBundle
dotnet workload install wasm-tools
dotnet tool install --global vanilla-test.tool --version 2.1.0 --add-source ./packages
dotnet vanilla-test --browser --project tests/MyProject.Tests.csprojThe tool resolves paths from the selected project, creates a generated host under obj/vanilla-test/browser-host/, and publishes a Release net10.0 application for browser-wasm. With no --out-dir, the AppBundle lands in dist/vanilla-test/ beside that project.
dist/vanilla-test/
├── index.html
├── browser.js
├── runtests.mjs
├── _framework/
└── .vanilla-test-browser-outputThis is a multi-file deployment. Keep the complete _framework/ tree beside the page and scripts. The ownership marker lets later builds safely refresh the directory; the tool refuses to overwrite an unrelated nonempty destination.
MSTest 4.3.3 does not expose the stable Microsoft.Testing.Platform browser path this lane needs. The generated host therefore uses MSTest attributes plus deterministic reflection. It runs public, parameterless test methods; parameterized and data-expanded runner features stay native.
5. Test a custom page
Start from the tool's built-in runner, preserve its required hooks, and add visible site checks:
<h1
data-csharp-browser-site-check="browser site renders its heading"
data-csharp-browser-expected="Dashboard tests"
>Dashboard tests</h1>
<code data-csharp-browser-target>browser-wasm</code>
<p data-csharp-browser-result>Starting…</p>
<strong data-csharp-browser-score>0/?</strong>
<ol data-csharp-browser-checks></ol>
<pre data-csharp-browser-console></pre>
<script type="module" src="./browser.js"></script>dotnet vanilla-test --browser \
--project tests/MyProject.Tests.csproj \
--page tests/browser.html \
--out-dir artifacts/browserThe custom page becomes the AppBundle's index.html. Each marked element must be visible. When data-csharp-browser-expected is present, its rendered text must match exactly. The target marker must say browser-wasm.
6. Serve and verify the whole directory
npx --yes node-http-server@10.0.0 \
--root dist/vanilla-test \
--port 4173Open http://localhost:4173/. The pinned node-http-server command serves the complete AppBundle from its generated root. The page imports _framework/dotnet.js, captures the .NET console stream, renders browser checks, and verifies that the MSTest summary has no failed methods. Static hosting must preserve the generated paths and serve WebAssembly assets with an appropriate MIME type.
For a command-line CI pass, run the included Node entry from the AppBundle:
node tests/dist/vanilla-test/runtests.mjs --output Detailed7. Know what the reflection host runs
- Public instance methods with
[TestMethod]on[TestClass]types are discovered in deterministic type-and-method order. - A fresh class instance is constructed for every method.
- Parameterless synchronous,
Task, andValueTaskmethods are supported. [Ignore],[TestInitialize],[TestCleanup],IDisposable, andIAsyncDisposableare honored.- Parameterized methods fail with an explicit unsupported message; data-row expansion and
TestContextinjection are not emulated.
The repository uses this exact host to run its same seven core MSTest methods, including the Behavioral Given/When/Then journey, in the browser. Use native dotnet test when a suite depends on broader adapter behavior.
Next
Complete examples
Use the native class, MSTest inventory, CLI invocation, or custom page directly.
Open C# examples →API contract
Review every public member, stable error code, result property, and tool option.
Open the C# API →