All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m35s
AccountStep now exposes OnValidityChanged EventCallback<bool> and fires it at the end of every Validate() call (including OnInitialized). Routes.razor drops the @ref/IsValid polling pattern in favour of _accountValid updated via the callback + StateHasChanged, matching the existing OnRunningChanged pattern used by ApplyStep. Adds 5 bUnit regression tests covering: initial-invalid, all-valid, re-invalid on clear, short/non-numeric PIN, and pre-populated state on Back→Forward re-mount. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
104 lines
3.5 KiB
C#
104 lines
3.5 KiB
C#
using Bunit;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using SilverOS.Welcome.App.Components;
|
|
using SilverOS.Welcome.App.Components.Steps;
|
|
using Xunit;
|
|
|
|
public class AccountStepTests : TestContext
|
|
{
|
|
// Helper: register WizardState and render AccountStep with an OnValidityChanged capture.
|
|
private (IRenderedComponent<AccountStep> cut, Func<bool?> lastValidity) RenderStep(WizardState? state = null)
|
|
{
|
|
var wizardState = state ?? new WizardState();
|
|
Services.AddSingleton(wizardState);
|
|
|
|
bool? captured = null;
|
|
var cut = RenderComponent<AccountStep>(p =>
|
|
p.Add(s => s.OnValidityChanged,
|
|
EventCallback.Factory.Create<bool>(this, v => captured = v)));
|
|
|
|
return (cut, () => captured);
|
|
}
|
|
|
|
[Fact]
|
|
public void OnValidityChanged_fires_false_on_initial_mount_with_empty_fields()
|
|
{
|
|
var (_, lastValidity) = RenderStep();
|
|
|
|
Assert.NotNull(lastValidity());
|
|
Assert.False(lastValidity(), "Step should be invalid on first mount (empty fields).");
|
|
}
|
|
|
|
[Fact]
|
|
public void OnValidityChanged_fires_true_after_all_valid_inputs_are_entered()
|
|
{
|
|
var (cut, lastValidity) = RenderStep();
|
|
|
|
// Simulate user filling in all four fields.
|
|
cut.Find("#username").Input("alice");
|
|
cut.Find("#password").Input("Secret1!");
|
|
cut.Find("#adminpassword").Input("Admin1!");
|
|
cut.Find("#bitlockerpin").Input("123456");
|
|
|
|
Assert.True(lastValidity(), "Step should be valid after all fields are correctly filled.");
|
|
}
|
|
|
|
[Fact]
|
|
public void OnValidityChanged_fires_false_when_a_field_is_cleared_after_being_valid()
|
|
{
|
|
var (cut, lastValidity) = RenderStep();
|
|
|
|
cut.Find("#username").Input("alice");
|
|
cut.Find("#password").Input("Secret1!");
|
|
cut.Find("#adminpassword").Input("Admin1!");
|
|
cut.Find("#bitlockerpin").Input("123456");
|
|
|
|
Assert.True(lastValidity()); // sanity
|
|
|
|
// Clear a required field — must revert to invalid.
|
|
cut.Find("#username").Input("");
|
|
|
|
Assert.False(lastValidity(), "Step should become invalid again when a required field is cleared.");
|
|
}
|
|
|
|
[Fact]
|
|
public void OnValidityChanged_fires_false_when_pin_is_non_numeric_or_too_short()
|
|
{
|
|
var (cut, lastValidity) = RenderStep();
|
|
|
|
cut.Find("#username").Input("alice");
|
|
cut.Find("#password").Input("Secret1!");
|
|
cut.Find("#adminpassword").Input("Admin1!");
|
|
|
|
// Too short — 5 digits.
|
|
cut.Find("#bitlockerpin").Input("12345");
|
|
Assert.False(lastValidity(), "PIN with only 5 digits must be invalid.");
|
|
|
|
// Non-numeric.
|
|
cut.Find("#bitlockerpin").Input("abc123");
|
|
Assert.False(lastValidity(), "Non-numeric PIN must be invalid.");
|
|
|
|
// Exactly 6 digits — valid.
|
|
cut.Find("#bitlockerpin").Input("123456");
|
|
Assert.True(lastValidity(), "Exactly 6 numeric digits is valid.");
|
|
}
|
|
|
|
[Fact]
|
|
public void OnValidityChanged_fires_true_on_mount_when_wizard_state_already_populated()
|
|
{
|
|
var prefilledState = new WizardState
|
|
{
|
|
Username = "alice",
|
|
Password = "Secret1!",
|
|
AdminPassword = "Admin1!",
|
|
BitLockerPin = "123456"
|
|
};
|
|
|
|
var (_, lastValidity) = RenderStep(prefilledState);
|
|
|
|
Assert.True(lastValidity(),
|
|
"Step should fire valid=true on mount when WizardState already has valid values (Back→Forward re-mount).");
|
|
}
|
|
}
|