mirror of
https://github.com/fergalmoran/turnstone.git
synced 2025-12-26 03:39:20 +00:00
Add useSWR error handling, errorMessage prop and errorbox component
This commit is contained in:
@@ -59,6 +59,7 @@ const App = () => {
|
|||||||
debounceWait={250}
|
debounceWait={250}
|
||||||
defaultListbox={defaultListbox}
|
defaultListbox={defaultListbox}
|
||||||
defaultListboxIsImmutable={false}
|
defaultListboxIsImmutable={false}
|
||||||
|
errorMessage={'Sorry, something has broken!'}
|
||||||
id='autocomplete'
|
id='autocomplete'
|
||||||
listbox={listbox}
|
listbox={listbox}
|
||||||
listboxIsImmutable={true}
|
listboxIsImmutable={true}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@
|
|||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listbox {
|
.listbox,
|
||||||
|
.errorbox {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
border-left: 1px solid #ccc;
|
border-left: 1px solid #ccc;
|
||||||
@@ -41,12 +42,16 @@
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.noItems {
|
.noItems,
|
||||||
margin: 8em auto;
|
.errorMessage {
|
||||||
height: 38px;
|
margin: 2em auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.errorMessage {
|
||||||
|
color: rgb(175, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
.groupHeading {
|
.groupHeading {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const App = () => {
|
|||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
clearButton={true}
|
clearButton={true}
|
||||||
debounceWait={0}
|
debounceWait={0}
|
||||||
|
errorMessage={'Houston we have a problem'}
|
||||||
listbox={listbox1}
|
listbox={listbox1}
|
||||||
listboxIsImmutable={true}
|
listboxIsImmutable={true}
|
||||||
maxItems={10}
|
maxItems={10}
|
||||||
@@ -47,6 +48,7 @@ const App = () => {
|
|||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
clearButton={true}
|
clearButton={true}
|
||||||
debounceWait={0}
|
debounceWait={0}
|
||||||
|
errorMessage={'Something is broken'}
|
||||||
listbox={listbox2}
|
listbox={listbox2}
|
||||||
listboxIsImmutable={true}
|
listboxIsImmutable={true}
|
||||||
matchText={true}
|
matchText={true}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export const SET_QUERY = 'SET_QUERY'
|
export const SET_QUERY = 'SET_QUERY'
|
||||||
export const SET_ITEMS = 'SET_ITEMS'
|
export const SET_ITEMS = 'SET_ITEMS'
|
||||||
|
export const SET_ITEMS_ERROR = 'SET_ITEMS_ERROR'
|
||||||
export const CLEAR = 'CLEAR'
|
export const CLEAR = 'CLEAR'
|
||||||
export const SET_HIGHLIGHTED = 'SET_HIGHLIGHTED'
|
export const SET_HIGHLIGHTED = 'SET_HIGHLIGHTED'
|
||||||
export const CLEAR_HIGHLIGHTED = 'CLEAR_HIGHLIGHTED'
|
export const CLEAR_HIGHLIGHTED = 'CLEAR_HIGHLIGHTED'
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ export const setItems = (items) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const setItemsError = () => {
|
||||||
|
return {
|
||||||
|
type: types.SET_ITEMS_ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const clear = () => {
|
export const clear = () => {
|
||||||
return {
|
return {
|
||||||
type: types.CLEAR
|
type: types.CLEAR
|
||||||
|
|||||||
@@ -18,6 +18,13 @@ describe('Actions', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('setItemsError returns expected action', () => {
|
||||||
|
const action = actions.setItemsError()
|
||||||
|
expect(action).toEqual({
|
||||||
|
type: 'SET_ITEMS_ERROR'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('clear returns expected action', () => {
|
test('clear returns expected action', () => {
|
||||||
const action = actions.clear()
|
const action = actions.clear()
|
||||||
expect(action).toEqual({
|
expect(action).toEqual({
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useRef, useContext } from 'react'
|
import React, { useState, useRef, useContext } from 'react'
|
||||||
import { StateContext } from '../context/state'
|
import { StateContext } from '../context/state'
|
||||||
import Listbox from './listbox'
|
import Listbox from './listbox'
|
||||||
|
import Errorbox from './errorbox'
|
||||||
import { useDebounce } from 'use-debounce'
|
import { useDebounce } from 'use-debounce'
|
||||||
import useData from './hooks/useData'
|
import useData from './hooks/useData'
|
||||||
import undef from '../utils/undef'
|
import undef from '../utils/undef'
|
||||||
@@ -8,6 +9,7 @@ import isUndefined from '../utils/isUndefined'
|
|||||||
import defaultStyles from './styles/input.styles.js'
|
import defaultStyles from './styles/input.styles.js'
|
||||||
import {
|
import {
|
||||||
useItemsState,
|
useItemsState,
|
||||||
|
useItemsError,
|
||||||
useAutoFocus,
|
useAutoFocus,
|
||||||
useQueryChange,
|
useQueryChange,
|
||||||
useHighlight,
|
useHighlight,
|
||||||
@@ -33,6 +35,7 @@ export default function Container(props) {
|
|||||||
defaultListbox,
|
defaultListbox,
|
||||||
defaultListboxIsImmutable,
|
defaultListboxIsImmutable,
|
||||||
disabled,
|
disabled,
|
||||||
|
errorMessage,
|
||||||
id,
|
id,
|
||||||
listboxIsImmutable,
|
listboxIsImmutable,
|
||||||
maxItems,
|
maxItems,
|
||||||
@@ -53,6 +56,7 @@ export default function Container(props) {
|
|||||||
: [{ ...props.listbox, ...{ name: '', ratio: maxItems } }]
|
: [{ ...props.listbox, ...{ name: '', ratio: maxItems } }]
|
||||||
|
|
||||||
const listboxId = `${id}-listbox`
|
const listboxId = `${id}-listbox`
|
||||||
|
const errorboxId = `${id}-errorbox`
|
||||||
|
|
||||||
// Global state from context
|
// Global state from context
|
||||||
const { state, dispatch } = useContext(StateContext)
|
const { state, dispatch } = useContext(StateContext)
|
||||||
@@ -66,6 +70,11 @@ export default function Container(props) {
|
|||||||
const queryInput = useRef(null)
|
const queryInput = useRef(null)
|
||||||
const typeaheadInput = useRef(null)
|
const typeaheadInput = useRef(null)
|
||||||
|
|
||||||
|
// Calculated states
|
||||||
|
const hasClearButton = clearButton && !!state.query
|
||||||
|
const isExpanded = hasFocus && state.itemsLoaded
|
||||||
|
const isErrorExpanded = !!props.errorMessage && state.itemsError
|
||||||
|
|
||||||
// Checks whether or not SWR data is to be treated as immutable
|
// Checks whether or not SWR data is to be treated as immutable
|
||||||
const isImmutable = (() => {
|
const isImmutable = (() => {
|
||||||
return listboxIsImmutable &&
|
return listboxIsImmutable &&
|
||||||
@@ -77,7 +86,7 @@ export default function Container(props) {
|
|||||||
})()
|
})()
|
||||||
|
|
||||||
// Hook to retrieve data using SWR
|
// Hook to retrieve data using SWR
|
||||||
const swrData = useData(
|
const swrResult = useData(
|
||||||
debouncedQuery.toLowerCase(),
|
debouncedQuery.toLowerCase(),
|
||||||
isImmutable,
|
isImmutable,
|
||||||
listbox,
|
listbox,
|
||||||
@@ -85,10 +94,13 @@ export default function Container(props) {
|
|||||||
minQueryLength,
|
minQueryLength,
|
||||||
maxItems,
|
maxItems,
|
||||||
dispatch
|
dispatch
|
||||||
).data
|
)
|
||||||
|
|
||||||
// Store retrieved data in global state as state.items
|
// Store retrieved data in global state as state.items
|
||||||
useItemsState(swrData)
|
useItemsState(swrResult.data)
|
||||||
|
|
||||||
|
// Store retrieved error if there is one
|
||||||
|
useItemsError(swrResult.error)
|
||||||
|
|
||||||
// Autofocus on render if prop is true
|
// Autofocus on render if prop is true
|
||||||
useAutoFocus(queryInput, autoFocus)
|
useAutoFocus(queryInput, autoFocus)
|
||||||
@@ -114,14 +126,6 @@ export default function Container(props) {
|
|||||||
if (typeof f === 'function') f(queryInput.current.value, highlightedItem)
|
if (typeof f === 'function') f(queryInput.current.value, highlightedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasClearButton = () => {
|
|
||||||
return clearButton && !!state.query
|
|
||||||
}
|
|
||||||
|
|
||||||
const isExpanded = (() => {
|
|
||||||
return hasFocus && state.itemsLoaded
|
|
||||||
})()
|
|
||||||
|
|
||||||
// Handle different keypresses and call the appropriate action creators
|
// Handle different keypresses and call the appropriate action creators
|
||||||
const checkKey = (evt) => {
|
const checkKey = (evt) => {
|
||||||
switch (evt.keyCode) {
|
switch (evt.keyCode) {
|
||||||
@@ -223,7 +227,7 @@ export default function Container(props) {
|
|||||||
ref={typeaheadInput}
|
ref={typeaheadInput}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{hasClearButton() && (
|
{hasClearButton && (
|
||||||
<div
|
<div
|
||||||
className={customStyles.clearButton}
|
className={customStyles.clearButton}
|
||||||
style={defaultStyles.clearButton}
|
style={defaultStyles.clearButton}
|
||||||
@@ -240,6 +244,10 @@ export default function Container(props) {
|
|||||||
noItemsMessage={noItemsMessage}
|
noItemsMessage={noItemsMessage}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isErrorExpanded && (
|
||||||
|
<Errorbox id={errorboxId} errorMessage={errorMessage} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { fruits } from '../../data'
|
|||||||
vi.mock('./listbox', () => ({ default: () => 'Listbox' }))
|
vi.mock('./listbox', () => ({ default: () => 'Listbox' }))
|
||||||
vi.mock('./hooks/containerEffects', () => ({
|
vi.mock('./hooks/containerEffects', () => ({
|
||||||
useItemsState: vi.fn(),
|
useItemsState: vi.fn(),
|
||||||
|
useItemsError: vi.fn(),
|
||||||
useAutoFocus: vi.fn(),
|
useAutoFocus: vi.fn(),
|
||||||
useQueryChange: vi.fn(),
|
useQueryChange: vi.fn(),
|
||||||
useHighlight: vi.fn(),
|
useHighlight: vi.fn(),
|
||||||
|
|||||||
15
src/lib/components/errorbox.jsx
Normal file
15
src/lib/components/errorbox.jsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import React, { useContext } from 'react'
|
||||||
|
import { StateContext } from '../context/state'
|
||||||
|
import defaultStyles from './styles/listbox.styles.js'
|
||||||
|
|
||||||
|
export default function Errorbox(props) {
|
||||||
|
const { id, errorMessage } = props
|
||||||
|
const { state } = useContext(StateContext)
|
||||||
|
const { customStyles } = state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id={id} className={customStyles.errorbox} style={defaultStyles.listbox}>
|
||||||
|
<div className={customStyles.errorMessage}>{errorMessage}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useContext } from 'react'
|
import { useEffect, useContext } from 'react'
|
||||||
import setify from 'setify' // Sets input value without changing cursor position
|
import setify from 'setify' // Sets input value without changing cursor position
|
||||||
import { StateContext } from '../../context/state'
|
import { StateContext } from '../../context/state'
|
||||||
import { setItems } from '../../actions/actions'
|
import { setItems, setItemsError } from '../../actions/actions'
|
||||||
import isUndefined from '../../utils/isUndefined'
|
import isUndefined from '../../utils/isUndefined'
|
||||||
import undef from '../../utils/undef'
|
import undef from '../../utils/undef'
|
||||||
import startsWithCaseInsensitive from '../../utils/startsWithCaseInsensitive'
|
import startsWithCaseInsensitive from '../../utils/startsWithCaseInsensitive'
|
||||||
@@ -14,6 +14,14 @@ export const useItemsState = (swrData) => {
|
|||||||
}, [swrData])
|
}, [swrData])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useItemsError = (error) => {
|
||||||
|
const { dispatch } = useContext(StateContext)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(error) dispatch(setItemsError())
|
||||||
|
}, [error])
|
||||||
|
}
|
||||||
|
|
||||||
export const useAutoFocus = (queryInput, autoFocus) => { // TODO: might be able to use autofocus property of input for this - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autofocus
|
export const useAutoFocus = (queryInput, autoFocus) => { // TODO: might be able to use autofocus property of input for this - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-autofocus
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (autoFocus) queryInput.current.focus()
|
if (autoFocus) queryInput.current.focus()
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ export const fetcher = (query, listbox, defaultListbox, minQueryLength, maxItems
|
|||||||
|
|
||||||
return groups.flat()
|
return groups.flat()
|
||||||
})
|
})
|
||||||
|
.catch(() => {throw('Something went wrong')})
|
||||||
|
//TODO Put a .catch here https://javascript.info/promise-error-handling
|
||||||
}
|
}
|
||||||
|
|
||||||
const useData = (query, isImmutable, listbox, defaultListbox, minQueryLength, maxItems) => {
|
const useData = (query, isImmutable, listbox, defaultListbox, minQueryLength, maxItems) => {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const StateContextProvider = (props) => {
|
|||||||
const [state, dispatch] = useReducer(reducer, {
|
const [state, dispatch] = useReducer(reducer, {
|
||||||
query: text,
|
query: text,
|
||||||
items,
|
items,
|
||||||
|
itemsError: false,
|
||||||
itemsLoaded: false,
|
itemsLoaded: false,
|
||||||
highlighted: undef,
|
highlighted: undef,
|
||||||
selected: undef,
|
selected: undef,
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ Turnstone.propTypes = {
|
|||||||
defaultListboxIsImmutable: PropTypes.bool,
|
defaultListboxIsImmutable: PropTypes.bool,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
displayField: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
displayField: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||||
|
errorMessage: PropTypes.string,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
listbox: listboxRules.isRequired,
|
listbox: listboxRules.isRequired,
|
||||||
listboxIsImmutable: PropTypes.bool,
|
listboxIsImmutable: PropTypes.bool,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const reducer = (state, action) => {
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case types.SET_QUERY:
|
case types.SET_QUERY:
|
||||||
newState = {
|
newState = {
|
||||||
|
itemsError: false,
|
||||||
query: action.query,
|
query: action.query,
|
||||||
selected: undef
|
selected: undef
|
||||||
}
|
}
|
||||||
@@ -29,6 +30,7 @@ const reducer = (state, action) => {
|
|||||||
case types.SET_ITEMS:
|
case types.SET_ITEMS:
|
||||||
newState = {
|
newState = {
|
||||||
items: action.items,
|
items: action.items,
|
||||||
|
itemsError: false,
|
||||||
highlighted: (action.items.length && state.query.length)
|
highlighted: (action.items.length && state.query.length)
|
||||||
? highlightedItem(0, action.items)
|
? highlightedItem(0, action.items)
|
||||||
: undef
|
: undef
|
||||||
@@ -40,10 +42,17 @@ const reducer = (state, action) => {
|
|||||||
return {
|
return {
|
||||||
query: '',
|
query: '',
|
||||||
items: [],
|
items: [],
|
||||||
|
itemsError: false,
|
||||||
itemsLoaded: false,
|
itemsLoaded: false,
|
||||||
highlighted: undef,
|
highlighted: undef,
|
||||||
selected: undef
|
selected: undef
|
||||||
}
|
}
|
||||||
|
case types.SET_ITEMS_ERROR:
|
||||||
|
return {
|
||||||
|
items: [],
|
||||||
|
itemsError: true,
|
||||||
|
itemsLoaded: false
|
||||||
|
}
|
||||||
case types.SET_HIGHLIGHTED:
|
case types.SET_HIGHLIGHTED:
|
||||||
return { highlighted: highlightedItem(action.index, state.items) }
|
return { highlighted: highlightedItem(action.index, state.items) }
|
||||||
case types.CLEAR_HIGHLIGHTED:
|
case types.CLEAR_HIGHLIGHTED:
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import defaultListbox from '../../../examples/_shared/defaultListbox'
|
|||||||
describe('SET_QUERY action', () => {
|
describe('SET_QUERY action', () => {
|
||||||
test('produces expected new state', () => {
|
test('produces expected new state', () => {
|
||||||
const state = {
|
const state = {
|
||||||
|
itemsError: true,
|
||||||
query: 'foo',
|
query: 'foo',
|
||||||
selected: {index: 0, text: 'Foobar'},
|
selected: {index: 0, text: 'Foobar'},
|
||||||
props: {
|
props: {
|
||||||
@@ -17,6 +18,7 @@ describe('SET_QUERY action', () => {
|
|||||||
const action = actions.setQuery('bar')
|
const action = actions.setQuery('bar')
|
||||||
|
|
||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
|
itemsError: false,
|
||||||
query: 'bar',
|
query: 'bar',
|
||||||
selected: undef,
|
selected: undef,
|
||||||
props: {
|
props: {
|
||||||
@@ -37,6 +39,7 @@ describe('SET_QUERY action', () => {
|
|||||||
const action = actions.setQuery('')
|
const action = actions.setQuery('')
|
||||||
|
|
||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
|
itemsError: false,
|
||||||
query: '',
|
query: '',
|
||||||
selected: undef,
|
selected: undef,
|
||||||
itemsLoaded: false,
|
itemsLoaded: false,
|
||||||
@@ -56,6 +59,7 @@ describe('SET_QUERY action', () => {
|
|||||||
const action = actions.setQuery('f')
|
const action = actions.setQuery('f')
|
||||||
|
|
||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
|
itemsError: false,
|
||||||
query: 'f',
|
query: 'f',
|
||||||
selected: undef,
|
selected: undef,
|
||||||
itemsLoaded: false,
|
itemsLoaded: false,
|
||||||
@@ -78,6 +82,7 @@ describe('SET_QUERY action', () => {
|
|||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
query: '',
|
query: '',
|
||||||
selected: undef,
|
selected: undef,
|
||||||
|
itemsError: false,
|
||||||
itemsLoaded: true,
|
itemsLoaded: true,
|
||||||
props: {
|
props: {
|
||||||
minQueryLength: 1,
|
minQueryLength: 1,
|
||||||
@@ -91,6 +96,7 @@ describe('SET_ITEMS action', () => {
|
|||||||
test('produces expected new state', () => {
|
test('produces expected new state', () => {
|
||||||
const state = {
|
const state = {
|
||||||
query: 'foo',
|
query: 'foo',
|
||||||
|
itemsError: true,
|
||||||
itemsLoaded: false
|
itemsLoaded: false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +111,7 @@ describe('SET_ITEMS action', () => {
|
|||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
query: 'foo',
|
query: 'foo',
|
||||||
items,
|
items,
|
||||||
|
itemsError: false,
|
||||||
itemsLoaded: true,
|
itemsLoaded: true,
|
||||||
highlighted: { index: 0, text: 'foo' }
|
highlighted: { index: 0, text: 'foo' }
|
||||||
})
|
})
|
||||||
@@ -122,6 +129,7 @@ describe('SET_ITEMS action', () => {
|
|||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
query: 'foo',
|
query: 'foo',
|
||||||
items,
|
items,
|
||||||
|
itemsError: false,
|
||||||
highlighted: undef
|
highlighted: undef
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -138,6 +146,7 @@ describe('SET_ITEMS action', () => {
|
|||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
query: '',
|
query: '',
|
||||||
items,
|
items,
|
||||||
|
itemsError: false,
|
||||||
highlighted: undef
|
highlighted: undef
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -158,12 +167,36 @@ describe('SET_ITEMS action', () => {
|
|||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
query: '',
|
query: '',
|
||||||
items,
|
items,
|
||||||
|
itemsError: false,
|
||||||
itemsLoaded: true,
|
itemsLoaded: true,
|
||||||
highlighted: undef
|
highlighted: undef
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('SET_ITEMS_ERROR action', () => {
|
||||||
|
test('produces expected new state', () => {
|
||||||
|
let action
|
||||||
|
const state = {
|
||||||
|
items: [
|
||||||
|
{text: 'foo'},
|
||||||
|
{text: 'foobar'},
|
||||||
|
{text: 'foofoo'}
|
||||||
|
],
|
||||||
|
itemsError: false,
|
||||||
|
itemsLoaded: true
|
||||||
|
}
|
||||||
|
|
||||||
|
action = actions.setItemsError()
|
||||||
|
|
||||||
|
expect(reducer(state, action)).toEqual({
|
||||||
|
items: [],
|
||||||
|
itemsError: true,
|
||||||
|
itemsLoaded: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('CLEAR action', () => {
|
describe('CLEAR action', () => {
|
||||||
test('produces expected new state', () => {
|
test('produces expected new state', () => {
|
||||||
let action
|
let action
|
||||||
@@ -174,6 +207,7 @@ describe('CLEAR action', () => {
|
|||||||
{text: 'foobar'},
|
{text: 'foobar'},
|
||||||
{text: 'foofoo'}
|
{text: 'foofoo'}
|
||||||
],
|
],
|
||||||
|
itemsError: true,
|
||||||
itemsLoaded: true,
|
itemsLoaded: true,
|
||||||
highlighted: { index: 0, text: 'foo' },
|
highlighted: { index: 0, text: 'foo' },
|
||||||
selected: {text: 'foo'}
|
selected: {text: 'foo'}
|
||||||
@@ -184,6 +218,7 @@ describe('CLEAR action', () => {
|
|||||||
expect(reducer(state, action)).toEqual({
|
expect(reducer(state, action)).toEqual({
|
||||||
query: '',
|
query: '',
|
||||||
items: [],
|
items: [],
|
||||||
|
itemsError: false,
|
||||||
itemsLoaded: false,
|
itemsLoaded: false,
|
||||||
highlighted: undef,
|
highlighted: undef,
|
||||||
selected: undef
|
selected: undef
|
||||||
|
|||||||
Reference in New Issue
Block a user