First pass at some integration tests

This commit is contained in:
Tom Southall
2022-02-19 22:20:39 +00:00
parent ec8a714f73
commit 9484556d65
9 changed files with 1677 additions and 1213 deletions

2772
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,6 @@
},
"dependencies": {
"first-of-type": "^1.0.0",
"nanoid": "^3.3.1",
"prop-types": "^15.8.1",
"react-use": "^17.3.2",
"setify": "^1.0.4",
@@ -34,13 +33,17 @@
"use-debounce": "^7.0.1"
},
"devDependencies": {
"@testing-library/dom": "^8.11.3",
"@testing-library/react": "^12.1.3",
"@testing-library/react-hooks": "^7.0.2",
"@testing-library/user-event": "^13.5.0",
"@vitejs/plugin-react": "^1.0.7",
"c8": "^7.11.0",
"eslint": "^8.9.0",
"eslint-plugin-react": "^7.28.0",
"jsdom": "^19.0.0",
"msw": "^0.36.8",
"nanoid": "^3.3.1",
"node-fetch": "^2.6.7",
"react": "^17.0.2",
"react-dom": "^17.0.2",

View File

@@ -19,6 +19,7 @@ const App = () => {
id={'autocomplete'}
itemGroupsAreImmutable={true}
maxItems={10}
name={'search'}
noItemsMessage={'No matching fruit found'}
placeholder={'Type something fruity'}
styles={styles}

View File

@@ -0,0 +1,99 @@
import * as React from 'react'
import { render, screen, cleanup } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { describe, expect, test, afterEach } from 'vitest'
import Turnstone from '../index'
import { fruits } from '../../data'
describe('Integration tests', () => {
afterEach(cleanup)
test('Minimal render includes expected elements', () => {
const placeholder = 'Test placeholder'
render(<Turnstone
data={fruits}
dataSearchType={'startswith'}
placeholder={placeholder}
/>)
expect(screen.getByRole('combobox'))
expect(screen.getByPlaceholderText(placeholder)).toBeDefined()
expect(screen.queryByText('listbox')).toBeNull().toBeDefined()
expect(screen.queryByRole('button', { name: /clear contents/i })).toBeNull()
})
test('Supplying a text prop populates the query input and opens the dropdown', async () => {
const text = 'pe'
render(<Turnstone
autoFocus={true}
data={fruits}
dataSearchType={'startswith'}
text={text}
/>)
expect(screen.getByDisplayValue(text)).toBeDefined()
expect(screen.queryByRole('button', { name: /clear contents/i })).toBeDefined()
expect(await screen.findByRole('listbox')).toBeDefined()
expect(await screen.getByDisplayValue('Peach')).toBeDefined()
})
test('Supplying a clearButton prop displays the clear button', () => {
const text = 'pe'
render(<Turnstone
data={fruits}
dataSearchType={'startswith'}
text={text}
/>)
expect(screen.queryByRole('button', { name: /clear contents/i })).toBeDefined()
})
test('Changing the typed text produces the expected dropdown results', async () => {
const placeholder = 'test'
render(<Turnstone
data={fruits}
dataSearchType={'startswith'}
placeholder={placeholder}
/>)
const container = screen.getByRole('combobox')
const input = screen.getByPlaceholderText(placeholder)
const typeahead = container.children[1]
expect(input).toBeDefined()
expect(typeahead).toBeDefined()
expect(screen.queryByRole('listbox')).toBeNull()
userEvent.type(screen.getByRole('textbox'), 'p')
expect(await screen.findByRole('listbox')).toBeDefined()
expect(typeahead.value).toBe('Peach')
expect(input.value).toBe('P')
expect(screen.getByRole('option', { name: /peach/i }).getAttribute('aria-selected')).toBe('true')
userEvent.type(screen.getByRole('textbox'), 'i', { skipClick: true })
expect(screen.getByRole('listbox')).toBeDefined()
expect(await screen.findByDisplayValue('Pineapple')).toBeDefined()
expect(input.value).toBe('Pi')
expect(screen.getByRole('option', { name: /pineapple/i }).getAttribute('aria-selected')).toBe('true')
userEvent.type(screen.getByRole('textbox'), '{arrowdown}', { skipClick: true })
expect(screen.getByRole('listbox')).toBeDefined()
expect(await screen.findByDisplayValue('Pitaya')).toBeDefined()
expect(input.value).toBe('Pi')
expect(screen.getByRole('option', { name: /pineapple/i }).getAttribute('aria-selected')).toBe('false')
expect(screen.getByRole('option', { name: /pitaya/i }).getAttribute('aria-selected')).toBe('true')
userEvent.type(screen.getByRole('textbox'), '{arrowup}', { skipClick: true })
expect(screen.getByRole('listbox')).toBeDefined()
expect(await screen.findByDisplayValue('Pineapple')).toBeDefined()
expect(input.value).toBe('Pi')
expect(screen.getByRole('option', { name: /pineapple/i }).getAttribute('aria-selected')).toBe('true')
expect(screen.getByRole('option', { name: /pitaya/i }).getAttribute('aria-selected')).toBe('false')
userEvent.type(screen.getByRole('textbox'), '{backspace}', { skipClick: true })
expect(await screen.findByDisplayValue('Peach')).toBeDefined()
userEvent.type(screen.getByRole('textbox'), '{backspace}', { skipClick: true })
expect(screen.queryByRole('listbox')).toBeNull()
expect(input.value).toBe('')
expect(typeahead.value).toBe('')
})
})

View File

@@ -2,7 +2,6 @@ import * as types from './actionTypes'
import undef from '../utils/undef'
export const setQuery = (query) => {
console.log('setQuery', {query})
const payload = {
query,
selected: undef

View File

@@ -35,7 +35,6 @@ exports[`Container > Component renders correctly 1`] = `
"zIndex": 1,
}
}
tabIndex="1"
type="text"
/>
<input

View File

@@ -39,12 +39,14 @@ export default function Container(props) {
itemGroupsAreImmutable,
maxItems,
minQueryLength,
name,
noItemsMessage,
onChange,
onSelect,
onEnter,
onTab,
placeholder
placeholder,
tabIndex
} = props
// Destructure itemGroups prop
@@ -196,6 +198,7 @@ export default function Container(props) {
aria-haspopup='listbox'>
<input
id={id}
name={name}
className={customStyles.query}
style={defaultStyles.query}
disabled={isDisabled}
@@ -205,7 +208,7 @@ export default function Container(props) {
autoCorrect='off'
autoCapitalize='off'
spellCheck='false'
tabIndex='1'
tabIndex={tabIndex}
ref={queryInput}
onKeyDown={checkKey}
onInput={handleInput}

View File

@@ -92,6 +92,7 @@ Turnstone.propTypes = {
`Prop "minQueryLength" must be a number greater than ${propDefaults.minQueryLength - 1}`
)
},
name: PropTypes.string,
noItemsMessage: PropTypes.string,
onChange: PropTypes.func,
onSelect: PropTypes.func,
@@ -101,6 +102,7 @@ Turnstone.propTypes = {
maxItems: PropTypes.number,
splitChar: PropTypes.string,
styles: PropTypes.object,
tabIndex: PropTypes.number,
text: PropTypes.string
}

View File

@@ -3,6 +3,6 @@ import { defineConfig } from 'vite'
export default defineConfig({
test: {
globals: false,
environment: 'node'
environment: 'jsdom'
}
})