@@ -18,14 +18,17 @@ vi.mock('vuetify', async (importOriginal) => {
1818 } ;
1919} ) ;
2020
21- // Mock auth store — report logged in + org so the drawer actually renders
21+ // Mock auth store — report logged in + org so the drawer actually renders.
22+ // authStoreState is a mutable hoisted object so individual tests can override
23+ // serverConfig (e.g. to enable billing.meterMode) without re-mocking.
24+ const authStoreState = vi . hoisted ( ( ) => ( {
25+ isLoggedIn : true ,
26+ user : { currentOrganization : { _id : 'org1' , name : 'Org' } } ,
27+ serverConfig : { organizations : { enabled : false } } ,
28+ signout : vi . fn ( ) ,
29+ } ) ) ;
2230vi . mock ( '../../auth/stores/auth.store' , ( ) => ( {
23- useAuthStore : ( ) => ( {
24- isLoggedIn : true ,
25- user : { currentOrganization : { _id : 'org1' , name : 'Org' } } ,
26- serverConfig : { organizations : { enabled : false } } ,
27- signout : vi . fn ( ) ,
28- } ) ,
31+ useAuthStore : ( ) => authStoreState ,
2932} ) ) ;
3033
3134// Mock core store — we inject our own nav + navBottom arrays per test
@@ -64,10 +67,11 @@ const makeConfig = (overrides = {}) => ({
6467 * @param {Object } opts
6568 * @param {Array } opts.nav - items for the main nav list
6669 * @param {Array } opts.navBottom - items for the bottom nav list
70+ * @param {Object } [opts.stubsOverride] - additional stubs merged after defaults (e.g. to replace the gauge stub)
6771 * @param {Object } [opts.configOverrides] - partial config overrides (e.g. { app: { logoFile: '/logo.svg' } })
6872 * @returns {import('@vue/test-utils').VueWrapper }
6973 */
70- const mountNav = ( { nav = [ ] , navBottom = [ ] , configOverrides = { } } = { } ) => {
74+ const mountNav = ( { nav = [ ] , navBottom = [ ] , stubsOverride = { } , configOverrides = { } } = { } ) => {
7175 coreStoreState . nav = nav ;
7276 coreStoreState . navBottom = navBottom ;
7377 const vuetify = createVuetify ( { components, directives } ) ;
@@ -82,6 +86,9 @@ const mountNav = ({ nav = [], navBottom = [], configOverrides = {} } = {}) => {
8286 'router-link' : { template : '<a><slot /></a>' } ,
8387 // Stub v-navigation-drawer to a plain wrapper — the real one needs a <v-layout> ancestor
8488 'v-navigation-drawer' : { template : '<div class="v-navigation-drawer"><slot /><slot name="append" /></div>' } ,
89+ // Stub the gauge to prevent it from auto-fetching billing data on mount
90+ BillingNavComputeGaugeComponent : { template : '<div class="stub-billing-nav-compute-gauge" />' } ,
91+ ...stubsOverride ,
8592 } ,
8693 } ,
8794 } ) ;
@@ -92,6 +99,7 @@ describe('core.navigation.component — navItemBind', () => {
9299 setActivePinia ( createPinia ( ) ) ;
93100 coreStoreState . nav = [ ] ;
94101 coreStoreState . navBottom = [ ] ;
102+ authStoreState . serverConfig = { organizations : { enabled : false } } ;
95103 } ) ;
96104
97105 it ( 'returns { to } for a regular internal route' , ( ) => {
@@ -143,6 +151,7 @@ describe('core.navigation.component — navItemBind', () => {
143151describe ( 'core.navigation.component — template rendering' , ( ) => {
144152 beforeEach ( ( ) => {
145153 setActivePinia ( createPinia ( ) ) ;
154+ authStoreState . serverConfig = { organizations : { enabled : false } } ;
146155 } ) ;
147156
148157 it ( 'renders a regular nav item as a router-link (no href attribute)' , ( ) => {
@@ -231,6 +240,8 @@ describe('core.navigation.component — compute gauge slot', () => {
231240 setActivePinia ( createPinia ( ) ) ;
232241 coreStoreState . nav = [ ] ;
233242 coreStoreState . navBottom = [ ] ;
243+ // Reset auth state to default (no billing) so tests are independent
244+ authStoreState . serverConfig = { organizations : { enabled : false } } ;
234245 } ) ;
235246
236247 it ( 'meterMode computed returns false when serverConfig has no billing.meterMode' , ( ) => {
@@ -294,11 +305,27 @@ describe('core.navigation.component — compute gauge slot', () => {
294305 expect ( signOutPos ) . toBeGreaterThan ( accountPos ) ;
295306 expect ( signOutPos ) . toBeGreaterThan ( settingsPos ) ;
296307 } ) ;
308+
309+ it ( 'renders stubbed BillingNavComputeGaugeComponent when meterMode is true' , ( ) => {
310+ // Override auth state so meterMode resolves to true for this test only.
311+ // The try/finally below resets it immediately so the override cannot leak
312+ // into subsequent tests/describes even if mountNav() ever throws.
313+ const defaultServerConfig = { organizations : { enabled : false } } ;
314+ authStoreState . serverConfig = { organizations : { enabled : false } , billing : { meterMode : true } } ;
315+ try {
316+ const wrapper = mountNav ( ) ;
317+ expect ( wrapper . vm . meterMode ) . toBe ( true ) ;
318+ expect ( wrapper . find ( '.stub-billing-nav-compute-gauge' ) . exists ( ) ) . toBe ( true ) ;
319+ } finally {
320+ authStoreState . serverConfig = defaultServerConfig ;
321+ }
322+ } ) ;
297323} ) ;
298324
299325describe ( 'core.navigation.component — sidenav logo' , ( ) => {
300326 beforeEach ( ( ) => {
301327 setActivePinia ( createPinia ( ) ) ;
328+ authStoreState . serverConfig = { organizations : { enabled : false } } ;
302329 } ) ;
303330
304331 it ( 'renders a v-img when config.app.logoFile is set' , ( ) => {
0 commit comments