Files
ComfyUI_frontend/src/views/UserSelectView.test.ts
pythongosssss 37f0fbcbef fix: add guard to prevent user store re-initialization (#11959)
## 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)
2026-05-06 12:57:36 +00:00

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()
})
})