Kane CLI Browser Testing
LambdaTest/kane-cli
Drives a real browser through the kane-cli tool and designs requirement-linked test suites from a PRD or a plain description, with mobile and cloud-grid runs.
Writes UI tests that reproduce a GitHub issue in .NET MAUI and keeps iterating until the tests actually fail, proving they catch the bug.
$ npx skills add dotnet/maui --skill write-ui-tests -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install dotnet/maui write-ui-tests --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/dotnet/maui.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.github/skills/write-ui-tests .claude/skills/write-ui-tests && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "write-ui-tests" agent skill from https://github.com/dotnet/maui/tree/main/.github/skills/write-ui-tests into .claude/skills/write-ui-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "write-ui-tests", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/dotnet/maui/tree/main/.github/skills/write-ui-testsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add dotnet/maui --skill write-ui-tests -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install dotnet/maui write-ui-tests --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dotnet/maui.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.github/skills/write-ui-tests .agents/skills/write-ui-tests && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "write-ui-tests" agent skill from https://github.com/dotnet/maui/tree/main/.github/skills/write-ui-tests into .agents/skills/write-ui-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "write-ui-tests", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add dotnet/maui --skill write-ui-tests -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install dotnet/maui write-ui-tests --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dotnet/maui.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.github/skills/write-ui-tests .cursor/skills/write-ui-tests && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "write-ui-tests" agent skill from https://github.com/dotnet/maui/tree/main/.github/skills/write-ui-tests into .cursor/skills/write-ui-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "write-ui-tests", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/dotnet/maui.git --path .github/skills/write-ui-tests--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add dotnet/maui --skill write-ui-tests -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install dotnet/maui write-ui-tests --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dotnet/maui.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.github/skills/write-ui-tests .gemini/skills/write-ui-tests && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "write-ui-tests" agent skill from https://github.com/dotnet/maui/tree/main/.github/skills/write-ui-tests into .gemini/skills/write-ui-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "write-ui-tests", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install dotnet/maui write-ui-testsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add dotnet/maui --skill write-ui-tests -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/dotnet/maui.git skills-src && mkdir -p .github/skills && cp -r skills-src/.github/skills/write-ui-tests .github/skills/write-ui-tests && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "write-ui-tests" agent skill from https://github.com/dotnet/maui/tree/main/.github/skills/write-ui-tests into .github/skills/write-ui-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "write-ui-tests", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add dotnet/maui --skill write-ui-tests -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install dotnet/maui write-ui-tests --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/dotnet/maui.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.github/skills/write-ui-tests .opencode/skills/write-ui-tests && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "write-ui-tests" agent skill from https://github.com/dotnet/maui/tree/main/.github/skills/write-ui-tests into .opencode/skills/write-ui-tests/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "write-ui-tests", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
write-ui-testsWrites UI tests that reproduce a GitHub issue in .NET MAUI and keeps iterating until the tests actually fail, proving they catch the bug.
Starting from an issue number, a description or repro steps and the affected platforms, the agent reads the repository's UI test guidelines, creates a HostApp page for the issue and writes the matching test following .NET MAUI conventions, such as file names built from the issue number and the Issue and Category attributes. The excerpt shows these conventions and file locations but is cut off before the remaining test steps.
The defining rule is that the skill cannot finish until the tests fail. A passing test does not show that it catches the bug, so the agent iterates on the test code, tries other platforms and asks you before going further if tests still pass after three iterations. For platform choice it starts with the one named in the issue, or Android when all platforms are affected because the emulator boots faster. Appium is needed to execute UI tests.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 7d38fd0. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
dotnetpwshxcrunjqFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Requires git, PowerShell, .NET SDK, and Appium for UI test execution.
From compatibility in the SKILL.md frontmatter.
MAUI UI Test Writer loads about 3k tokens when it runs. Until then it costs about 55 tokens; SKILL.md has 826 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from dotnet/maui at commit 7d38fd0, republished under its MIT licence (© dotnet). 826 words, ~2,965 tokens.
.claude/skills/write-ui-tests/SKILL.md (or your agent's skills folder).Creates UI tests that reproduce a GitHub issue, following .NET MAUI conventions. Verifies the tests actually fail before completing.
YOU CANNOT COMPLETE THIS SKILL UNTIL TESTS FAIL.
A test that passes does NOT prove it catches the bug. You MUST:
If tests keep passing after 3 iterations:
Common mistakes that lead to passing tests:
Before invoking, ensure you have:
Platform selection guidance:
platform/iOS label → test on iOS firstplatform/Android label → test on Android firstcat .github/instructions/uitests.instructions.mdThis contains the authoritative conventions for:
IssueXXXXX.cs for C#-only, or IssueXXXXX.xaml/.xaml.cs for XAML)TestCases.HostApp/Issues/, TestCases.Shared.Tests/Tests/Issues/)[Issue()], [Category()])Location: src/Controls/tests/TestCases.HostApp/Issues/IssueXXXXX.cs
namespace Maui.Controls.Sample.Issues;
[Issue(IssueTracker.Github, XXXXX, "Brief description of issue", PlatformAffected.All)]
public partial class IssueXXXXX : ContentPage
{
public IssueXXXXX()
{
// Create UI that reproduces the issue
var button = new Button
{
Text = "Test Button",
AutomationId = "TestButton" // Required for Appium
};
var resultLabel = new Label
{
Text = "Waiting...",
AutomationId = "ResultLabel"
};
button.Clicked += (s, e) =>
{
resultLabel.Text = "Success";
};
Content = new VerticalStackLayout
{
Children = { button, resultLabel }
};
}
}Key requirements:
AutomationId to all interactive elements[Issue()] attribute with tracker, number, description, platformNote: XAML is optional. C#-only pages (as shown above) are simpler and preferred for most test scenarios. Use XAML only when the bug specifically relates to XAML parsing or markup behavior.
Location: src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/IssueXXXXX.cs
namespace Microsoft.Maui.TestCases.Tests.Issues;
public class IssueXXXXX : _IssuesUITest
{
public override string Issue => "Brief description matching HostApp";
public IssueXXXXX(TestDevice device) : base(device) { }
[Test]
[Category(UITestCategories.Button)] // Pick ONE appropriate category
public void ButtonClickUpdatesLabel()
{
// Wait for element to be ready
App.WaitForElement("TestButton");
// Interact with the UI
App.Tap("TestButton");
// Verify expected behavior
var labelText = App.FindElement("ResultLabel").GetText();
Assert.That(labelText, Is.EqualTo("Success"));
}
}Key requirements:
_IssuesUITestAutomationId values as HostApp[Category()] attribute (check UITestCategories.cs for options)App.WaitForElement() before interactions# For Android
dotnet build src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj -c Debug -f net10.0-android --no-restore -v q
# For iOS
dotnet build src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj -c Debug -f net10.0-ios --no-restore -v q
# Test project (platform-independent)
dotnet build src/Controls/tests/TestCases.Shared.Tests/Controls.TestCases.Shared.Tests.csproj -c Debug --no-restore -v qTests must FAIL to prove they catch the bug. Run verification:
pwsh .github/skills/verify-tests-fail-without-fix/scripts/verify-tests-fail.ps1 -Platform <platform> -TestFilter "IssueXXXXX"Replace <platform> with android, ios, or maccatalyst based on the issue's affected platforms.
The script auto-detects that only test files exist (no fix files) and runs in "verify failure only" mode.
Why FAIL = success? The test must fail NOW (before the fix) to prove it catches the bug. After the fix is applied, it should pass. A test that passes now proves nothing.
If tests FAIL → ✅ Success! Tests correctly reproduce the bug. Proceed to Output.
If tests PASS → ❌ STOP. Test doesn't catch the bug. Iterate:
Console.WriteLine in HostApp to trace execution"Tests are passing after 3 iterations. This means either: (a) my test scenario doesn't correctly reproduce the bug, (b) the bug may already be fixed on this branch, or (c) I'm missing something from the issue description. How would you like me to proceed?"
Common reasons tests pass when they shouldn't:
| Symptom | Likely Cause | Fix |
|---|---|---|
| Test passes on all attempts | Test scenario doesn't match bug | Re-read issue reproduction steps carefully |
| Test asserts pass but bug exists | Asserting wrong property/element | Check what exactly the bug affects |
| Works on Android, fails on iOS | Bug is platform-specific | Try both platforms |
| Bug involves timing | Race condition not captured | Add delays or event handlers |
| Bug involves navigation | Page lifecycle not exercised | Ensure pages are actually pushed/popped |
Do NOT mark this skill complete until tests FAIL.
⚠️ ONLY use this output format if tests FAIL. If tests pass, you have not completed this skill.
After completion (tests verified to fail), report:
✅ Tests created and verified for Issue #XXXXX
**Files:**
- `src/Controls/tests/TestCases.HostApp/Issues/IssueXXXXX.cs`
- `src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/IssueXXXXX.cs`
**Test method:** `ButtonClickUpdatesLabel`
**Category:** `UITestCategories.Button`
**Verification:** Tests FAIL as expected (bug reproduced)
**Failure message:** `Expected "X" but got "Y"` (include actual assertion failure)If tests PASS after multiple iterations, report instead:
⚠️ Tests created but NOT verified for Issue #XXXXX
**Files:** [list files]
**Status:** Tests PASS when they should FAIL
**Iterations tried:** 3
**Problem:** [describe why test may not be catching the bug]
**Next steps:** Need guidance on reproduction steps// HostApp: Add a way to trigger and observe the property
var picker = new Picker { AutomationId = "TestPicker" };
var statusLabel = new Label { AutomationId = "StatusLabel" };
picker.PropertyChanged += (s, e) => {
if (e.PropertyName == nameof(Picker.IsOpen))
statusLabel.Text = $"IsOpen={picker.IsOpen}";
};
// Test: Verify the property changes correctly
App.Tap("TestPicker");
App.WaitForElement("StatusLabel");
var status = App.FindElement("StatusLabel").GetText();
Assert.That(status, Does.Contain("IsOpen=True"));// Test: Use GetRect() for position/size assertions
var rect = App.WaitForElement("TestElement").GetRect();
Assert.That(rect.Height, Is.GreaterThan(0));
Assert.That(rect.Y, Is.GreaterThanOrEqualTo(safeAreaTop));// Use retryTimeout for animations - keeps retrying until success
App.Tap("AnimatedButton");
VerifyScreenshot(retryTimeout: TimeSpan.FromSeconds(2));
// retryTimeout handles timing variance, small tolerance for cross-machine rendering
VerifyScreenshot(tolerance: 0.5, retryTimeout: TimeSpan.FromSeconds(2));// Only limit platforms when NECESSARY
[Test]
[Category(UITestCategories.Picker)]
public void PickerDismissResetsIsOpen()
{
// This test should run on all platforms unless there's
// a specific technical reason it can't
App.WaitForElement("TestPicker");
// ...
}When running tests on iOS, you may need to target a specific device or iOS version:
# Default: iPhone Xs with iOS 18.5
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform ios -TestFilter "Issue12345"
# Find iPhone Xs with iOS 18.5 and get its UDID
UDID=$(xcrun simctl list devices available --json | jq -r '
.devices | to_entries
| map(select(.key | contains("iOS-18-5")))
| map(.value) | flatten
| map(select(.name == "iPhone Xs")) | first | .udid')
# Run with specific device
pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform ios -TestFilter "Issue12345" -DeviceUdid "$UDID"Finding different device/version combinations:
# iPhone 16 Pro with any iOS version
UDID=$(xcrun simctl list devices available --json | jq -r '
.devices[][] | select(.name == "iPhone 16 Pro") | .udid' | head -1)
# Any device with iOS 18.0
UDID=$(xcrun simctl list devices available --json | jq -r '
.devices | to_entries
| map(select(.key | contains("iOS-18-0")))
| map(.value) | flatten | .[0].udid')Before running verify-tests-fail.ps1, confirm:
TestCases.HostApp/Issues/IssueXXXXX.csTestCases.Shared.Tests/Tests/Issues/IssueXXXXX.cs[Issue()] attribute present with all parametersAutomationId values match between HostApp and test_IssuesUITest[Category()] attribute from UITestCategories.cs.github/instructions/uitests.instructions.mdsrc/Controls/tests/TestCases.Shared.Tests/UITestCategories.cssrc/Controls/tests/TestCases.Shared.Tests/Tests/Issues/© dotnet, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .github/skills/write-ui-tests of dotnet/maui.
Open the folder on GitHubat commit 7d38fd0
MAUI UI Test Writer next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| MAUI UI Test Writer this skilldotnet/maui | 23k | — | ~3k | Automated safety check: Pass | MIT | |
| Kane CLI Browser TestingLambdaTest/kane-cli | 247 | — | ~8.4k | Automated safety check: Pass | Apache-2.0 | |
| Releaselycorp-jp/sim-use | 1.4k | — | ~1.7k | Automated safety check: Pass | Apache-2.0 | |
| Fix Random CI Test Failuredotnet/macios | 2.9k | — | ~1.3k | Automated safety check: Pass | Custom licence | |
| Argent QA Flowsbbplayer-app/BBPlayer | 1.1k | — | ~3.2k | Automated safety check: Pass | MIT | |
| Simulator Audio E2Ehyochan/react-native-nitro-sound | 961 | — | ~1.1k | Automated safety check: Pass | MIT |
LambdaTest/kane-cli
Drives a real browser through the kane-cli tool and designs requirement-linked test suites from a PRD or a plain description, with mobile and cloud-grid runs.
lycorp-jp/sim-use
Cut a sim-use release end-to-end. An agent skill from lycorp-jp/sim-use.
dotnet/macios
Investigate and fix flaky/random CI test failures in dotnet/macios.
bbplayer-app/BBPlayer
Create repeatable QA regression E2E tests as Argent flows from test cases, tickets, or acceptance criteria.
hyochan/react-native-nitro-sound
Build and run repeatable react-native-nitro-sound recorder/player regression tests on an iOS Simulator or Android emulator, with explicit virtual-device selection, microphone permission, Maestro…
Redth/Maui.Gtk
End-to-end workflow for building, deploying, inspecting, and debugging .NET MAUI and MAUI Blazor Hybrid apps as an AI agent.
dotnet/maui
Mines local Copilot CLI session logs for dotnet/maui to rank costly or failing runs, tag recurring failure modes, propose repo edits and emit guard evals.
dotnet/maui
Reviews the tests added in a pull request for fix coverage, quality, edge cases and test type, and recommends lighter test types where they would do.
dotnet/maui
Produces evidence-backed ship-readiness verdicts for .NET MAUI Servicing Releases and Previews, and drafts public-safe release handoff pages from the result.
dotnet/maui
Interprets pinned managed benchmark evidence for a dotnet/maui pull request and writes a narrative for the performance review workflow, without running or publishing anything.
dotnet/maui
Checks that a pull request's title and description match its implementation and reviews the code for best practices before merge, without posting anything.
dotnet/maui
Adds MAUI-specific guardrails on top of the maestro-cli skill and Maestro MCP tools for darc, BAR, and channel or feed lookups in dotnet/maui.
Categories
Writes UI tests that reproduce a GitHub issue in .NET MAUI and keeps iterating until the tests actually fail, proving they catch the bug. NET MAUI conventions, such as file names built from the issue number and the Issue and Category attributes. The excerpt shows these conventions and file locations but is cut off before the remaining test steps.
MAUI UI Test Writer fits situations like: A pull request has no tests and needs a UI test for the bug it fixes; an issue needs a reproduction test before anyone starts on a fix; existing tests do not adequately cover a reported bug.
Run `npx skills add dotnet/maui --skill write-ui-tests -a claude-code`. Or copy the skill folder (.github/skills/write-ui-tests in dotnet/maui) into .claude/skills/write-ui-tests in your project. Claude Code loads it when a task matches its description.
Run `npx skills add dotnet/maui --skill write-ui-tests -a codex`. Or copy the skill folder (.github/skills/write-ui-tests in dotnet/maui) into .agents/skills/write-ui-tests in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add dotnet/maui --skill write-ui-tests -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/write-ui-tests, .gemini/skills/write-ui-tests, .github/skills/write-ui-tests and .opencode/skills/write-ui-tests in your project.
Going by SKILL.md and its folder, MAUI UI Test Writer needs the command-line tools its instructions call (dotnet, pwsh, xcrun and jq). Our summary lists: git, PowerShell and the .NET SDK; Appium for running UI tests. Compatibility (from SKILL.md): Requires git, PowerShell, .NET SDK, and Appium for UI test execution..
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
MAUI UI Test Writer is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with MAUI UI Test Writer: Kane CLI Browser Testing (LambdaTest/kane-cli, 247 stars), Release (lycorp-jp/sim-use, 1.4k stars), Fix Random CI Test Failure (dotnet/macios, 2.9k stars) and Argent QA Flows (bbplayer-app/BBPlayer, 1.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
dotnet (a GitHub organization, an official publisher) maintains it in dotnet/maui, which has 23,322 GitHub stars. The repository holds 27 skills in this directory. The repository was last updated on October 7, 2026.
Source: dotnet/maui on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.