diff --git a/src/PostIt.Tests/MainPageButtonsTests.cs b/src/PostIt.Tests/MainPageButtonsTests.cs
new file mode 100644
index 00000000..26636635
--- /dev/null
+++ b/src/PostIt.Tests/MainPageButtonsTests.cs
@@ -0,0 +1,207 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Headless;
+using Avalonia.Headless.XUnit;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using CommunityToolkit.Mvvm.Input;
+using Yavsc.Api.Client;
+using Yavsc.Blogspot;
+using PostIt.Services;
+using PostIt.ViewModels;
+using PostIt.Views;
+
+namespace PostIt.Tests;
+
+///
+/// Regression coverage for the three toolbar buttons on
+/// that the user reported as inoperative:
+/// "ACL", "Mes cercles", and "[DEV] Signature".
+///
+/// Pattern (per the Avalonia headless testing docs —
+/// TestableApp.Headless.XUnit/CalculatorTests): name every
+/// interactive control in the XAML with x:Name="...", then
+/// in the test focus the named control and raise the click via
+/// window.KeyPressQwerty(PhysicalKey.Enter, ...). This is
+/// the supported path — searching the visual tree via
+/// GetVisualDescendants().OfType<Button>() for a
+/// button by Content text is brittle and was tried first; it does
+/// not work reliably when the page is hosted inside an
+/// , which wraps the
+/// pushed page in an internal container that the visual-tree walk
+/// does not always expose under headless.
+///
+/// The assertion is on the post-click top of
+/// :
+/// the user's bug is "I click and the dialog / page never opens",
+/// so the test fails when the click doesn't push anything onto the
+/// stack. We pin γ + sniff léger — the new top must be a non-null
+/// , but we do not yet assert the concrete type
+/// (that would require a fully stubbed App.ServiceProvider,
+/// which is the next iteration of this suite).
+///
+/// Each test exercises the bit that would silently break if
+/// the wiring was reverted:
+///
+/// "ACL" — click with a selected post pushes a page onto
+/// the stack.
+/// "Mes cercles" — click pushes a page onto the stack.
+/// "[DEV] Signature" — click pushes a page onto the
+/// stack.
+///
+///
+public class MainPageButtonsTests
+{
+ ///
+ /// Fake that throws on any
+ /// wire call. These tests never invoke a command that hits
+ /// the API — only the click → nav side of the pipeline is
+ /// asserted.
+ ///
+ private sealed class ThrowingApi : YavscApiClient
+ {
+ public ThrowingApi() : base(
+ new Settings
+ {
+ Authentication = new AuthenticationSettings
+ {
+ Authority = "https://stub.invalid",
+ ClientId = "stub",
+ Scopes = new[] { "openid" },
+ },
+ },
+ new TokenStore(System.IO.Path.GetTempFileName()))
+ { }
+ }
+
+ private static MainPageViewModel MakeViewModel(BlogPostDto? selectedPost = null)
+ {
+ var api = new ThrowingApi();
+ var blog = new BlogApiClient(api, "http://localhost/");
+ var vm = new MainPageViewModel(blog);
+ if (selectedPost is not null) vm.SelectedPost = selectedPost;
+ return vm;
+ }
+
+ ///
+ /// Mount a real (as
+ /// SessionStatusBannerTests does), push a
+ /// with the given VM onto
+ /// NavRoot. PushAsync is awaited (via
+ /// GetAwaiter().GetResult()) so the page is on the
+ /// nav stack before the test tries to interact with its
+ /// named buttons. The window is shown so the visual tree is
+ /// realised and KeyPressQwerty has a real
+ /// to dispatch against.
+ ///
+ private static (MainWindow window, MainPage page) MountMainPage(MainPageViewModel vm)
+ {
+ var window = new MainWindow();
+ var page = new MainPage { DataContext = vm };
+ window.Show();
+ window.NavRoot.PushAsync(page).GetAwaiter().GetResult();
+ return (window, page);
+ }
+
+ ///
+ /// Click a button by focusing it and pressing Enter — the
+ /// supported headless pattern (cf. CalculatorTests in the
+ /// Avalonia.Samples repo). Returns the nav-stack count
+ /// before the click so the caller can assert on the delta.
+ /// KeyPressQwerty is dispatched on the
+ /// itself — it is the that owns the
+ /// headless implementation, and routing the key through any
+ /// descendant TopLevel (e.g. one obtained via
+ /// TopLevel.GetTopLevel(button)) fails with a
+ /// NullReferenceException from the headless impl
+ /// because the descendant does not carry the
+ /// PlatformHandle the harness expects.
+ ///
+ private static int ClickAndCapture(MainWindow window, Button button)
+ {
+ var stackBefore = window.NavRoot.NavigationStack.Count;
+ button.Focus();
+ window.KeyPressQwerty(PhysicalKey.Enter, RawInputModifiers.None);
+ return stackBefore;
+ }
+
+ [AvaloniaFact]
+ public void Acl_button_click_pushes_a_page_onto_nav_stack()
+ {
+ // Arrange: a VM whose SelectedPost is non-null so
+ // CanManageAcl evaluates to true and the button is
+ // armed.
+ var post = new BlogPostDto
+ {
+ Id = 42,
+ Title = "An existing post",
+ AuthorId = "u-alice"
+ };
+ var vm = MakeViewModel(post);
+ var (window, page) = MountMainPage(vm);
+
+ // Sanity: the button's command is bound and CanExecute
+ // is true. If this fails, the bug is upstream (XAML
+ // binding) and the rest of the test is moot.
+ var aclButton = page.ManageAclButton;
+ Assert.NotNull(aclButton.Command);
+ Assert.True(aclButton.Command.CanExecute(null));
+
+ // Act
+ var stackBefore = ClickAndCapture(window, aclButton);
+
+ // Assert γ + sniff léger: stack grew, new top is a Page.
+ Assert.True(window.NavRoot.NavigationStack.Count > stackBefore,
+ $"Click on ACL must push a new page onto the nav stack. Stack size before: {stackBefore}, after: {window.NavRoot.NavigationStack.Count}.");
+ var pushed = window.NavRoot.NavigationStack.Last();
+ Assert.NotNull(pushed);
+ Assert.IsAssignableFrom(pushed);
+ }
+
+ [AvaloniaFact]
+ public void Circles_button_click_pushes_a_page_onto_nav_stack()
+ {
+ // Arrange: OpenCircles has no CanExecute guard today —
+ // any click should fire it and push the page.
+ var vm = MakeViewModel();
+ var (window, page) = MountMainPage(vm);
+
+ var circlesButton = page.OpenCirclesButton;
+ Assert.NotNull(circlesButton.Command);
+
+ // Act
+ var stackBefore = ClickAndCapture(window, circlesButton);
+
+ // Assert
+ Assert.True(window.NavRoot.NavigationStack.Count > stackBefore,
+ "Click on 'Mes cercles' must push a new page onto the nav stack.");
+ var pushed = window.NavRoot.NavigationStack.Last();
+ Assert.NotNull(pushed);
+ Assert.IsAssignableFrom(pushed);
+ }
+
+ [AvaloniaFact]
+ public void Signature_dev_button_click_pushes_a_page_onto_nav_stack()
+ {
+ // Arrange: the "[DEV] Signature" button uses XAML's
+ // Click="OpenSignatureDev" attribute, so we don't bind
+ // a Command here — we drive the click directly. The
+ // handler resolves App.ServiceProvider, which is null
+ // in a unit test, and early-returns; that is the
+ // failure mode the test pins.
+ var vm = MakeViewModel();
+ var (window, page) = MountMainPage(vm);
+
+ var signatureButton = page.OpenSignatureDevButton;
+
+ // Act
+ var stackBefore = ClickAndCapture(window, signatureButton);
+
+ // Assert
+ Assert.True(window.NavRoot.NavigationStack.Count > stackBefore,
+ "Click on '[DEV] Signature' must push a new page onto the nav stack.");
+ var pushed = window.NavRoot.NavigationStack.Last();
+ Assert.NotNull(pushed);
+ Assert.IsAssignableFrom(pushed);
+ }
+}
diff --git a/src/PostIt/PostIt/Views/MainPage.axaml b/src/PostIt/PostIt/Views/MainPage.axaml
index 0246857e..86bcf7dd 100644
--- a/src/PostIt/PostIt/Views/MainPage.axaml
+++ b/src/PostIt/PostIt/Views/MainPage.axaml
@@ -33,8 +33,12 @@
-
-
+
+