Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions frontend/__mocks__/@heroui/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const React = require('react')

const passthrough = (name) => {
const C = ({ children, className, ...props }) =>

Check warning on line 4 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'className' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp2&open=AZ0-j7dsUQIsvQ7tNHp2&pullRequest=4434

Check warning on line 4 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp1&open=AZ0-j7dsUQIsvQ7tNHp1&pullRequest=4434
React.createElement('div', { 'data-testid': name, className, ...props }, children)
C.displayName = name
return C
}

module.exports = {
Breadcrumbs: ({ children, className, separator, 'aria-label': ariaLabel, ...props }) => {

Check warning on line 11 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp3&open=AZ0-j7dsUQIsvQ7tNHp3&pullRequest=4434

Check warning on line 11 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'className' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp4&open=AZ0-j7dsUQIsvQ7tNHp4&pullRequest=4434

Check warning on line 11 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'separator' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp5&open=AZ0-j7dsUQIsvQ7tNHp5&pullRequest=4434

Check warning on line 11 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'aria-label' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp6&open=AZ0-j7dsUQIsvQ7tNHp6&pullRequest=4434
const items = React.Children.toArray(children)
return React.createElement('nav', { 'aria-label': ariaLabel, className },
React.createElement('ol', { 'data-slot': 'list' },
items.map((item, i) =>
React.createElement(React.Fragment, { key: i },

Check warning on line 16 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp7&open=AZ0-j7dsUQIsvQ7tNHp7&pullRequest=4434
item,
i < items.length - 1
? React.createElement('li', { 'data-slot': 'separator' }, separator)
: null
)
)
)
)
},
BreadcrumbsItem: ({ children, className, isDisabled, ...props }) => React.createElement('li', { className, 'aria-disabled': isDisabled || undefined, ...props }, children),

Check warning on line 26 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'isDisabled' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp-&open=AZ0-j7dsUQIsvQ7tNHp-&pullRequest=4434

Check warning on line 26 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp8&open=AZ0-j7dsUQIsvQ7tNHp8&pullRequest=4434

Check warning on line 26 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'className' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp9&open=AZ0-j7dsUQIsvQ7tNHp9&pullRequest=4434
BreadcrumbsRoot: passthrough('BreadcrumbsRoot'),
Button: ({ children, variant, className, ...props }) => React.createElement('button', { 'data-testid': 'dropdown-button', 'data-variant': variant, className, ...props }, children),

Check warning on line 28 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'className' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqB&open=AZ0-j7dsUQIsvQ7tNHqB&pullRequest=4434

Check warning on line 28 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'variant' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqA&open=AZ0-j7dsUQIsvQ7tNHqA&pullRequest=4434

Check warning on line 28 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHp_&open=AZ0-j7dsUQIsvQ7tNHp_&pullRequest=4434
ButtonRoot: passthrough('ButtonRoot'),
Dropdown: ({ children, ...props }) => React.createElement('div', { 'data-testid': 'dropdown' }, children),

Check warning on line 30 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqC&open=AZ0-j7dsUQIsvQ7tNHqC&pullRequest=4434
DropdownTrigger: ({ children }) => React.createElement('div', { 'data-testid': 'dropdown-trigger' }, children),

Check warning on line 31 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqD&open=AZ0-j7dsUQIsvQ7tNHqD&pullRequest=4434
DropdownMenu: ({ children, onAction, selectedKeys, selectionMode, ...props }) => React.createElement('div', { 'data-testid': 'dropdown-menu', 'data-selected-keys': selectedKeys, 'data-selection-mode': selectionMode, ...props }, children),

Check warning on line 32 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'onAction' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqF&open=AZ0-j7dsUQIsvQ7tNHqF&pullRequest=4434

Check warning on line 32 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'selectionMode' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqH&open=AZ0-j7dsUQIsvQ7tNHqH&pullRequest=4434

Check warning on line 32 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqE&open=AZ0-j7dsUQIsvQ7tNHqE&pullRequest=4434

Check warning on line 32 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'selectedKeys' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqG&open=AZ0-j7dsUQIsvQ7tNHqG&pullRequest=4434
DropdownItem: ({ children, onPress, ...props }) => React.createElement('div', { 'data-testid': 'dropdown-item', onClick: onPress, ...props }, children),

Check warning on line 33 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqI&open=AZ0-j7dsUQIsvQ7tNHqI&pullRequest=4434

Check warning on line 33 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'onPress' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqJ&open=AZ0-j7dsUQIsvQ7tNHqJ&pullRequest=4434
DropdownSection: ({ children, 'data-title': title, ...props }) => React.createElement('div', { 'data-testid': 'dropdown-section', 'data-title': title, ...props }, title ? React.createElement('span', { 'data-testid': 'dropdown-section-title' }, title) : null, children),

Check warning on line 34 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqK&open=AZ0-j7dsUQIsvQ7tNHqK&pullRequest=4434

Check warning on line 34 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'data-title' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqL&open=AZ0-j7dsUQIsvQ7tNHqL&pullRequest=4434
DropdownRoot: passthrough('DropdownRoot'),
DropdownPopover: passthrough('DropdownPopover'),
Input: ({ className, id, type, value, onChange, placeholder, ...props }) => React.createElement('input', { id, type: type || 'text', value, onChange, placeholder, className }),

Check warning on line 37 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'id' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqN&open=AZ0-j7dsUQIsvQ7tNHqN&pullRequest=4434

Check warning on line 37 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'className' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqM&open=AZ0-j7dsUQIsvQ7tNHqM&pullRequest=4434

Check warning on line 37 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'onChange' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqQ&open=AZ0-j7dsUQIsvQ7tNHqQ&pullRequest=4434

Check warning on line 37 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'value' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqP&open=AZ0-j7dsUQIsvQ7tNHqP&pullRequest=4434

Check warning on line 37 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'placeholder' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqR&open=AZ0-j7dsUQIsvQ7tNHqR&pullRequest=4434

Check warning on line 37 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'type' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqO&open=AZ0-j7dsUQIsvQ7tNHqO&pullRequest=4434
InputRoot: passthrough('InputRoot'),
Autocomplete: passthrough('Autocomplete'),
AutocompleteRoot: passthrough('AutocompleteRoot'),
ListBoxItem: ({ children, ...props }) => React.createElement('div', props, children),

Check warning on line 41 in frontend/__mocks__/@heroui/react.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'children' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZ0-j7dsUQIsvQ7tNHqS&open=AZ0-j7dsUQIsvQ7tNHqS&pullRequest=4434
PaginationRoot: passthrough('PaginationRoot'),
PaginationContent: passthrough('PaginationContent'),
PaginationItem: passthrough('PaginationItem'),
PaginationLink: passthrough('PaginationLink'),
PaginationPrevious: passthrough('PaginationPrevious'),
PaginationNext: passthrough('PaginationNext'),
PaginationEllipsis: passthrough('PaginationEllipsis'),
ToastProvider: () => null,
Tooltip: passthrough('Tooltip'),
Modal: passthrough('Modal'),
ModalRoot: passthrough('ModalRoot'),
ModalBody: passthrough('ModalBody'),
ModalHeader: passthrough('ModalHeader'),
ModalFooter: passthrough('ModalFooter'),
ModalContent: passthrough('ModalContent'),
ModalTrigger: passthrough('ModalTrigger'),
Skeleton: passthrough('Skeleton'),
Select: passthrough('Select'),
SelectItem: passthrough('SelectItem'),
addToast: jest.fn(),
}
96 changes: 15 additions & 81 deletions frontend/__tests__/unit/components/ModuleForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -413,19 +413,11 @@ describe('ModuleForm', () => {
jest.advanceTimersByTime(350)
})
await waitFor(() => expect(mockQuery).toHaveBeenCalled())
const selectButton = screen.getByTestId('autocomplete-select-single')
const items = await screen.findAllByTestId('autocomplete-item')
await act(async () => {
fireEvent.click(selectButton)
fireEvent.click(items[0])
})
expect(mockSetFormData).toHaveBeenCalled()
const setterFn = mockSetFormData.mock.calls[mockSetFormData.mock.calls.length - 1][0]
const result = setterFn(defaultFormData)
expect(result).toEqual(
expect.objectContaining({
projectId: 'project-1',
projectName: 'Test Project',
})
)
})

