- OidcLoginPhase enum + IProgress<OidcLoginPhase> on YavscApiClient.LoginInteractiveAsync, surfaced in the UI as PhaseLabel (FR). Lets operators see where the flow actually stalls, in particular whether the postit://callback ever arrives on the running instance. - YavscApiClient.TrySilentLoginAsync: silent refresh at boot. Returns false (and purges the store) when the refresh token is rejected by the OP. - App.OnFrameworkInitializationCompleted auto-routes: HomePage is the navigation root; on Opened the app calls TrySilentLoginAsync and pushes MainPage if a session is restored. Logout pops back to HomePage via the new persistent SessionStatusBanner (Connecté / Déconnecté + Logout button). - PostIt.Desktop.Program.Main now detects the postit://callback URL BEFORE Avalonia boots, hands it off via SingleInstance, and exits. Stops the 2nd PostIt instance from flashing its own MainWindow while the 1st instance is still waiting on the named pipe. The check in App.OnFrameworkInitializationCompleted is kept as belt-and-braces defence-in-depth. - SchemeUrlDetector: pure platform-independent detector extracted for unit testing. - Tests: 7 new SchemeUrlDetectorTests + 5 new phase / silent refresh tests in YavscApiClientTests.
79 lines
2.4 KiB
C#
79 lines
2.4 KiB
C#
using PostIt.Services;
|
|
using Xunit;
|
|
|
|
namespace PostIt.Tests;
|
|
|
|
/// <summary>
|
|
/// Tests for the platform-independent scheme-URL detector. The
|
|
/// detector is the first guard against the OS launching a fresh
|
|
/// PostIt instance with the postit://callback URL — it must match
|
|
/// even when Avalonia has not booted, otherwise the 2nd instance
|
|
/// flashes its own MainWindow before shutting down.
|
|
/// </summary>
|
|
public class SchemeUrlDetectorTests
|
|
{
|
|
[Fact]
|
|
public void FindCallbackUrl_returns_null_when_no_args()
|
|
{
|
|
Assert.Null(SchemeUrlDetector.FindCallbackUrl(System.Array.Empty<string>()));
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCallbackUrl_returns_null_when_no_postit_arg_present()
|
|
{
|
|
var args = new[]
|
|
{
|
|
"/usr/bin/postit-desktop",
|
|
"--some-flag",
|
|
"value",
|
|
};
|
|
Assert.Null(SchemeUrlDetector.FindCallbackUrl(args));
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCallbackUrl_returns_url_when_postit_scheme_present()
|
|
{
|
|
var args = new[]
|
|
{
|
|
"/usr/bin/postit-desktop",
|
|
"postit://callback?code=abc&state=xyz",
|
|
};
|
|
var hit = SchemeUrlDetector.FindCallbackUrl(args);
|
|
Assert.Equal("postit://callback?code=abc&state=xyz", hit);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCallbackUrl_is_case_insensitive_on_scheme()
|
|
{
|
|
var args = new[] { "POSTIT://callback?code=abc" };
|
|
Assert.Equal("POSTIT://callback?code=abc", SchemeUrlDetector.FindCallbackUrl(args));
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCallbackUrl_ignores_args_that_mention_scheme_without_prefix()
|
|
{
|
|
// "postit-something://x" must NOT match — the prefix is the
|
|
// scheme followed by "://", nothing else.
|
|
var args = new[] { "postit-something://callback?code=abc" };
|
|
Assert.Null(SchemeUrlDetector.FindCallbackUrl(args));
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCallbackUrl_returns_first_match_when_multiple_present()
|
|
{
|
|
// Defensive: an OS shouldn't hand us two URLs in argv, but if
|
|
// it ever does we want a deterministic answer (first).
|
|
var args = new[]
|
|
{
|
|
"postit://callback?code=first",
|
|
"postit://callback?code=second",
|
|
};
|
|
Assert.Equal("postit://callback?code=first", SchemeUrlDetector.FindCallbackUrl(args));
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCallbackUrl_returns_null_for_null_args()
|
|
{
|
|
Assert.Null(SchemeUrlDetector.FindCallbackUrl(null!));
|
|
}
|
|
}
|