Skip to content

Commit fa8efc5

Browse files
authored
fix(069-B2): green dashboard-usage-switcher unit tests (MCP-900) (#576)
The 069-B1 switcher tests broke when 069-B2 (#571) swapped the inline usage panel for the real async Usage.vue. Two mount-side problems: - The usage panel wrapper carried v-if="usageEverActive", so it was absent from the DOM on first paint and the exists() assertion failed. Move the lazy gate onto the inner <Suspense> instead: the wrapper div is now always present (hidden via v-show), while the chart bundle + usage fetch inside UsageView still mount only on first switch (SC-004), and the Overview subtree is preserved across switches (SC-006). - shallowMount stubbed both <Suspense> and the async UsageView, so the real Usage.vue never rendered (no fetch, no window buttons). Un-stub Suspense and swap the async wrapper for an eagerly-imported Usage.vue so the fetch-on-activation and window-re-fetch logic actually runs; a dynamic import() never settles inside flushPromises + Suspense. Usage's chart grandchildren stay shallow-stubbed (no jsdom canvas). Related #571
1 parent cf85600 commit fa8efc5

2 files changed

Lines changed: 25 additions & 6 deletions

File tree

frontend/src/views/Dashboard.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
>Usage</a>
2222
</div>
2323

24-
<!-- Usage view: lazy-mounted on first switch so the chart bundle and the
25-
usage fetch don't block Dashboard first paint (SC-004). Kept alive with
26-
v-show after mount so re-switching is instant. -->
27-
<div v-if="usageEverActive" v-show="activeView === 'usage'" data-test="dashboard-usage-panel">
28-
<Suspense>
24+
<!-- Usage view: the panel wrapper is always in the DOM (kept hidden with
25+
v-show so switching back is instant and the Overview subtree is never
26+
torn down, SC-006). The heavy chart bundle + the usage fetch inside
27+
UsageView are lazy-mounted only on first switch (v-if="usageEverActive")
28+
so they never block Dashboard first paint (SC-004). -->
29+
<div v-show="activeView === 'usage'" data-test="dashboard-usage-panel">
30+
<Suspense v-if="usageEverActive">
2931
<UsageView />
3032
<template #fallback>
3133
<div class="flex justify-center py-16"><span class="loading loading-spinner loading-lg"></span></div>

frontend/tests/unit/dashboard-usage-switcher.spec.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ vi.mock('@/composables/useSecurityScannerStatus', () => ({
5858
}))
5959

6060
import Dashboard from '@/views/Dashboard.vue'
61+
// Dashboard imports Usage.vue lazily via defineAsyncComponent so the chart
62+
// bundle stays out of first paint (SC-004). A dynamic import() never settles
63+
// inside flushPromises (microtask-only) + Suspense, so the lazy panel would be
64+
// stuck on its fallback spinner under test. Import the real Usage.vue eagerly
65+
// here and swap it in as a synchronous stub for the async wrapper — this
66+
// exercises the genuine Usage.vue switcher/fetch logic without the async race.
67+
import UsageView from '@/views/Usage.vue'
6168

6269
// jsdom has no EventSource; the system store opens one on mount.
6370
class FakeEventSource {
@@ -71,7 +78,17 @@ function mountDashboard() {
7178
return shallowMount(Dashboard, {
7279
global: {
7380
plugins: [createPinia()],
74-
stubs: { RouterLink: { template: '<a><slot /></a>' } },
81+
stubs: {
82+
RouterLink: { template: '<a><slot /></a>' },
83+
// Un-stub the <Suspense> wrapper that shallowMount would otherwise
84+
// replace with a stub (which swallows its children), and swap the lazy
85+
// async UsageView for the eagerly-imported real Usage.vue so the
86+
// switcher's fetch-on-activation + window-re-fetch logic actually runs.
87+
// Usage.vue's heavy chart grandchildren (CallHistogram/Bar etc.) stay
88+
// shallow-stubbed and never reach jsdom's missing canvas.
89+
Suspense: false,
90+
UsageView,
91+
},
7592
},
7693
})
7794
}

0 commit comments

Comments
 (0)