@ -1,25 +1,45 @@
/* eslint-disable jest/require-top-level-describe */
import React from 'react' ;
import React , { useState } from 'react' ;
import { fireEvent , render } from '@testing-library/react' ;
import userEvent from '@testing-library/user-event' ;
import { TextField } from './text-field' ;
// userEvent setup function as per testing-library docs
// https://testing-library.com/docs/user-event/intr
function setup ( jsx ) {
return {
user : userEvent . setup ( ) ,
... render ( jsx ) ,
} ;
}
// Custom userEvent setup function that renders the component in a controlled environment.
// This is used for the showClearButton and related props as the clearButton will only show in a controlled environment.
function setupControlled ( FormComponent , props ) {
const ControlledWrapper = ( ) => {
const [ value , setValue ] = useState ( '' ) ;
return (
< FormComponent
value = { value }
onChange = { ( e ) => setValue ( e . target . value ) }
{ ... props }
/ >
) ;
} ;
return { user : userEvent . setup ( ) , ... render ( < ControlledWrapper / > ) } ;
}
describe ( 'TextField' , ( ) => {
it ( 'should render correctly' , ( ) => {
const { getByRole } = render ( < TextField / > ) ;
expect ( getByRole ( 'textbox' ) ) . toBeDefined ( ) ;
} ) ;
it ( 'should render and be able to input text' , ( ) => {
const { getByTestId } = render (
< TextField inputProps = { { 'data-testid' : 'text-field' } } / > ,
) ;
const textField = getByTestId ( 'text-field' ) ;
expect ( textField . value ) . toBe ( '' ) ; // initial value is empty string
fireEvent . change ( textField , { target : { value : 'text value' } } ) ;
expect ( textField . value ) . toBe ( 'text value' ) ;
fireEvent . change ( textField , { target : { value : '' } } ) ; // reset value
expect ( textField . value ) . toBe ( '' ) ; // value is empty string after reset
it ( 'should render and be able to input text' , async ( ) => {
const { user , getByRole } = setup ( < TextField / > ) ;
const textField = getByRole ( 'textbox' ) ;
await user . type ( textField , 'text value' ) ;
expect ( textField ) . toHaveValue ( 'text value' ) ;
} ) ;
it ( 'should render and fire onFocus and onBlur events' , ( ) => {
const onFocus = jest . fn ( ) ;
@ -38,124 +58,80 @@ describe('TextField', () => {
fireEvent . blur ( textField ) ;
expect ( onBlur ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
it ( 'should render and fire onChange event' , ( ) => {
it ( 'should render and fire onChange event' , async ( ) => {
const onChange = jest . fn ( ) ;
const { getByTestId } = render (
const { user , getByRole } = setup (
< TextField
inputProps = { { 'data-testid' : 'text-field' } }
onChange = { onChange }
/ > ,
) ;
const textField = getByTestId ( 'text-field ' ) ;
const textField = getByRole ( 'textbox ' ) ;
fireEvent . change ( textField , { target : { value : 'text value' } } ) ;
expect ( onChange ) . toHaveBeenCalledTimes ( 1 ) ;
await user . type ( textField , '123' ) ;
expect ( textField ) . toHaveValue ( '123' ) ;
expect ( onChange ) . toHaveBeenCalledTimes ( 3 ) ;
} ) ;
it ( 'should render and fire onClick event' , ( ) => {
it ( 'should render and fire onClick event' , async ( ) => {
const onClick = jest . fn ( ) ;
const { getByTestId } = render (
< TextField
inputProps = { { 'data-testid' : 'text-field' } }
onClick = { onClick }
/ > ,
const { user , getByTestId } = setup (
< TextField data - testid = "text-field" onClick = { onClick } / > ,
) ;
const textField = getByTestId ( 'text-field' ) ;
fireEvent . click ( textField ) ;
await user . click ( getByTestId ( 'text-field' ) ) ;
expect ( onClick ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
it ( 'should render showClear button when showClear is true and value exists' , ( ) => {
const { getByRole , getByTestId } = render (
< TextField
clearButtonProps = { { 'data-testid' : 'clear-button' } }
clearButtonIconProps = { { 'data-testid' : 'clear-button-icon' } }
showClear
/ > ,
) ;
const textField = getByRole ( 'textbox' ) ;
expect ( textField . value ) . toBe ( '' ) ; // initial value is empty string
fireEvent . change ( textField , { target : { value : 'text value' } } ) ;
expect ( textField . value ) . toBe ( 'text value' ) ;
expect ( getByTestId ( 'clear-button' ) ) . toBeDefined ( ) ;
expect ( getByTestId ( 'clear-button-icon' ) ) . toBeDefined ( ) ;
} ) ;
it ( 'should render with the rightAccessory' , ( ) => {
const { getByText } = render (
< TextField rightAccessory = { < div > right - accessory < /div>} / > ,
) ;
expect ( getByText ( 'right-accessory' ) ) . toBeDefined ( ) ;
} ) ;
it ( 'should still render with the rightAccessory when showClear is true' , ( ) => {
const { getByRole , getByTestId , getByText } = render (
< TextField
clearButtonProps = { { 'data-testid' : 'clear-button' } }
clearButtonIconProps = { { 'data-testid' : 'clear-button-icon' } }
rightAccessory = { < div > right - accessory < / d i v > }
showClear
/ > ,
) ;
const textField = getByRole ( 'textbox' ) ;
expect ( textField . value ) . toBe ( '' ) ; // initial value is empty string
fireEvent . change ( textField , { target : { value : 'text value' } } ) ;
expect ( textField . value ) . toBe ( 'text value' ) ;
expect ( getByTestId ( 'clear-button' ) ) . toBeDefined ( ) ;
expect ( getByTestId ( 'clear-button-icon' ) ) . toBeDefined ( ) ;
expect ( getByText ( 'right-accessory' ) ) . toBeDefined ( ) ;
it ( 'should render showClearButton button when showClearButton is true and value exists' , async ( ) => {
// As showClearButton is intended to be used with a controlled input we need to use setupControlled
const { user , getByRole } = setupControlled ( TextField , {
showClearButton : true ,
} ) ;
await user . type ( getByRole ( 'textbox' ) , 'test value' ) ;
expect ( getByRole ( 'textbox' ) ) . toHaveValue ( 'test value' ) ;
expect ( getByRole ( 'button' , { name : /Clear/u } ) ) . toBeDefined ( ) ;
} ) ;
it ( 'should clear text when clear button is clicked' , ( ) => {
const { getByRole , getByTestId } = render (
< TextField
clearButtonProps = { { 'data-testid' : 'clear-button' } }
clearButtonIconProps = { { 'data-testid' : 'clear-button-icon' } }
rightAccessory = { < div > right - accessory < / d i v > }
showClear
/ > ,
) ;
const textField = getByRole ( 'textbox' ) ;
fireEvent . change ( textField , { target : { value : 'text value' } } ) ;
expect ( textField . value ) . toBe ( 'text value' ) ;
fireEvent . click ( getByTestId ( 'clear-button' ) ) ;
expect ( textField . value ) . toBe ( '' ) ;
it ( 'should still render with the rightAccessory when showClearButton is true' , async ( ) => {
// As showClearButton is intended to be used with a controlled input we need to use setupControlled
const { user , getByRole , getByText } = setupControlled ( TextField , {
showClearButton : true ,
rightAccessory : < div > right - accessory < / d i v > ,
} ) ;
await user . type ( getByRole ( 'textbox' ) , 'test value' ) ;
expect ( getByRole ( 'textbox' ) ) . toHaveValue ( 'test value' ) ;
expect ( getByRole ( 'button' , { name : /Clear/u } ) ) . toBeDefined ( ) ;
expect ( getByText ( 'right-accessory' ) ) . toBeDefined ( ) ;
} ) ;
it ( 'should fire onClear event when passed to onClear prop' , ( ) => {
const onClear = jest . fn ( ) ;
const { getByRole , getByTestId } = render (
< TextField
onClear = { onClear }
clearButtonProps = { { 'data-testid' : 'clear-button' } }
clearButtonIconProps = { { 'data-testid' : 'clear-button-icon' } }
showClear
/ > ,
) ;
const textField = getByRole ( 'textbox' ) ;
fireEvent . change ( textField , { target : { value : 'text value' } } ) ;
expect ( textField . value ) . toBe ( 'text value' ) ;
fireEvent . click ( getByTestId ( 'clear-button' ) ) ;
expect ( onClear ) . toHaveBeenCalledTimes ( 1 ) ;
it ( 'should fire onClick event when passed to clearButtonOnClick when clear button is clicked' , async ( ) => {
// As showClearButton is intended to be used with a controlled input we need to use setupControlled
const fn = jest . fn ( ) ;
const { user , getByRole } = setupControlled ( TextField , {
showClearButton : true ,
clearButtonOnClick : fn ,
} ) ;
await user . type ( getByRole ( 'textbox' ) , 'test value' ) ;
await user . click ( getByRole ( 'button' , { name : /Clear/u } ) ) ;
expect ( fn ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
it ( 'should fire clearButtonProps.onClick event when passed to clearButtonProps.onClick prop' , ( ) => {
const onClear = jest . fn ( ) ;
const onClick = jest . fn ( ) ;
const { getByRole , getByTestId } = render (
< TextField
onClear = { onClear }
clearButtonProps = { { 'data-testid' : 'clear-button' , onClick } }
clearButtonIconProps = { { 'data-testid' : 'clear-button-icon' } }
showClear
/ > ,
) ;
const textField = getByRole ( 'textbox' ) ;
fireEvent . change ( textField , { target : { value : 'text value' } } ) ;
expect ( textField . value ) . toBe ( 'text value' ) ;
fireEvent . click ( getByTestId ( 'clear-button' ) ) ;
expect ( onClear ) . toHaveBeenCalledTimes ( 1 ) ;
expect ( onClick ) . toHaveBeenCalledTimes ( 1 ) ;
it ( 'should fire onClick event when passed to clearButtonProps.onClick prop' , async ( ) => {
// As showClearButton is intended to be used with a controlled input we need to use setupControlled
const fn = jest . fn ( ) ;
const { user , getByRole } = setupControlled ( TextField , {
showClearButton : true ,
clearButtonProps : { onClick : fn } ,
} ) ;
await user . type ( getByRole ( 'textbox' ) , 'test value' ) ;
await user . click ( getByRole ( 'button' , { name : /Clear/u } ) ) ;
expect ( fn ) . toHaveBeenCalledTimes ( 1 ) ;
} ) ;
it ( 'should be able to accept inputProps' , ( ) => {
const { getByRole } = render (
const { getByTestId } = render (
< TextField inputProps = { { 'data-testid' : 'text-field' } } / > ,
) ;
const textField = getByRole ( 'textbox' ) ;
expect ( textField ) . toBeDefined ( ) ;
expect ( getByTestId ( 'text-field' ) ) . toBeDefined ( ) ;
} ) ;
} ) ;