mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 13:49:09 +03:00
* multi-select v2
* update values
* multi-select 2 wip
* multi select 2
* multi select with combobox
* use includs
* finish multi select
* wrap badges
* overflow-x-scroll
* more
* remove multi select old from menu
* add inline search input mode in multi-select
* fix size type
* reset input when adding item
* update studio multiselector
* remove console.log
* flex-1
* remove old multi-select and decrease badge padding
* remove removeEventListener
* fix errors
* fix
* try only command
* restore inline
* Revert "fix"
This reverts commit 2fc1bea1c6.
* change callback depencency
* remove useCallback
* sdf
* remove Popover from multiselect
* udpate troubleshooting multiselect
* update
* form
* multiselect changelog
* try to remove useCallback
* fox
* bug found: checkbox in CommandItem no good
* clean up commented code
* clean up
* restore loading check
* cleanup type
* autofocus combobox input
* autofocus
* remove badgeLimit auto
* focus trigger button when hitting escape
* add tests for multi-select
* add disabled example
* remove console and useless function
* showResetIcon
* showResetIcon
* handleClose
* reset focus after reset
126 lines
4.6 KiB
TypeScript
126 lines
4.6 KiB
TypeScript
import { render, fireEvent, screen } from '@testing-library/react'
|
|
import { describe, it, expect } from 'vitest'
|
|
import {
|
|
MultiSelector,
|
|
MultiSelectorContent,
|
|
MultiSelectorInput,
|
|
MultiSelectorItem,
|
|
MultiSelectorList,
|
|
MultiSelectorTrigger,
|
|
} from 'ui-patterns/multi-select'
|
|
import { useState } from 'react'
|
|
|
|
// This fixes a "ReferenceError: ResizeObserver is not defined" error in the test
|
|
class ResizeObserver {
|
|
observe() {}
|
|
unobserve() {}
|
|
disconnect() {}
|
|
}
|
|
|
|
global.ResizeObserver = ResizeObserver
|
|
|
|
function MultiSelectDemo() {
|
|
const [selectedValues, setSelectedValues] = useState<string[]>([])
|
|
|
|
return (
|
|
<MultiSelector values={selectedValues} onValuesChange={setSelectedValues}>
|
|
<MultiSelectorTrigger className="w-72" label="Select fruits" badgeLimit="wrap" />
|
|
<MultiSelectorContent>
|
|
<MultiSelectorInput placeholder="Search fruits" showResetIcon />
|
|
<MultiSelectorList>
|
|
<MultiSelectorItem value="Apple">Apple</MultiSelectorItem>
|
|
<MultiSelectorItem value="Banana">Banana</MultiSelectorItem>
|
|
<MultiSelectorItem value="Cherry">Cherry</MultiSelectorItem>
|
|
<MultiSelectorItem value="Date">Date</MultiSelectorItem>
|
|
<MultiSelectorItem value="Elderberrie">Elderberrie</MultiSelectorItem>
|
|
<MultiSelectorItem value="Fig">Fig</MultiSelectorItem>
|
|
<MultiSelectorItem value="Grape">Grape</MultiSelectorItem>
|
|
<MultiSelectorItem value="Kiwi">Kiwi</MultiSelectorItem>
|
|
<MultiSelectorItem value="Mango" disabled>
|
|
Mango
|
|
</MultiSelectorItem>
|
|
<MultiSelectorItem value="Strawberry">Strawberry</MultiSelectorItem>
|
|
</MultiSelectorList>
|
|
</MultiSelectorContent>
|
|
</MultiSelector>
|
|
)
|
|
}
|
|
|
|
describe('multi-select', () => {
|
|
it('opens the dropdown when the MultiSelectorTrigger is clicked', () => {
|
|
render(<MultiSelectDemo />)
|
|
|
|
const trigger = screen.getByRole('combobox')
|
|
expect(screen.queryByText('Apple')).not.toBeInTheDocument() // Dropdown should be closed initially
|
|
|
|
fireEvent.click(trigger) // Click on the trigger to open
|
|
expect(screen.getByText('Apple')).toBeInTheDocument() // Apple should be visible in the dropdown
|
|
})
|
|
|
|
it('adds and removes value when toggling MultiSelectorItem', () => {
|
|
render(<MultiSelectDemo />)
|
|
|
|
const trigger = screen.getByRole('combobox')
|
|
fireEvent.click(trigger) // Open the dropdown
|
|
|
|
const appleItem = screen.getByText('Apple')
|
|
fireEvent.click(appleItem) // Select the "Apple" item
|
|
expect(trigger).toHaveTextContent('Apple') // "Apple" should appear in the selected values
|
|
|
|
fireEvent.click(appleItem) // Select the "Apple" item
|
|
expect(trigger).not.toHaveTextContent('Apple') // "Apple" should not be selected anymore
|
|
})
|
|
|
|
it('closes the dropdown when clicking outside the component', () => {
|
|
render(<MultiSelectDemo />)
|
|
|
|
const trigger = screen.getByRole('combobox')
|
|
fireEvent.click(trigger) // Open the dropdown
|
|
expect(screen.getByText('Apple')).toBeInTheDocument() // Ensure it's open
|
|
|
|
fireEvent.click(document.body) // Click outside the component
|
|
|
|
setTimeout(() => {
|
|
expect(screen.queryByText('Apple')).not.toBeInTheDocument() // The dropdown should be closed
|
|
}, 100)
|
|
})
|
|
|
|
it('removes the last value when hitting Backspace', () => {
|
|
render(<MultiSelectDemo />)
|
|
|
|
const trigger = screen.getByRole('combobox')
|
|
fireEvent.click(trigger) // Open the dropdown
|
|
|
|
const appleItem = screen.getByText('Apple')
|
|
fireEvent.click(appleItem) // Select the "Apple" item
|
|
expect(trigger).toHaveTextContent('Apple') // "Apple" should be in the selected values
|
|
|
|
fireEvent.keyDown(trigger, { key: 'Backspace' }) // Press Backspace
|
|
expect(trigger).not.toHaveTextContent('Apple') // "Apple" should be removed
|
|
})
|
|
|
|
it('supports searching and filtering items', () => {
|
|
render(<MultiSelectDemo />)
|
|
|
|
const trigger = screen.getByRole('combobox')
|
|
fireEvent.click(trigger) // Open the dropdown
|
|
|
|
const searchInput = screen.getByPlaceholderText('Search fruits')
|
|
fireEvent.change(searchInput, { target: { value: 'Ap' } }) // Search for "Ap"
|
|
|
|
expect(screen.getByText('Apple')).toBeInTheDocument() // "Apple" should be visible
|
|
expect(screen.queryByText('Banana')).not.toBeInTheDocument() // "Banana" should not be visible
|
|
})
|
|
|
|
it('prevents selecting disabled items', () => {
|
|
render(<MultiSelectDemo />)
|
|
|
|
const trigger = screen.getByRole('combobox')
|
|
fireEvent.click(trigger) // Open the dropdown
|
|
|
|
const disabledItem = screen.getByText('Mango')
|
|
fireEvent.click(disabledItem)
|
|
expect(trigger).not.toHaveTextContent('Mango') // Mango should not be selectable
|
|
})
|
|
})
|