test(ui): bUnit coverage for the SMTP page transport selector state machine
This commit is contained in:
@@ -37,6 +37,55 @@ public class SmtpConfigurationPageTests : BunitContext
|
||||
Credentials = "user:pass",
|
||||
};
|
||||
|
||||
private static SmtpConfiguration OAuth2Sample() =>
|
||||
new("smtp.example.com", "OAuth2", "noreply@example.com")
|
||||
{
|
||||
Id = 1,
|
||||
Port = 587,
|
||||
TlsMode = "StartTLS",
|
||||
Credentials = "client-secret",
|
||||
};
|
||||
|
||||
private static SmtpConfiguration EwsSample() =>
|
||||
new("https://mail.example.com/ews/exchange.asmx", "Basic", "noreply@example.com")
|
||||
{
|
||||
Id = 2,
|
||||
Port = 587,
|
||||
TlsMode = "StartTLS",
|
||||
Transport = "Ews",
|
||||
Credentials = @"domain\user:pass",
|
||||
};
|
||||
|
||||
private IRenderedComponent<SmtpConfigurationPage> RenderWith(
|
||||
INotificationRepository repo, params SmtpConfiguration[] configs)
|
||||
{
|
||||
repo.GetAllSmtpConfigurationsAsync()
|
||||
.Returns(Task.FromResult<IReadOnlyList<SmtpConfiguration>>(configs.ToList()));
|
||||
Services.AddSingleton(repo);
|
||||
WireAuth();
|
||||
|
||||
var cut = Render<SmtpConfigurationPage>();
|
||||
cut.WaitForState(() => cut.Markup.Contains(configs[0].Host));
|
||||
return cut;
|
||||
}
|
||||
|
||||
private static void ClickEdit(IRenderedComponent<SmtpConfigurationPage> cut)
|
||||
=> cut.FindAll("button").First(b => b.TextContent.Contains("Edit")).Click();
|
||||
|
||||
private static void ClickSave(IRenderedComponent<SmtpConfigurationPage> cut)
|
||||
=> cut.FindAll("button").First(b => b.TextContent.Contains("Save")).Click();
|
||||
|
||||
/// <summary>Locates a select by an option it offers — the page has no element ids.</summary>
|
||||
private static AngleSharp.Dom.IElement SelectWithOption(
|
||||
IRenderedComponent<SmtpConfigurationPage> cut, string optionText)
|
||||
=> cut.FindAll("select")
|
||||
.Single(s => s.QuerySelectorAll("option").Any(o => o.TextContent == optionText));
|
||||
|
||||
private static bool HasSelectWithOption(
|
||||
IRenderedComponent<SmtpConfigurationPage> cut, string optionText)
|
||||
=> cut.FindAll("select")
|
||||
.Any(s => s.QuerySelectorAll("option").Any(o => o.TextContent == optionText));
|
||||
|
||||
[Fact]
|
||||
public void EditForm_RendersTlsModeSelectWithAllThreeModes()
|
||||
{
|
||||
@@ -110,4 +159,105 @@ public class SmtpConfigurationPageTests : BunitContext
|
||||
repo.Received().SaveChangesAsync();
|
||||
});
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Transport selector (EWS) — form state machine
|
||||
// ========================================================================
|
||||
|
||||
[Fact]
|
||||
public void EditForm_WithEwsTransport_HidesPortTlsAndAuthTypeAndForcesBasicAuth()
|
||||
{
|
||||
var repo = Substitute.For<INotificationRepository>();
|
||||
var cut = RenderWith(repo, OAuth2Sample());
|
||||
|
||||
ClickEdit(cut);
|
||||
SelectWithOption(cut, "Ews").Change("Ews");
|
||||
|
||||
// Port input, TLS select and Auth Type select are all gone under EWS.
|
||||
Assert.Empty(cut.FindAll("input[type=number]"));
|
||||
Assert.False(HasSelectWithOption(cut, "StartTLS"));
|
||||
Assert.False(HasSelectWithOption(cut, "OAuth2"));
|
||||
Assert.Contains("EWS URL", cut.Markup);
|
||||
|
||||
// The forced auth type is only observable through what gets persisted: the row
|
||||
// loaded as OAuth2 must save as Basic because EWS supports Basic only.
|
||||
cut.Find("input[type=text]").Change("https://mail.example.com/ews/exchange.asmx");
|
||||
ClickSave(cut);
|
||||
|
||||
cut.WaitForAssertion(() =>
|
||||
repo.Received().UpdateSmtpConfigurationAsync(Arg.Is<SmtpConfiguration>(
|
||||
c => c.Transport == "Ews"
|
||||
&& c.AuthType == "Basic"
|
||||
&& c.Host == "https://mail.example.com/ews/exchange.asmx")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EditForm_SwitchingEwsBackToSmtp_RestoresAuthTypeAndReshowsPortAndTls()
|
||||
{
|
||||
var repo = Substitute.For<INotificationRepository>();
|
||||
var cut = RenderWith(repo, OAuth2Sample());
|
||||
|
||||
ClickEdit(cut);
|
||||
SelectWithOption(cut, "Ews").Change("Ews");
|
||||
SelectWithOption(cut, "Ews").Change("Smtp");
|
||||
|
||||
// Port and TLS controls are back...
|
||||
Assert.Single(cut.FindAll("input[type=number]"));
|
||||
Assert.True(HasSelectWithOption(cut, "StartTLS"));
|
||||
Assert.True(HasSelectWithOption(cut, "OAuth2"));
|
||||
|
||||
// ...and the round trip left the pre-switch values (OAuth2 / 587 / StartTLS) intact.
|
||||
ClickSave(cut);
|
||||
|
||||
cut.WaitForAssertion(() =>
|
||||
repo.Received().UpdateSmtpConfigurationAsync(Arg.Is<SmtpConfiguration>(
|
||||
c => c.Transport == "Smtp"
|
||||
&& c.AuthType == "OAuth2"
|
||||
&& c.Port == 587
|
||||
&& c.TlsMode == "StartTLS")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Save_WithEwsTransportAndNonHttpsHost_ShowsFormErrorAndDoesNotPersist()
|
||||
{
|
||||
var repo = Substitute.For<INotificationRepository>();
|
||||
var cut = RenderWith(repo, OAuth2Sample());
|
||||
|
||||
ClickEdit(cut);
|
||||
SelectWithOption(cut, "Ews").Change("Ews");
|
||||
cut.Find("input[type=text]").Change("http://mail.example.com/ews/exchange.asmx");
|
||||
ClickSave(cut);
|
||||
|
||||
cut.WaitForAssertion(() => Assert.Contains("absolute https://", cut.Markup));
|
||||
repo.DidNotReceive().UpdateSmtpConfigurationAsync(Arg.Any<SmtpConfiguration>());
|
||||
repo.DidNotReceive().SaveChangesAsync();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyView_ShowsTransportBadgeAndHidesPortAndTlsForEwsRows()
|
||||
{
|
||||
var ewsCut = RenderWith(Substitute.For<INotificationRepository>(), EwsSample());
|
||||
|
||||
ewsCut.WaitForAssertion(() =>
|
||||
{
|
||||
Assert.Contains("<span class=\"badge bg-secondary\">Ews</span>", ewsCut.Markup);
|
||||
Assert.Contains("EWS URL", ewsCut.Markup);
|
||||
Assert.DoesNotContain("TLS Mode", ewsCut.Markup);
|
||||
// The EWS URL is rendered bare — no ":port" suffix as the SMTP host row has.
|
||||
Assert.DoesNotContain("exchange.asmx:587", ewsCut.Markup);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadOnlyView_LegacyRowWithNullTransport_ShowsSmtpBadgeAndKeepsPortAndTls()
|
||||
{
|
||||
var cut = RenderWith(Substitute.For<INotificationRepository>(), Sample());
|
||||
|
||||
cut.WaitForAssertion(() =>
|
||||
{
|
||||
Assert.Contains("<span class=\"badge bg-secondary\">Smtp</span>", cut.Markup);
|
||||
Assert.Contains("smtp.example.com:587", cut.Markup);
|
||||
Assert.Contains("TLS Mode", cut.Markup);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user