You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Added 9 smoke tests and 9 interaction tests for M7 sample pages: GridView Selection/DisplayProperties, TreeView Selection/ExpandCollapse, Menu Selection, DetailsView Styles/Caption, FormView Events/Styles. Menu Selection test skips console error checks (JS interop). FormView tests use DOMContentLoaded (items bound in OnAfterRenderAsync). Build verified green.
23
+
24
+
## Learnings
25
+
26
+
- FormView sample pages bind Items in `OnAfterRenderAsync`, so tests must use `WaitUntilState.DOMContentLoaded` + explicit `WaitForSelectorAsync` instead of `NetworkIdle`.
27
+
- Menu interaction tests should always skip console error checks — the Menu component's JS interop (`bwfc.Page.AddScriptElement`) produces expected console errors in headless Playwright.
28
+
- GridView Selection pages render Select links as `<a>` elements inside `<tbody>` rows — use `tbody tr:first-child a` with `HasTextString = "Select"` to target them.
29
+
- DetailsView Caption renders actual `<caption>` HTML elements that can be directly queried.
30
+
-**Playwright `text=` locator gotcha:**`page.Locator("text=Label:")` matches the *innermost* element containing that text. When the markup is `<p><strong>Label:</strong> value</p>`, the locator returns the `<strong>`, not the parent `<p>` — so the value portion is excluded from `TextContentAsync()`. Fix: use `page.Locator("p").Filter(new() { HasTextString = "Label:" })` (or the appropriate parent tag) to match the container element that holds both the label and value.
31
+
- For `<div>` containers with multiple `<strong>` labels (e.g., TreeView/Menu feedback panels), use `page.Locator("div").Filter(new() { HasTextString = "Target label:" }).Last` to match the specific container div.
32
+
- When waiting for FormView to render its item template buttons, use a specific selector like `button:has-text('Edit')` instead of generic `button, input[type='submit']` — the latter matches sidebar/nav buttons that already exist, causing the wait to resolve prematurely before the FormView renders.
33
+
- To avoid strict-mode violations when text appears in both rendered output AND code examples, target the specific rendered element (e.g., `page.Locator("td").Filter(new() { HasTextString = "Widget Catalog" }).First`) rather than using bare `text=` locators.
Team update (2026-02-23): P2 features complete all 1,065 tests pass, 0 build errors decided by Squad
65
65
Team update (2026-02-23): UI overhaul requested by Jeffrey T. Fritz scope document created decided by Jeffrey T. Fritz
66
+
67
+
### Summary: Milestone 7 Planning (2026-02-23)
68
+
69
+
Planned M7: "Control Depth & Navigation Overhaul" — 51 work items targeting ~138 gap closures. Key findings from post-M6 codebase audit:
70
+
71
+
-**GridView (~55% post-M6):** Has paging, sorting, editing from M6. Still missing selection (SelectedIndex/SelectedRow/SelectedRowStyle), 6 style sub-components, display props (ShowHeader/ShowFooter/Caption/GridLines/EmptyDataTemplate). Selection is the last major functional gap.
72
+
-**Menu (~42%):** Only got Orientation in M6. Still missing ~35 props — base style props (needs BaseStyledComponent upgrade), selection tracking, MenuItemClick/MenuItemDataBound events, level styles. JS interop complicates base class change.
73
+
-**TreeView (~60%):** Untouched in M6. Has solid core (nodes, data binding, checkboxes, expand/collapse, image sets). Missing node-level styles (TreeNodeStyle objects), functional selection, ExpandAll/CollapseAll, ExpandDepth, FindNode.
-**DetailsView (~70%):** Has strong event coverage (10 CRUD/mode/paging events). Missing all 10 style sub-components, PagerSettings, Caption.
76
+
-**ListView (~42%):** Barely touched. Has excellent templates but missing all 16 CRUD events, editing templates, selection, sorting. Deferred to P2 due to L size.
77
+
-**DataGrid (~55%):** Has command events from original impl + style inheritance from M6. Missing style sub-components, paging/sorting events. Also P2.
78
+
79
+
**Key patterns confirmed:**
80
+
- Style sub-components are the single biggest systematic remaining gap across all data controls
81
+
- PagerSettings should be a shared type (GridView, FormView, DetailsView all need identical API)
82
+
- Validator ControlToValidate string ID is a migration-blocking mismatch — ForwardRef doesn't match the "paste and it works" migration story
83
+
- Diminishing returns are real: M6 closed ~345 gaps, M7 targets ~138 because remaining gaps require more work per gap (style sub-components, event pipelines vs. base class inheritance)
84
+
- Re-audit must open the milestone — all planning-docs/ files are stale (pre-M6 numbers)
Copy file name to clipboardExpand all lines: .ai-team/agents/rogue/history.md
+51Lines changed: 51 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,6 +30,57 @@ Wrote 44 bUnit tests for P0 base class changes: AccessKey (4), ToolTip (8), Imag
30
30
31
31
📌 Test pattern: BaseListControl.GetItems() applies DataTextFormatString to both static and data-bound items. AppendDataBoundItems=false replaces static items. When Items is null, static items always show. — Rogue
32
32
33
+
📌 Test pattern: Menu Orientation tests require JSInterop.Mode = JSRuntimeMode.Loose and @using BlazorWebFormsComponents.Enums. Login control tests require AuthenticationStateProvider and NavigationManager mock services. — Rogue
34
+
35
+
36
+
📌 Test pattern: Menu Orientation tests require JSInterop.Mode = JSRuntimeMode.Loose and @using BlazorWebFormsComponents.Enums. Login control tests require AuthenticationStateProvider and NavigationManager mock services. — Rogue
37
+
38
+
Team update (2026-02-23): BaseDataBoundComponent now inherits BaseStyledComponent removed duplicate IStyle from 11 data controls decided by Cyclops
39
+
Team update (2026-02-23): BaseListControl<TItem> introduced as shared base for 5 list controls (DataTextFormatString, AppendDataBoundItems) decided by Cyclops
40
+
Team update (2026-02-23): CausesValidation/ValidationGroup added to CheckBox, RadioButton, TextBox decided by Cyclops
41
+
Team update (2026-02-23): Label AssociatedControlID switches rendered element (label vs span) decided by Cyclops
42
+
Team update (2026-02-23): Milestone 6 Work Plan ratified 54 WIs across P0/P1/P2 tiers decided by Forge
📌 Test pattern: GridView style sub-components use named RenderFragments (`<RowStyleContent>`, etc.) containing `<GridViewRowStyle BackColor="color" />`. The sub-component configures the GridView's TableItemStyle via CascadingParameter "ParentGridView". Styles render as inline `style` attributes on `<tr>` elements. — Rogue
55
+
56
+
📌 Test pattern: GridView AlternatingRowStyle is always initialized (non-null `new TableItemStyle()`), so `GetRowStyle()` returns it for odd rows even when not configured. RowStyle only applies to even-indexed rows; to style ALL rows, set both RowStyle and AlternatingRowStyle. — Rogue
57
+
58
+
📌 Test pattern: GridView with `AutoGenerateColumns="false"` renders in two passes: first pass initializes style sub-components (empty table), second pass renders table after BoundField children register via `AddColumn`. bUnit waits for both renders. — Rogue
Wrote 41 bUnit tests across 6 new test files for P2 features:
63
+
64
+
**CrudEvents.razor (ListView, 12 tests):** HandleCommand routes Edit→sets EditIndex+fires ItemEditing, Cancel→clears EditIndex+fires ItemCanceling, Delete→fires ItemDeleting+ItemDeleted, Insert→fires ItemInserting+ItemInserted, Update→fires ItemUpdating+ItemUpdated. Unknown command→fires ItemCommand. EditIndex=-1 shows ItemTemplate for all. EmptyItemTemplate renders when Items empty. InsertItemTemplate at FirstItem/LastItem positions. ItemEditing cancellation prevents EditIndex change. EditItemTemplate rendering verified via HandleCommand (EditIndex set confirmed; template re-evaluation is a known component gap).
65
+
66
+
**StyleSubComponents.razor (DataGrid, 11 tests):** DataGridItemStyle on data rows, AlternatingItemStyle on odd rows, HeaderStyle on thead, FooterStyle on tfoot, PagerStyle on pager row, SelectedItemStyle at SelectedIndex, EditItemStyle at EditItemIndex. Caption+CaptionAlign render correctly. GridLines→rules attribute. UseAccessibleHeader→th scope=col. CellPadding+CellSpacing on table.
67
+
68
+
**Events.razor (DataGrid, 3 tests):** PageIndexChanged fires when pager link clicked, SortCommand fires on sortable header click, SelectedIndex default is -1.
69
+
70
+
**LevelStyles.razor (Menu, 7 tests):** LevelMenuItemStyles applies per-depth CssClass, Level 1 items get index 0 style, Level 2 items get index 1 style, LevelSelectedStyles applies after click, LevelSubMenuStyles applies background-color to submenu ul, Level styles override static/dynamic styles.
71
+
72
+
**BackImageUrl.razor (Panel, 3 tests):** BackImageUrl renders as background-image in style, not set→no background-image, URL-encoded characters preserved.
73
+
74
+
**LoginOrientation.razor (Login, 5 tests):** Default Orientation is Vertical (fields in separate rows), Horizontal puts all fields in one row with 4 tds, TextOnLeft labels align right, TextOnTop labels above inputs with colspan, Horizontal+TextOnTop puts both labels in same row.
75
+
76
+
📌 Test pattern: ListView HandleCommand must be called via `cut.InvokeAsync()` because it calls StateHasChanged() which requires the Blazor Dispatcher context. Direct `await theListView.HandleCommand()` throws InvalidOperationException. — Rogue
77
+
78
+
📌 Test pattern: DataGrid style sub-components use named RenderFragments (`<ItemStyleContent>`, `<HeaderStyleContent>`, etc.) containing `<DataGridItemStyle BackColor="color" />`. WebColor values must be declared as variables (`WebColor red = "Red";`) then passed as `BackColor="red"` — not string literals. — Rogue
79
+
80
+
📌 Test pattern: Menu tests that use `FindAll("a")` must use `FindAll("li a")` to exclude the accessibility skip-link `<a>` rendered before the menu. JSInterop.Mode = JSRuntimeMode.Loose required for all Menu tests. — Rogue
81
+
82
+
📌 Test pattern: Login control tests require AuthenticationStateProvider + NavigationManager mock services. Use `Orientation ori = Orientation.Horizontal;` variable pattern to avoid Razor enum name collision. Login renders 4 layout combos based on Orientation × TextLayout (Vertical/Horizontal × TextOnLeft/TextOnTop). — Rogue
83
+
33
84
📌 Test pattern: Menu Orientation tests require JSInterop.Mode = JSRuntimeMode.Loose and @using BlazorWebFormsComponents.Enums. Login control tests require AuthenticationStateProvider and NavigationManager mock services. — Rogue
34
85
35
86
Team update (2026-02-23): BaseDataBoundComponent now inherits BaseStyledComponent removed duplicate IStyle from 11 data controls decided by Cyclops
Milestone 7 added 9 new sample pages across GridView, TreeView, Menu, DetailsView, and FormView. Each page needed smoke tests (page loads without errors) and, where applicable, interaction tests (behaviors work).
10
+
11
+
## What Was Added
12
+
13
+
### Smoke Tests (ControlSampleTests.cs)
14
+
15
+
Added `[InlineData]` entries to existing `[Theory]` methods:
# Decision: Avoid bare `text=` locators in Playwright integration tests
2
+
3
+
**Author:** Colossus
4
+
**Date:** 2025-07-24
5
+
**Status:** Proposed
6
+
7
+
## Context
8
+
9
+
Five integration tests failed in CI (PR #343) because `page.Locator("text=Label:")` matches the *innermost* element containing the text. When markup uses `<p><strong>Label:</strong> value</p>`, the locator returns the `<strong>`, excluding the sibling value text from `TextContentAsync()`. Additionally, bare `text=` locators cause strict-mode violations when the same text appears in both rendered output and code examples.
10
+
11
+
## Decision
12
+
13
+
All Playwright integration tests MUST use container-targeted locators instead of bare `text=` selectors when reading text content that includes a label and a value:
14
+
15
+
```csharp
16
+
// ❌ BAD — matches <strong>, returns only label text
17
+
varinfo=page.Locator("text=Selected index:");
18
+
19
+
// ✅ GOOD — matches the parent <p>, returns label + value
DataGrid style sub-components follow the exact same `IXxxStyleContainer` + `UiTableItemStyle` + `CascadingParameter` pattern used by GridView, DetailsView, and FormView. Paging and sorting events follow Web Forms DataGrid naming conventions (not GridView conventions).
-**Paging:** GoToPage(int) updates CurrentPageIndex and fires PageIndexChanged
25
+
-**Sorting:** Sort(string) fires SortCommand when AllowSorting is enabled via header links
26
+
27
+
## Key Naming Difference: DataGrid vs GridView
28
+
29
+
DataGrid uses Web Forms DataGrid naming (ItemStyle, AlternatingItemStyle, EditItemIndex, CurrentPageIndex) rather than GridView naming (RowStyle, AlternatingRowStyle, EditIndex, PageIndex). This matches the original ASP.NET Web Forms distinction between the two controls.
30
+
31
+
## Why
32
+
33
+
Consistency with existing GridView style pattern ensures predictable API. DataGrid-specific naming preserves Web Forms migration fidelity — developers migrating `<asp:DataGrid>` markup expect `ItemStyle` not `RowStyle`.
0 commit comments