11import React from 'react' ;
22import { useLocation } from '@reach/router' ;
3- import { render , screen , fireEvent } from '@testing-library/react' ;
3+ import { render , screen , fireEvent , waitFor } from '@testing-library/react' ;
44import '@testing-library/jest-dom/extend-expect' ;
55import { LanguageSelector } from './LanguageSelector' ;
66import { useLayoutContext } from 'src/contexts/layout-context' ;
7+ import { navigate } from '../Link' ;
78
89jest . mock ( 'src/contexts/layout-context' , ( ) => ( {
910 useLayoutContext : jest . fn ( ) ,
@@ -19,6 +20,10 @@ jest.mock('@ably/ui/core/Badge', () => ({
1920 default : ( { children } : { children : React . ReactNode } ) => < div > { children } </ div > ,
2021} ) ) ;
2122
23+ jest . mock ( '../Link' , ( ) => ( {
24+ navigate : jest . fn ( ) ,
25+ } ) ) ;
26+
2227const mockUseLayoutContext = useLayoutContext as jest . Mock ;
2328
2429jest . mock ( '@reach/router' , ( ) => ( {
@@ -28,19 +33,20 @@ jest.mock('@reach/router', () => ({
2833
2934const mockUseLocation = useLocation as jest . Mock ;
3035
31- const mockLanguageData = {
32- pubsub : {
33- javascript : 1.0 ,
34- python : 1.0 ,
35- ruby : 1.0 ,
36+ jest . mock ( 'src/data/languages' , ( ) => ( {
37+ languageData : {
38+ pubsub : {
39+ javascript : '1.0' ,
40+ python : '1.0' ,
41+ ruby : '1.0' ,
42+ } ,
3643 } ,
37- } ;
38-
39- const mockLanguageInfo = {
40- javascript : { label : 'JavaScript' } ,
41- python : { label : 'Python' } ,
42- ruby : { label : 'Ruby' } ,
43- } ;
44+ languageInfo : {
45+ javascript : { label : 'JavaScript' } ,
46+ python : { label : 'Python' } ,
47+ ruby : { label : 'Ruby' } ,
48+ } ,
49+ } ) ) ;
4450
4551describe ( 'LanguageSelector' , ( ) => {
4652 beforeEach ( ( ) => {
@@ -55,26 +61,10 @@ describe('LanguageSelector', () => {
5561 activePage : {
5662 tree : [ 0 ] ,
5763 languages : [ 'javascript' , 'python' ] ,
64+ language : 'javascript' ,
5865 } ,
5966 products : [ [ 'pubsub' ] ] ,
6067 } ) ;
61-
62- Object . defineProperty ( window , 'location' , {
63- writable : true ,
64- value : { search : '' } ,
65- } ) ;
66-
67- jest . spyOn ( window , 'URLSearchParams' ) . mockImplementation (
68- ( ) =>
69- ( {
70- get : jest . fn ( ) . mockReturnValue ( null ) ,
71- } ) as unknown as URLSearchParams ,
72- ) ;
73-
74- jest . mock ( 'src/data/languages' , ( ) => ( {
75- languageData : mockLanguageData ,
76- languageInfo : mockLanguageInfo ,
77- } ) ) ;
7868 } ) ;
7969
8070 afterEach ( ( ) => {
@@ -85,44 +75,60 @@ describe('LanguageSelector', () => {
8575 render ( < LanguageSelector /> ) ;
8676 expect ( screen . getByText ( 'icon-gui-chevron-down-micro' ) ) . toBeInTheDocument ( ) ;
8777 expect ( screen . getByText ( 'icon-tech-javascript' ) ) . toBeInTheDocument ( ) ;
78+ expect ( screen . getByText ( 'JavaScript' ) ) . toBeInTheDocument ( ) ;
8879 } ) ;
8980
90- it ( 'opens the dropdown menu on click' , ( ) => {
81+ it ( 'opens the dropdown menu on click' , async ( ) => {
9182 render ( < LanguageSelector /> ) ;
92- fireEvent . click ( screen . getByText ( 'icon-gui-chevron-down-micro' ) ) ;
93- expect ( screen . getByText ( 'Code Language' ) ) . toBeInTheDocument ( ) ;
83+ const trigger = screen . getByRole ( 'combobox' , { name : / s e l e c t c o d e l a n g u a g e / i } ) ;
84+ fireEvent . click ( trigger ) ;
85+
86+ await waitFor ( ( ) => {
87+ expect ( screen . getByText ( 'Code Language' ) ) . toBeInTheDocument ( ) ;
88+ } ) ;
9489 } ) ;
9590
96- it ( 'renders language options' , ( ) => {
91+ it ( 'renders language options' , async ( ) => {
9792 render ( < LanguageSelector /> ) ;
98- fireEvent . click ( screen . getByText ( 'icon-gui-chevron-down-micro' ) ) ;
99- expect ( screen . getByText ( 'JavaScript' ) ) . toBeInTheDocument ( ) ;
100- expect ( screen . getByText ( 'Python' ) ) . toBeInTheDocument ( ) ;
93+ const trigger = screen . getByRole ( 'combobox' , { name : / s e l e c t c o d e l a n g u a g e / i } ) ;
94+ fireEvent . click ( trigger ) ;
95+
96+ await waitFor ( ( ) => {
97+ const items = screen . getAllByText ( 'JavaScript' ) ;
98+ // One in trigger, one in dropdown
99+ expect ( items . length ) . toBeGreaterThanOrEqual ( 1 ) ;
100+ expect ( screen . getByText ( 'Python' ) ) . toBeInTheDocument ( ) ;
101+ } ) ;
101102 } ) ;
102103
103- it ( 'closes the dropdown menu on outside click' , ( ) => {
104+ it ( 'closes the dropdown menu on escape key' , async ( ) => {
104105 render ( < LanguageSelector /> ) ;
105- fireEvent . click ( screen . getByText ( 'icon-gui-chevron-down-micro' ) ) ;
106- fireEvent . mouseDown ( document ) ;
107- expect ( screen . queryByText ( 'Code Language' ) ) . not . toBeInTheDocument ( ) ;
106+ const trigger = screen . getByRole ( 'combobox' , { name : / s e l e c t c o d e l a n g u a g e / i } ) ;
107+ fireEvent . click ( trigger ) ;
108+
109+ await waitFor ( ( ) => {
110+ expect ( screen . getByText ( 'Code Language' ) ) . toBeInTheDocument ( ) ;
111+ } ) ;
112+
113+ fireEvent . keyDown ( trigger , { key : 'Escape' , code : 'Escape' } ) ;
114+
115+ await waitFor ( ( ) => {
116+ expect ( screen . queryByText ( 'Code Language' ) ) . not . toBeInTheDocument ( ) ;
117+ } ) ;
108118 } ) ;
109119
110- it ( 'filters options based on activePage.languages' , ( ) => {
120+ it ( 'filters options based on activePage.languages' , async ( ) => {
111121 render ( < LanguageSelector /> ) ;
112- fireEvent . click ( screen . getByText ( 'icon-gui-chevron-down-micro' ) ) ;
113- expect ( screen . getByText ( 'JavaScript' ) ) . toBeInTheDocument ( ) ;
114- expect ( screen . getByText ( 'Python' ) ) . toBeInTheDocument ( ) ;
115- expect ( screen . queryByText ( 'Ruby' ) ) . not . toBeInTheDocument ( ) ;
116- } ) ;
122+ const trigger = screen . getByRole ( 'combobox' , { name : / s e l e c t c o d e l a n g u a g e / i } ) ;
123+ fireEvent . click ( trigger ) ;
117124
118- it ( 'sets the default option to Python when ?lang=python is in the URL' , ( ) => {
119- mockUseLocation . mockReturnValue ( {
120- pathname : '/some-path' ,
121- search : '?lang=python' ,
122- hash : '' ,
123- state : null ,
125+ await waitFor ( ( ) => {
126+ expect ( screen . getByText ( 'Python' ) ) . toBeInTheDocument ( ) ;
127+ expect ( screen . queryByText ( 'Ruby' ) ) . not . toBeInTheDocument ( ) ;
124128 } ) ;
129+ } ) ;
125130
131+ it ( 'sets the default option to Python when language is python' , ( ) => {
126132 mockUseLayoutContext . mockReturnValue ( {
127133 activePage : {
128134 tree : [ 0 ] ,
@@ -132,20 +138,25 @@ describe('LanguageSelector', () => {
132138 products : [ [ 'pubsub' ] ] ,
133139 } ) ;
134140
135- jest . spyOn ( window , 'URLSearchParams' ) . mockImplementation (
136- ( ) =>
137- ( {
138- get : jest . fn ( ( key ) => {
139- if ( key === 'lang' ) {
140- return 'python' ;
141- }
142- return null ;
143- } ) ,
144- } ) as unknown as URLSearchParams ,
145- ) ;
146-
147141 render ( < LanguageSelector /> ) ;
148142 expect ( screen . getByText ( 'icon-tech-python' ) ) . toBeInTheDocument ( ) ;
149- expect ( screen . queryByText ( 'icon-tech-javascript' ) ) . not . toBeInTheDocument ( ) ;
143+ expect ( screen . getByText ( 'Python' ) ) . toBeInTheDocument ( ) ;
144+ } ) ;
145+
146+ it ( 'navigates when a language option is selected' , async ( ) => {
147+ render ( < LanguageSelector /> ) ;
148+ const trigger = screen . getByRole ( 'combobox' , { name : / s e l e c t c o d e l a n g u a g e / i } ) ;
149+ fireEvent . click ( trigger ) ;
150+
151+ await waitFor ( ( ) => {
152+ expect ( screen . getByText ( 'Python' ) ) . toBeInTheDocument ( ) ;
153+ } ) ;
154+
155+ const pythonOption = screen . getByRole ( 'option' , { name : / p y t h o n / i } ) ;
156+ fireEvent . click ( pythonOption ) ;
157+
158+ await waitFor ( ( ) => {
159+ expect ( navigate ) . toHaveBeenCalledWith ( '/some-path?lang=python' ) ;
160+ } ) ;
150161 } ) ;
151162} ) ;
0 commit comments