Dashboard.Ui test coverage: 23.6% -> ~97% (restores the 90% Codecov floor) - #213
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Salvaged work from the parallel build before stopping. Compiles clean; 173 passing / 4 failing on both TFMs. Project went 66 -> 188 [TestMethod]. New test files: DashboardApiClientTests.cs 48 (committed separately, 3ef6281) ErrorsTabTests.cs 14 (committed separately, c6d7558) QueueDetailTests.cs 16 StaleTabTests.cs 11 ConfigTabTests.cs 7 ConsumersTabTests.cs 6 AutoRefreshTests.cs 6 MessagesTabTests.cs 5 HomeTests.cs (extended) KNOWN FAILING (4, identical on net8.0 and net10.0): MessagesTab ChangingStatusFilter_RequeriesWithSelectedValue Home ShowsErrorMessage_WhenLoadConnectionsThrows QueueDetail ClickingWaitingCard_FiltersMessagesTab_ToWaitingStatus QueueDetail ClickingErrorCard_SwitchesActiveTabToErrors STILL MISSING (181 uncovered lines unaddressed): ConnectionDetailTests.cs (85 misses) MessageDetailDrawerTests.cs (90 misses) HistoryResponseTests.cs (6 misses) Also fixes a compile break left by an interrupted builder: bUnit 2.x renamed IRenderedComponent<T>.SetParametersAndRender to Render. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- MessagesTab: MudSelect.SelectOption(2) resolves to the index overload, not the value; invoke ValueChanged directly to exercise OnStatusFilterChanged. - Home: re-stubbing GetConnectionsAsync after a throwing setup re-invokes the throw; use a single call-count stub instead. - QueueDetail: "div.mud-paper" also matches MudPopoverProvider's two popover containers; select the cards by .mud-elevation-2. - QueueDetail: cut.Instance is the ContainerFragment wrapper, so reflect over FindComponent<QueueDetail>().Instance for _activeTab. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers source-not-found, queue/job table rendering, empty states, consumer count chip vs zero, load failure + retry recovery, queue-row navigation with and without names, breadcrumb single- vs multi-source, and the same-parameters reload guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers the closed/no-id load guards, metadata rendering (optional fields on and off), detail-load failure, best-effort swallowing of body/header/retry failures, JSON formatting branches, decoding-error/type/interceptor display, header and retry tables, read-only gating, the edit/save/cancel cycle including blank-input and exception paths, delete confirm-then-commit, requeue/reset/cancel success and failure, close, and the reload guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds empty state, all StatusName/StatusColor branches, every FormatDuration range, TruncateId with and without a value, expand/collapse of the exception child row, status-filter and pagination requeries, the RefreshVersion reload, and purge confirm/success/failure. Also drives HistoryResponse.StatusName through all seven branches. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Login: submit via button and Enter key, blank-credential and non-Enter no-ops, asserted through bUnit JSInterop invocations. - SourceHealthMonitor: ExecuteAsync startup poll + graceful stop, the already-cancelled shutdown path, and the transition log lines (the logger substitute reports IsEnabled=false by default, so they were never reached). - QueueDetail: in-flight spinner, tab change, RefreshCounts via the drawer's OnDataChanged, and the swallowed-failure paths for refresh and manual refresh. - MessagesTab: id truncation, delayed chip, pagination, row-click callback with and without a queue id, refresh and filter-version reloads. - ConsumersTab: spinner, both uptime format branches, refresh reload. - EmptyLayout: renders the body inside the dark-theme container. Dashboard.Ui local line coverage 77.97% -> 97.24%; 273 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe pull request adds broad automated coverage for dashboard API clients, source health monitoring, Blazor pages, shared tabs, message actions, login interactions, auto-refresh behavior, and layout rendering. ChangesDashboard test coverage
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Checkov (3.3.8)Source/DotNetWorkQueue.Dashboard.Ui.Tests/DotNetWorkQueue.Dashboard.Ui.Tests.csprojTraceback (most recent call last): Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/HistoryTabTests.cs (1)
161-173: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAssertion on
"-"is too weak to verify the missing-QueueId placeholder.A bare
"-"appears throughout the rendered markup (timestamps, CSS class names, other placeholders), so this passes regardless of whether the QueueId cell actually renders a dash. Tighten to a cell-scoped assertion like the<td>-</td>form used inConnectionDetailTests, or query the specific queue-id cell.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/HistoryTabTests.cs` around lines 161 - 173, Strengthen the assertion in RendersDash_WhenQueueIdMissing so it verifies the QueueId table cell specifically renders the "-" placeholder, rather than searching the entire markup. Use a cell-scoped assertion such as the rendered <td>-</td> form or query the specific QueueId cell, while preserving the existing missing-QueueId test setup.Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/AutoRefreshTests.cs (1)
42-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
TogglingOn_StartsTimerdoes not assert timer behavior.
refreshCountis checked as0immediately after toggling on, which is trivially true and independent of whether a timer was started. The test name implies verifying the timer, but nothing exercises a tick. Consider driving the callback deterministically (e.g. inject/override the interval to a small value andWaitForAssertion, or expose the timer for test control) so the assertion actually guards the start behavior. Same applies toTogglingOff_StopsTimer, which only re-assertsToggled.Also note the
toggle.InvokeAsync(...)/select.InvokeAsync(...)calls here and throughout the file are not awaited; awaiting them (make the methodsasync Task) avoids swallowed exceptions and ordering surprises.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/AutoRefreshTests.cs` around lines 42 - 54, Update TogglingOn_StartsTimer and TogglingOff_StopsTimer to deterministically exercise timer ticks and assert the OnRefresh callback behavior, rather than only checking immediate state. Use the component’s existing timer configuration or test-control seam, and await toggle/select InvokeAsync calls by converting affected tests to async Task so state changes and exceptions are observed reliably.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Layout/EmptyLayoutTests.cs`:
- Around line 40-41: Update the test method in EmptyLayoutTests to locate the
div.mud-theme-dark element and assert that its inner HTML contains
layout-body-marker, rather than searching the full cut.Markup. Keep the existing
themed-wrapper assertion and verify the body marker is nested within that
element.
In `@Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/LoginTests.cs`:
- Around line 130-135: Update SetCredentials to return Task and await both
cut.InvokeAsync credential updates. Make each of its four call sites await
SetCredentials before triggering submit or the Enter action, ensuring the
updated username and password state is applied first.
In
`@Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/QueueDetailTests.cs`:
- Around line 234-261: Update
OpenMessageDrawer_ViaMessagesTabCallback_OpensDrawerWithMessageId and
ClosingDrawer_ViaOpenChangedCallback_ClearsSelectedMessage to return async Task
and await each cut.InvokeAsync call before reading or asserting drawer state.
Preserve the existing assertions and test behavior while ensuring callback
exceptions and asynchronous updates are observed.
In
`@Source/DotNetWorkQueue.Dashboard.Ui.Tests/Services/SourceHealthMonitorTests.cs`:
- Around line 250-286: The ExecuteAsync_PollsOnStartup_AndExitsGracefullyOnStop
test asserts health before the asynchronous initial poll is guaranteed to
complete. Wait until GetHealth(source.Slug).Status becomes Healthy before
calling StopAsync, or invoke PollAllSourcesAsync explicitly, while preserving
the existing startup/shutdown assertions.
---
Nitpick comments:
In
`@Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/AutoRefreshTests.cs`:
- Around line 42-54: Update TogglingOn_StartsTimer and TogglingOff_StopsTimer to
deterministically exercise timer ticks and assert the OnRefresh callback
behavior, rather than only checking immediate state. Use the component’s
existing timer configuration or test-control seam, and await toggle/select
InvokeAsync calls by converting affected tests to async Task so state changes
and exceptions are observed reliably.
In
`@Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/HistoryTabTests.cs`:
- Around line 161-173: Strengthen the assertion in
RendersDash_WhenQueueIdMissing so it verifies the QueueId table cell
specifically renders the "-" placeholder, rather than searching the entire
markup. Use a cell-scoped assertion such as the rendered <td>-</td> form or
query the specific QueueId cell, while preserving the existing missing-QueueId
test setup.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9fb1299c-5861-4267-8284-32dbe6846d24
📒 Files selected for processing (15)
Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Layout/EmptyLayoutTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/ConnectionDetailTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/HomeTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/LoginTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/QueueDetailTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/AutoRefreshTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/ConfigTabTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/ConsumersTabTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/ErrorsTabTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/HistoryTabTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/MessageDetailDrawerTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/MessagesTabTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/StaleTabTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Services/DashboardApiClientTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Services/SourceHealthMonitorTests.cs
SonarCloud (47 issues, all in the new test code): - CS8632 x30: the component under test is Nullable=enable, so its nullable signatures leak into test code. Set <Nullable>annotations</Nullable> on the test project — annotations without nullable warnings — instead of scattering #nullable enable pragmas. - CS4014 x8: NSubstitute Received()/DidNotReceive() assertions on Task-returning members are themselves Tasks; inside async test methods they were unawaited. Awaited, which is NSubstitute's documented idiom for async members. - MUD0012: reading MudTextField.Value from outside the component is disallowed and GetState is not accessible to test code, so assert on the rendered textarea content instead. - MSTEST0037 x2: Assert.AreEqual(false, nullableBool) -> IsNotNull + IsFalse. CodeRabbit: - EmptyLayout: assert the body marker against the themed wrapper's InnerHtml, so the test fails if the body ever renders outside it. - Login: SetCredentials fire-and-forgot both InvokeAsync calls; it now returns Task and all four call sites await it before submitting. - QueueDetail: the two drawer tests are async and await their InvokeAsync calls (same root cause as the CS4014 batch). - SourceHealthMonitor: the ExecuteAsync test asserted health without waiting for the startup poll; it now gates on a TaskCompletionSource the poll signals. Test project Release build is clean (0 warnings besides the pre-existing NU1902 on AngleSharp, a bUnit transitive). 273 tests pass on both TFMs; still no production-code changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
Source/DotNetWorkQueue.Dashboard.Ui.Tests/DotNetWorkQueue.Dashboard.Ui.Tests.csproj (1)
5-7: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy liftKeep nullable flow warnings on for the test project.
Nullable=annotationspreserves?syntax but turns off flow analysis in files that don't opt into#nullable enable, so possible-null dereferences in the suite can still slip through. Switch the project toenableand address the resulting diagnostics.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Source/DotNetWorkQueue.Dashboard.Ui.Tests/DotNetWorkQueue.Dashboard.Ui.Tests.csproj` around lines 5 - 7, Update the test project’s Nullable setting from annotations to enable so nullable flow analysis remains active, then resolve all resulting nullable diagnostics throughout the test suite without suppressing valid warnings.Source: MCP tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@Source/DotNetWorkQueue.Dashboard.Ui.Tests/DotNetWorkQueue.Dashboard.Ui.Tests.csproj`:
- Around line 5-7: Update the test project’s Nullable setting from annotations
to enable so nullable flow analysis remains active, then resolve all resulting
nullable diagnostics throughout the test suite without suppressing valid
warnings.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: fc8e5a81-b846-43bb-837a-dbb55ec7e07e
📒 Files selected for processing (8)
Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Layout/EmptyLayoutTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/LoginTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/QueueDetailTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/HistoryTabTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/MessageDetailDrawerTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/MessagesTabTests.csSource/DotNetWorkQueue.Dashboard.Ui.Tests/DotNetWorkQueue.Dashboard.Ui.Tests.csprojSource/DotNetWorkQueue.Dashboard.Ui.Tests/Services/SourceHealthMonitorTests.cs
🚧 Files skipped from review as they are similar to previous changes (7)
- Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Layout/EmptyLayoutTests.cs
- Source/DotNetWorkQueue.Dashboard.Ui.Tests/Services/SourceHealthMonitorTests.cs
- Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/MessagesTabTests.cs
- Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/HistoryTabTests.cs
- Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Shared/MessageDetailDrawerTests.cs
- Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/QueueDetailTests.cs
- Source/DotNetWorkQueue.Dashboard.Ui.Tests/Components/Pages/LoginTests.cs
|



Why
Codecov master sits at 88.09% against a 90% floor. The shortfall is not erosion — it is one untested project.
DotNetWorkQueue.Dashboard.Uiwas at 23.6%; removing it from the totals reproduces the historical ~90% exactly. Covering it is the only work that moves the number (the transports and core are already integration-covered).See
docs/code-coverage.mdfor the full rebaseline, including why Codecov and the local ReportGenerator badge differ by ~2.5 points (Codecov excludes partially-covered lines fromhits; ReportGenerator counts them as covered).What
Test-only change.
git diff master -- Source/DotNetWorkQueue.Dashboard.Ui/is empty — no production code was modified.The test project goes from 66 to 273 test methods across:
DashboardApiClientMessageDetailDrawerQueueDetailConnectionDetailHistoryTabErrorsTabMessagesTabStaleTabSourceHealthMonitorConsumersTabLoginConfigTab,AutoRefresh,Home,EmptyLayout, servicesFour tests carried over from earlier work were failing. All four were test bugs, not component bugs:
MudSelect.SelectOption(2)resolves to the index overload rather than the value — invokeValueChangedinstead.div.mud-paperalso matches the two popover containersMudPopoverProviderrenders ahead of page content — the status cards are selected via.mud-elevation-2.cut.Instanceis theContainerFragmentwrapper, so private-field reflection has to go throughFindComponent<QueueDetail>().Instance.One real coverage trap worth noting:
SourceHealthMonitor's state-transition log statements are guarded by_logger.IsEnabled(LogLevel.Information), and an NSubstituteILoggerreturnsfalseby default — so those lines were never being executed by the existing tests.Numbers
Local Coverlet,
Source/DotNetWorkQueue.Dashboard.Ui/only: 23.6% -> 97.24% line coverage, 66 misses remaining.Measured Codecov-style (deduped by line, partials excluded from hits): 1096 hits vs the 307 master baseline = +789. Master needs +639 for 90%, which projects to roughly 90.4%.
Verification
dotnet build Source\DotNetWorkQueueNoTests.sln -c Release -p:CI=true— 0 warnings, 0 errorsThread.Sleepin the test project (async waits useWaitForAssertion)🤖 Generated with Claude Code
Summary by CodeRabbit