|
| 1 | +# Project Context |
| 2 | + |
| 3 | +- **Owner:** Frank (fboucher) |
| 4 | +- **Project:** NoteBookmark — bookmark and note-taking app; web + MAUI mobile |
| 5 | +- **Stack:** .NET 9, C#, xUnit, bUnit (Blazor testing), ASP.NET Core API tests |
| 6 | +- **Branch:** v-next |
| 7 | +- **Created:** 2026-04-03 |
| 8 | + |
| 9 | +## Key Test Projects |
| 10 | + |
| 11 | +- `NoteBookmark.Api.Tests` — API integration/unit tests |
| 12 | +- `NoteBookmark.AIServices.Tests` — AI service tests |
| 13 | +- Blazor component tests — bUnit (to be added) |
| 14 | + |
| 15 | +## Testing Priorities |
| 16 | + |
| 17 | +- #119 SharedUI extraction — regression tests to verify BlazorApp behavior unchanged |
| 18 | +- #120 MAUI scaffold — auth smoke tests |
| 19 | +- #122 SQLite storage — unit tests for ILocalDataService |
| 20 | +- #126 Sync engine — critical: test conflict resolution (last-write-wins) |
| 21 | + |
| 22 | +## Learnings |
| 23 | + |
| 24 | +### From Leia's #119 Completion |
| 25 | + |
| 26 | +**SharedUI extraction complete** — 11 components now in NoteBookmark.SharedUI RCL (PR #129 draft, branch squad/119-extract-sharedui) |
| 27 | + |
| 28 | +**Testing focus for #119 regression verification:** |
| 29 | +- NoteDialogTests, SuggestionListTests, MinimalLayoutTests all updated to reference SharedUI namespaces |
| 30 | +- BlazorApp.Tests now has ProjectReference to NoteBookmark.SharedUI |
| 31 | +- All component tests passing post-extraction |
| 32 | + |
| 33 | +**What stayed in BlazorApp (not in SharedUI):** |
| 34 | +- `App.razor`, `Routes.razor` — host/routing |
| 35 | +- `MainLayout.razor` — references auth-specific LoginDisplay |
| 36 | +- `LoginDisplay.razor` — depends on OpenIdConnect |
| 37 | +- `Home.razor`, `Login.razor`, `Logout.razor`, `Error.razor` — web-specific |
| 38 | + |
| 39 | +**For future testing (#120+):** |
| 40 | +- Blazor component tests in SharedUI should be isolated from BlazorApp |
| 41 | +- MAUI will need auth-specific wiring (not depend on OpenIdConnect pieces) |
| 42 | +### Issue #119 — bUnit Regression Tests (2026-04-03) |
| 43 | + |
| 44 | +**Test project:** `NoteBookmark.BlazorApp.Tests` (Microsoft.NET.Sdk.Razor, net10.0) |
| 45 | +**bUnit version:** 2.7.2 (major API change from 1.x — uses `BunitContext`, `Render<T>`, not `TestContext`/`RenderComponent<T>`) |
| 46 | +**Results:** 20 passed, 5 skipped, 0 failed |
| 47 | + |
| 48 | +**Key learnings:** |
| 49 | + |
| 50 | +1. **bUnit 2.x requires `BunitContext` not `TestContext`.** Also `Render<T>()` replaces `RenderComponent<T>()`. Found via build errors after upgrading from expected 1.x API. |
| 51 | + |
| 52 | +2. **bUnit 2.x auth requires `AddAuthorization()` (bUnit extension), not `AddAuthorizationCore()`.** The bUnit runtime registers a `PlaceholderAuthorizationService` that throws `MissingBunitAuthorizationException` unless you call the bUnit-specific extension. `AddAuthorization()` returns `BunitAuthorizationContext` on which you call `SetAuthorized("user")`. |
| 53 | + |
| 54 | +3. **FluentUI components need `JSInterop.Mode = Loose` + `AddFluentUIComponents()`.** Without Loose mode, FluentUI's internal JS calls fail silently-loudly. Simple helper `AddFluentUI()` centralizes this setup. |
| 55 | + |
| 56 | +4. **NoteDialog is the hardest component to unit-test.** It accesses `Dialog.Instance.Parameters.Title` during initial render (in markup, not just event handlers). bUnit 2.x rejects null cascade values. Full fix requires refactoring NoteDialog to use `EventCallback<NoteDialogResult>` instead of `Dialog.CloseAsync()`. |
| 57 | + |
| 58 | +5. **PostNoteClient moved to NoteBookmark.SharedUI** as part of Leia's extraction. Previously in BlazorApp. |
| 59 | + |
| 60 | +6. **Components stayed in BlazorApp** (not extracted): `NavMenu`, `MainLayout`, `LoginDisplay`. Only `MinimalLayout`, `SuggestionList`, `NoteDialog` went to SharedUI. |
| 61 | + |
| 62 | +7. **Referencing a `Microsoft.NET.Sdk.Web` project from `Microsoft.NET.Sdk.Razor`** works but requires `<FrameworkReference Include="Microsoft.AspNetCore.App" />` in the test project. Using plain `Microsoft.NET.Sdk` does NOT pick up Razor-compiled component types. |
| 63 | + |
| 64 | +--- |
| 65 | + |
| 66 | +## Run Complete — 2026-04-03T15:30 |
| 67 | + |
| 68 | +**Status:** ✅ COMPLETED |
| 69 | +**Branch:** squad/119-extract-sharedui |
| 70 | +**PR:** #129 (draft) |
| 71 | + |
| 72 | +Biggs' regression testing confirmed zero behavioral changes from Leia's component extraction. Test suite created in `NoteBookmark.BlazorApp.Tests` with 20 passing tests and 5 skipped (NoteDialog, awaiting component refactor). Build green. |
| 73 | + |
| 74 | +**Cross-agent note:** Identified component-level refactoring needed in NoteDialog: replace `Dialog.CloseAsync()` with `EventCallback<NoteDialogResult>` to eliminate cascade dependency and enable full test coverage. Recommending this for future dev cycle. |
| 75 | + |
| 76 | +Ready for Wedge to scaffold MAUI app (#120). |
| 77 | + |
| 78 | +--- |
| 79 | + |
| 80 | +## Issue #121 — Proactive Delta API Integration Tests (2026-04-03) |
| 81 | + |
| 82 | +**Branch:** `squad/121-date-modified-delta-api` (created from v-next, Han picks this up) |
| 83 | +**File:** `src/NoteBookmark.Api.Tests/Integration/DeltaApiTests.cs` |
| 84 | +**Status:** ✅ COMMITTED — tests compile, intentionally RED until Han ships |
| 85 | + |
| 86 | +### What was written |
| 87 | +8 integration tests covering `modifiedAfter` query param for both list endpoints: |
| 88 | + |
| 89 | +**Posts (GET /api/posts/?modifiedAfter=):** |
| 90 | +1. `GetPosts_WithModifiedAfter_ReturnsOnlyRecentPosts` |
| 91 | +2. `GetPosts_WithModifiedAfter_FutureTimestamp_ReturnsEmpty` |
| 92 | +3. `GetPosts_WithoutModifiedAfter_ReturnsAllPosts` (non-breaking baseline) |
| 93 | +4. `GetPosts_WithModifiedAfter_MultipleResults` |
| 94 | + |
| 95 | +**Notes (GET /api/notes/?modifiedAfter=):** |
| 96 | +Same 4 patterns mirrored for notes. |
| 97 | + |
| 98 | +### Patterns used |
| 99 | + |
| 100 | +**Timing-based seeding:** Since `DateModified` doesn't exist on `Post` / `Note` domain models yet, tests use `Task.Delay(150ms)` + `DateTime.UtcNow` threshold to separate "old" from "new" entities created via HTTP POST. Han's implementation will set `DateModified` server-side on create, making the filter effective. |
| 101 | + |
| 102 | +**RowKey-presence assertions:** Rather than asserting total list counts (fragile under shared Azurite state), tests assert that specific entities (by RowKey) are present or absent. This survives data leakage between test methods sharing the same `IClassFixture<NoteBookmarkApiTestFactory>` instance. |
| 103 | + |
| 104 | +**Non-breaking baseline test:** `GetPosts_WithoutModifiedAfter_ReturnsAllPosts` documents that omitting the new param must not change existing behaviour — a regression guard for Han. |
| 105 | + |
| 106 | +### Discoveries |
| 107 | +- `PostL` (the response DTO returned by GET /api/posts/) **already has `DateModified`** defined in the domain model — Han only needs to populate it and wire the filter. |
| 108 | +- `Note` does NOT yet have `DateModified` — Han must add it alongside the filter. |
| 109 | +- `NoteEnpoints.cs` has a typo in the filename (missing 'd') — pre-existing, not touched. |
| 110 | +- Build: ✅ 0 errors, 8 pre-existing warnings (unchanged). |
0 commit comments