Skip to content

Commit 75a0e35

Browse files
test: add tests for dialogService and cloudRemoteConfig
Addresses review feedback: #11464 (review)
1 parent 36841d6 commit 75a0e35

2 files changed

Lines changed: 211 additions & 0 deletions

File tree

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest'
2+
3+
const {
4+
mockIsLoggedIn,
5+
mockCanAccessSubscriptionFeatures,
6+
mockRefreshRemoteConfig,
7+
mockRegisterExtension,
8+
mockWatchDebounced
9+
} = vi.hoisted(() => ({
10+
mockIsLoggedIn: { value: false },
11+
mockCanAccessSubscriptionFeatures: { value: true },
12+
mockRefreshRemoteConfig: vi.fn(),
13+
mockRegisterExtension: vi.fn(),
14+
mockWatchDebounced: vi.fn()
15+
}))
16+
17+
vi.mock('@vueuse/core', () => ({
18+
watchDebounced: mockWatchDebounced
19+
}))
20+
21+
vi.mock('@/composables/auth/useCurrentUser', () => ({
22+
useCurrentUser: () => ({
23+
isLoggedIn: mockIsLoggedIn
24+
})
25+
}))
26+
27+
vi.mock('@/composables/billing/useBillingContext', () => ({
28+
useBillingContext: () => ({
29+
canAccessSubscriptionFeatures: mockCanAccessSubscriptionFeatures
30+
})
31+
}))
32+
33+
vi.mock('@/platform/remoteConfig/refreshRemoteConfig', () => ({
34+
refreshRemoteConfig: mockRefreshRemoteConfig
35+
}))
36+
37+
vi.mock('@/services/extensionService', () => ({
38+
useExtensionService: () => ({
39+
registerExtension: mockRegisterExtension
40+
})
41+
}))
42+
43+
describe('cloudRemoteConfig extension', () => {
44+
beforeEach(() => {
45+
vi.clearAllMocks()
46+
vi.resetModules()
47+
mockIsLoggedIn.value = false
48+
mockCanAccessSubscriptionFeatures.value = true
49+
})
50+
51+
it('registers extension with correct name', async () => {
52+
await import('./cloudRemoteConfig')
53+
54+
expect(mockRegisterExtension).toHaveBeenCalledWith(
55+
expect.objectContaining({
56+
name: 'Comfy.Cloud.RemoteConfig'
57+
})
58+
)
59+
})
60+
61+
it('setup watches isLoggedIn and canAccessSubscriptionFeatures', async () => {
62+
await import('./cloudRemoteConfig')
63+
64+
const registeredExtension = mockRegisterExtension.mock.calls[0][0]
65+
await registeredExtension.setup()
66+
67+
expect(mockWatchDebounced).toHaveBeenCalledWith(
68+
[mockIsLoggedIn, mockCanAccessSubscriptionFeatures],
69+
expect.any(Function),
70+
expect.objectContaining({ debounce: 256, immediate: true })
71+
)
72+
})
73+
74+
it('watch callback refreshes config when logged in', async () => {
75+
await import('./cloudRemoteConfig')
76+
77+
const registeredExtension = mockRegisterExtension.mock.calls[0][0]
78+
await registeredExtension.setup()
79+
80+
// Get the callback passed to watchDebounced
81+
const watchCallback = mockWatchDebounced.mock.calls[0][1]
82+
83+
// Simulate logged in state
84+
mockIsLoggedIn.value = true
85+
watchCallback()
86+
87+
expect(mockRefreshRemoteConfig).toHaveBeenCalled()
88+
})
89+
90+
it('watch callback does not refresh when not logged in', async () => {
91+
await import('./cloudRemoteConfig')
92+
93+
const registeredExtension = mockRegisterExtension.mock.calls[0][0]
94+
await registeredExtension.setup()
95+
96+
const watchCallback = mockWatchDebounced.mock.calls[0][1]
97+
98+
mockIsLoggedIn.value = false
99+
watchCallback()
100+
101+
expect(mockRefreshRemoteConfig).not.toHaveBeenCalled()
102+
})
103+
})

