11import "@testing-library/jest-dom/extend-expect" ;
22
3- import { fireEvent , render } from "@testing-library/react" ;
3+ import { render } from "@testing-library/react" ;
4+ import userEvent from "@testing-library/user-event" ;
45
56import React from "react" ;
67import Select from "react-select" ;
@@ -56,27 +57,55 @@ const renderForm = (select: React.ReactNode) => {
5657} ;
5758
5859describe ( "The openMenu event helper" , ( ) => {
59- it ( "opens the menu" , ( ) => {
60+ it ( "opens the menu" , async ( ) => {
6061 const { getByLabelText, queryByText } = renderForm (
6162 < Select { ...defaultProps } />
6263 ) ;
6364 // option is not yet visible
6465 expect ( queryByText ( "Chocolate" ) ) . toBeNull ( ) ;
65- selectEvent . openMenu ( getByLabelText ( "Food" ) ) ;
66+ await selectEvent . openMenu ( getByLabelText ( "Food" ) ) ;
6667 // option can now be seen because menu is open
6768 expect ( queryByText ( "Chocolate" ) ) . toBeInTheDocument ( ) ;
6869 } ) ;
6970
7071 it ( "does not prevent selecting options" , async ( ) => {
7172 const { form, input, getByText } = renderForm ( < Select { ...defaultProps } /> ) ;
72- selectEvent . openMenu ( input ) ;
73+ await selectEvent . openMenu ( input ) ;
7374 expect ( getByText ( "Chocolate" ) ) . toBeInTheDocument ( ) ;
7475 expect ( getByText ( "Vanilla" ) ) . toBeInTheDocument ( ) ;
7576 expect ( getByText ( "Strawberry" ) ) . toBeInTheDocument ( ) ;
7677 expect ( getByText ( "Mango" ) ) . toBeInTheDocument ( ) ;
7778 await selectEvent . select ( input , "Strawberry" ) ;
7879 expect ( form ) . toHaveFormValues ( { food : "strawberry" } ) ;
7980 } ) ;
81+
82+ it ( "allows passing custom userEvent option" , async ( ) => {
83+ const user = userEvent . setup ( ) ;
84+ jest . spyOn ( user , "click" ) ;
85+ jest . spyOn ( user , "type" ) ;
86+
87+ const { input } = renderForm ( < Select { ...defaultProps } /> ) ;
88+
89+ await selectEvent . openMenu ( input , { user } ) ;
90+
91+ expect ( user . click ) . toHaveBeenCalledWith ( input ) ;
92+ expect ( user . type ) . toHaveBeenCalledWith ( input , "{ArrowDown}" ) ;
93+ } ) ;
94+
95+ it ( "allows passing custom userEvent option with setup" , async ( ) => {
96+ const user = userEvent . setup ( ) ;
97+ jest . spyOn ( user , "click" ) ;
98+ jest . spyOn ( user , "type" ) ;
99+
100+ const userSelectEvent = selectEvent . setup ( user ) ;
101+
102+ const { input } = renderForm ( < Select { ...defaultProps } /> ) ;
103+
104+ await userSelectEvent . openMenu ( input ) ;
105+
106+ expect ( user . click ) . toHaveBeenCalledWith ( input ) ;
107+ expect ( user . type ) . toHaveBeenCalledWith ( input , "{ArrowDown}" ) ;
108+ } ) ;
80109} ) ;
81110
82111describe ( "The select event helpers" , ( ) => {
@@ -240,6 +269,7 @@ describe("The select event helpers", () => {
240269 } ) ;
241270
242271 it ( "selects an option in an async input" , async ( ) => {
272+ const user = userEvent . setup ( ) ;
243273 const loadOptions = ( _ : string , callback : Callback ) =>
244274 setTimeout ( ( ) => callback ( OPTIONS ) , 100 ) ;
245275 const { form, input } = renderForm (
@@ -248,7 +278,7 @@ describe("The select event helpers", () => {
248278 expect ( form ) . toHaveFormValues ( { food : "" } ) ;
249279
250280 // start typing to trigger the `loadOptions`
251- fireEvent . change ( input , { target : { value : "Choc" } } ) ;
281+ await user . type ( input , "Choc" ) ;
252282 await selectEvent . select ( input , "Chocolate" ) ;
253283 expect ( form ) . toHaveFormValues ( { food : "chocolate" } ) ;
254284 } ) ;
@@ -344,6 +374,42 @@ describe("The select event helpers", () => {
344374 expect ( form ) . toHaveFormValues ( { food : "vanilla" } ) ;
345375 } ) ;
346376
377+ it ( "allows passing custom userEvent option" , async ( ) => {
378+ const user = userEvent . setup ( ) ;
379+ jest . spyOn ( user , "click" ) ;
380+ jest . spyOn ( user , "type" ) ;
381+
382+ const { input } = renderForm ( < Select { ...defaultProps } /> ) ;
383+
384+ await selectEvent . select ( input , "Chocolate" , { user } ) ;
385+
386+ // Open the dropdown
387+ expect ( user . type ) . toHaveBeenCalledWith ( input , "{ArrowDown}" ) ;
388+ expect ( user . click ) . toHaveBeenNthCalledWith ( 1 , input ) ;
389+
390+ // Difficult to get correct element here but it's fine as long as we get an element
391+ expect ( user . click ) . toHaveBeenNthCalledWith ( 2 , expect . any ( HTMLDivElement ) ) ;
392+ } ) ;
393+
394+ it ( "allows passing custom userEvent option with setup" , async ( ) => {
395+ const user = userEvent . setup ( ) ;
396+ jest . spyOn ( user , "click" ) ;
397+ jest . spyOn ( user , "type" ) ;
398+
399+ const userSelectEvent = selectEvent . setup ( user ) ;
400+
401+ const { input } = renderForm ( < Select { ...defaultProps } /> ) ;
402+
403+ await userSelectEvent . select ( input , "Chocolate" ) ;
404+
405+ // Open the dropdown
406+ expect ( user . type ) . toHaveBeenCalledWith ( input , "{ArrowDown}" ) ;
407+ expect ( user . click ) . toHaveBeenNthCalledWith ( 1 , input ) ;
408+
409+ // Difficult to get correct element here but it's fine as long as we get an element
410+ expect ( user . click ) . toHaveBeenNthCalledWith ( 2 , expect . any ( HTMLDivElement ) ) ;
411+ } ) ;
412+
347413 describe ( "when asynchronously generating the list of options" , ( ) => {
348414 // from https://github.com/JedWatson/react-select/blob/v3.0.0/docs/examples/CreatableAdvanced.js
349415 // mixed with Async Creatable Example from https://react-select.com/creatable
@@ -416,6 +482,56 @@ describe("The select event helpers", () => {
416482
417483 expect ( form ) . toHaveFormValues ( { food : "papaya" } ) ;
418484 } ) ;
485+
486+ it ( "allows passing custom userEvent option" , async ( ) => {
487+ const user = userEvent . setup ( ) ;
488+ jest . spyOn ( user , "click" ) ;
489+ jest . spyOn ( user , "type" ) ;
490+
491+ const { input } = renderForm ( < CreatableAdvanced { ...defaultProps } /> ) ;
492+
493+ await selectEvent . create ( input , "papaya" , { user } ) ;
494+
495+ // Open the dropdown
496+ expect ( user . click ) . toHaveBeenNthCalledWith ( 1 , input ) ;
497+ expect ( user . type ) . toHaveBeenCalledWith ( input , "{ArrowDown}" ) ;
498+
499+ // Create option
500+ expect ( user . type ) . toHaveBeenNthCalledWith ( 2 , input , "papaya" ) ;
501+
502+ // Open dropdown again
503+ expect ( user . click ) . toHaveBeenNthCalledWith ( 2 , input ) ;
504+
505+ // Select the new option
506+ // Difficult to get correct element here but it's fine as long as we get an element
507+ expect ( user . click ) . toHaveBeenNthCalledWith ( 3 , expect . any ( HTMLDivElement ) ) ;
508+ } ) ;
509+
510+ it ( "allows passing custom userEvent option with setup" , async ( ) => {
511+ const user = userEvent . setup ( ) ;
512+ jest . spyOn ( user , "click" ) ;
513+ jest . spyOn ( user , "type" ) ;
514+
515+ const userSelectEvent = selectEvent . setup ( user ) ;
516+
517+ const { input } = renderForm ( < CreatableAdvanced { ...defaultProps } /> ) ;
518+
519+ await userSelectEvent . create ( input , "papaya" ) ;
520+
521+ // Open the dropdown
522+ expect ( user . click ) . toHaveBeenNthCalledWith ( 1 , input ) ;
523+ expect ( user . type ) . toHaveBeenCalledWith ( input , "{ArrowDown}" ) ;
524+
525+ // Create option
526+ expect ( user . type ) . toHaveBeenNthCalledWith ( 2 , input , "papaya" ) ;
527+
528+ // Open dropdown again
529+ expect ( user . click ) . toHaveBeenNthCalledWith ( 2 , input ) ;
530+
531+ // Select the new option
532+ // Difficult to get correct element here but it's fine as long as we get an element
533+ expect ( user . click ) . toHaveBeenNthCalledWith ( 3 , expect . any ( HTMLDivElement ) ) ;
534+ } ) ;
419535 } ) ;
420536
421537 describe ( "when rendering the dropdown in a portal" , ( ) => {
@@ -452,39 +568,119 @@ describe("The select event helpers", () => {
452568 await selectEvent . create ( input , "papaya" , { container : document . body } ) ;
453569 expect ( form ) . toHaveFormValues ( { food : "papaya" } ) ;
454570 } ) ;
571+ } ) ;
572+ } ) ;
455573
456- it ( "clears the first item in a multi-select dropdown" , async ( ) => {
457- const { form, input } = renderForm (
458- < Creatable
459- { ...defaultProps }
460- isMulti
461- defaultValue = { [ OPTIONS [ 0 ] , OPTIONS [ 1 ] , OPTIONS [ 2 ] ] }
462- menuPortalTarget = { document . body }
463- />
464- ) ;
465- expect ( form ) . toHaveFormValues ( {
466- food : [ "chocolate" , "vanilla" , "strawberry" ] ,
467- } ) ;
468-
469- await selectEvent . clearFirst ( input ) ;
470- expect ( form ) . toHaveFormValues ( { food : [ "vanilla" , "strawberry" ] } ) ;
574+ describe ( "clearFirst" , ( ) => {
575+ it ( "clears the first item in a multi-select dropdown" , async ( ) => {
576+ const { form, input } = renderForm (
577+ < Creatable
578+ { ...defaultProps }
579+ isMulti
580+ defaultValue = { [ OPTIONS [ 0 ] , OPTIONS [ 1 ] , OPTIONS [ 2 ] ] }
581+ menuPortalTarget = { document . body }
582+ />
583+ ) ;
584+ expect ( form ) . toHaveFormValues ( {
585+ food : [ "chocolate" , "vanilla" , "strawberry" ] ,
471586 } ) ;
472587
473- it ( "clears all items" , async ( ) => {
474- const { form, input } = renderForm (
475- < Creatable
476- { ...defaultProps }
477- isMulti
478- defaultValue = { [ OPTIONS [ 0 ] , OPTIONS [ 1 ] , OPTIONS [ 2 ] ] }
479- menuPortalTarget = { document . body }
480- />
481- ) ;
482- expect ( form ) . toHaveFormValues ( {
483- food : [ "chocolate" , "vanilla" , "strawberry" ] ,
484- } ) ;
588+ await selectEvent . clearFirst ( input ) ;
589+ expect ( form ) . toHaveFormValues ( { food : [ "vanilla" , "strawberry" ] } ) ;
590+ } ) ;
485591
486- await selectEvent . clearAll ( input ) ;
487- expect ( form ) . toHaveFormValues ( { food : "" } ) ;
592+ it ( "allows passing custom userEvent option" , async ( ) => {
593+ const user = userEvent . setup ( ) ;
594+ jest . spyOn ( user , "click" ) ;
595+
596+ const { input } = renderForm (
597+ < Creatable
598+ { ...defaultProps }
599+ isMulti
600+ defaultValue = { [ OPTIONS [ 0 ] , OPTIONS [ 1 ] , OPTIONS [ 2 ] ] }
601+ menuPortalTarget = { document . body }
602+ />
603+ ) ;
604+
605+ await selectEvent . clearFirst ( input , { user } ) ;
606+
607+ expect ( user . click ) . toHaveBeenCalledWith ( expect . any ( SVGSVGElement ) ) ;
608+ } ) ;
609+
610+ it ( "allows passing custom userEvent option with setup" , async ( ) => {
611+ const user = userEvent . setup ( ) ;
612+ jest . spyOn ( user , "click" ) ;
613+
614+ const userSelectEvent = selectEvent . setup ( user ) ;
615+
616+ const { input } = renderForm (
617+ < Creatable
618+ { ...defaultProps }
619+ isMulti
620+ defaultValue = { [ OPTIONS [ 0 ] , OPTIONS [ 1 ] , OPTIONS [ 2 ] ] }
621+ menuPortalTarget = { document . body }
622+ />
623+ ) ;
624+
625+ await userSelectEvent . clearFirst ( input ) ;
626+
627+ expect ( user . click ) . toHaveBeenCalledWith ( expect . any ( SVGSVGElement ) ) ;
628+ } ) ;
629+ } ) ;
630+
631+ describe ( "clearAll" , ( ) => {
632+ it ( "clears all items" , async ( ) => {
633+ const { form, input } = renderForm (
634+ < Creatable
635+ { ...defaultProps }
636+ isMulti
637+ defaultValue = { [ OPTIONS [ 0 ] , OPTIONS [ 1 ] , OPTIONS [ 2 ] ] }
638+ menuPortalTarget = { document . body }
639+ />
640+ ) ;
641+ expect ( form ) . toHaveFormValues ( {
642+ food : [ "chocolate" , "vanilla" , "strawberry" ] ,
488643 } ) ;
644+
645+ await selectEvent . clearAll ( input ) ;
646+ expect ( form ) . toHaveFormValues ( { food : "" } ) ;
647+ } ) ;
648+
649+ it ( "allows passing custom userEvent option" , async ( ) => {
650+ const user = userEvent . setup ( ) ;
651+ jest . spyOn ( user , "click" ) ;
652+
653+ const { input } = renderForm (
654+ < Creatable
655+ { ...defaultProps }
656+ isMulti
657+ defaultValue = { [ OPTIONS [ 0 ] , OPTIONS [ 1 ] , OPTIONS [ 2 ] ] }
658+ menuPortalTarget = { document . body }
659+ />
660+ ) ;
661+
662+ await selectEvent . clearAll ( input , { user } ) ;
663+
664+ expect ( user . click ) . toHaveBeenCalledWith ( expect . any ( SVGSVGElement ) ) ;
665+ } ) ;
666+
667+ it ( "allows passing custom userEvent option with setup" , async ( ) => {
668+ const user = userEvent . setup ( ) ;
669+ jest . spyOn ( user , "click" ) ;
670+
671+ const userSelectEvent = selectEvent . setup ( user ) ;
672+
673+ const { input } = renderForm (
674+ < Creatable
675+ { ...defaultProps }
676+ isMulti
677+ defaultValue = { [ OPTIONS [ 0 ] , OPTIONS [ 1 ] , OPTIONS [ 2 ] ] }
678+ menuPortalTarget = { document . body }
679+ />
680+ ) ;
681+
682+ await userSelectEvent . clearAll ( input ) ;
683+
684+ expect ( user . click ) . toHaveBeenCalledWith ( expect . any ( SVGSVGElement ) ) ;
489685 } ) ;
490686} ) ;
0 commit comments