Skip to content

Commit

Permalink
update test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
prv-proton committed Jan 7, 2025
1 parent 747384f commit 3c988de
Show file tree
Hide file tree
Showing 3 changed files with 338 additions and 3 deletions.
168 changes: 168 additions & 0 deletions frontend/src/components/__tests__/BCDateFloatingFilter.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { BCDateFloatingFilter } from './BCDateFloatingFilter'
import { format } from 'date-fns'

// Mock Material-UI components
vi.mock('@mui/material', () => ({
FormControl: ({ children, ...props }) => <div {...props}>{children}</div>,
IconButton: ({ children, onClick, ...props }) => (
<button onClick={onClick} {...props}>
{children}
</button>
),
InputAdornment: ({ children }) => <div>{children}</div>
}))

vi.mock('@mui/x-date-pickers', () => ({
DatePicker: ({ value, onChange, onOpen, onClose, slotProps, ...props }) => (
<div>
<input
type="text"
value={value ? format(value, 'yyyy-MM-dd') : ''}
onChange={(e) => onChange(new Date(e.target.value))}
{...props}
/>
{slotProps.textField.InputProps.startAdornment}
{slotProps.textField.InputProps.endAdornment}
</div>
)
}))

describe('BCDateFloatingFilter', () => {
const mockOnModelChange = vi.fn()
const defaultProps = {
model: null,
onModelChange: mockOnModelChange,
disabled: false,
minDate: '2013-01-01',
maxDate: '2040-01-01',
initialFilterType: 'equals',
label: 'Select Date'
}

beforeEach(() => {
mockOnModelChange.mockClear()
})

it('renders with default props', () => {
render(<BCDateFloatingFilter {...defaultProps} />)

expect(screen.getByRole('group')).toBeInTheDocument()
expect(screen.getByLabelText('Open calendar')).toBeInTheDocument()
expect(screen.getByLabelText('Date Picker')).toBeInTheDocument()
})

it('handles date selection', async () => {
render(<BCDateFloatingFilter {...defaultProps} />)

const input = screen.getByLabelText('Date Picker')
const testDate = '2024-01-01'

fireEvent.change(input, { target: { value: testDate } })

expect(mockOnModelChange).toHaveBeenCalledWith({
type: 'equals',
dateFrom: testDate,
dateTo: null,
filterType: 'date'
})
})

it('handles date clearing', async () => {
const initialModel = {
type: 'equals',
dateFrom: '2024-01-01',
dateTo: null,
filterType: 'date'
}

render(<BCDateFloatingFilter {...defaultProps} model={initialModel} />)

const clearButton = screen.getByLabelText('Clear date')
fireEvent.click(clearButton)

expect(mockOnModelChange).toHaveBeenCalledWith(null)
})

it('initializes with model date when provided', () => {
const modelWithDate = {
type: 'equals',
dateFrom: '2024-01-01',
dateTo: null,
filterType: 'date'
}

render(<BCDateFloatingFilter {...defaultProps} model={modelWithDate} />)

const input = screen.getByLabelText('Date Picker')
expect(input).toHaveValue('2024-01-01')
})

it('disables input when disabled prop is true', () => {
render(<BCDateFloatingFilter {...defaultProps} disabled={true} />)

const input = screen.getByLabelText('Date Picker')
expect(input).toBeDisabled()
})

it('handles invalid date input', async () => {
render(<BCDateFloatingFilter {...defaultProps} />)

const input = screen.getByLabelText('Date Picker')
fireEvent.change(input, { target: { value: 'invalid-date' } })

expect(mockOnModelChange).toHaveBeenCalledWith(null)
})

it('opens calendar on calendar icon click', () => {
render(<BCDateFloatingFilter {...defaultProps} />)

const calendarButton = screen.getByLabelText('Open calendar')
fireEvent.click(calendarButton)

// Since we're mocking the DatePicker, we can't directly test if the calendar opens,
// but we can verify the click handler was called
expect(calendarButton).toBeInTheDocument()
})

it('maintains proper ARIA attributes', () => {
render(<BCDateFloatingFilter {...defaultProps} />)

const container = screen.getByRole('group')
expect(container).toHaveAttribute('aria-labelledby', 'date-picker-label')

const datePicker = screen.getByLabelText('Date Picker')
expect(datePicker).toHaveAttribute('aria-describedby', 'date-picker-description')
})

it('respects min and max date constraints', () => {
const customProps = {
...defaultProps,
minDate: '2023-01-01',
maxDate: '2025-01-01'
}

render(<BCDateFloatingFilter {...customProps} />)

const input = screen.getByLabelText('Date Picker')
expect(input).toBeInTheDocument()
// Note: Actual min/max date validation would be handled by the DatePicker component
})

it('updates when model changes externally', () => {
const { rerender } = render(<BCDateFloatingFilter {...defaultProps} />)

const newModel = {
type: 'equals',
dateFrom: '2024-02-01',
dateTo: null,
filterType: 'date'
}

rerender(<BCDateFloatingFilter {...defaultProps} model={newModel} />)

const input = screen.getByLabelText('Date Picker')
expect(input).toHaveValue('2024-02-01')
})
})
166 changes: 166 additions & 0 deletions frontend/src/components/__tests__/BCSelectFloatingFilter.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { BCSelectFloatingFilter } from '../BCDataGrid/components'

