Skip to content

Commit 3865e54

Browse files
authored
1.20.6 (#3986)
1 parent 7ea8c34 commit 3865e54

File tree

6 files changed

+333
-18
lines changed

6 files changed

+333
-18
lines changed
-23 KB
Loading

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@comfyorg/comfyui-frontend",
33
"private": true,
4-
"version": "1.20.5",
4+
"version": "1.20.6",
55
"type": "module",
66
"repository": "https://github.com/Comfy-Org/ComfyUI_frontend",
77
"homepage": "https://comfy.org",
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
import { Form } from '@primevue/forms'
2+
import { VueWrapper, mount } from '@vue/test-utils'
3+
import Button from 'primevue/button'
4+
import PrimeVue from 'primevue/config'
5+
import InputText from 'primevue/inputtext'
6+
import Password from 'primevue/password'
7+
import ProgressSpinner from 'primevue/progressspinner'
8+
import ToastService from 'primevue/toastservice'
9+
import { beforeEach, describe, expect, it, vi } from 'vitest'
10+
import { nextTick } from 'vue'
11+
import { createI18n } from 'vue-i18n'
12+
13+
import enMessages from '@/locales/en/main.json'
14+
15+
import SignInForm from './SignInForm.vue'
16+
17+
type ComponentInstance = InstanceType<typeof SignInForm>
18+
19+
// Mock firebase auth modules
20+
vi.mock('firebase/app', () => ({
21+
initializeApp: vi.fn(),
22+
getApp: vi.fn()
23+
}))
24+
25+
vi.mock('firebase/auth', () => ({
26+
getAuth: vi.fn(),
27+
setPersistence: vi.fn(),
28+
browserLocalPersistence: {},
29+
onAuthStateChanged: vi.fn(),
30+
signInWithEmailAndPassword: vi.fn(),
31+
signOut: vi.fn(),
32+
sendPasswordResetEmail: vi.fn()
33+
}))
34+
35+
// Mock the auth composables and stores
36+
const mockSendPasswordReset = vi.fn()
37+
vi.mock('@/composables/auth/useFirebaseAuthActions', () => ({
38+
useFirebaseAuthActions: vi.fn(() => ({
39+
sendPasswordReset: mockSendPasswordReset
40+
}))
41+
}))
42+
43+
let mockLoading = false
44+
vi.mock('@/stores/firebaseAuthStore', () => ({
45+
useFirebaseAuthStore: vi.fn(() => ({
46+
get loading() {
47+
return mockLoading
48+
}
49+
}))
50+
}))
51+
52+
// Mock toast
53+
const mockToastAdd = vi.fn()
54+
vi.mock('primevue/usetoast', () => ({
55+
useToast: vi.fn(() => ({
56+
add: mockToastAdd
57+
}))
58+
}))
59+
60+
describe('SignInForm', () => {
61+
beforeEach(() => {
62+
vi.clearAllMocks()
63+
mockSendPasswordReset.mockReset()
64+
mockToastAdd.mockReset()
65+
mockLoading = false
66+
})
67+
68+
const mountComponent = (
69+
props = {},
70+
options = {}
71+
): VueWrapper<ComponentInstance> => {
72+
const i18n = createI18n({
73+
legacy: false,
74+
locale: 'en',
75+
messages: { en: enMessages }
76+
})
77+
78+
return mount(SignInForm, {
79+
global: {
80+
plugins: [PrimeVue, i18n, ToastService],
81+
components: {
82+
Form,
83+
Button,
84+
InputText,
85+
Password,
86+
ProgressSpinner
87+
}
88+
},
89+
props,
90+
...options
91+
})
92+
}
93+
94+
describe('Forgot Password Link', () => {
95+
it('shows disabled style when email is empty', async () => {
96+
const wrapper = mountComponent()
97+
await nextTick()
98+
99+
const forgotPasswordSpan = wrapper.find(
100+
'span.text-muted.text-base.font-medium.cursor-pointer'
101+
)
102+
103+
expect(forgotPasswordSpan.classes()).toContain('text-link-disabled')
104+
})
105+
106+
it('shows toast and focuses email input when clicked while disabled', async () => {
107+
const wrapper = mountComponent()
108+
const forgotPasswordSpan = wrapper.find(
109+
'span.text-muted.text-base.font-medium.cursor-pointer'
110+
)
111+
112+
// Mock getElementById to track focus
113+
const mockFocus = vi.fn()
114+
const mockElement = { focus: mockFocus }
115+
vi.spyOn(document, 'getElementById').mockReturnValue(mockElement as any)
116+
117+
// Click forgot password link while email is empty
118+
await forgotPasswordSpan.trigger('click')
119+
await nextTick()
120+
121+
// Should show toast warning
122+
expect(mockToastAdd).toHaveBeenCalledWith({
123+
severity: 'warn',
124+
summary: enMessages.auth.login.emailPlaceholder,
125+
life: 5000
126+
})
127+
128+
// Should focus email input
129+
expect(document.getElementById).toHaveBeenCalledWith(
130+
'comfy-org-sign-in-email'
131+
)
132+
expect(mockFocus).toHaveBeenCalled()
133+
134+
// Should NOT call sendPasswordReset
135+
expect(mockSendPasswordReset).not.toHaveBeenCalled()
136+
})
137+
138+
it('calls handleForgotPassword with email when link is clicked', async () => {
139+
const wrapper = mountComponent()
140+
const component = wrapper.vm as any
141+
142+
// Spy on handleForgotPassword
143+
const handleForgotPasswordSpy = vi.spyOn(
144+
component,
145+
'handleForgotPassword'
146+
)
147+
148+
const forgotPasswordSpan = wrapper.find(
149+
'span.text-muted.text-base.font-medium.cursor-pointer'
150+
)
151+
152+
// Click the forgot password link
153+
await forgotPasswordSpan.trigger('click')
154+
155+
// Should call handleForgotPassword
156+
expect(handleForgotPasswordSpy).toHaveBeenCalled()
157+
})
158+
})
159+
160+
describe('Form Submission', () => {
161+
it('emits submit event when onSubmit is called with valid data', async () => {
162+
const wrapper = mountComponent()
163+
const component = wrapper.vm as any
164+
165+
// Call onSubmit directly with valid data
166+
component.onSubmit({
167+
valid: true,
168+
values: { email: '[email protected]', password: 'password123' }
169+
})
170+
171+
// Check emitted event
172+
expect(wrapper.emitted('submit')).toBeTruthy()
173+
expect(wrapper.emitted('submit')?.[0]).toEqual([
174+
{
175+
176+
password: 'password123'
177+
}
178+
])
179+
})
180+
181+
it('does not emit submit event when form is invalid', async () => {
182+
const wrapper = mountComponent()
183+
const component = wrapper.vm as any
184+
185+
// Call onSubmit with invalid form
186+
component.onSubmit({ valid: false, values: {} })
187+
188+
// Should not emit submit event
189+
expect(wrapper.emitted('submit')).toBeFalsy()
190+
})
191+
})
192+
193+
describe('Loading State', () => {
194+
it('shows spinner when loading', async () => {
195+
mockLoading = true
196+
197+
try {
198+
const wrapper = mountComponent()
199+
await nextTick()
200+
201+
expect(wrapper.findComponent(ProgressSpinner).exists()).toBe(true)
202+
expect(wrapper.findComponent(Button).exists()).toBe(false)
203+
} catch (error) {
204+
// Fallback test - check HTML content if component rendering fails
205+
mockLoading = true
206+
const wrapper = mountComponent()
207+
expect(wrapper.html()).toContain('p-progressspinner')
208+
expect(wrapper.html()).not.toContain('<button')
209+
}
210+
})
211+
212+
it('shows button when not loading', () => {
213+
mockLoading = false
214+
215+
const wrapper = mountComponent()
216+
217+
expect(wrapper.findComponent(ProgressSpinner).exists()).toBe(false)
218+
expect(wrapper.findComponent(Button).exists()).toBe(true)
219+
})
220+
})
221+
222+
describe('Component Structure', () => {
223+
it('renders email input with correct attributes', () => {
224+
const wrapper = mountComponent()
225+
const emailInput = wrapper.findComponent(InputText)
226+
227+
expect(emailInput.attributes('id')).toBe('comfy-org-sign-in-email')
228+
expect(emailInput.attributes('autocomplete')).toBe('email')
229+
expect(emailInput.attributes('name')).toBe('email')
230+
expect(emailInput.attributes('type')).toBe('text')
231+
})
232+
233+
it('renders password input with correct attributes', () => {
234+
const wrapper = mountComponent()
235+
const passwordInput = wrapper.findComponent(Password)
236+
237+
// Check props instead of attributes for Password component
238+
expect(passwordInput.props('inputId')).toBe('comfy-org-sign-in-password')
239+
// Password component passes name as prop, not attribute
240+
expect(passwordInput.props('name')).toBe('password')
241+
expect(passwordInput.props('feedback')).toBe(false)
242+
expect(passwordInput.props('toggleMask')).toBe(true)
243+
})
244+
245+
it('renders form with correct resolver', () => {
246+
const wrapper = mountComponent()
247+
const form = wrapper.findComponent(Form)
248+
249+
expect(form.props('resolver')).toBeDefined()
250+
})
251+
})
252+
253+
describe('Focus Behavior', () => {
254+
it('focuses email input when handleForgotPassword is called with invalid email', async () => {
255+
const wrapper = mountComponent()
256+
const component = wrapper.vm as any
257+
258+
// Mock getElementById to track focus
259+
const mockFocus = vi.fn()
260+
const mockElement = { focus: mockFocus }
261+
vi.spyOn(document, 'getElementById').mockReturnValue(mockElement as any)
262+
263+
// Call handleForgotPassword with no email
264+
await component.handleForgotPassword('', false)
265+
266+
// Should focus email input
267+
expect(document.getElementById).toHaveBeenCalledWith(
268+
'comfy-org-sign-in-email'
269+
)
270+
expect(mockFocus).toHaveBeenCalled()
271+
})
272+
273+
it('does not focus email input when valid email is provided', async () => {
274+
const wrapper = mountComponent()
275+
const component = wrapper.vm as any
276+
277+
// Mock getElementById
278+
const mockFocus = vi.fn()
279+
const mockElement = { focus: mockFocus }
280+
vi.spyOn(document, 'getElementById').mockReturnValue(mockElement as any)
281+
282+
// Call handleForgotPassword with valid email
283+
await component.handleForgotPassword('[email protected]', true)
284+
285+
// Should NOT focus email input
286+
expect(document.getElementById).not.toHaveBeenCalled()
287+
expect(mockFocus).not.toHaveBeenCalled()
288+
289+
// Should call sendPasswordReset
290+
expect(mockSendPasswordReset).toHaveBeenCalledWith('[email protected]')
291+
})
292+
})
293+
})

0 commit comments

Comments
 (0)