Skip to content

feat: implement Sprint 4 Blazor theme system (#81–#86) - #95

Merged
9 commits merged into
devfrom
squad/85-bunit-theme-tests
Apr 23, 2026
Merged

feat: implement Sprint 4 Blazor theme system (#81–#86)#95
9 commits merged into
devfrom
squad/85-bunit-theme-tests

Conversation

@mpaulosky

@mpaulosky mpaulosky commented Apr 22, 2026

Copy link
Copy Markdown
Owner

Summary

Working as Legolas (Frontend Developer)

Implements the complete Sprint 4 theme system across all 6 issues.

Closes #81, Closes #82, Closes #83, Closes #84, Closes #85, Closes #86


Changes

#81 — CSS Restructuring

  • Moved CSS entry point to src/Web/Styles/input.css (Tailwind v4 @import, @source, @theme inline)
  • Extracted OKLCH colour palettes into src/Web/Styles/themes.css (:root.color-blue/red/green/yellow)
  • Updated package.json tw:build and tw:watch to use new input path

#82 — ThemeProvider Component

  • ThemeProvider.razor — three nested CascadingValue wrappers: typed ThemeProvider, named "CurrentColor", named "CurrentBrightness"
  • ThemeProvider.razor.csIJSRuntime, SetColor/SetBrightness using optimistic state update (property + StateHasChanged() before await) for correct bUnit testability

#83 — ThemeSelector Sub-Components

  • ThemeColorDropdownComponent.razor[CascadingParameter(Name="CurrentColor")], select with 4 options, aria-label="Colour theme"
  • ThemeBrightnessToggleComponent.razor[CascadingParameter(Name="CurrentBrightness")], toggle button with moon/sun SVG, interpolated aria-label
  • ThemeSelector.razor[CascadingParameter] ThemeProvider? Provider, wires EventCallbacks to null-safe Provider calls

#84 — App.razor / NavMenu Integration

  • App.razor — wraps <Routes /> with <ThemeProvider @rendermode="InteractiveServer">
  • NavMenu.razor — removed 3 @inject directives, @implements IDisposable, 30+ lines of inline theme code; replaced with <ThemeSelector />
  • _Imports.razor — added @using MyBlog.Web.Components.Theme

#85 — bUnit Tests

  • Fixed 2 pre-existing compile errors in ThemeSelectorTests.cs (positional because arg)
  • Rewrote NavMenuTests 4th test: renders ThemeProvider wrapping NavMenu, uses WaitForAssertion for async JS-based theme load and set calls

#86 — Architecture Tests

  • ThemeLayerTests.cs — 2 tests verifying Theme namespace isolation in the Web assembly

Test Results

  • ✅ 156/156 unit tests pass
  • ✅ 8/8 architecture tests pass
  • ✅ Tailwind CSS compiles successfully with new input path

@github-actions github-actions Bot added the squad Squad triage inbox — Lead will assign to a member label Apr 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ PR Added to Squad Triage Queue

This PR has been labeled with squad and added to the triage queue.

Next steps:

  • The squad Lead will review and assign to an appropriate team member
  • A squad:member label will be added after triage

If you know which squad member should handle this, you can add the appropriate squad:member label yourself.

@github-actions

github-actions Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Test Results Summary

174 tests  +168   172 ✅ +166   3m 9s ⏱️ + 3m 9s
  4 suites +  3     0 💤 ±  0 
  4 files   +  3     2 ❌ +  2 

For more details on these failures, see this check.

Results for commit cf44636. ± Comparison against base commit 0a0263d.

♻️ This comment has been updated with latest results.

@mpaulosky mpaulosky changed the title [Sprint 4] Scaffold bUnit tests for ThemeProvider and ThemeSelector feat: implement Sprint 4 Blazor theme system (#81–#86) Apr 22, 2026
@codecov

codecov Bot commented Apr 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.24390% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.77%. Comparing base (0a0263d) to head (cf44636).
⚠️ Report is 31 commits behind head on dev.

Files with missing lines Patch % Lines
src/Web/Components/Theme/ThemeProvider.razor.cs 91.30% 2 Missing ⚠️
src/Web/Components/Theme/ThemeSelector.razor 71.42% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             dev      #95       +/-   ##
==========================================
+ Coverage   0.00%   68.77%   +68.77%     
==========================================
  Files         49       55        +6     
  Lines        832      852       +20     
  Branches     118      120        +2     
==========================================
+ Hits           0      586      +586     
+ Misses       714      244      -470     
+ Partials     118       22       -96     
Files with missing lines Coverage Δ
src/Web/Components/Layout/NavMenu.razor 100.00% <ø> (+100.00%) ⬆️
...ponents/Theme/ThemeBrightnessToggleComponent.razor 100.00% <100.00%> (ø)
...Components/Theme/ThemeColorDropdownComponent.razor 100.00% <100.00%> (ø)
src/Web/Components/Theme/ThemeProvider.razor 100.00% <100.00%> (ø)
src/Web/Components/Theme/ThemeProvider.razor.cs 91.30% <91.30%> (ø)
src/Web/Components/Theme/ThemeSelector.razor 71.42% <71.42%> (ø)

... and 42 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

mpaulosky and others added 2 commits April 21, 2026 19:11
Add bUnit test scaffolding for Sprint 4 Theme components ahead of
production code (Issues #82 and #83). Tests cover:

ThemeProviderTests (9 tests):
- Renders child content and renders without error
- Calls themeManager.getColor / getBrightness on AfterFirstRender
- Loads color and brightness from JS and exposes as CurrentColor/CurrentBrightness
- SetColor calls themeManager.setColor with new value
- SetBrightness calls themeManager.setBrightness and updates CurrentBrightness
- Error resilience when JS throws (swallows exception, uses defaults)

ThemeSelectorTests (~20 tests, 4 classes):
- ThemeSelectorTests: renders without error, contains both sub-components
- ThemeBrightnessToggleTests: renders, sun/moon icons, click toggles brightness, a11y label
- ThemeColorDropdownTests: renders, 4 color options, current color selected, color change propagates, Theory for all colors, a11y label
- ThemeProviderWithSelectorIntegrationTests: cascaded color/brightness, dropdown change triggers setColor JS, toggle click triggers setBrightness JS

NOTE: Build fails with CS0234 until Legolas merges #82 and #83.
This branch depends on those PRs to compile and run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Issue #81: CSS restructuring — move to src/Web/Styles/input.css + themes.css
  with OKLCH colour palettes and updated package.json scripts
- Issue #82: ThemeProvider component with cascading values (typed + named)
  and JS-backed SetColor/SetBrightness using optimistic state update
- Issue #83: ThemeSelector, ThemeColorDropdownComponent, and
  ThemeBrightnessToggleComponent with EventCallback-based API
- Issue #84: App.razor wraps Routes in ThemeProvider; NavMenu fully
  refactored to use ThemeSelector, removing all inline theme code,
  IDisposable, and three injections; _Imports.razor updated
- Issue #85: Fixed scaffold errors in ThemeSelectorTests.cs; updated
  NavMenuTests 4th test to render ThemeProvider wrapping NavMenu
- Issue #86: ThemeLayerTests.cs architecture tests for theme namespace

Working as Legolas (Frontend Developer)
Closes #81, #82, #83, #84, #85, #86

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mpaulosky
mpaulosky force-pushed the squad/85-bunit-theme-tests branch from d891916 to e7d1842 Compare April 22, 2026 02:11
Boromir and others added 7 commits April 21, 2026 19:19
Tests were previously split into Domain.Tests, Web.Tests, Web.Tests.Bunit,
Web.Tests.Integration, and AppHost.Tests. These directories no longer exist.

Old → New mappings:
  tests/Domain.Tests       → tests/Unit.Tests/Unit.Tests.csproj
  tests/Web.Tests          → tests/Unit.Tests/Unit.Tests.csproj
  tests/Web.Tests.Bunit    → tests/Unit.Tests/Unit.Tests.csproj
  tests/Web.Tests.Integration → tests/Integration.Tests/Integration.Tests.csproj
  tests/AppHost.Tests      → tests/E2E.Tests/E2E.Tests.csproj

Files changed:
  - .github/workflows/squad-test.yml
  - .github/workflows/squad-release.yml
  - .github/workflows/squad-insider-release.yml

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…und_ReturnsFailResult

Mixed concrete 'id' value with Arg.Any<CancellationToken>() in GetByIdAsync
setup. NSubstitute 5.x can throw RedundantArgumentMatcherException when
concrete values are mixed with arg matchers due to the thread-local pending
specification queue becoming misaligned across test ordering.

Fix: wrap all arguments in explicit matchers using Arg.Is<Guid>() so
NSubstitute unambiguously consumes the full specification.

Line 63: Arg.Is<Guid>(g => g == id) replaces bare id literal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The E2E.Tests project uses Aspire.Hosting.Testing with HttpClient for
integration tests — it does not use Microsoft.Playwright. The
'playwright.ps1 install' step referenced a file that was never generated
by the build, causing CI to fail unconditionally.

Removed the 'Install Playwright browsers' step entirely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…gle test-unit job

Both jobs were running the exact same test suite (tests/Unit.Tests/Unit.Tests.csproj)
after the consolidation of Domain.Tests and Web.Tests. This caused duplicate test
reporting and was confusing. Consolidate into a single 'test-unit' job and update
job dependencies in coverage and report jobs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The test-bunit job was running the same test suite as test-unit
(tests/Unit.Tests/Unit.Tests.csproj), creating duplicate test reports and
unnecessary CI time. Remove the separate test-bunit job and consolidate
all unit tests into the test-unit job.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The ThemeProvider should render in static SSR context to avoid JS interop
issues, while Routes with interactive components are marked with
@rendermode="InteractiveServer". This allows the theme to initialize
properly in SSR context before interactive rendering begins.

Resolves AppHost.Tests 500 error in E2E tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The E2E tests timeout in CI after 100 seconds when starting the Aspire
host with MongoDB. Increase timeout to 300 seconds to allow sufficient
time for the application to start, especially in resource-constrained CI
environments.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Branch Rate Complexity Health
ServiceDefaults 0% 0% 18
Web 0% 0% 352
Domain 0% 0% 77
ServiceDefaults 0% 0% 18
Web 0% 0% 352
Domain 0% 0% 77
ServiceDefaults 0% 0% 18
Web 65% 67% 352
Domain 87% 92% 77
ServiceDefaults 0% 0% 18
Web 65% 67% 352
Domain 87% 92% 77
Summary 32% (1082 / 3368) 32% (394 / 1216) 1788

@mpaulosky mpaulosky closed this pull request by merging all changes into dev in b157f75 Apr 23, 2026
@mpaulosky
mpaulosky deleted the squad/85-bunit-theme-tests branch April 23, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

squad Squad triage inbox — Lead will assign to a member

Projects

None yet

1 participant