it('updates project field when ProjectSelector is cleared', async () => {
Expand Down Expand Up @@ -787,106 +779,48 @@ describe('ProjectSelector', () => {
})
})

describe('Selection Handling - handleSelectionChange (lines 401-421)', () => {
it('handles selection via Set (lines 403-404)', async () => {
describe('Selection Handling', () => {
it('selects a project when item is clicked', async () => {
mockQuery.mockResolvedValue({
data: {
searchProjects: [{ id: 'project-1', name: 'Test Project 1' }],
},
})

renderProjectSelector()

// First trigger a search to populate items
const input = screen.getByTestId('autocomplete-input')
await act(async () => {
fireEvent.change(input, { target: { value: 'Test' } })
jest.advanceTimersByTime(350)
})

await waitFor(() => {
expect(mockQuery).toHaveBeenCalled()
})

// Then select via Set
const selectButton = screen.getByTestId('autocomplete-select-item')
await act(async () => {
fireEvent.click(selectButton)
})

// Verify that typing triggers onProjectChange with the search term
await waitFor(() => {
expect(mockOnProjectChange).toHaveBeenCalledWith(null, 'Test')
})
})

it('handles "all" key selection (lines 405-406)', async () => {
mockQuery.mockResolvedValue({
data: {
searchProjects: [{ id: 'project-1', name: 'Test Project 1' }],
},
})

renderProjectSelector({ value: 'project-1', defaultName: 'Test Project 1' })
const allButton = screen.getByTestId('autocomplete-select-all')

await act(async () => {
fireEvent.click(allButton)
})

// The component's handleSelectionChange doesn't handle 'all' directly
// This test verifies the current behavior where it's not called
expect(mockOnProjectChange).not.toHaveBeenCalled()
})

it('handles single key selection (lines 407-408)', async () => {
mockQuery.mockResolvedValue({
data: {
searchProjects: [{ id: 'project-1', name: 'Test Project 1' }],
},
})

renderProjectSelector()

// First trigger a search
const input = screen.getByTestId('autocomplete-input')
await act(async () => {
fireEvent.change(input, { target: { value: 'Test' } })
jest.advanceTimersByTime(350)
})

await waitFor(() => {
expect(mockQuery).toHaveBeenCalled()
})
await waitFor(() => expect(mockQuery).toHaveBeenCalled())

// Select via single key
const singleButton = screen.getByTestId('autocomplete-select-single')
const items = await screen.findAllByTestId('autocomplete-item')
await act(async () => {
fireEvent.click(singleButton)
fireEvent.click(items[0])
})

// Verify onProjectChange is called with the selected project
expect(mockOnProjectChange).toHaveBeenCalledWith('project-1', 'Test Project 1')
})

it('clears selection when clear button is clicked (lines 411-413)', async () => {
it('clears selection when clear button is clicked', async () => {
renderProjectSelector({ value: 'project-1', defaultName: 'Existing Project' })
const clearButton = screen.getByTestId('autocomplete-clear')

await act(async () => {
fireEvent.click(clearButton)
})

// Now expected to call onProjectChange with null
expect(mockOnProjectChange).toHaveBeenCalledWith(null, '')
})
})

describe('useEffect - Value Sync (lines 349-356)', () => {
it('syncs inputValue when defaultName changes (line 351)', () => {
describe('useEffect - Value Sync', () => {
it('syncs inputValue when defaultName changes', () => {
const { rerender } = renderProjectSelector({ value: 'proj-1', defaultName: 'Project 1' })

// Rerender with different defaultName
rerender(
<ProjectSelector
value="proj-1"
Expand All @@ -899,10 +833,9 @@ describe('ProjectSelector', () => {
expect(input).toHaveValue('Updated Project Name')
})

it('clears inputValue when value and defaultName become empty (line 353)', () => {
it('clears inputValue when value and defaultName become empty', () => {
const { rerender } = renderProjectSelector({ value: 'proj-1', defaultName: 'Project 1' })

// Rerender with empty values
rerender(<ProjectSelector value="" defaultName="" onProjectChange={mockOnProjectChange} />)

const input = screen.getByTestId('autocomplete-input')
Expand Down Expand Up @@ -988,16 +921,17 @@ describe('ProjectSelector', () => {
expect(screen.getByTestId('autocomplete-error')).toHaveTextContent('Project is required')
})

it('hides error message when user is typing', () => {
it('shows error message when user has typed but parent marks field invalid', () => {
renderProjectSelector({
value: '',
defaultName: 'Typing...',
isInvalid: true,
errorMessage: 'Project is required',
})

// When typing (inputValue has text but no value selected), error should be hidden
expect(screen.queryByTestId('autocomplete-error')).not.toBeInTheDocument()
// ProjectSelector renders whatever error the parent passes via props
// touched/validation logic is handled by the parent form, not this component
expect(screen.queryByTestId('autocomplete-error')).toBeInTheDocument()
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
})
})

Expand Down
4 changes: 2 additions & 2 deletions frontend/__tests__/unit/components/ProgramForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ describe('ProgramForm Component', () => {
expect(startDateLabel).toBeInTheDocument()

// Find the date input element using getByLabelText
const startDateInput = screen.getByLabelText('Start Date') as HTMLInputElement
const startDateInput = screen.getByLabelText(/Start Date/) as HTMLInputElement
await user.type(startDateInput, '2024-01-15')

expect(mockSetFormData).toHaveBeenCalled()
Expand All @@ -739,7 +739,7 @@ describe('ProgramForm Component', () => {
expect(endDateLabel).toBeInTheDocument()

// Find the date input element using getByLabelText
const endDateInput = screen.getByLabelText('End Date') as HTMLInputElement
const endDateInput = screen.getByLabelText(/End Date/) as HTMLInputElement
await user.type(endDateInput, '2024-12-31')

expect(mockSetFormData).toHaveBeenCalled()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jest.mock('@heroui/react', () => ({
{children}
</div>
),
DropdownSection: ({ children, title }: { children: React.ReactNode; title: string }) => (
DropdownSection: ({ children, 'data-title': title }: { children: React.ReactNode; 'data-title': string }) => (
<fieldset data-testid="dropdown-section" data-title={title}>
<legend id={`section-${title}`} className="section-title">
{title}
Expand Down Expand Up @@ -586,7 +586,7 @@ describe('ProjectsDashboardDropDown Component', () => {
render(<ProjectsDashboardDropDown {...defaultProps} onAction={mockOnAction} />)

const button = screen.getByTestId('dropdown-button')
expect(button).toHaveAttribute('data-variant', 'solid')
expect(button).toHaveAttribute('data-variant', 'primary')
})

it('renders proper flex layout structure', () => {
Expand Down
Loading