mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 01:26:33 +08:00
fix webtest
This commit is contained in:
parent
511df81201
commit
1fb6d1286f
@ -1,3 +1,4 @@
|
|||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { act, fireEvent, render, screen } from '@testing-library/react'
|
import { act, fireEvent, render, screen } from '@testing-library/react'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { AppModeEnum } from '@/types/app'
|
import { AppModeEnum } from '@/types/app'
|
||||||
@ -123,6 +124,10 @@ vi.mock('@/service/use-apps', () => ({
|
|||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
vi.mock('@/service/apps', () => ({
|
||||||
|
fetchWorkflowOnlineUsers: vi.fn().mockResolvedValue({}),
|
||||||
|
}))
|
||||||
|
|
||||||
// Mock tag store
|
// Mock tag store
|
||||||
vi.mock('@/app/components/base/tag-management/store', () => ({
|
vi.mock('@/app/components/base/tag-management/store', () => ({
|
||||||
useStore: (selector: (state: { tagList: any[], setTagList: any, showTagManagementModal: boolean, setShowTagManagementModal: any }) => any) => {
|
useStore: (selector: (state: { tagList: any[], setTagList: any, showTagManagementModal: boolean, setShowTagManagementModal: any }) => any) => {
|
||||||
@ -244,6 +249,21 @@ beforeAll(() => {
|
|||||||
} as unknown as typeof IntersectionObserver
|
} as unknown as typeof IntersectionObserver
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const renderList = () => {
|
||||||
|
const queryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
retry: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return render(
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<List />
|
||||||
|
</QueryClientProvider>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
describe('List', () => {
|
describe('List', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks()
|
vi.clearAllMocks()
|
||||||
@ -265,13 +285,13 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('Rendering', () => {
|
describe('Rendering', () => {
|
||||||
it('should render without crashing', () => {
|
it('should render without crashing', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
// Tab slider renders app type tabs
|
// Tab slider renders app type tabs
|
||||||
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render tab slider with all app types', () => {
|
it('should render tab slider with all app types', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
||||||
expect(screen.getByText('app.types.workflow')).toBeInTheDocument()
|
expect(screen.getByText('app.types.workflow')).toBeInTheDocument()
|
||||||
@ -282,48 +302,48 @@ describe('List', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should render search input', () => {
|
it('should render search input', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
// Input component renders a searchbox
|
// Input component renders a searchbox
|
||||||
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render tag filter', () => {
|
it('should render tag filter', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
// Tag filter renders with placeholder text
|
// Tag filter renders with placeholder text
|
||||||
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render created by me checkbox', () => {
|
it('should render created by me checkbox', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
expect(screen.getByText('app.showMyCreatedAppsOnly')).toBeInTheDocument()
|
expect(screen.getByText('app.showMyCreatedAppsOnly')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render app cards when apps exist', () => {
|
it('should render app cards when apps exist', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByTestId('app-card-app-1')).toBeInTheDocument()
|
expect(screen.getByTestId('app-card-app-1')).toBeInTheDocument()
|
||||||
expect(screen.getByTestId('app-card-app-2')).toBeInTheDocument()
|
expect(screen.getByTestId('app-card-app-2')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render new app card for editors', () => {
|
it('should render new app card for editors', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
expect(screen.getByTestId('new-app-card')).toBeInTheDocument()
|
expect(screen.getByTestId('new-app-card')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render footer when branding is disabled', () => {
|
it('should render footer when branding is disabled', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
expect(screen.getByTestId('footer')).toBeInTheDocument()
|
expect(screen.getByTestId('footer')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render drop DSL hint for editors', () => {
|
it('should render drop DSL hint for editors', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
expect(screen.getByText('app.newApp.dropDSLToCreateApp')).toBeInTheDocument()
|
expect(screen.getByText('app.newApp.dropDSLToCreateApp')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Tab Navigation', () => {
|
describe('Tab Navigation', () => {
|
||||||
it('should call setActiveTab when tab is clicked', () => {
|
it('should call setActiveTab when tab is clicked', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
fireEvent.click(screen.getByText('app.types.workflow'))
|
fireEvent.click(screen.getByText('app.types.workflow'))
|
||||||
|
|
||||||
@ -331,7 +351,7 @@ describe('List', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should call setActiveTab for all tab', () => {
|
it('should call setActiveTab for all tab', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
fireEvent.click(screen.getByText('app.types.all'))
|
fireEvent.click(screen.getByText('app.types.all'))
|
||||||
|
|
||||||
@ -341,12 +361,12 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('Search Functionality', () => {
|
describe('Search Functionality', () => {
|
||||||
it('should render search input field', () => {
|
it('should render search input field', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle search input change', () => {
|
it('should handle search input change', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
const input = screen.getByRole('textbox')
|
const input = screen.getByRole('textbox')
|
||||||
fireEvent.change(input, { target: { value: 'test search' } })
|
fireEvent.change(input, { target: { value: 'test search' } })
|
||||||
@ -355,7 +375,7 @@ describe('List', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should handle search input interaction', () => {
|
it('should handle search input interaction', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
const input = screen.getByRole('textbox')
|
const input = screen.getByRole('textbox')
|
||||||
expect(input).toBeInTheDocument()
|
expect(input).toBeInTheDocument()
|
||||||
@ -365,7 +385,7 @@ describe('List', () => {
|
|||||||
// Set initial keywords to make clear button visible
|
// Set initial keywords to make clear button visible
|
||||||
mockQueryState.keywords = 'existing search'
|
mockQueryState.keywords = 'existing search'
|
||||||
|
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Find and click clear button (Input component uses .group class for clear icon container)
|
// Find and click clear button (Input component uses .group class for clear icon container)
|
||||||
const clearButton = document.querySelector('.group')
|
const clearButton = document.querySelector('.group')
|
||||||
@ -380,12 +400,12 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('Tag Filter', () => {
|
describe('Tag Filter', () => {
|
||||||
it('should render tag filter component', () => {
|
it('should render tag filter component', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render tag filter with placeholder', () => {
|
it('should render tag filter with placeholder', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Tag filter is rendered
|
// Tag filter is rendered
|
||||||
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
||||||
@ -394,12 +414,12 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('Created By Me Filter', () => {
|
describe('Created By Me Filter', () => {
|
||||||
it('should render checkbox with correct label', () => {
|
it('should render checkbox with correct label', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
expect(screen.getByText('app.showMyCreatedAppsOnly')).toBeInTheDocument()
|
expect(screen.getByText('app.showMyCreatedAppsOnly')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle checkbox change', () => {
|
it('should handle checkbox change', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Checkbox component uses data-testid="checkbox-{id}"
|
// Checkbox component uses data-testid="checkbox-{id}"
|
||||||
// CheckboxWithLabel doesn't pass testId, so id is undefined
|
// CheckboxWithLabel doesn't pass testId, so id is undefined
|
||||||
@ -414,7 +434,7 @@ describe('List', () => {
|
|||||||
it('should not render new app card for non-editors', () => {
|
it('should not render new app card for non-editors', () => {
|
||||||
mockIsCurrentWorkspaceEditor.mockReturnValue(false)
|
mockIsCurrentWorkspaceEditor.mockReturnValue(false)
|
||||||
|
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.queryByTestId('new-app-card')).not.toBeInTheDocument()
|
expect(screen.queryByTestId('new-app-card')).not.toBeInTheDocument()
|
||||||
})
|
})
|
||||||
@ -422,7 +442,7 @@ describe('List', () => {
|
|||||||
it('should not render drop DSL hint for non-editors', () => {
|
it('should not render drop DSL hint for non-editors', () => {
|
||||||
mockIsCurrentWorkspaceEditor.mockReturnValue(false)
|
mockIsCurrentWorkspaceEditor.mockReturnValue(false)
|
||||||
|
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.queryByText(/drop dsl file to create app/i)).not.toBeInTheDocument()
|
expect(screen.queryByText(/drop dsl file to create app/i)).not.toBeInTheDocument()
|
||||||
})
|
})
|
||||||
@ -432,7 +452,7 @@ describe('List', () => {
|
|||||||
it('should redirect dataset operators to datasets page', () => {
|
it('should redirect dataset operators to datasets page', () => {
|
||||||
mockIsCurrentWorkspaceDatasetOperator.mockReturnValue(true)
|
mockIsCurrentWorkspaceDatasetOperator.mockReturnValue(true)
|
||||||
|
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(mockReplace).toHaveBeenCalledWith('/datasets')
|
expect(mockReplace).toHaveBeenCalledWith('/datasets')
|
||||||
})
|
})
|
||||||
@ -442,7 +462,7 @@ describe('List', () => {
|
|||||||
it('should call refetch when refresh key is set in localStorage', () => {
|
it('should call refetch when refresh key is set in localStorage', () => {
|
||||||
localStorage.setItem('needRefreshAppList', '1')
|
localStorage.setItem('needRefreshAppList', '1')
|
||||||
|
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(mockRefetch).toHaveBeenCalled()
|
expect(mockRefetch).toHaveBeenCalled()
|
||||||
expect(localStorage.getItem('needRefreshAppList')).toBeNull()
|
expect(localStorage.getItem('needRefreshAppList')).toBeNull()
|
||||||
@ -451,22 +471,23 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('Edge Cases', () => {
|
describe('Edge Cases', () => {
|
||||||
it('should handle multiple renders without issues', () => {
|
it('should handle multiple renders without issues', () => {
|
||||||
const { rerender } = render(<List />)
|
const { unmount } = renderList()
|
||||||
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
||||||
|
|
||||||
rerender(<List />)
|
unmount()
|
||||||
|
renderList()
|
||||||
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render app cards correctly', () => {
|
it('should render app cards correctly', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByText('Test App 1')).toBeInTheDocument()
|
expect(screen.getByText('Test App 1')).toBeInTheDocument()
|
||||||
expect(screen.getByText('Test App 2')).toBeInTheDocument()
|
expect(screen.getByText('Test App 2')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should render with all filter options visible', () => {
|
it('should render with all filter options visible', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
expect(screen.getByRole('textbox')).toBeInTheDocument()
|
||||||
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
||||||
@ -476,14 +497,14 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('Dragging State', () => {
|
describe('Dragging State', () => {
|
||||||
it('should show drop hint when DSL feature is enabled for editors', () => {
|
it('should show drop hint when DSL feature is enabled for editors', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
expect(screen.getByText('app.newApp.dropDSLToCreateApp')).toBeInTheDocument()
|
expect(screen.getByText('app.newApp.dropDSLToCreateApp')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('App Type Tabs', () => {
|
describe('App Type Tabs', () => {
|
||||||
it('should render all app type tabs', () => {
|
it('should render all app type tabs', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
expect(screen.getByText('app.types.all')).toBeInTheDocument()
|
||||||
expect(screen.getByText('app.types.workflow')).toBeInTheDocument()
|
expect(screen.getByText('app.types.workflow')).toBeInTheDocument()
|
||||||
@ -494,7 +515,7 @@ describe('List', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should call setActiveTab for each app type', () => {
|
it('should call setActiveTab for each app type', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
const appTypeTexts = [
|
const appTypeTexts = [
|
||||||
{ mode: AppModeEnum.WORKFLOW, text: 'app.types.workflow' },
|
{ mode: AppModeEnum.WORKFLOW, text: 'app.types.workflow' },
|
||||||
@ -513,7 +534,7 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('Search and Filter Integration', () => {
|
describe('Search and Filter Integration', () => {
|
||||||
it('should display search input with correct attributes', () => {
|
it('should display search input with correct attributes', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
const input = screen.getByRole('textbox')
|
const input = screen.getByRole('textbox')
|
||||||
expect(input).toBeInTheDocument()
|
expect(input).toBeInTheDocument()
|
||||||
@ -521,13 +542,13 @@ describe('List', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should have tag filter component', () => {
|
it('should have tag filter component', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
expect(screen.getByText('common.tag.placeholder')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should display created by me label', () => {
|
it('should display created by me label', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByText('app.showMyCreatedAppsOnly')).toBeInTheDocument()
|
expect(screen.getByText('app.showMyCreatedAppsOnly')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
@ -535,14 +556,14 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('App List Display', () => {
|
describe('App List Display', () => {
|
||||||
it('should display all app cards from data', () => {
|
it('should display all app cards from data', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByTestId('app-card-app-1')).toBeInTheDocument()
|
expect(screen.getByTestId('app-card-app-1')).toBeInTheDocument()
|
||||||
expect(screen.getByTestId('app-card-app-2')).toBeInTheDocument()
|
expect(screen.getByTestId('app-card-app-2')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should display app names correctly', () => {
|
it('should display app names correctly', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByText('Test App 1')).toBeInTheDocument()
|
expect(screen.getByText('Test App 1')).toBeInTheDocument()
|
||||||
expect(screen.getByText('Test App 2')).toBeInTheDocument()
|
expect(screen.getByText('Test App 2')).toBeInTheDocument()
|
||||||
@ -551,7 +572,7 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('Footer Visibility', () => {
|
describe('Footer Visibility', () => {
|
||||||
it('should render footer when branding is disabled', () => {
|
it('should render footer when branding is disabled', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByTestId('footer')).toBeInTheDocument()
|
expect(screen.getByTestId('footer')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
@ -563,14 +584,14 @@ describe('List', () => {
|
|||||||
describe('Additional Coverage', () => {
|
describe('Additional Coverage', () => {
|
||||||
it('should render dragging state overlay when dragging', () => {
|
it('should render dragging state overlay when dragging', () => {
|
||||||
mockDragging = true
|
mockDragging = true
|
||||||
const { container } = render(<List />)
|
const { container } = renderList()
|
||||||
|
|
||||||
// Component should render successfully with dragging state
|
// Component should render successfully with dragging state
|
||||||
expect(container).toBeInTheDocument()
|
expect(container).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle app mode filter in query params', () => {
|
it('should handle app mode filter in query params', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
const workflowTab = screen.getByText('app.types.workflow')
|
const workflowTab = screen.getByText('app.types.workflow')
|
||||||
fireEvent.click(workflowTab)
|
fireEvent.click(workflowTab)
|
||||||
@ -579,7 +600,7 @@ describe('List', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should render new app card for editors', () => {
|
it('should render new app card for editors', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
expect(screen.getByTestId('new-app-card')).toBeInTheDocument()
|
expect(screen.getByTestId('new-app-card')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
@ -587,7 +608,7 @@ describe('List', () => {
|
|||||||
|
|
||||||
describe('DSL File Drop', () => {
|
describe('DSL File Drop', () => {
|
||||||
it('should handle DSL file drop and show modal', () => {
|
it('should handle DSL file drop and show modal', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Simulate DSL file drop via the callback
|
// Simulate DSL file drop via the callback
|
||||||
const mockFile = new File(['test content'], 'test.yml', { type: 'application/yaml' })
|
const mockFile = new File(['test content'], 'test.yml', { type: 'application/yaml' })
|
||||||
@ -601,7 +622,7 @@ describe('List', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should close DSL modal when onClose is called', () => {
|
it('should close DSL modal when onClose is called', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Open modal via DSL file drop
|
// Open modal via DSL file drop
|
||||||
const mockFile = new File(['test content'], 'test.yml', { type: 'application/yaml' })
|
const mockFile = new File(['test content'], 'test.yml', { type: 'application/yaml' })
|
||||||
@ -619,7 +640,7 @@ describe('List', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should close DSL modal and refetch when onSuccess is called', () => {
|
it('should close DSL modal and refetch when onSuccess is called', () => {
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Open modal via DSL file drop
|
// Open modal via DSL file drop
|
||||||
const mockFile = new File(['test content'], 'test.yml', { type: 'application/yaml' })
|
const mockFile = new File(['test content'], 'test.yml', { type: 'application/yaml' })
|
||||||
@ -642,7 +663,7 @@ describe('List', () => {
|
|||||||
describe('Tag Filter Change', () => {
|
describe('Tag Filter Change', () => {
|
||||||
it('should handle tag filter value change', () => {
|
it('should handle tag filter value change', () => {
|
||||||
vi.useFakeTimers()
|
vi.useFakeTimers()
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// TagFilter component is rendered
|
// TagFilter component is rendered
|
||||||
expect(screen.getByTestId('tag-filter')).toBeInTheDocument()
|
expect(screen.getByTestId('tag-filter')).toBeInTheDocument()
|
||||||
@ -666,7 +687,7 @@ describe('List', () => {
|
|||||||
|
|
||||||
it('should handle empty tag filter selection', () => {
|
it('should handle empty tag filter selection', () => {
|
||||||
vi.useFakeTimers()
|
vi.useFakeTimers()
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Trigger tag filter change with empty array
|
// Trigger tag filter change with empty array
|
||||||
act(() => {
|
act(() => {
|
||||||
@ -688,7 +709,7 @@ describe('List', () => {
|
|||||||
describe('Infinite Scroll', () => {
|
describe('Infinite Scroll', () => {
|
||||||
it('should call fetchNextPage when intersection observer triggers', () => {
|
it('should call fetchNextPage when intersection observer triggers', () => {
|
||||||
mockServiceState.hasNextPage = true
|
mockServiceState.hasNextPage = true
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Simulate intersection
|
// Simulate intersection
|
||||||
if (intersectionCallback) {
|
if (intersectionCallback) {
|
||||||
@ -705,7 +726,7 @@ describe('List', () => {
|
|||||||
|
|
||||||
it('should not call fetchNextPage when not intersecting', () => {
|
it('should not call fetchNextPage when not intersecting', () => {
|
||||||
mockServiceState.hasNextPage = true
|
mockServiceState.hasNextPage = true
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
// Simulate non-intersection
|
// Simulate non-intersection
|
||||||
if (intersectionCallback) {
|
if (intersectionCallback) {
|
||||||
@ -723,7 +744,7 @@ describe('List', () => {
|
|||||||
it('should not call fetchNextPage when loading', () => {
|
it('should not call fetchNextPage when loading', () => {
|
||||||
mockServiceState.hasNextPage = true
|
mockServiceState.hasNextPage = true
|
||||||
mockServiceState.isLoading = true
|
mockServiceState.isLoading = true
|
||||||
render(<List />)
|
renderList()
|
||||||
|
|
||||||
if (intersectionCallback) {
|
if (intersectionCallback) {
|
||||||
act(() => {
|
act(() => {
|
||||||
@ -741,7 +762,7 @@ describe('List', () => {
|
|||||||
describe('Error State', () => {
|
describe('Error State', () => {
|
||||||
it('should handle error state in useEffect', () => {
|
it('should handle error state in useEffect', () => {
|
||||||
mockServiceState.error = new Error('Test error')
|
mockServiceState.error = new Error('Test error')
|
||||||
const { container } = render(<List />)
|
const { container } = renderList()
|
||||||
|
|
||||||
// Component should still render
|
// Component should still render
|
||||||
expect(container).toBeInTheDocument()
|
expect(container).toBeInTheDocument()
|
||||||
|
|||||||
@ -35,12 +35,14 @@ describe('Avatar', () => {
|
|||||||
it.each([
|
it.each([
|
||||||
{ size: undefined, expected: '30px', label: 'default (30px)' },
|
{ size: undefined, expected: '30px', label: 'default (30px)' },
|
||||||
{ size: 50, expected: '50px', label: 'custom (50px)' },
|
{ size: 50, expected: '50px', label: 'custom (50px)' },
|
||||||
])('should apply $label size to img element', ({ size, expected }) => {
|
])('should apply $label size to avatar container', ({ size, expected }) => {
|
||||||
const props = { name: 'Test', avatar: 'https://example.com/avatar.jpg', size }
|
const props = { name: 'Test', avatar: 'https://example.com/avatar.jpg', size }
|
||||||
|
|
||||||
render(<Avatar {...props} />)
|
render(<Avatar {...props} />)
|
||||||
|
|
||||||
expect(screen.getByRole('img')).toHaveStyle({
|
const img = screen.getByRole('img')
|
||||||
|
const wrapper = img.parentElement as HTMLElement
|
||||||
|
expect(wrapper).toHaveStyle({
|
||||||
width: expected,
|
width: expected,
|
||||||
height: expected,
|
height: expected,
|
||||||
fontSize: expected,
|
fontSize: expected,
|
||||||
@ -60,7 +62,7 @@ describe('Avatar', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('className prop', () => {
|
describe('className prop', () => {
|
||||||
it('should merge className with default avatar classes on img', () => {
|
it('should merge className with default avatar classes on container', () => {
|
||||||
const props = {
|
const props = {
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
avatar: 'https://example.com/avatar.jpg',
|
avatar: 'https://example.com/avatar.jpg',
|
||||||
@ -70,8 +72,9 @@ describe('Avatar', () => {
|
|||||||
render(<Avatar {...props} />)
|
render(<Avatar {...props} />)
|
||||||
|
|
||||||
const img = screen.getByRole('img')
|
const img = screen.getByRole('img')
|
||||||
expect(img).toHaveClass('custom-class')
|
const wrapper = img.parentElement as HTMLElement
|
||||||
expect(img).toHaveClass('shrink-0', 'flex', 'items-center', 'rounded-full', 'bg-primary-600')
|
expect(wrapper).toHaveClass('custom-class')
|
||||||
|
expect(wrapper).toHaveClass('shrink-0', 'flex', 'items-center', 'rounded-full', 'bg-primary-600')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should merge className with default avatar classes on fallback div', () => {
|
it('should merge className with default avatar classes on fallback div', () => {
|
||||||
@ -277,10 +280,11 @@ describe('Avatar', () => {
|
|||||||
render(<Avatar {...props} />)
|
render(<Avatar {...props} />)
|
||||||
|
|
||||||
const img = screen.getByRole('img')
|
const img = screen.getByRole('img')
|
||||||
|
const wrapper = img.parentElement as HTMLElement
|
||||||
expect(img).toHaveAttribute('alt', 'Test User')
|
expect(img).toHaveAttribute('alt', 'Test User')
|
||||||
expect(img).toHaveAttribute('src', 'https://example.com/avatar.jpg')
|
expect(img).toHaveAttribute('src', 'https://example.com/avatar.jpg')
|
||||||
expect(img).toHaveStyle({ width: '64px', height: '64px' })
|
expect(wrapper).toHaveStyle({ width: '64px', height: '64px' })
|
||||||
expect(img).toHaveClass('custom-avatar')
|
expect(wrapper).toHaveClass('custom-avatar')
|
||||||
|
|
||||||
// Trigger load to verify onError callback
|
// Trigger load to verify onError callback
|
||||||
fireEvent.load(img)
|
fireEvent.load(img)
|
||||||
|
|||||||
@ -132,7 +132,12 @@ const createMockLocalStorage = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mockLocalStorage: ReturnType<typeof createMockLocalStorage>
|
let mockLocalStorage: ReturnType<typeof createMockLocalStorage> = createMockLocalStorage()
|
||||||
|
Object.defineProperty(globalThis, 'localStorage', {
|
||||||
|
value: mockLocalStorage,
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks()
|
vi.clearAllMocks()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user