import { renderHook, act } from '@testing-library/react-hooks'
import React from 'react'
import {
SearchkitClient,
SearchkitContext,
SearchkitProvider,
useSearchkit,
useSearchkitQuery,
useSearchkitVariables,
useSearchkitQueryValue,
SearchkitClientConfig
} from '../searchkit'
const initial = {
query: '',
filters: [],
sortBy: '',
page: {
size: 10,
from: 0
}
}
const createSearchkitClient = (config: SearchkitClientConfig = {}) => {
const state = Object.assign({}, initial)
const setState = (arg) => {
Object.assign(state, arg(state))
}
const api = new SearchkitClient(config)
api.setSearchState = setState
api.searchState = state
return api
}
describe('Searchkit Client', () => {
it('should be exportable', () => {
expect(SearchkitClient).not.toBeNull()
expect(SearchkitProvider).not.toBeNull()
expect(SearchkitContext).not.toBeNull()
expect(useSearchkit).not.toBeNull()
})
it('default state to be empty', () => {
const api = createSearchkitClient()
expect(api.getQuery()).toBe('')
expect(api.getFilters()).toEqual([])
expect(api.getFiltersByIdentifier('anId')).toEqual([])
expect(api.canResetSearch()).toBe(false)
expect(api.baseSearchState.page.size).toBe(10)
})
it('allow to change items per page', () => {
const api = createSearchkitClient({
itemsPerPage: 20
})
expect(api.baseSearchState.page.size).toBe(20)
})
it('should be able to manipulate query', () => {
const api = createSearchkitClient()
expect(api.getQuery()).toBe('')
api.setQuery('heat')
expect(api.getQuery()).toBe('heat')
expect(api.canResetSearch()).toBeTruthy()
api.setQuery('')
expect(api.canResetSearch()).toBeFalsy()
})
it('should be able to manipulate filters', () => {
const api = createSearchkitClient()
expect(api.getFilters()).toEqual([])
api.addFilter({ identifier: 'type', value: 'Movie' })
expect(api.getFilters()).toEqual([{ identifier: 'type', value: 'Movie' }])
expect(api.getFiltersByIdentifier('type')).toEqual([{ identifier: 'type', value: 'Movie' }])
expect(api.getFiltersByIdentifier('missing')).toEqual([])
expect(api.canResetSearch()).toBeTruthy()
// setting the query should reset filters
api.setQuery('new query')
expect(api.getFilters()).toEqual([])
expect(api.canResetSearch()).toBeTruthy()
})
it('should be able to manage pagination', () => {
const api = createSearchkitClient()
api.setPage({ from: 10, size: 10 })
})
it('should toggle filter and keep order', () => {
const api = createSearchkitClient()
api.addFilter({ identifier: 'type', value: 'Movies' })
api.addFilter({ identifier: 'type', value: 'Games' })
expect(api.getFilters()).toEqual([
{ identifier: 'type', value: 'Games' },
{ identifier: 'type', value: 'Movies' }
])
api.toggleFilter({ identifier: 'type', value: 'Movies' })
expect(api.getFilters()).toEqual([{ identifier: 'type', value: 'Games' }])
api.toggleFilter({ identifier: 'type', value: 'Movies' })
expect(api.getFilters()).toEqual([
{ identifier: 'type', value: 'Movies' },
{ identifier: 'type', value: 'Games' }
])
})
it('should toggle range filters', () => {
const api = createSearchkitClient()
api.addFilter({ identifier: 'type', min: 0, max: 100 })
expect(api.getFilters()).toEqual([{ identifier: 'type', min: 0, max: 100 }])
api.toggleFilter({ identifier: 'type', min: 0, max: 100 })
expect(api.getFilters()).toEqual([])
})
it('should toggle range filters min / max optional', () => {
const api = createSearchkitClient()
api.addFilter({ identifier: 'type', min: 0, max: null })
expect(api.getFilters()).toEqual([{ identifier: 'type', min: 0, max: null }])
api.toggleFilter({ identifier: 'type', min: 0, max: null })
expect(api.getFilters()).toEqual([])
})
it('should toggle level value filters', () => {
const api = createSearchkitClient()
api.addFilter({ identifier: 'type', value: 'test', level: 1 })
api.addFilter({ identifier: 'type', value: 'level2', level: 2 })
expect(api.getFilters()).toEqual([
{ identifier: 'type', value: 'level2', level: 2 },
{ identifier: 'type', value: 'test', level: 1 }
])
api.toggleFilter({ identifier: 'type', value: 'level2', level: 2 })
expect(api.getFilters()).toEqual([{ identifier: 'type', value: 'test', level: 1 }])
})
it('should toggle date range filters', () => {
const api = createSearchkitClient()
const filter = {
identifier: 'type',
dateMin: '2012-12-26T00:00:00.000Z',
dateMax: '2020-12-26T00:00:00.000Z'
}
api.addFilter({ ...filter })
expect(api.getFilters()).toEqual([filter])
api.toggleFilter({ ...filter })
expect(api.getFilters()).toEqual([])
})
it('should toggle date range filters min / max optional', () => {
const api = createSearchkitClient()
api.addFilter({ identifier: 'released', dateMin: '2020-12-26T00:00:00.000Z', dateMax: null })
expect(api.getFilters()).toEqual([
{ identifier: 'released', dateMin: '2020-12-26T00:00:00.000Z', dateMax: null }
])
api.toggleFilter({ identifier: 'released', dateMin: '2020-12-26T00:00:00.000Z', dateMax: null })
expect(api.getFilters()).toEqual([])
})
it('should remove multiple filters by id', () => {
const api = createSearchkitClient()
api.addFilter({ identifier: 'type', value: 'Movies' })
api.addFilter({ identifier: 'type', value: 'Games' })
api.removeFiltersByIdentifier('type')
expect(api.getFilters()).toEqual([])
})
it('should determine whether a filter has been applied or not', () => {
const api = createSearchkitClient()
api.addFilter({ identifier: 'type', value: 'Movies' })
api.addFilter({ identifier: 'type', value: 'Games' })
expect(api.isFilterSelected({ identifier: 'type', value: 'Movies' })).toBeTruthy()
expect(api.isFilterSelected({ identifier: 'type', value: 'no match' })).toBeFalsy()
})
it('should pass state within callback', () => {
const callback = jest.fn()
const api = createSearchkitClient()
api.setCallbackFn(callback)
api.setQuery('test')
api.addFilter({ identifier: 'type', value: 'Movies' })
api.setPage({ from: 10, size: 20 })
api.setSortBy('released')
api.search()
expect(callback).toBeCalledWith({
filters: [{ identifier: 'type', value: 'Movies' }],
page: { from: 10, size: 20 },
query: 'test',
sortBy: 'released'
})
})
it('Searchkit Provider + Hook', () => {
const api = createSearchkitClient()
const wrapper = ({ children }) => {children}
const { result } = renderHook(() => useSearchkit(), { wrapper })
act(() => {
result.current.setQuery('test')
})
expect(api.getQuery()).toBe('test')
})
it('variables lifecycle', async () => {
const api = createSearchkitClient()
api.updateBaseSearchState({
query: 'test',
filters: [{ identifier: 'type', value: 'Movies' }],
sortBy: 'released'
})
const wrapper = ({ children }) => {children}
const variablesHook = renderHook(() => useSearchkitVariables(), { wrapper })
expect(variablesHook.result.current).toEqual({
filters: [{ identifier: 'type', value: 'Movies' }],
page: { from: 0, size: 10 },
query: 'test',
sortBy: 'released'
})
act(() => {
api.setQuery('hello')
})
variablesHook.rerender()
expect(variablesHook.result.current).toEqual({
filters: [{ identifier: 'type', value: 'Movies' }],
page: { from: 0, size: 10 },
query: 'test',
sortBy: 'released'
})
act(() => {
api.search()
})
expect(variablesHook.result.current).toEqual({
filters: [],
page: { from: 0, size: 10 },
query: 'hello',
sortBy: 'released'
})
})
})
describe('useSearchkitQuery', () => {
it('should update when api state is updated', () => {
const api = createSearchkitClient()
api.updateBaseSearchState({
query: 'test',
filters: [{ identifier: 'type', value: 'Movies' }],
sortBy: 'released'
})
const wrapper = ({ children }) => {children}
const queryValueHook = renderHook(() => useSearchkitQueryValue(), { wrapper })
expect(queryValueHook.result.current[0]).toEqual('test')
act(() => {
api.setQuery('hello')
})
queryValueHook.rerender()
expect(queryValueHook.result.current[0]).toEqual('hello')
act(() => {
queryValueHook.result.current[1]('test')
})
expect(queryValueHook.result.current[0]).toEqual('test')
})
})