import React from 'react'
import { render } from '../__utils/test-utils'
import userEvent from '@testing-library/user-event'
import { SearchInput } from './search-input'

describe('SearchInput', () => {
    describe('Layout', () => {
        it('should have correct role', () => {
            const { getByRole } = render(<SearchInput expanded />)
            expect(getByRole('search')).toBeInTheDocument()
        })
        it('should use placeholder', () => {
            const { getByPlaceholderText } = render(
                <SearchInput expanded placeholder="test placeholder" />
            )
            expect(getByPlaceholderText('test placeholder')).toBeInTheDocument()
        })
        it('should use value', () => {
            const { getByDisplayValue } = render(
                <SearchInput expanded value="test value" />
            )
            expect(getByDisplayValue('test value')).toBeInTheDocument()
        })
        it('should use defaultValue', () => {
            const { getByDisplayValue } = render(
                <SearchInput expanded defaultValue="test value" />
            )
            expect(getByDisplayValue('test value')).toBeInTheDocument()
        })
    })
    describe('Interaction', () => {
        it('should update uncontrolled', async () => {
            const spy = jest.fn()
            const { getByLabelText } = render(
                <SearchInput expanded onChange={spy} />
            )
            await userEvent.keyboard('{Tab}')
            expect(getByLabelText('Search')).toHaveFocus()
            expect(spy).toHaveBeenCalledTimes(0)
            await userEvent.keyboard('abcd')
            expect(getByLabelText('Search')).toHaveValue('abcd')
            expect(spy).toHaveBeenCalledTimes(4)
        })
        it('should clear value uncontrolled', async () => {
            const spy = jest.fn()
            const { getByLabelText } = render(
                <SearchInput
                    expanded
                    defaultValue="Hello world"
                    onChange={spy}
                />
            )
            expect(spy).toHaveBeenCalledTimes(0)
            await userEvent.click(getByLabelText('Clear search'))
            expect(getByLabelText('Search')).toHaveValue('')
            expect(spy).toHaveBeenCalledTimes(1)
            expect(spy).toHaveBeenCalledWith(
                '',
                expect.objectContaining({ type: 'change' })
            )
        })
        it('should not update controlled but call onChange', async () => {
            const spy = jest.fn()
            const { getByLabelText } = render(
                <SearchInput expanded value="" onChange={spy} />
            )
            await userEvent.keyboard('{Tab}')
            expect(getByLabelText('Search')).toHaveFocus()
            expect(spy).toHaveBeenCalledTimes(0)
            await userEvent.keyboard('abcd')
            expect(getByLabelText('Search')).toHaveValue('')
            expect(spy).toHaveBeenCalledTimes(4)
        })
        it('should not clear value controlled but call onClear', async () => {
            const spy = jest.fn()
            const { getByLabelText } = render(
                <SearchInput expanded value="Hello world" onChange={spy} />
            )
            expect(spy).toHaveBeenCalledTimes(0)
            await userEvent.click(getByLabelText('Clear search'))
            expect(getByLabelText('Search')).toHaveValue('Hello world')
            expect(spy).toHaveBeenCalledTimes(1)
            expect(spy).toHaveBeenCalledWith(
                '',
                expect.objectContaining({ type: 'change' })
            )
        })
    })
})
