User Input
$ARGUMENTS
You MUST consider the user input before proceeding (if not empty).
Overview
You are executing the Run Tests Skill. This skill builds and runs Uno Platform runtime tests with the correct base64 filter encoding that the test runner requires. It handles the non-obvious encoding requirement and provides correct platform-specific commands.
Execution Workflow
Phase 0: Parse User Input
Determine what to run from the user's input:
- All tests: No filter needed
- Specific test class: e.g.,
Given_Button→ resolve to fully qualified name - Specific test method: e.g.,
Given_Button.When_ContentSet→ resolve to fully qualified name - Multiple tests: Pipe-separated list of fully qualified names
If the user provides partial names, search src/Uno.UI.RuntimeTests/Tests/ to resolve fully qualified test names (namespace + class + method).
Determine target platform from user input. Supported platforms:
| Platform | Keyword(s) | Default |
|---|---|---|
| Skia Desktop | desktop, skia, or unspecified |
Yes |
| Skia WASM | wasm, webassembly, browser |
No |
Default: Skia Desktop (fastest build and execution).
Choose Skia WASM only when:
- The user explicitly asks for WASM/browser testing, OR
- The bug or behavior is WASM-specific (e.g., DOM interaction, browser rendering, JS interop)
Strict mode: If the user input contains the keyword strict, omit the -p:UnoFastDevBuild=true and -p:UnoTargetFrameworkOverride=net11.0-desktop flags from the build command in Phase 1 so the build runs with full CI-equivalent analyzer coverage and all cross-targeted TFMs. Use this only when verifying that a change still compiles cleanly under CI strictness — for normal iteration the default (fast) flags should be left on.
Phase 1: Build the Test App
CRITICAL: Set timeout to 15+ minutes. NEVER cancel builds.
The default build commands below pass -p:UnoFastDevBuild=true (disables analyzers for local iteration — has no effect on CI) and -p:UnoTargetFrameworkOverride=net11.0-desktop (skips the redundant cross-targeted output for Skia libraries). Combined, these cut a clean SamplesApp desktop build from ~3:23 → ~1:59 and a Uno.UI-incremental rebuild from ~2:23 → ~0:58 on a 32-core Windows machine. Omit both flags if the user requested strict mode (see Phase 0).
Skia Desktop (default)
dotnet build src/SamplesApp/SamplesApp/SamplesApp.csproj -c Release -f net11.0-desktop -p:UnoFastDevBuild=true -p:UnoTargetFrameworkOverride=net11.0-desktop
Skia WASM
dotnet publish src/SamplesApp/SamplesApp/SamplesApp.csproj -c Release -f net11.0-browserwasm -p:UnoFastDevBuild=true -p:UnoTargetFrameworkOverride=net11.0-browserwasm
Note: WASM requires publish (not just build) to produce the static web assets needed for hosting.
If the build fails:
- Read the error output
- Diagnose the issue (missing restore, compilation error, etc.)
- Fix or report the issue before attempting to run tests
Phase 2: Construct the Filter
If running specific tests (not all tests):
Format the filter string: Fully qualified test names, pipe-separated
- Single test:
Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml.Given_Control.When_Scenario - Multiple tests:
Test1|Test2|Test3
- Single test:
Base64 encode the filter (the
UITEST_RUNTIME_TESTS_FILTERenv var accepts ONLY base64-encoded values):bash (Windows Git Bash / Linux / macOS):
export UITEST_RUNTIME_TESTS_FILTER=$(echo -n "fully.qualified.TestName" | base64)PowerShell:
$env:UITEST_RUNTIME_TESTS_FILTER = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("fully.qualified.TestName"))For multiple tests, join with
|before encoding:export UITEST_RUNTIME_TESTS_FILTER=$(echo -n "Namespace.Test1|Namespace.Test2" | base64)WASM-specific: When passing the filter via URL query parameter, replace
=with!in the base64 string to avoid URL parsing issues. The app reverses this substitution before decoding:FILTER_B64=$(echo -n "fully.qualified.TestName" | base64) FILTER_B64_ESCAPED=${FILTER_B64//=/!}
Phase 3: Run Tests
Skia Desktop (default)
Navigate to the build output and execute:
cd src/SamplesApp/SamplesApp/bin/Release/net11.0-desktop
dotnet SamplesApp.dll --runtime-tests=test-results.xml
If running filtered tests, set the env var first:
export UITEST_RUNTIME_TESTS_FILTER=$(echo -n "fully.qualified.TestName" | base64) && cd src/SamplesApp/SamplesApp/bin/Release/net11.0-desktop && dotnet SamplesApp.dll --runtime-tests=test-results.xml
Results are output in NUnit XML format to test-results.xml (relative to CWD).
Skia WASM
WASM tests run in a browser. The published app is served over HTTP, and test parameters are passed as URL query parameters. The app writes results back via a companion HTTP server.
Step 1: Locate the publish output
PUBLISH_DIR="src/SamplesApp/SamplesApp/bin/Release/net11.0-browserwasm/publish/wwwroot"
Step 2: Start the HTTP file server and the file-creation companion server
# Serve the published app on port 8000
python -m http.server 8000 -d "$PUBLISH_DIR" &
HTTP_PID=$!
# Start the companion server that receives file-write POST requests on port 8001
python build/test-scripts/skia-browserwasm-file-creation-server.py 8001 &
COMPANION_PID=$!
sleep 5
Step 3: Construct the URL with test parameters
The results file path must be an absolute path (the companion server writes to it):
RESULTS_FILE="$(pwd)/wasm-test-results.xml"
URL-encode the parameters and build the URL:
# Helper: basic URL encoding
rawurlencode() {
python -c "import urllib.parse; print(urllib.parse.quote('$1', safe=''))"
}
RESULTS_ENCODED=$(rawurlencode "$RESULTS_FILE")
Without filter:
http://localhost:8000/?--runtime-tests=$RESULTS_ENCODED
With filter (note the = → ! replacement):
FILTER_B64=$(echo -n "fully.qualified.TestName" | base64)
FILTER_B64_ESCAPED=${FILTER_B64//=/!}
FILTER_ENCODED=$(rawurlencode "$FILTER_B64_ESCAPED")
URL="http://localhost:8000/?--runtime-tests=${RESULTS_ENCODED}&--runtime-test-filter=${FILTER_ENCODED}"
Step 4: Open the URL in a browser
If the Playwright MCP tool is available (mcp__playwright__browser_navigate), use it — no manual browser needed:
mcp__playwright__browser_navigate(url: "<the constructed URL>")
Keep the tab open until tests complete. If the results file does not appear within 10 minutes, use mcp__playwright__browser_take_screenshot to inspect the state.
If Playwright is not available, open the URL with the OS default browser and instruct the user to keep it open:
On Windows (Git Bash):
start "" "$URL"
On Linux:
google-chrome --no-sandbox "$URL" &
On macOS:
open "$URL"
Step 5: Wait for results
The test runner writes a canary file ($RESULTS_FILE.canary) when it starts and the actual results file when complete. Poll from bash:
# Wait for the results file (poll every 10 seconds, timeout 10 minutes)
for i in $(seq 1 60); do [ -f "$RESULTS_FILE" ] && break; sleep 10; done
Step 6: Cleanup
kill $HTTP_PID $COMPANION_PID 2>/dev/null || true
Phase 4: Parse and Report Results
- Read the test results XML file (NUnit format)
- Report summary: total tests, passed, failed, skipped
- For failures: extract failure messages and stack traces
- If tests failed, suggest investigation steps:
- Check if the test is platform-specific
- Check if the failure is a known issue
- Suggest using
/bug-investigatefor complex failures
Platform Quick Reference
| Skia Desktop | Skia WASM | |
|---|---|---|
| Project | SamplesApp (net11.0-desktop) |
SamplesApp (net11.0-browserwasm) |
| Build command | dotnet build ... -c Release -f net11.0-desktop -p:UnoFastDevBuild=true -p:UnoTargetFrameworkOverride=net11.0-desktop |
dotnet publish ... -c Release -f net11.0-browserwasm -p:UnoFastDevBuild=true -p:UnoTargetFrameworkOverride=net11.0-browserwasm |
| Run method | dotnet SamplesApp.dll --runtime-tests=... |
Browser navigates to URL with query params |
| Filter delivery | UITEST_RUNTIME_TESTS_FILTER env var |
--runtime-test-filter URL query param |
Base64 = handling |
Standard base64 | Replace = with ! before URL-encoding |
| Results delivery | Written directly to disk | Written via companion HTTP server on port+1 |
| Dependencies | None | Python (http.server), browser |
| Speed | Fast | Slower (publish + browser startup) |
| Recommended for | Default / local dev | WASM-specific bugs, platform divergence |
Technical Reference
Environment Variable
- Name:
UITEST_RUNTIME_TESTS_FILTER - Format: Base64-encoded, UTF-8 string
- Separator:
|(pipe) between multiple test names - Scope: Must be set in the same shell session that runs the test app (desktop), or passed as URL param (WASM)
Code Path
App.Tests.cs:HandleRuntimeTests() → SampleChooserViewModel.RunRuntimeTests() → Convert.FromBase64String() → Split("|") → UnitTestEngineConfig.Filters[]
Key Files
- Entry point:
src/SamplesApp/SamplesApp.Shared/App.Tests.cs - Filter decoding:
src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.cs - Config:
src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UnitTest/UnitTestEngineConfig.cs - Test location:
src/Uno.UI.RuntimeTests/Tests/ - WASM CI script:
build/test-scripts/wasm-run-skia-runtime-tests.sh - WASM companion server:
build/test-scripts/skia-browserwasm-file-creation-server.py - Test-authoring conventions:
.claude/rules/runtime-tests.md
CI-Only Options
--runtime-tests-group/--runtime-tests-group-count: For CI test sharding