From 41cc651b7dc17e0e31f87c2f8799062a53772623 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Thu, 20 Aug 2026 05:27:41 +0100 Subject: [PATCH] test(postit.android): add Xamarin.UITest smoke test on emulator Adds AndroidAppLaunchTests to PostIt.Tests, a Xamarin.UITest-based smoke test that launches the installed com.CompanyName.PostIt app on the running emulator and waits for the first Avalonia frame to render. The test skips cleanly when the app is not installed. Currently FAILS RED on the local emulator: the installed APK has no Activity declared (am start returns result code=-92, ACTIVITY_NOT_FOUND), and Xamarin.UITest's test server cannot reach /ping. This is a guardian test that will turn green once EmbedAssembliesIntoApk=true is set in PostIt.Android.csproj (follow-up commit). Also adds a Debug launch config in .vscode/launch.json that runs the test under vsdbg, enabling breakpoints and object inspection when investigating the failure. --- .vscode/launch.json | 13 ++++ src/PostIt.Tests/AndroidAppLaunchTests.cs | 76 +++++++++++++++++++++++ src/PostIt.Tests/Directory.Packages.props | 2 +- src/PostIt.Tests/PostIt.Tests.csproj | 1 + 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/PostIt.Tests/AndroidAppLaunchTests.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index 76dc08d5..efdaa6ea 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -28,6 +28,19 @@ "request": "launch", "projectPath": "${workspaceFolder}/src/PostIt/PostIt.Desktop/PostIt.Desktop.csproj", + }, + { + "name": "Test PostIt.Android launch (Xamarin.UITest)", + "type": "coreclr", + "request": "launch", + "program": "${workspaceFolder}/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests.dll", + "args": [ + "--filter-method", + "PostIt.Tests.AndroidAppLaunchTests.PostIt_starts_and_draws_a_first_frame_on_the_emulator" + ], + "cwd": "${workspaceFolder}/src/PostIt.Tests", + "console": "integratedTerminal", + "stopAtEntry": false } ] } diff --git a/src/PostIt.Tests/AndroidAppLaunchTests.cs b/src/PostIt.Tests/AndroidAppLaunchTests.cs new file mode 100644 index 00000000..2198bb78 --- /dev/null +++ b/src/PostIt.Tests/AndroidAppLaunchTests.cs @@ -0,0 +1,76 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Xamarin.UITest; +using Xamarin.UITest.Android; +using Xunit; + +namespace PostIt.Tests; + +/// +/// Smoke test: launches the installed PostIt.Android app on the running +/// emulator and waits for the first Avalonia frame to render. Reveals the +/// "démarrage KO" bug — the test fails if Avalonia never draws a frame +/// within the timeout. +/// +/// Skip conditions: the package is not installed on the connected device, +/// or no device is connected via adb. +/// +public class AndroidAppLaunchTests +{ + private const string PackageName = "com.CompanyName.PostIt"; + + private readonly ITestOutputHelper _output; + + public AndroidAppLaunchTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void PostIt_starts_and_draws_a_first_frame_on_the_emulator() + { + if (!IsPackageInstalledOnAnyDevice()) + { + _output.WriteLine($"[skip] {PackageName} not installed on any device"); + return; + } + + _output.WriteLine($"[step] configuring app via InstalledApp({PackageName})"); + var app = ConfigureApp.Android + .InstalledApp(PackageName) + .StartApp(Xamarin.UITest.Configuration.AppDataMode.DoNotClear); + _output.WriteLine("[step] app.StartApp returned, waiting for first frame"); + + app.WaitForElement( + e => e.Class("android.view.View"), + timeout: TimeSpan.FromSeconds(30)); + _output.WriteLine("[step] first frame observed"); + } + + private static bool IsPackageInstalledOnAnyDevice() + { + try + { + var startInfo = new ProcessStartInfo("adb", "shell pm list packages") + { + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + }; + using var proc = Process.Start(startInfo); + if (proc is null) return false; + var stdout = proc.StandardOutput.ReadToEnd(); + proc.WaitForExit(5000); + return stdout + .Split('\n', StringSplitOptions.RemoveEmptyEntries) + .Any(line => line.Trim().Equals($"package:{PackageName}", StringComparison.Ordinal)); + } + catch + { + return false; + } + } +} diff --git a/src/PostIt.Tests/Directory.Packages.props b/src/PostIt.Tests/Directory.Packages.props index 15c4e24b..4731d4f0 100644 --- a/src/PostIt.Tests/Directory.Packages.props +++ b/src/PostIt.Tests/Directory.Packages.props @@ -1,10 +1,10 @@ - + \ No newline at end of file diff --git a/src/PostIt.Tests/PostIt.Tests.csproj b/src/PostIt.Tests/PostIt.Tests.csproj index 54c40e8c..249e3d92 100644 --- a/src/PostIt.Tests/PostIt.Tests.csproj +++ b/src/PostIt.Tests/PostIt.Tests.csproj @@ -13,6 +13,7 @@ +