src/services/dialogService.test.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { createPinia, setActivePinia } from 'pinia'
2+
import { beforeEach, describe, expect, it, vi } from 'vitest'
3+
4+
const {
5+
mockCanAccessSubscriptionFeatures,
6+
mockIsFreeTier,
7+
mockBillingType,
8+
mockShowDialog
9+
} = vi.hoisted(() => ({
10+
mockCanAccessSubscriptionFeatures: { value: true },
11+
mockIsFreeTier: { value: false },
12+
mockBillingType: { value: 'legacy' as 'legacy' | 'workspace' },
13+
mockShowDialog: vi.fn()
14+
}))
15+
16+
vi.mock('@/composables/billing/useBillingContext', () => ({
17+
useBillingContext: () => ({
18+
canAccessSubscriptionFeatures: mockCanAccessSubscriptionFeatures,
19+
isFreeTier: mockIsFreeTier,
20+
type: mockBillingType
21+
})
22+
}))
23+
24+
vi.mock('@/stores/dialogStore', () => ({
25+
useDialogStore: () => ({
26+
showDialog: mockShowDialog,
27+
closeDialog: vi.fn()
28+
})
29+
}))
30+
31+
vi.mock('@/platform/telemetry', () => ({
32+
useTelemetry: () => ({
33+
trackEvent: vi.fn()
34+
})
35+
}))
36+
37+
vi.mock('@/i18n', () => ({
38+
t: (key: string) => key
39+
}))
40+
41+
vi.mock('@/platform/distribution/types', () => ({
42+
isCloud: true
43+
}))
44+
45+
describe('dialogService', () => {
46+
beforeEach(() => {
47+
setActivePinia(createPinia())
48+
vi.clearAllMocks()
49+
mockCanAccessSubscriptionFeatures.value = true
50+
mockIsFreeTier.value = false
51+
mockBillingType.value = 'legacy'
52+
})
53+
54+
describe('showTopUpCreditsDialog', () => {
55+
it('shows top up dialog for legacy billing when canAccessSubscriptionFeatures is true', async () => {
56+
mockCanAccessSubscriptionFeatures.value = true
57+
mockIsFreeTier.value = false
58+
mockBillingType.value = 'legacy'
59+
60+
const { useDialogService } = await import('./dialogService')
61+
const dialogService = useDialogService()
62+
63+
await dialogService.showTopUpCreditsDialog()
64+
65+
expect(mockShowDialog).toHaveBeenCalledWith(
66+
expect.objectContaining({
67+
key: 'top-up-credits'
68+
})
69+
)
70+
})
71+
72+
it('shows workspace top up dialog when type is workspace', async () => {
73+
mockCanAccessSubscriptionFeatures.value = true
74+
mockIsFreeTier.value = false
75+
mockBillingType.value = 'workspace'
76+
77+
const { useDialogService } = await import('./dialogService')
78+
const dialogService = useDialogService()
79+
80+
await dialogService.showTopUpCreditsDialog()
81+
82+
expect(mockShowDialog).toHaveBeenCalledWith(
83+
expect.objectContaining({
84+
key: 'top-up-credits'
85+
})
86+
)
87+
})
88+
89+
it('passes options to dialog when canAccessSubscriptionFeatures', async () => {
90+
mockCanAccessSubscriptionFeatures.value = true
91+
mockIsFreeTier.value = false
92+
93+
const { useDialogService } = await import('./dialogService')
94+
const dialogService = useDialogService()
95+
96+
await dialogService.showTopUpCreditsDialog({
97+
isInsufficientCredits: true
98+
})
99+
100+
expect(mockShowDialog).toHaveBeenCalledWith(
101+
expect.objectContaining({
102+
key: 'top-up-credits',
103+
props: { isInsufficientCredits: true }
104+
})
105+
)
106+
})
107+
})
108+
})

0 commit comments

Comments
 (0)