From 44cdae5e6d294daa44b462168a490e5e954ccd00 Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Fri, 21 Nov 2025 09:07:21 +0100 Subject: [PATCH] Add XAML unit testing guidelines --- .../xaml-unittests.instructions.md | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 .github/instructions/xaml-unittests.instructions.md diff --git a/.github/instructions/xaml-unittests.instructions.md b/.github/instructions/xaml-unittests.instructions.md new file mode 100644 index 000000000000..5ac046594c77 --- /dev/null +++ b/.github/instructions/xaml-unittests.instructions.md @@ -0,0 +1,149 @@ +--- +description: "Guidelines for writing XAML unit tests in the Controls.Xaml.UnitTests project" +--- + +# XAML Unit Testing Guidelines + +This guide provides conventions for writing XAML unit tests in `src/Controls/tests/Xaml.UnitTests/`. + +## 1. File Naming and Location for Issue Tests + +When writing a test for a GitHub issue: + +- **Location**: Place the test file in the `Issues/` folder +- **Naming convention**: `MauiXXXXX.xaml` and `MauiXXXXX.xaml.cs` (where XXXXX is the GitHub issue number) + +**Example:** +``` +src/Controls/tests/Xaml.UnitTests/Issues/ +├── Maui12345.xaml +└── Maui12345.xaml.cs +``` + +## 2. Basic Test Pattern + +Most unit tests will: +1. Check that the XAML page can be created/inflated +2. Perform some assertions on the created page +3. Apply to all `[XamlInflator]` test variations (runtime, XamlC, SourceGen) + +**XAML file (Maui12345.xaml):** +```xaml + + + + +``` + +**Code-behind (Maui12345.xaml.cs):** +```csharp +namespace Microsoft.Maui.Controls.Xaml.UnitTests; + +public partial class Maui12345 : ContentPage +{ + public Maui12345() + { + InitializeComponent(); + } + + [TestFixture] + class Tests + { + [Test] + public void MyTest([Values] XamlInflator inflator) + { + var page = new Maui12345(inflator); + Assert.That(page, Is.Not.Null); + // Additional assertions + } + } +} +``` + +**Note**: Only add `[SetUp]` and `[TearDown]` methods if your test requires special initialization (e.g., setting up `DispatcherProvider` or `Application.Current`). Most tests don't need them. + +## 3. Testing IL Correctness (XamlC) or Source Generation + +When the test specifically validates compile-time behavior for a specific inflator: + +**XamlC (IL generation):** +```csharp +[Test] +public void MyTest([Values] XamlInflator inflator) +{ + if (inflator == XamlInflator.XamlC) + Assert.Throws(() => MockCompiler.Compile(typeof(Maui12345))); + else + { + var page = new Maui12345(inflator); + Assert.That(page, Is.Not.Null); + } +} +``` + +**Source Generation:** +```csharp +using static Microsoft.Maui.Controls.Xaml.UnitTests.MockSourceGenerator; + +[Test] +public void MyTest([Values] XamlInflator inflator) +{ + if (inflator == XamlInflator.SourceGen) + { + var result = CreateMauiCompilation() + .WithAdditionalSource( +""" +namespace Microsoft.Maui.Controls.Xaml.UnitTests; + +[XamlProcessing(XamlInflator.Runtime, true)] +public partial class Maui12345 : ContentPage +{ + public Maui12345() => InitializeComponent(); +} +""") + .RunMauiSourceGenerator(typeof(Maui12345)); + Assert.That(result.Diagnostics, Is.Empty); // or Is.Not.Empty for error cases + } + else + { + var page = new Maui12345(inflator); + Assert.That(page, Is.Not.Null); + } +} +``` + +## 4. Handling Invalid Code Generation + +When testing scenarios where code generation is **expected to fail** or produce invalid code, use special file extensions to prevent build failures: + +| Extension | Behavior | Use Case | +|-----------|----------|----------| +| `.rt.xaml` | Runtime inflation only | XamlC/SourceGen should fail, but runtime should work | +| `.rtsg.xaml` | Runtime + SourceGen only | XamlC should fail | +| `.rtxc.xaml` | Runtime + XamlC only | SourceGen should fail | + +**Why?** These extensions prevent the compiler and build tasks from processing the XAML file, allowing your test to execute and verify the expected behavior. + +**Example:** +``` +Issues/ +├── Maui12345.rt.xaml # Only inflated at runtime (compiler/sourcegen skip) +└── Maui12345.xaml.cs +``` + +## Quick Reference + +| Scenario | Location | Naming | Special Extension | +|----------|----------|--------|-------------------| +| Issue test | `Issues/` | `MauiXXXXX.*` | None (unless invalid codegen) | +| Invalid XamlC | `Issues/` | `MauiXXXXX.rt.xaml` | `.rt.xaml` | +| Invalid SourceGen | `Issues/` | `MauiXXXXX.rt.xaml` or `.rtxc.xaml` | Depends on what should fail | +| Test XamlC IL | Anywhere | Any | Use `MockCompiler` | +| Test SourceGen | Anywhere | Any | Use `MockSourceGenerator` | + +## Related Documentation + +- `.github/copilot-instructions.md` - General MAUI development guidelines +- `.github/instructions/uitests.instructions.md` - UI testing guidelines (different from XAML unit tests)