describe('BCSelectFloatingFilter', () => {
const mockOnModelChange = vi.fn()
const defaultProps = {
model: null,
onModelChange: mockOnModelChange,
optionsQuery: () => ({
data: [
{ value: '1', label: 'Option 1' },
{ value: '2', label: 'Option 2' },
{ value: '3', label: 'Option 3' }
],
isLoading: false,
isError: false,
error: null
}),
valueKey: 'value',
labelKey: 'label',
disabled: false,
params: {},
initialFilterType: 'equals',
multiple: false,
initialSelectedValues: []
}

beforeEach(() => {
mockOnModelChange.mockClear()
})

it('renders with default props', () => {
render(<BCSelectFloatingFilter {...defaultProps} />)

const select = screen.getByRole('combobox')
expect(select).toBeInTheDocument()
expect(screen.getByText('Select')).toBeInTheDocument()
expect(screen.getAllByRole('option')).toHaveLength(4) // Including the default "Select" option
})

it('handles single selection', async () => {
render(<BCSelectFloatingFilter {...defaultProps} />)

const select = screen.getByRole('combobox')
fireEvent.change(select, { target: { value: '1' } })

expect(mockOnModelChange).toHaveBeenCalledWith({
type: 'equals',
filter: '1'
})
})

it('handles multiple selection when multiple prop is true', () => {
render(<BCSelectFloatingFilter {...defaultProps} multiple={true} />)

const select = screen.getByRole('combobox')
fireEvent.change(select, {
target: {
options: [
{ selected: true, value: '1' },
{ selected: true, value: '2' }
]
}
})

expect(mockOnModelChange).toHaveBeenCalledWith({
type: 'equals',
filter: ['1', '2']
})
})

it('shows loading state', () => {
const loadingProps = {
...defaultProps,
optionsQuery: () => ({
data: null,
isLoading: true,
isError: false,
error: null
})
}

render(<BCSelectFloatingFilter {...loadingProps} />)
expect(screen.getByText('Loading...')).toBeInTheDocument()
})

it('shows error state', () => {
const errorProps = {
...defaultProps,
optionsQuery: () => ({
data: null,
isLoading: false,
isError: true,
error: { message: 'Failed to load' }
})
}

render(<BCSelectFloatingFilter {...errorProps} />)
expect(
screen.getByText('Error loading options: Failed to load')
).toBeInTheDocument()
})

it('clears selection when clear button is clicked', async () => {
render(<BCSelectFloatingFilter {...defaultProps} />)

// First select a value
const select = screen.getByRole('combobox')
fireEvent.change(select, { target: { value: '1' } })

// Then clear it
const clearButton = screen.getByLabelText('Clear selection')
fireEvent.click(clearButton)

expect(mockOnModelChange).toHaveBeenLastCalledWith(null)
})

it('initializes with model value when provided', () => {
const modelProps = {
...defaultProps,
model: { type: 'equals', filter: '2' }
}

render(<BCSelectFloatingFilter {...modelProps} />)
const select = screen.getByRole('combobox')
expect(select).toHaveValue('2')
})

it('initializes with initialSelectedValues when provided', () => {
const initialValueProps = {
...defaultProps,
initialSelectedValues: ['1']
}

render(<BCSelectFloatingFilter {...initialValueProps} />)
const select = screen.getByRole('combobox')
expect(select).toHaveValue('1')
})

it('disables select when disabled prop is true', () => {
render(<BCSelectFloatingFilter {...defaultProps} disabled={true} />)
const select = screen.getByRole('combobox')
expect(select).toBeDisabled()
})

it('handles empty/null selection in single select mode', () => {
render(<BCSelectFloatingFilter {...defaultProps} />)

const select = screen.getByRole('combobox')
fireEvent.change(select, { target: { value: '0' } })

expect(mockOnModelChange).toHaveBeenCalledWith(null)
})

it('maintains proper ARIA attributes', () => {
render(<BCSelectFloatingFilter {...defaultProps} />)

const container = screen.getByRole('group')
expect(container).toHaveAttribute('aria-labelledby', 'select-filter-label')

const combobox = screen.getByRole('combobox')
expect(combobox).toHaveAttribute('aria-controls', 'select-filter')
expect(combobox).toHaveAttribute('aria-expanded', 'false')
})
})
7 changes: 4 additions & 3 deletions frontend/src/views/Admin/AdminMenu/components/_schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,13 @@ export const userActivityColDefs = [
headerName: 'Transaction Type',
floatingFilterComponent: BCSelectFloatingFilter,
floatingFilterComponentParams: {
valueKey: 'action',
labelKey: 'action',
valueKey: 'value',
labelKey: 'label',
optionsQuery: () => ({
data: [
...Object.values(TRANSACTION_TYPES).map((value) => ({
action: value
label: value.replace(/([A-Z])/g, ' $1').trim(),
value
}))
],
isLoading: false
Expand Down

0 comments on commit 3c988de

Please sign in to comment.