Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions BlogWriter.Web.Tests/HelpDialogTestHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Bunit;
using Microsoft.JSInterop;

namespace BlogWriter.Web.Tests;

Expand All @@ -8,7 +7,4 @@ internal static class HelpDialogTestHelpers
public static void AllowDialogOpen(BunitContext context) =>
context.JSInterop.SetupVoid("blogWriterDialog.show", _ => true);

public static void FailClipboardCopy(BunitContext context) =>
context.JSInterop.SetupVoid("navigator.clipboard.writeText", _ => true)
.SetException(new JSException("Clipboard permission denied."));
}
37 changes: 9 additions & 28 deletions BlogWriter.Web.Tests/RunCommandDialogTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,20 @@ public sealed class RunCommandDialogTests : BunitContext
public RunCommandDialogTests() => JSInterop.Mode = JSRuntimeMode.Loose;

[Fact]
public void Dialog_ShowsExactRunCommandAndAccessibleModal()
public void Dialog_ShowsAboutTextAndAccessibleModal()
{
HelpDialogTestHelpers.AllowDialogOpen(this);
IRenderedComponent<RunCommandDialog> cut = Render<RunCommandDialog>();

Assert.Equal(RunCommandDialog.CommandText, cut.Find(".run-command-text").TextContent);
Assert.Contains(RunCommandDialog.HttpsPort, cut.Find(".run-command-port").TextContent);
Assert.Contains("About BlogWriter", cut.Markup);
Assert.Contains("BlogWriter", cut.Markup);
Assert.Contains("An open source program", cut.Markup);
Assert.Contains("(c) Copyright 2026 Jesse Liberty", cut.Markup);
Assert.Contains("See License", cut.Markup);
Assert.Equal("dialog", cut.Find("dialog").GetAttribute("role"));
Assert.Equal("true", cut.Find("dialog").GetAttribute("aria-modal"));
Assert.Equal("Copy", cut.Find(".dialog-actions button").TextContent.Trim());
}

[Fact]
public void Dialog_CopyReportsSuccess()
{
HelpDialogTestHelpers.AllowDialogOpen(this);
IRenderedComponent<RunCommandDialog> cut = Render<RunCommandDialog>();

cut.Find(".dialog-actions button").Click();

Assert.Contains("Command copied", cut.Markup);
}

[Fact]
public void Dialog_CopyFailureKeepsCommandVisibleAndReportsFailure()
{
HelpDialogTestHelpers.AllowDialogOpen(this);
HelpDialogTestHelpers.FailClipboardCopy(this);
IRenderedComponent<RunCommandDialog> cut = Render<RunCommandDialog>();

cut.Find(".dialog-actions button").Click();

Assert.Contains(RunCommandDialog.CommandText, cut.Markup);
Assert.Contains("Copying was not available", cut.Markup);
Assert.DoesNotContain("Copy", cut.FindAll(".dialog-actions button").Select(button => button.TextContent));
Assert.DoesNotContain("HTTPS port", cut.Markup);
Assert.Equal("Close", cut.Find(".dialog-actions button").TextContent.Trim());
}
}
33 changes: 5 additions & 28 deletions BlogWriter.Web/Components/RunCommandDialog.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,24 @@

<div class="dialog-backdrop">
<dialog @ref="_dialog" role="dialog" aria-modal="true" aria-labelledby="run-command-title" aria-describedby="run-command-copy" class="confirm-dialog run-command-dialog">
<p class="dialog-kicker">Developer help</p>
<h2 id="run-command-title">Run Blog Writer</h2>
<p id="run-command-copy">Use this command in the repository terminal:</p>
<code class="run-command-text">@CommandText</code>
<p class="run-command-port">HTTPS port: @HttpsPort</p>
@if (!string.IsNullOrWhiteSpace(CopyMessage))
{
<p class="copy-message" role="status">@CopyMessage</p>
}
<p class="dialog-kicker">About BlogWriter</p>
<h2 id="run-command-title">BlogWriter</h2>
<p id="run-command-copy">An open source program</p>
<p>(c) Copyright 2026 Jesse Liberty</p>
<p>See License</p>
<div class="dialog-actions">
<button type="button" @onclick="CopyAsync">Copy</button>
<button type="button" data-command="close-help" @onclick="Close">Close</button>
</div>
</dialog>
</div>

@code {
public const string CommandText = "dotnet run --project BlogWriter.Web/BlogWriter.Web.csproj --launch-profile https";
public const string HttpsPort = "7056";

private ElementReference _dialog;
private bool _opened;

[Parameter]
public EventCallback Closed { get; set; }

private string? CopyMessage { get; set; }

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
Expand All @@ -40,19 +30,6 @@
}
}

private async Task CopyAsync()
{
try
{
await JS.InvokeVoidAsync("navigator.clipboard.writeText", CommandText);
CopyMessage = "Command copied.";
}
catch (JSException)
{
CopyMessage = "Copying was not available. Select the command above to copy it manually.";
}
}

private async Task Close() => await Closed.InvokeAsync();

public async ValueTask DisposeAsync()
Expand Down
Loading