test(web): enhance unit tests for credential and popup components

- Updated tests for CredentialItem to improve delete button interaction and check icon rendering.
- Enhanced PopupItem tests by mocking credential panel state for various scenarios, ensuring accurate rendering based on credit status.
- Adjusted Popup tests to include trial credits mock for better coverage of credit management logic.
- Refactored model list item tests to include wrapper for consistent rendering context.
This commit is contained in:
CodingOnStar
2026-03-09 14:19:14 +08:00
parent 456c95adb1
commit 0e0a6ad043
5 changed files with 83 additions and 8 deletions

View File

@ -122,14 +122,16 @@ describe('CredentialItem', () => {
render(<CredentialItem credential={credential} disabled onDelete={onDelete} />)
fireEvent.click(screen.getByTestId('delete-icon').closest('button') as HTMLButtonElement)
const deleteButton = screen.getAllByRole('button')
.find(b => b.querySelector('.i-ri-delete-bin-line'))!
fireEvent.click(deleteButton)
expect(onDelete).not.toHaveBeenCalled()
})
// showSelectedIcon=true: check icon area is always rendered; check icon only appears when IDs match
it('should render check icon area when showSelectedIcon=true and selectedCredentialId matches', () => {
render(
const { container } = render(
<CredentialItem
credential={credential}
showSelectedIcon
@ -137,7 +139,7 @@ describe('CredentialItem', () => {
/>,
)
expect(screen.getByTestId('check-icon')).toBeInTheDocument()
expect(container.querySelector('.i-ri-check-line')).toBeInTheDocument()
})
it('should not render check icon when showSelectedIcon=true but selectedCredentialId does not match', () => {

View File

@ -43,6 +43,22 @@ vi.mock('@/app/components/base/tooltip', () => ({
default: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}))
const mockCredentialPanelState = vi.hoisted(() => vi.fn())
vi.mock('../provider-added-card/use-credential-panel-state', () => ({
useCredentialPanelState: mockCredentialPanelState,
}))
vi.mock('../provider-added-card/use-change-provider-priority', () => ({
useChangeProviderPriority: () => ({
isChangingPriority: false,
handleChangePriority: vi.fn(),
}),
}))
vi.mock('../provider-added-card/model-auth-dropdown/dropdown-content', () => ({
default: () => null,
}))
const mockSetShowModelModal = vi.hoisted(() => vi.fn())
vi.mock('@/context/modal-context', () => ({
useModalContext: () => ({
@ -100,6 +116,16 @@ describe('PopupItem', () => {
mockUseAppContext.mockReturnValue({
currentWorkspace: { trial_credits: 200, trial_credits_used: 0 },
})
mockCredentialPanelState.mockReturnValue({
variant: 'api-active',
priority: 'apiKey',
supportsCredits: false,
showPrioritySwitcher: false,
hasCredentials: true,
isCreditsExhausted: false,
credentialName: 'my-api-key',
credits: 200,
})
})
it('should call onSelect when clicking an active model', () => {
@ -206,6 +232,16 @@ describe('PopupItem', () => {
},
})],
})
mockCredentialPanelState.mockReturnValue({
variant: 'api-required-configure',
priority: 'apiKey',
supportsCredits: false,
showPrioritySwitcher: false,
hasCredentials: false,
isCreditsExhausted: false,
credentialName: undefined,
credits: 0,
})
render(<PopupItem model={makeModel()} onSelect={vi.fn()} onHide={vi.fn()} />)
@ -218,6 +254,16 @@ describe('PopupItem', () => {
preferred_provider_type: PreferredProviderTypeEnum.system,
})],
})
mockCredentialPanelState.mockReturnValue({
variant: 'credits-active',
priority: 'credits',
supportsCredits: true,
showPrioritySwitcher: true,
hasCredentials: false,
isCreditsExhausted: false,
credentialName: undefined,
credits: 200,
})
render(<PopupItem model={makeModel()} onSelect={vi.fn()} onHide={vi.fn()} />)
@ -233,6 +279,16 @@ describe('PopupItem', () => {
mockUseAppContext.mockReturnValue({
currentWorkspace: { trial_credits: 100, trial_credits_used: 100 },
})
mockCredentialPanelState.mockReturnValue({
variant: 'credits-exhausted',
priority: 'credits',
supportsCredits: true,
showPrioritySwitcher: true,
hasCredentials: false,
isCreditsExhausted: true,
credentialName: undefined,
credits: 0,
})
render(<PopupItem model={makeModel()} onSelect={vi.fn()} onHide={vi.fn()} />)

View File

@ -49,6 +49,16 @@ vi.mock('@/context/provider-context', () => ({
useProviderContext: () => ({ modelProviders: [] }),
}))
vi.mock('../provider-added-card/use-trial-credits', () => ({
useTrialCredits: () => ({
credits: 200,
totalCredits: 200,
isExhausted: false,
isLoading: false,
nextCreditResetDate: undefined,
}),
}))
vi.mock('next-themes', () => ({
useTheme: () => ({ theme: 'light' }),
}))

View File

@ -155,6 +155,7 @@ describe('ModelListItem', () => {
provider={mockProvider}
isConfigurable={false}
/>,
{ wrapper: createWrapper() },
)
// Assert
@ -180,6 +181,7 @@ describe('ModelListItem', () => {
provider={mockProvider}
isConfigurable={false}
/>,
{ wrapper: createWrapper() },
)
// Assert - Badge component should render
@ -200,6 +202,7 @@ describe('ModelListItem', () => {
provider={mockProvider}
isConfigurable={false}
/>,
{ wrapper: createWrapper() },
)
// Assert - ConfigModel should show because plan.type === 'sandbox'
@ -219,6 +222,7 @@ describe('ModelListItem', () => {
provider={mockProvider}
isConfigurable={false}
/>,
{ wrapper: createWrapper() },
)
// Assert - ConfigModel should NOT show because plan.type !== 'sandbox' and load balancing is disabled
@ -238,6 +242,7 @@ describe('ModelListItem', () => {
provider={mockProvider}
isConfigurable={false}
/>,
{ wrapper: createWrapper() },
)
// Assert - ConfigModel should not render because status is not active/disabled
@ -259,6 +264,7 @@ describe('ModelListItem', () => {
provider={mockProvider}
isConfigurable={true}
/>,
{ wrapper: createWrapper() },
)
// Assert

View File

@ -438,7 +438,7 @@ describe('PluginTaskList Component', () => {
// Translation key is returned as text in tests, multiple matches expected (title + status)
expect(screen.getAllByText(/task\.installing/i).length).toBeGreaterThan(0)
// Verify section container is rendered
expect(document.querySelector('.max-h-\\[200px\\]')).toBeInTheDocument()
expect(document.querySelector('.max-h-\\[300px\\]')).toBeInTheDocument()
})
it('should render success plugins section when plugins exist', () => {
@ -467,7 +467,7 @@ describe('PluginTaskList Component', () => {
)
// All sections should be present
expect(document.querySelectorAll('.max-h-\\[200px\\]').length).toBe(3)
expect(document.querySelectorAll('.max-h-\\[300px\\]').length).toBe(3)
})
})
@ -523,8 +523,9 @@ describe('PluginTaskList Component', () => {
/>,
)
// The individual clear button has the text 'operation.clear'
fireEvent.click(screen.getByRole('button', { name: /operation\.clear/i }))
const closeButton = screen.getAllByRole('button')
.find(btn => btn.querySelector('.i-ri-close-line'))!
fireEvent.click(closeButton)
expect(handleClearSingle).toHaveBeenCalledWith('task-123', 'error-plugin-1')
})
@ -844,7 +845,7 @@ describe('PluginTasks Integration', () => {
fireEvent.click(document.getElementById('plugin-task-trigger')!)
// All sections should be visible
const sections = document.querySelectorAll('.max-h-\\[200px\\]')
const sections = document.querySelectorAll('.max-h-\\[300px\\]')
expect(sections.length).toBe(3)
})
})