mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-24 14:45:36 +00:00
## Summary Make `userStore.initialize()` idempotent and concurrency-safe so the bootstrap, router-guard, and UserSelectView callers share a single getUserConfig fetch instead of racing/duplicaitng calls. ## Changes - **What**: - cache initialize in a promise so callers all re-use the same result - remove now redundant is initialized guard - tests ## Review Focus - Current user switch/logout uses `window.location.reload()`, no callers intentionally call initialize to reinit. In future if this changes we may want to add a parameter to skip the cache or a separate function. - Failed initializes are not cached to allow callers to retry - Not practical for e2e tests, the unit tests prove that the requests are deduped. All a e2e test would do is mock/spy on the network requests to show multiple requests do not happen - which the unit tests do a better job of. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11959-fix-add-guard-to-prevent-user-store-re-initialization-3576d73d3650817db7b0e52cc25f9b7b) by [Unito](https://www.unito.io)
119 lines
3.2 KiB
TypeScript
119 lines
3.2 KiB
TypeScript
import { render, screen, waitFor } from '@testing-library/vue'
|
|
import userEvent from '@testing-library/user-event'
|
|
import PrimeVue from 'primevue/config'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { createI18n } from 'vue-i18n'
|
|
|
|
import UserSelectView from './UserSelectView.vue'
|
|
|
|
const i18n = createI18n({
|
|
legacy: false,
|
|
locale: 'en',
|
|
messages: { en: {} }
|
|
})
|
|
|
|
const mockRouterPush = vi.hoisted(() => vi.fn())
|
|
vi.mock('vue-router', () => ({
|
|
useRouter: () => ({ push: mockRouterPush })
|
|
}))
|
|
|
|
const userStoreMock = vi.hoisted(() => ({
|
|
users: [] as Array<{ userId: string; username: string }>,
|
|
initialize: vi.fn().mockResolvedValue(undefined),
|
|
createUser: vi.fn(),
|
|
login: vi.fn().mockResolvedValue(undefined)
|
|
}))
|
|
vi.mock('@/stores/userStore', () => ({
|
|
useUserStore: () => userStoreMock
|
|
}))
|
|
|
|
vi.mock('@/views/templates/BaseViewTemplate.vue', () => ({
|
|
default: {
|
|
name: 'BaseViewTemplate',
|
|
template: '<div><slot /></div>'
|
|
}
|
|
}))
|
|
|
|
const mountView = () =>
|
|
render(UserSelectView, {
|
|
global: {
|
|
plugins: [i18n, PrimeVue]
|
|
}
|
|
})
|
|
|
|
describe('UserSelectView', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
userStoreMock.users = []
|
|
})
|
|
|
|
it('initializes the user store on mount', async () => {
|
|
mountView()
|
|
|
|
await waitFor(() =>
|
|
expect(userStoreMock.initialize).toHaveBeenCalledTimes(1)
|
|
)
|
|
})
|
|
|
|
it('shows an error when login is attempted without a selection', async () => {
|
|
mountView()
|
|
|
|
await userEvent.click(
|
|
screen.getByRole('button', { name: 'userSelect.next' })
|
|
)
|
|
|
|
expect(await screen.findByText('No user selected')).toBeInTheDocument()
|
|
expect(userStoreMock.login).not.toHaveBeenCalled()
|
|
expect(mockRouterPush).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('creates a new user, logs in, and navigates home', async () => {
|
|
const newUser = { userId: 'u1', username: 'bob' }
|
|
userStoreMock.createUser.mockResolvedValueOnce(newUser)
|
|
mountView()
|
|
|
|
await userEvent.type(
|
|
screen.getByPlaceholderText('userSelect.enterUsername'),
|
|
'bob'
|
|
)
|
|
await userEvent.click(
|
|
screen.getByRole('button', { name: 'userSelect.next' })
|
|
)
|
|
|
|
expect(userStoreMock.createUser).toHaveBeenCalledWith('bob')
|
|
expect(userStoreMock.login).toHaveBeenCalledWith(newUser)
|
|
expect(mockRouterPush).toHaveBeenCalledWith('/')
|
|
})
|
|
|
|
it('shows an error when the entered username already exists', async () => {
|
|
userStoreMock.users = [{ userId: 'u1', username: 'bob' }]
|
|
mountView()
|
|
|
|
await userEvent.type(
|
|
screen.getByPlaceholderText('userSelect.enterUsername'),
|
|
'bob'
|
|
)
|
|
|
|
expect(
|
|
await screen.findByText('User "bob" already exists')
|
|
).toBeInTheDocument()
|
|
})
|
|
|
|
it('surfaces createUser failures as a login error', async () => {
|
|
userStoreMock.createUser.mockRejectedValueOnce(new Error('boom'))
|
|
mountView()
|
|
|
|
await userEvent.type(
|
|
screen.getByPlaceholderText('userSelect.enterUsername'),
|
|
'bob'
|
|
)
|
|
await userEvent.click(
|
|
screen.getByRole('button', { name: 'userSelect.next' })
|
|
)
|
|
|
|
expect(await screen.findByText('boom')).toBeInTheDocument()
|
|
expect(userStoreMock.login).not.toHaveBeenCalled()
|
|
expect(mockRouterPush).not.toHaveBeenCalled()
|
|
})
|
|
})
|