docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)

Comment/XML-doc changes only:
- add summaries to ~10k test methods, fixtures, fakes and helpers
  (+ <param> on theories, <returns> on async Task methods,
  <inheritdoc/> on interface implementations the checker can resolve)
- strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N,
  #NN, Component-0NN) from comments, keeping the explanatory text;
  reword false positives in comments only
- real docs on fakes implementing BCL/library interfaces
  (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime)
- reword the last 5 src/ false positives (CWE-1236, failures-1,
  year-0001, M365)

Only non-comment edits: four one-line nested classes split across lines
so members can carry docs. Build 0 errors / 0 warnings.
This commit is contained in:
Joseph Doherty
2026-10-07 15:05:49 -04:00
parent 0ffd4bdbea
commit 513fa1aa16
998 changed files with 17896 additions and 2395 deletions
@@ -9,7 +9,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components.Audit;
/// <summary>
/// bUnit tests for <see cref="AuditDrilldownDrawer"/> (#23 M7 Bundle C / M7-T4..T8).
/// bUnit tests for <see cref="AuditDrilldownDrawer"/>.
///
/// The drawer is a child component opened from the Audit Log page when a grid row
/// is clicked. It renders the offcanvas chrome (header, open/close) and delegates
@@ -24,6 +24,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components.Audit;
/// </summary>
public class AuditDrilldownDrawerTests : BunitContext
{
/// <summary>Initializes the test context with loose JS interop and the services the drawer needs.</summary>
public AuditDrilldownDrawerTests()
{
// Default to Loose so the cURL clipboard call does not blow up tests
@@ -70,6 +71,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Extra = extra,
};
/// <summary>Verifies that the drawer renders the occurred-at UTC field.</summary>
[Fact]
public void Drawer_RendersField_OccurredAtUtc()
{
@@ -86,6 +88,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains("2026-05-20T12:30:45", cut.Markup);
}
/// <summary>Verifies that a JSON request summary is pretty-printed with indentation.</summary>
[Fact]
public void Drawer_JsonRequestSummary_PrettyPrinted_Indented()
{
@@ -104,6 +107,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Matches(@"\n\s+""b"":\s*""two""", cut.Markup);
}
/// <summary>Verifies that a non-JSON request summary is rendered verbatim.</summary>
[Fact]
public void Drawer_NonJsonRequestSummary_RenderedVerbatim()
{
@@ -118,6 +122,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains("not really json {{}", cut.Markup);
}
/// <summary>Verifies that a DbOutbound event renders its SQL block.</summary>
[Fact]
public void Drawer_DbOutboundChannel_RendersSqlBlock()
{
@@ -140,6 +145,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains("abc", cut.Markup);
}
/// <summary>Verifies that an API outbound event shows the copy-as-cURL button.</summary>
[Fact]
public void Drawer_ApiOutbound_ShowsCopyAsCurlButton()
{
@@ -152,6 +158,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains("data-test=\"copy-as-curl\"", cut.Markup);
}
/// <summary>Verifies that a non-API channel event hides the copy-as-cURL button.</summary>
[Fact]
public void Drawer_NotApiChannel_HidesCopyAsCurlButton()
{
@@ -165,6 +172,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.DoesNotContain("data-test=\"copy-as-curl\"", cut.Markup);
}
/// <summary>Verifies that a null correlation id hides the show-all button.</summary>
[Fact]
public void Drawer_NullCorrelationId_HidesShowAllButton()
{
@@ -177,6 +185,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.DoesNotContain("data-test=\"show-all-events\"", cut.Markup);
}
/// <summary>Verifies that a redacted body shows the redaction badge.</summary>
[Fact]
public void Drawer_RedactedBody_ShowsRedactionBadge()
{
@@ -191,6 +200,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains("data-test=\"redaction-badge-request\"", cut.Markup);
}
/// <summary>Verifies that a non-redacted body hides the redaction badge.</summary>
[Fact]
public void Drawer_NonRedactedBody_HidesBadge()
{
@@ -203,6 +213,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.DoesNotContain("data-test=\"redaction-badge-request\"", cut.Markup);
}
/// <summary>Verifies that show-all-for-operation navigates with the correlation id in the query string.</summary>
[Fact]
public void ShowAllForOperation_Navigates_WithCorrelationIdQueryString()
{
@@ -220,6 +231,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains(corr.ToString(), nav.Uri);
}
/// <summary>Verifies that a null execution id hides the view-this-execution button.</summary>
[Fact]
public void Drawer_NullExecutionId_HidesViewThisExecutionButton()
{
@@ -232,6 +244,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.DoesNotContain("data-test=\"view-this-execution\"", cut.Markup);
}
/// <summary>Verifies that a non-null execution id shows the view-this-execution button.</summary>
[Fact]
public void Drawer_NonNullExecutionId_ShowsViewThisExecutionButton()
{
@@ -244,6 +257,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains("data-test=\"view-this-execution\"", cut.Markup);
}
/// <summary>Verifies that view-this-execution navigates with the execution id in the query string.</summary>
[Fact]
public void ViewThisExecution_Navigates_WithExecutionIdQueryString()
{
@@ -260,6 +274,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains($"/audit/log?executionId={exec}", nav.Uri);
}
/// <summary>Verifies that a null parent execution id hides the view-parent-execution button.</summary>
[Fact]
public void Drawer_NullParentExecutionId_HidesViewParentExecutionButton()
{
@@ -272,6 +287,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.DoesNotContain("data-test=\"view-parent-execution\"", cut.Markup);
}
/// <summary>Verifies that a non-null parent execution id shows the view-parent-execution button.</summary>
[Fact]
public void Drawer_NonNullParentExecutionId_ShowsViewParentExecutionButton()
{
@@ -284,6 +300,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains("data-test=\"view-parent-execution\"", cut.Markup);
}
/// <summary>Verifies that view-parent-execution navigates with the parent execution id in the query string.</summary>
[Fact]
public void ViewParentExecution_Navigates_WithExecutionIdQueryString()
{
@@ -303,6 +320,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains($"/audit/log?executionId={parent}", nav.Uri);
}
/// <summary>Verifies that a null execution id hides the view-execution-chain button.</summary>
[Fact]
public void Drawer_NullExecutionId_HidesViewExecutionChainButton()
{
@@ -315,6 +333,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.DoesNotContain("data-test=\"view-execution-chain\"", cut.Markup);
}
/// <summary>Verifies that a non-null execution id shows the view-execution-chain button.</summary>
[Fact]
public void Drawer_NonNullExecutionId_ShowsViewExecutionChainButton()
{
@@ -327,6 +346,7 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains("data-test=\"view-execution-chain\"", cut.Markup);
}
/// <summary>Verifies that view-execution-chain navigates to the execution tree page.</summary>
[Fact]
public void ViewExecutionChain_Navigates_ToExecutionTreePage()
{
@@ -345,6 +365,8 @@ public class AuditDrilldownDrawerTests : BunitContext
Assert.Contains($"/audit/execution-tree?executionId={exec}", nav.Uri);
}
/// <summary>Verifies that copy-as-cURL invokes the clipboard with the cURL command string.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task CopyAsCurl_InvokesClipboard_WithCurlString()
{
@@ -10,8 +10,8 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components.Audit;
/// <summary>
/// bUnit tests for <see cref="AuditEventDetail"/> — the reusable single-row
/// detail body extracted from <see cref="AuditDrilldownDrawer"/> (Task 1 of the
/// Execution-Tree Node Detail Modal feature).
/// detail body extracted from <see cref="AuditDrilldownDrawer"/> for reuse by the
/// Execution-Tree Node Detail Modal.
///
/// These tests render the detail component directly (not via the drawer) and
/// pin the contract the drawer — and any future modal host — relies on:
@@ -22,6 +22,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components.Audit;
/// </summary>
public class AuditEventDetailTests : BunitContext
{
/// <summary>Initializes the test context with loose JS interop so unrelated tests do not fail on the clipboard call.</summary>
public AuditEventDetailTests()
{
// Loose so the cURL clipboard call does not blow up tests that do not
@@ -67,6 +68,7 @@ public class AuditEventDetailTests : BunitContext
Extra = extra,
};
/// <summary>Verifies that the read-only field block renders the audit event fields.</summary>
[Fact]
public void RendersFieldBlock()
{
@@ -81,6 +83,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("2026-05-20T12:30:45", cut.Markup);
}
/// <summary>Verifies that the source node field renders between the site and instance fields.</summary>
[Fact]
public void RendersSourceNodeField_BetweenSiteAndInstance()
{
@@ -103,6 +106,7 @@ public class AuditEventDetailTests : BunitContext
$"Expected SourceSiteId < SourceNode < SourceInstanceId; got {siteIdx}, {nodeIdx}, {instanceIdx}");
}
/// <summary>Verifies that a null source node renders as a dash.</summary>
[Fact]
public void RendersSourceNodeField_AsDashWhenNull()
{
@@ -119,6 +123,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains(">—<", cut.Markup);
}
/// <summary>Verifies that the error section renders when the event carries an error.</summary>
[Fact]
public void ErrorSection_RendersWhenErrorPresent()
{
@@ -134,6 +139,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("stack trace here", cut.Markup);
}
/// <summary>Verifies that the error section is hidden when the event has no error.</summary>
[Fact]
public void ErrorSection_HiddenWhenNoError()
{
@@ -144,6 +150,7 @@ public class AuditEventDetailTests : BunitContext
Assert.DoesNotContain("data-test=\"section-error\"", cut.Markup);
}
/// <summary>Verifies that the request section pretty-prints a JSON payload.</summary>
[Fact]
public void RequestSection_PrettyPrintsJson()
{
@@ -156,6 +163,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Matches(@"\n\s+""a"":\s*1", cut.Markup);
}
/// <summary>Verifies that the response section renders when a response payload is present.</summary>
[Fact]
public void ResponseSection_RendersWhenPresent()
{
@@ -167,6 +175,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("data-test=\"response-body\"", cut.Markup);
}
/// <summary>Verifies that the extra section renders when extra data is present.</summary>
[Fact]
public void ExtraSection_RendersWhenPresent()
{
@@ -177,6 +186,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("data-test=\"section-extra\"", cut.Markup);
}
/// <summary>Verifies that a redacted body shows the redaction badge.</summary>
[Fact]
public void RedactedBody_ShowsRedactionBadge()
{
@@ -187,6 +197,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("data-test=\"redaction-badge-request\"", cut.Markup);
}
/// <summary>Verifies that a body that was not redacted hides the redaction badge.</summary>
[Fact]
public void NonRedactedBody_HidesRedactionBadge()
{
@@ -197,6 +208,7 @@ public class AuditEventDetailTests : BunitContext
Assert.DoesNotContain("data-test=\"redaction-badge-request\"", cut.Markup);
}
/// <summary>Verifies that a database outbound event renders its SQL block.</summary>
[Fact]
public void DbOutboundChannel_RendersSqlBlock()
{
@@ -210,6 +222,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("data-test=\"sql-parameters\"", cut.Markup);
}
/// <summary>Verifies that an API channel event shows the copy-as-cURL button.</summary>
[Fact]
public void ApiChannel_ShowsCopyAsCurlButton()
{
@@ -220,6 +233,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("data-test=\"copy-as-curl\"", cut.Markup);
}
/// <summary>Verifies that a non-API channel event hides the copy-as-cURL button.</summary>
[Fact]
public void NonApiChannel_HidesCopyAsCurlButton()
{
@@ -230,6 +244,7 @@ public class AuditEventDetailTests : BunitContext
Assert.DoesNotContain("data-test=\"copy-as-curl\"", cut.Markup);
}
/// <summary>Verifies that a null correlation id hides the show-all-for-operation button.</summary>
[Fact]
public void NullCorrelationId_HidesShowAllButton()
{
@@ -240,6 +255,7 @@ public class AuditEventDetailTests : BunitContext
Assert.DoesNotContain("data-test=\"show-all-events\"", cut.Markup);
}
/// <summary>Verifies that a non-null correlation id shows the show-all-for-operation button.</summary>
[Fact]
public void NonNullCorrelationId_ShowsShowAllButton()
{
@@ -250,6 +266,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("data-test=\"show-all-events\"", cut.Markup);
}
/// <summary>Verifies that the execution buttons render only when the matching execution ids are present.</summary>
[Fact]
public void ExecutionButtons_ConditionalOnExecutionIds()
{
@@ -264,6 +281,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains("data-test=\"view-execution-chain\"", cut.Markup);
}
/// <summary>Verifies that show-all-for-operation navigates with the correlation id in the query string.</summary>
[Fact]
public void ShowAllForOperation_Navigates_WithCorrelationIdQueryString()
{
@@ -278,6 +296,7 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains($"/audit/log?correlationId={corr}", nav.Uri);
}
/// <summary>Verifies that view-execution-chain navigates to the execution tree page.</summary>
[Fact]
public void ViewExecutionChain_Navigates_ToExecutionTreePage()
{
@@ -292,6 +311,8 @@ public class AuditEventDetailTests : BunitContext
Assert.Contains($"/audit/execution-tree?executionId={exec}", nav.Uri);
}
/// <summary>Verifies that copy-as-cURL invokes the clipboard with the generated cURL command.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task CopyAsCurl_InvokesClipboard_WithCurlString()
{
@@ -13,7 +13,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components.Audit;
/// <summary>
/// bUnit tests for <see cref="AuditFilterBar"/> (#23 M7-T2 / Bundle B).
/// bUnit tests for <see cref="AuditFilterBar"/>.
///
/// The bar carries the 10 spec filter elements plus the Errors-only toggle.
/// Channel is a single-select <c>&lt;select data-test="filter-channel-select"&gt;</c>;
@@ -33,6 +33,7 @@ public class AuditFilterBarTests : BunitContext
private readonly ISiteRepository _siteRepo;
private readonly IAuditLogQueryService _auditLogQueryService;
/// <summary>Initializes the bUnit context with substitute site and audit query services.</summary>
public AuditFilterBarTests()
{
_siteRepo = Substitute.For<ISiteRepository>();
@@ -44,7 +45,7 @@ public class AuditFilterBarTests : BunitContext
}));
Services.AddSingleton(_siteRepo);
// Task 15: the Node multi-select pulls its options from
// The Node multi-select pulls its options from
// IAuditLogQueryService.GetDistinctSourceNodesAsync. The default stub
// returns the two central nodes the cluster uses; individual tests can
// override via _auditLogQueryService.GetDistinctSourceNodesAsync(...).Returns(...).
@@ -56,6 +57,7 @@ public class AuditFilterBarTests : BunitContext
Services.AddSingleton(_auditLogQueryService);
}
/// <summary>Verifies that the filter bar renders all ten filter elements plus the errors-only toggle.</summary>
[Fact]
public void Render_AllTenElements_Plus_ErrorsOnlyToggle_Present()
{
@@ -86,6 +88,7 @@ public class AuditFilterBarTests : BunitContext
}
}
/// <summary>Verifies that applying the filters raises the filter-changed callback with the selected filters.</summary>
[Fact]
public void Apply_RaisesOnFilterChanged_WithSelectedFilters()
{
@@ -103,6 +106,7 @@ public class AuditFilterBarTests : BunitContext
Assert.Equal("Plant-A-OPC", captured.Target);
}
/// <summary>Verifies that choosing a different channel replaces the previous selection because the channel is single-select.</summary>
[Fact]
public void ChangingChannel_ReplacesTheSelection_SingleSelect()
{
@@ -125,6 +129,7 @@ public class AuditFilterBarTests : BunitContext
Assert.Null(captured!.Channels);
}
/// <summary>Verifies that selecting a channel narrows the available kind options.</summary>
[Fact]
public void Channel_Narrows_Kind_Options_When_Selected()
{
@@ -149,6 +154,7 @@ public class AuditFilterBarTests : BunitContext
Assert.DoesNotContain($"data-test=\"filter-kind-ms-opt-{AuditKind.InboundRequest}\"", cut.Markup);
}
/// <summary>Verifies that the errors-only toggle adds the failed, parked and discarded statuses when no status is selected.</summary>
[Fact]
public void ErrorsOnly_Toggle_Adds_FailedParkedDiscarded_ToStatus_WhenStatusIsEmpty()
{
@@ -161,7 +167,7 @@ public class AuditFilterBarTests : BunitContext
cut.Find("[data-test=\"filter-apply\"]").Click();
Assert.NotNull(captured);
// Task 9: Errors-only targets the full non-success set {Failed, Parked, Discarded}.
// Errors-only targets the full non-success set {Failed, Parked, Discarded}.
Assert.NotNull(captured!.Statuses);
Assert.Equal(3, captured.Statuses!.Count);
Assert.Contains(AuditStatus.Failed, captured.Statuses);
@@ -175,10 +181,11 @@ public class AuditFilterBarTests : BunitContext
Assert.Equal(new[] { AuditStatus.Delivered }, captured!.Statuses);
}
/// <summary>Verifies that the node multi-select renders its options from the query service and maps the selection through to the filter.</summary>
[Fact]
public void NodeMultiSelect_RendersOptions_FromQueryService_AndMapsThroughToFilter()
{
// Task 15: the Node filter pulls its option set from
// The Node filter pulls its option set from
// IAuditLogQueryService.GetDistinctSourceNodesAsync and threads the
// chip selection into AuditLogQueryFilter.SourceNodes.
AuditLogQueryFilter? captured = null;
@@ -199,10 +206,11 @@ public class AuditFilterBarTests : BunitContext
Assert.Equal(new[] { "central-a" }, captured.SourceNodes);
}
/// <summary>Verifies that applying with several status chips selected passes every selected status to the filter.</summary>
[Fact]
public void Apply_WithMultipleStatusChips_PassesAllSelectedStatuses()
{
// Task 9: multiple explicit Status chips all reach the filter — and they
// Multiple explicit Status chips all reach the filter — and they
// win over the Errors-only default.
AuditLogQueryFilter? captured = null;
var cut = Render<AuditFilterBar>(p => p
@@ -219,6 +227,7 @@ public class AuditFilterBarTests : BunitContext
Assert.Contains(AuditStatus.Failed, captured.Statuses);
}
/// <summary>Verifies that a pasted execution id is mapped through to the filter on apply.</summary>
[Fact]
public void Apply_WithPastedExecutionId_MapsThroughToFilter()
{
@@ -236,6 +245,7 @@ public class AuditFilterBarTests : BunitContext
Assert.Equal(executionId, captured!.ExecutionId);
}
/// <summary>Verifies that a blank or unparseable execution id leaves the filter execution id null.</summary>
[Fact]
public void Apply_WithBlankOrUnparseableExecutionId_LeavesFilterExecutionIdNull()
{
@@ -255,6 +265,7 @@ public class AuditFilterBarTests : BunitContext
Assert.Null(captured!.ExecutionId);
}
/// <summary>Verifies that a pasted parent execution id is mapped through to the filter on apply.</summary>
[Fact]
public void Apply_WithPastedParentExecutionId_MapsThroughToFilter()
{
@@ -272,6 +283,7 @@ public class AuditFilterBarTests : BunitContext
Assert.Equal(parentExecutionId, captured!.ParentExecutionId);
}
/// <summary>Verifies that a blank or unparseable parent execution id leaves the filter parent execution id null.</summary>
[Fact]
public void Apply_WithBlankOrUnparseableParentExecutionId_LeavesFilterParentExecutionIdNull()
{
@@ -291,6 +303,7 @@ public class AuditFilterBarTests : BunitContext
Assert.Null(captured!.ParentExecutionId);
}
/// <summary>Verifies that choosing the last-hour time range sets the from-UTC value to approximately one hour ago.</summary>
[Fact]
public void TimeRange_LastHour_PopulatesFromUtc_ApproxOneHourAgo()
{
@@ -10,7 +10,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components.Audit;
/// <summary>
/// bUnit tests for <see cref="AuditResultsGrid"/> (#23 M7-T3 / Bundle B). The grid
/// bUnit tests for <see cref="AuditResultsGrid"/>. The grid
/// renders 10 columns, paginates via keyset (passing the last row's
/// (OccurredAtUtc, EventId) back to the service), raises a row-click callback
/// that Bundle C wires to the drilldown drawer, and styles non-success status
@@ -39,6 +39,7 @@ public class AuditResultsGridTests : BunitContext
ErrorMessage = status == AuditStatus.Failed ? "boom — unreachable" : null,
};
/// <summary>Initializes a new instance of the <see cref="AuditResultsGridTests"/> class.</summary>
public AuditResultsGridTests()
{
_service = Substitute.For<IAuditLogQueryService>();
@@ -62,6 +63,7 @@ public class AuditResultsGridTests : BunitContext
});
}
/// <summary>Verifies the case: render, ten Columns, from Stub Service.</summary>
[Fact]
public void Render_TenColumns_FromStubService()
{
@@ -84,6 +86,7 @@ public class AuditResultsGridTests : BunitContext
}
}
/// <summary>Verifies the case: click, next Page, calls Service, with Cursor, of Last Row.</summary>
[Fact]
public void Click_NextPage_CallsService_WithCursor_OfLastRow()
{
@@ -105,6 +108,7 @@ public class AuditResultsGridTests : BunitContext
Assert.Equal(second.EventId, nextCall.Paging.AfterEventId);
}
/// <summary>Verifies the case: click, row, raises On Row Selected.</summary>
[Fact]
public void Click_Row_RaisesOnRowSelected()
{
@@ -122,10 +126,11 @@ public class AuditResultsGridTests : BunitContext
Assert.Equal(target.EventId, captured!.EventId);
}
/// <summary>Verifies the case: render, includes Node Column, between Site And Channel.</summary>
[Fact]
public void Render_IncludesNodeColumn_BetweenSiteAndChannel()
{
// Task 15: the grid surfaces SourceNode in a dedicated "Node" column
// The grid surfaces SourceNode in a dedicated "Node" column
// positioned between Site and Channel.
StubPage(new List<AuditEventView>
{
@@ -144,6 +149,7 @@ public class AuditResultsGridTests : BunitContext
Assert.True(nodeIdx < channelIdx, "Node column must precede Channel.");
}
/// <summary>Verifies the case: render, includes Execution Id Column.</summary>
[Fact]
public void Render_IncludesExecutionIdColumn()
{
@@ -158,6 +164,7 @@ public class AuditResultsGridTests : BunitContext
Assert.Contains("data-test=\"col-header-ExecutionId\"", cut.Markup);
}
/// <summary>Verifies the case: execution Id, non Null Row, renders Short Monospace Value.</summary>
[Fact]
public void ExecutionId_NonNullRow_RendersShortMonospaceValue()
{
@@ -175,6 +182,7 @@ public class AuditResultsGridTests : BunitContext
Assert.Equal(executionId.ToString(), cell.GetAttribute("title"));
}
/// <summary>Verifies the case: execution Id, null Row, renders Blank Placeholder, no Execution Id Cell.</summary>
[Fact]
public void ExecutionId_NullRow_RendersBlankPlaceholder_NoExecutionIdCell()
{
@@ -187,6 +195,7 @@ public class AuditResultsGridTests : BunitContext
Assert.Empty(cut.FindAll($"[data-test=\"execution-id-{row.EventId}\"]"));
}
/// <summary>Verifies the case: render, includes Parent Execution Id Column.</summary>
[Fact]
public void Render_IncludesParentExecutionIdColumn()
{
@@ -201,6 +210,7 @@ public class AuditResultsGridTests : BunitContext
Assert.Contains("data-test=\"col-header-ParentExecutionId\"", cut.Markup);
}
/// <summary>Verifies the case: parent Execution Id, non Null Row, renders Short Monospace Value.</summary>
[Fact]
public void ParentExecutionId_NonNullRow_RendersShortMonospaceValue()
{
@@ -218,6 +228,7 @@ public class AuditResultsGridTests : BunitContext
Assert.Equal(parentExecutionId.ToString(), cell.GetAttribute("title"));
}
/// <summary>Verifies the case: parent Execution Id, null Row, renders Blank Placeholder, no Parent Execution Id Cell.</summary>
[Fact]
public void ParentExecutionId_NullRow_RendersBlankPlaceholder_NoParentExecutionIdCell()
{
@@ -230,6 +241,7 @@ public class AuditResultsGridTests : BunitContext
Assert.Empty(cut.FindAll($"[data-test=\"parent-execution-id-{row.EventId}\"]"));
}
/// <summary>Verifies the case: status, failed Row, has Error Badge Class.</summary>
[Fact]
public void Status_FailedRow_HasErrorBadgeClass()
{
@@ -247,7 +259,7 @@ public class AuditResultsGridTests : BunitContext
Assert.Contains("bg-success", deliveredBadge.GetAttribute("class") ?? string.Empty);
}
// --- column resize + reorder UX (#23 follow-ups Task 10) ---------------
// --- column resize + reorder UX ---------------
//
// The drag interaction itself is browser-side (audit-grid.js) and covered
// by the Playwright suite. The bUnit tests below exercise the .NET-side
@@ -265,6 +277,7 @@ public class AuditResultsGridTests : BunitContext
private static int HeaderIndex(string markup, string key)
=> markup.IndexOf($"data-col-key=\"{key}\"", StringComparison.Ordinal);
/// <summary>Verifies the case: headers, render Resize Handle And Drag Key, for Every Column.</summary>
[Fact]
public void Headers_RenderResizeHandleAndDragKey_ForEveryColumn()
{
@@ -280,6 +293,7 @@ public class AuditResultsGridTests : BunitContext
}
}
/// <summary>Verifies the case: column Order Parameter, drives Header Order.</summary>
[Fact]
public void ColumnOrderParameter_DrivesHeaderOrder()
{
@@ -300,6 +314,8 @@ public class AuditResultsGridTests : BunitContext
}
}
/// <summary>Verifies the case: on Column Reordered, moves Column Into Target Slot, and Persists.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task OnColumnReordered_MovesColumnIntoTargetSlot_AndPersists()
{
@@ -318,6 +334,8 @@ public class AuditResultsGridTests : BunitContext
Assert.Contains("Status", (string)save.Arguments[1]!);
}
/// <summary>Verifies the case: on Column Resized, below Minimum, clamps To64px, and Persists.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task OnColumnResized_BelowMinimum_ClampsTo64px_AndPersists()
{
@@ -335,6 +353,7 @@ public class AuditResultsGridTests : BunitContext
i => i.Identifier == "auditGrid.save" && (string)i.Arguments[0]! == "columnWidths");
}
/// <summary>Verifies the case: stored Order, with Unknown Key, degrades Gracefully.</summary>
[Fact]
public void StoredOrder_WithUnknownKey_DegradesGracefully()
{
@@ -360,6 +379,7 @@ public class AuditResultsGridTests : BunitContext
}
}
/// <summary>Verifies the case: stored Widths, for Unknown Column, are Ignored.</summary>
[Fact]
public void StoredWidths_ForUnknownColumn_AreIgnored()
{
@@ -11,7 +11,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components.Audit;
/// <summary>
/// bUnit tests for <see cref="ExecutionDetailModal"/> (Execution-Tree Node Detail
/// Modal, Task 3). The modal opens on an execution-tree node double-click: given
/// Modal). The modal opens on an execution-tree node double-click: given
/// an <c>ExecutionId</c> it loads that execution's audit rows via
/// <see cref="IAuditLogQueryService"/> and shows a list → per-row detail.
///
@@ -24,6 +24,7 @@ public class ExecutionDetailModalTests : BunitContext
private readonly IAuditLogQueryService _service;
private readonly List<(AuditLogQueryFilter Filter, AuditLogPaging? Paging)> _calls = new();
/// <summary>Initializes a new instance of the <c>ExecutionDetailModalTests</c> class.</summary>
public ExecutionDetailModalTests()
{
_service = Substitute.For<IAuditLogQueryService>();
@@ -66,6 +67,7 @@ public class ExecutionDetailModalTests : BunitContext
});
}
/// <summary>Verifies that closed modal renders nothing and does not query.</summary>
[Fact]
public void ClosedModal_RendersNothing_AndDoesNotQuery()
{
@@ -79,6 +81,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.Empty(_calls);
}
/// <summary>Verifies that open transition queries by execution id with page size 100.</summary>
[Fact]
public void OpenTransition_QueriesByExecutionId_WithPageSize100()
{
@@ -101,6 +104,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.Equal(100, _calls[0].Paging!.PageSize);
}
/// <summary>Verifies that still open non open parameter change does not requery.</summary>
[Fact]
public void StillOpen_NonOpenParameterChange_DoesNotRequery()
{
@@ -119,6 +123,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.Single(_calls);
}
/// <summary>Verifies that multi row renders list view with one button per row.</summary>
[Fact]
public void MultiRow_RendersListView_WithOneButtonPerRow()
{
@@ -138,6 +143,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.Empty(cut.FindAll("[data-test=\"drawer-fields\"]"));
}
/// <summary>Verifies that multi row click row shows audit event detail.</summary>
[Fact]
public void MultiRow_ClickRow_ShowsAuditEventDetail()
{
@@ -158,6 +164,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.NotNull(cut.Find("[data-test=\"execution-detail-back\"]"));
}
/// <summary>Verifies that multi row back control returns to list.</summary>
[Fact]
public void MultiRow_BackControl_ReturnsToList()
{
@@ -180,6 +187,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.Empty(cut.FindAll("[data-test=\"drawer-fields\"]"));
}
/// <summary>Verifies that single row opens straight to detail no back control.</summary>
[Fact]
public void SingleRow_OpensStraightToDetail_NoBackControl()
{
@@ -197,6 +205,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.Empty(cut.FindAll("[data-test=\"execution-detail-back\"]"));
}
/// <summary>Verifies that zero row shows friendly empty state.</summary>
[Fact]
public void ZeroRow_ShowsFriendlyEmptyState()
{
@@ -211,6 +220,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.Contains("This execution emitted no audit rows.", empty.TextContent);
}
/// <summary>Verifies that query throws shows inline error state does not rethrow.</summary>
[Fact]
public void QueryThrows_ShowsInlineErrorState_DoesNotRethrow()
{
@@ -228,6 +238,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.Contains("db is down", error.TextContent);
}
/// <summary>Verifies that close button raises on close.</summary>
[Fact]
public void CloseButton_RaisesOnClose()
{
@@ -245,6 +256,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.True(closed);
}
/// <summary>Verifies that backdrop click raises on close.</summary>
[Fact]
public void BackdropClick_RaisesOnClose()
{
@@ -262,6 +274,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.True(closed);
}
/// <summary>Verifies that escape key raises on close.</summary>
[Fact]
public void EscapeKey_RaisesOnClose()
{
@@ -279,6 +292,7 @@ public class ExecutionDetailModalTests : BunitContext
Assert.True(closed);
}
/// <summary>Verifies that header shows short execution id and row count.</summary>
[Fact]
public void Header_ShowsShortExecutionId_AndRowCount()
{
@@ -6,7 +6,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Components.Audit;
/// <summary>
/// bUnit tests for <see cref="ExecutionTree"/> (Audit Log ParentExecutionId
/// feature, Task 10). The component takes the FLAT
/// feature). The component takes the FLAT
/// <see cref="ExecutionTreeNode"/> list the repository returns, assembles it
/// into a tree by joining <see cref="ExecutionTreeNode.ParentExecutionId"/> to a
/// parent node's <see cref="ExecutionTreeNode.ExecutionId"/>, and renders it
@@ -35,6 +35,7 @@ public class ExecutionTreeTests : BunitContext
rowCount == 0 ? null : new DateTime(2026, 5, 20, 12, 0, 0, DateTimeKind.Utc),
rowCount == 0 ? null : new DateTime(2026, 5, 20, 12, 0, 5, DateTimeKind.Utc));
/// <summary>Verifies that a single node renders as one tree node.</summary>
[Fact]
public void SingleNode_RendersOneTreeNode()
{
@@ -48,6 +49,7 @@ public class ExecutionTreeTests : BunitContext
Assert.Contains($"data-test=\"tree-node-{id}\"", cut.Markup);
}
/// <summary>Verifies that a multi-level tree is assembled from the flat node list.</summary>
[Fact]
public void MultiLevel_AssemblesTree_FromFlatList()
{
@@ -82,6 +84,7 @@ public class ExecutionTreeTests : BunitContext
Assert.True(childIdx < grandIdx, "child must render before grandchild");
}
/// <summary>Verifies that a stub node renders with a stub marker.</summary>
[Fact]
public void StubNode_RendersStubMarker()
{
@@ -104,6 +107,7 @@ public class ExecutionTreeTests : BunitContext
Assert.Contains("no audited actions", cut.Markup);
}
/// <summary>Verifies that the node the user arrived from is visually highlighted.</summary>
[Fact]
public void ArrivedFromNode_IsVisuallyHighlighted()
{
@@ -128,6 +132,7 @@ public class ExecutionTreeTests : BunitContext
Assert.DoesNotContain("execution-tree-node--current", other.GetAttribute("class") ?? string.Empty);
}
/// <summary>Verifies that each node link points to the audit log filtered by that node's execution.</summary>
[Fact]
public void NodeLink_PointsTo_AuditLogFilteredByThatExecution()
{
@@ -154,6 +159,7 @@ public class ExecutionTreeTests : BunitContext
Assert.Equal($"/audit/log?executionId={root}", rootLink.GetAttribute("href"));
}
/// <summary>Verifies that an empty node list renders nothing and does not throw.</summary>
[Fact]
public void EmptyNodeList_RendersNothingWithoutThrowing()
{
@@ -164,6 +170,7 @@ public class ExecutionTreeTests : BunitContext
Assert.DoesNotContain("data-test=\"tree-node-", cut.Markup);
}
/// <summary>Verifies that a cyclic flat list is handled without looping forever.</summary>
[Fact]
public void CyclicFlatList_TerminatesWithoutInfiniteLoop()
{
@@ -186,6 +193,7 @@ public class ExecutionTreeTests : BunitContext
Assert.Equal(1, CountOccurrences(cut.Markup, $"data-test=\"tree-node-{b}\""));
}
/// <summary>Verifies that toggling a node collapses its child subtree and toggling again re-expands it.</summary>
[Fact]
public void ToggleExpand_CollapsesAndReExpandsChildSubtree()
{
@@ -229,6 +237,7 @@ public class ExecutionTreeTests : BunitContext
cut.Find($"[data-test=\"tree-toggle-{root}\"]").GetAttribute("aria-expanded"));
}
/// <summary>Verifies that double-clicking a node raises <c>OnNodeActivated</c> with that node's execution id.</summary>
[Fact]
public void DoubleClickingNode_RaisesOnNodeActivated_WithExecutionId()
{
@@ -255,6 +264,7 @@ public class ExecutionTreeTests : BunitContext
Assert.Equal(root, activated);
}
/// <summary>Verifies that double-clicking a nested node bubbles the activation up to the root callback.</summary>
[Fact]
public void DoubleClickingNestedNode_BubblesOnNodeActivated_ToRoot()
{