From 2db667bde42a693a0cd111dc7f41d606ad04cdb7 Mon Sep 17 00:00:00 2001 From: Benjamin Lu Date: Wed, 28 Jan 2026 03:24:13 -0800 Subject: [PATCH] fix: stabilize useSubscription tests --- .../composables/useSubscription.test.ts | 103 ++++++++++++------ 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/src/platform/cloud/subscription/composables/useSubscription.test.ts b/src/platform/cloud/subscription/composables/useSubscription.test.ts index 31a8dd79b..db6533d11 100644 --- a/src/platform/cloud/subscription/composables/useSubscription.test.ts +++ b/src/platform/cloud/subscription/composables/useSubscription.test.ts @@ -1,23 +1,46 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { ref } from 'vue' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { effectScope } from 'vue' import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription' -// Create mocks -const mockIsLoggedIn = ref(false) -const mockReportError = vi.fn() -const mockAccessBillingPortal = vi.fn() -const mockShowSubscriptionRequiredDialog = vi.fn() -const mockGetAuthHeader = vi.fn(() => - Promise.resolve({ Authorization: 'Bearer test-token' }) -) -const mockPushDataLayerEvent = vi.fn() -const mockTelemetry = { - trackSubscription: vi.fn(), - trackMonthlySubscriptionCancelled: vi.fn() +const { + mockIsLoggedIn, + mockReportError, + mockAccessBillingPortal, + mockShowSubscriptionRequiredDialog, + mockGetAuthHeader, + mockPushDataLayerEvent, + mockTelemetry +} = vi.hoisted(() => ({ + mockIsLoggedIn: { value: false }, + mockReportError: vi.fn(), + mockAccessBillingPortal: vi.fn(), + mockShowSubscriptionRequiredDialog: vi.fn(), + mockGetAuthHeader: vi.fn(() => + Promise.resolve({ Authorization: 'Bearer test-token' }) + ), + mockPushDataLayerEvent: vi.fn(), + mockTelemetry: { + trackSubscription: vi.fn(), + trackMonthlySubscriptionCancelled: vi.fn() + } +})) + +let scope: ReturnType | undefined + +function useSubscriptionWithScope() { + if (!scope) { + throw new Error('Test scope not initialized') + } + + const subscription = scope.run(() => useSubscription()) + if (!subscription) { + throw new Error('Failed to initialize subscription composable') + } + + return subscription } -// Mock dependencies vi.mock('@/composables/auth/useCurrentUser', () => ({ useCurrentUser: vi.fn(() => ({ isLoggedIn: mockIsLoggedIn @@ -75,12 +98,24 @@ vi.mock('@/stores/firebaseAuthStore', () => ({ global.fetch = vi.fn() describe('useSubscription', () => { + afterEach(() => { + scope?.stop() + scope = undefined + }) + beforeEach(() => { + scope?.stop() + scope = effectScope() + vi.clearAllMocks() mockIsLoggedIn.value = false mockTelemetry.trackSubscription.mockReset() mockTelemetry.trackMonthlySubscriptionCancelled.mockReset() mockPushDataLayerEvent.mockReset() + mockPushDataLayerEvent.mockImplementation((event) => { + const dataLayer = window.dataLayer ?? (window.dataLayer = []) + dataLayer.push(event) + }) window.__CONFIG__ = { subscription_required: true } as typeof window.__CONFIG__ @@ -106,7 +141,7 @@ describe('useSubscription', () => { } as Response) mockIsLoggedIn.value = true - const { isActiveSubscription, fetchStatus } = useSubscription() + const { isActiveSubscription, fetchStatus } = useSubscriptionWithScope() await fetchStatus() expect(isActiveSubscription.value).toBe(true) @@ -123,7 +158,7 @@ describe('useSubscription', () => { } as Response) mockIsLoggedIn.value = true - const { isActiveSubscription, fetchStatus } = useSubscription() + const { isActiveSubscription, fetchStatus } = useSubscriptionWithScope() await fetchStatus() expect(isActiveSubscription.value).toBe(false) @@ -140,7 +175,7 @@ describe('useSubscription', () => { } as Response) mockIsLoggedIn.value = true - const { formattedRenewalDate, fetchStatus } = useSubscription() + const { formattedRenewalDate, fetchStatus } = useSubscriptionWithScope() await fetchStatus() // The date format may vary based on timezone, so we just check it's a valid date string @@ -150,7 +185,7 @@ describe('useSubscription', () => { }) it('should return empty string when renewal date is not available', () => { - const { formattedRenewalDate } = useSubscription() + const { formattedRenewalDate } = useSubscriptionWithScope() expect(formattedRenewalDate.value).toBe('') }) @@ -167,14 +202,14 @@ describe('useSubscription', () => { } as Response) mockIsLoggedIn.value = true - const { subscriptionTier, fetchStatus } = useSubscription() + const { subscriptionTier, fetchStatus } = useSubscriptionWithScope() await fetchStatus() expect(subscriptionTier.value).toBe('CREATOR') }) it('should return null when subscription tier is not available', () => { - const { subscriptionTier } = useSubscription() + const { subscriptionTier } = useSubscriptionWithScope() expect(subscriptionTier.value).toBeNull() }) @@ -194,7 +229,7 @@ describe('useSubscription', () => { } as Response) mockIsLoggedIn.value = true - const { fetchStatus } = useSubscription() + const { fetchStatus } = useSubscriptionWithScope() await fetchStatus() @@ -231,7 +266,7 @@ describe('useSubscription', () => { } as Response) mockIsLoggedIn.value = true - const { fetchStatus } = useSubscription() + const { fetchStatus } = useSubscriptionWithScope() await fetchStatus() @@ -258,7 +293,7 @@ describe('useSubscription', () => { json: async () => ({ message: 'Subscription not found' }) } as Response) - const { fetchStatus } = useSubscription() + const { fetchStatus } = useSubscriptionWithScope() await expect(fetchStatus()).rejects.toThrow() }) @@ -278,7 +313,7 @@ describe('useSubscription', () => { .spyOn(window, 'open') .mockImplementation(() => null) - const { subscribe } = useSubscription() + const { subscribe } = useSubscriptionWithScope() await subscribe() @@ -304,7 +339,7 @@ describe('useSubscription', () => { json: async () => ({}) } as Response) - const { subscribe } = useSubscription() + const { subscribe } = useSubscriptionWithScope() await expect(subscribe()).rejects.toThrow() }) @@ -321,7 +356,7 @@ describe('useSubscription', () => { }) } as Response) - const { requireActiveSubscription } = useSubscription() + const { requireActiveSubscription } = useSubscriptionWithScope() await requireActiveSubscription() @@ -338,7 +373,7 @@ describe('useSubscription', () => { }) } as Response) - const { requireActiveSubscription } = useSubscription() + const { requireActiveSubscription } = useSubscriptionWithScope() await requireActiveSubscription() @@ -352,7 +387,7 @@ describe('useSubscription', () => { .spyOn(window, 'open') .mockImplementation(() => null) - const { handleViewUsageHistory } = useSubscription() + const { handleViewUsageHistory } = useSubscriptionWithScope() handleViewUsageHistory() expect(windowOpenSpy).toHaveBeenCalledWith( @@ -368,7 +403,7 @@ describe('useSubscription', () => { .spyOn(window, 'open') .mockImplementation(() => null) - const { handleLearnMore } = useSubscription() + const { handleLearnMore } = useSubscriptionWithScope() handleLearnMore() expect(windowOpenSpy).toHaveBeenCalledWith( @@ -380,7 +415,7 @@ describe('useSubscription', () => { }) it('should call accessBillingPortal for invoice history', async () => { - const { handleInvoiceHistory } = useSubscription() + const { handleInvoiceHistory } = useSubscriptionWithScope() await handleInvoiceHistory() @@ -388,7 +423,7 @@ describe('useSubscription', () => { }) it('should call accessBillingPortal for manage subscription', async () => { - const { manageSubscription } = useSubscription() + const { manageSubscription } = useSubscriptionWithScope() await manageSubscription() @@ -424,7 +459,7 @@ describe('useSubscription', () => { .mockResolvedValueOnce(cancelledResponse as Response) try { - const { fetchStatus, manageSubscription } = useSubscription() + const { fetchStatus, manageSubscription } = useSubscriptionWithScope() await fetchStatus() await manageSubscription() @@ -468,7 +503,7 @@ describe('useSubscription', () => { .mockResolvedValueOnce(cancelledResponse as Response) try { - const { fetchStatus, manageSubscription } = useSubscription() + const { fetchStatus, manageSubscription } = useSubscriptionWithScope() await fetchStatus() await manageSubscription()