Skip to content

Commit 1ea3f33

Browse files
committed
test(ui-selectable): migrate old Selectable tests
1 parent 970075c commit 1ea3f33

File tree

5 files changed

+777
-602
lines changed

5 files changed

+777
-602
lines changed
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2015 - present Instructure, Inc.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
import React from 'react'
25+
import { Selectable } from '@instructure/ui'
26+
import { expect } from 'chai'
27+
import 'cypress-real-events'
28+
import '../support/component'
29+
30+
const defaultOptions = ['foo', 'bar', 'baz']
31+
32+
const getSelectable = (selectable) => (
33+
<span {...selectable.getRootProps()}>
34+
<label
35+
htmlFor={selectable.getInputProps().id}
36+
{...selectable.getLabelProps()}
37+
>
38+
Selectable
39+
</label>
40+
<input
41+
type="text"
42+
{...selectable.getTriggerProps()}
43+
{...selectable.getInputProps()}
44+
/>
45+
<ul {...selectable.getListProps()}>
46+
{defaultOptions.map((opt) => (
47+
<li key={opt} {...selectable.getOptionProps({ id: opt })}>
48+
{opt}
49+
</li>
50+
))}
51+
</ul>
52+
</span>
53+
)
54+
55+
describe('<Selectable />', () => {
56+
it('should fire onRequestHideOptions when escape is pressed', async () => {
57+
const onRequestHideOptions = cy.stub()
58+
let defaultPrevented = false
59+
60+
cy.mount(
61+
<div
62+
role="button"
63+
tabIndex={0}
64+
onKeyUp={(e) => {
65+
defaultPrevented = e.defaultPrevented
66+
}}
67+
>
68+
<Selectable
69+
isShowingOptions={true}
70+
onRequestHideOptions={onRequestHideOptions}
71+
>
72+
{(selectable) => getSelectable(selectable)}
73+
</Selectable>
74+
</div>
75+
)
76+
77+
cy.get('input')
78+
.focus()
79+
.realType('{esc}')
80+
.then(() => {
81+
cy.wrap(onRequestHideOptions).should('have.been.calledOnce')
82+
cy.wrap(defaultPrevented).should('be.true')
83+
})
84+
})
85+
86+
it('should fire onRequestHideOptions when options are hovered', async () => {
87+
const onRequestHighlightOption = cy.stub()
88+
89+
cy.mount(
90+
<Selectable onRequestHighlightOption={onRequestHighlightOption}>
91+
{(selectable) => getSelectable(selectable)}
92+
</Selectable>
93+
)
94+
95+
cy.get('li').as('options')
96+
97+
cy.get('@options').eq(0).trigger('mouseover')
98+
cy.wrap(onRequestHighlightOption)
99+
.should('have.been.called')
100+
.then((spy) => {
101+
expect(spy.lastCall.args[1]).to.have.property('id', defaultOptions[0])
102+
expect(spy.lastCall.args[1]).not.to.have.property('direction')
103+
})
104+
105+
cy.get('@options').eq(1).trigger('mouseover')
106+
cy.wrap(onRequestHighlightOption)
107+
.should('have.been.called')
108+
.then((spy) => {
109+
expect(spy.lastCall.args[1]).to.have.property('id', defaultOptions[1])
110+
expect(spy.lastCall.args[1]).not.to.have.property('direction')
111+
})
112+
})
113+
114+
it('should fire onRequestHideOptions when up/down arrows are pressed', async () => {
115+
const onRequestShowOptions = cy.stub()
116+
const onRequestHighlightOption = cy.stub()
117+
118+
cy.mount(
119+
<Selectable
120+
isShowingOptions={false}
121+
onRequestShowOptions={onRequestShowOptions}
122+
onRequestHighlightOption={onRequestHighlightOption}
123+
>
124+
{(selectable) => getSelectable(selectable)}
125+
</Selectable>
126+
)
127+
128+
cy.get('input[role$="combobox"]').as('input')
129+
cy.get('@input').type('{downArrow}')
130+
cy.wrap(onRequestHighlightOption).should('not.have.been.called')
131+
cy.wrap(onRequestShowOptions).should('have.been.called')
132+
133+
// Set prop: isShowingOptions, highlightedOptionId
134+
cy.mount(
135+
<Selectable
136+
isShowingOptions={true}
137+
highlightedOptionId={defaultOptions[0]}
138+
onRequestShowOptions={onRequestShowOptions}
139+
onRequestHighlightOption={onRequestHighlightOption}
140+
>
141+
{(selectable) => getSelectable(selectable)}
142+
</Selectable>
143+
)
144+
145+
cy.get('@input').type('{downArrow}')
146+
cy.wrap(onRequestHighlightOption)
147+
.should('have.been.called')
148+
.then((spy) => {
149+
expect(spy.lastCall.args[1]).to.have.property('direction', 1)
150+
expect(spy.lastCall.args[1]).not.to.have.property('id')
151+
})
152+
153+
// Set prop: highlightedOptionId
154+
cy.mount(
155+
<Selectable
156+
isShowingOptions={true}
157+
highlightedOptionId={defaultOptions[1]}
158+
onRequestShowOptions={onRequestShowOptions}
159+
onRequestHighlightOption={onRequestHighlightOption}
160+
>
161+
{(selectable) => getSelectable(selectable)}
162+
</Selectable>
163+
)
164+
165+
cy.get('@input').type('{upArrow}')
166+
cy.wrap(onRequestHighlightOption)
167+
.should('have.been.called')
168+
.then((spy) => {
169+
expect(spy.lastCall.args[1]).to.have.property('direction', -1)
170+
expect(spy.lastCall.args[1]).not.to.have.property('id')
171+
})
172+
})
173+
174+
it('should fire onRequestHideOptions when home/end is pressed', async () => {
175+
const onRequestHighlightOption = cy.stub()
176+
const onRequestHighlightFirstOption = cy.stub()
177+
const onRequestHighlightLastOption = cy.stub()
178+
179+
cy.mount(
180+
<Selectable
181+
isShowingOptions={true}
182+
highlightedOptionId={defaultOptions[1]}
183+
onRequestHighlightOption={onRequestHighlightOption}
184+
onRequestHighlightFirstOption={onRequestHighlightFirstOption}
185+
onRequestHighlightLastOption={onRequestHighlightLastOption}
186+
>
187+
{(selectable) => getSelectable(selectable)}
188+
</Selectable>
189+
)
190+
191+
cy.get('input[role$="combobox"]').as('input')
192+
193+
cy.get('@input').type('{home}')
194+
cy.get('@input').type('{end}')
195+
cy.wrap(onRequestHighlightFirstOption).should('have.been.calledOnce')
196+
cy.wrap(onRequestHighlightLastOption).should('have.been.calledOnce')
197+
cy.wrap(onRequestHighlightOption).should('not.have.been.called')
198+
})
199+
200+
it('should fire onRequestSelectOption when enter is pressed', async () => {
201+
const onRequestSelectOption = cy.stub()
202+
203+
cy.mount(
204+
<Selectable
205+
isShowingOptions={true}
206+
highlightedOptionId={defaultOptions[1]}
207+
onRequestSelectOption={onRequestSelectOption}
208+
>
209+
{(selectable) => getSelectable(selectable)}
210+
</Selectable>
211+
)
212+
cy.get('input[role$="combobox"]').as('input')
213+
214+
cy.get('@input').type('{enter}')
215+
cy.wrap(onRequestSelectOption)
216+
.should('have.been.called')
217+
.then((spy) => {
218+
expect(spy.lastCall.args[1]).to.have.property('id', defaultOptions[1])
219+
})
220+
})
221+
222+
it('should fire onRequestSelectOption when options are clicked', async () => {
223+
const onRequestSelectOption = cy.stub()
224+
225+
cy.mount(
226+
<Selectable
227+
isShowingOptions={true}
228+
onRequestSelectOption={onRequestSelectOption}
229+
>
230+
{(selectable) => getSelectable(selectable)}
231+
</Selectable>
232+
)
233+
234+
cy.get('li').as('options')
235+
236+
cy.get('@options').eq(1).click()
237+
cy.wrap(onRequestSelectOption)
238+
.should('have.been.called')
239+
.then((spy) => {
240+
expect(spy.lastCall.args[1]).to.have.property('id', defaultOptions[1])
241+
})
242+
})
243+
244+
it('getRootProps() should allow supplemental onKeyDown behavior', async () => {
245+
const onKeyDown = cy.stub()
246+
const onRequestHighlightOption = cy.stub()
247+
248+
cy.mount(
249+
<Selectable
250+
isShowingOptions={true}
251+
highlightedOptionId={defaultOptions[1]}
252+
onRequestHighlightOption={onRequestHighlightOption}
253+
>
254+
{(selectable) => (
255+
<span {...selectable.getRootProps({ onKeyDown })}>
256+
<input
257+
type="text"
258+
{...selectable.getTriggerProps()}
259+
{...selectable.getInputProps()}
260+
/>
261+
</span>
262+
)}
263+
</Selectable>
264+
)
265+
266+
cy.get('input[role$="combobox"]').as('input')
267+
268+
cy.get('@input').type('{downArrow}')
269+
cy.get('@input').type('{upArrow}')
270+
271+
cy.wrap(onRequestHighlightOption).should('have.been.calledTwice')
272+
cy.wrap(onKeyDown).should('have.been.calledTwice')
273+
})
274+
275+
it('getTriggerProps() should allow supplemental onKeyDown behavior', async () => {
276+
const onKeyDown = cy.stub()
277+
const onRequestHighlightOption = cy.stub()
278+
279+
cy.mount(
280+
<Selectable
281+
isShowingOptions={true}
282+
highlightedOptionId={defaultOptions[1]}
283+
onRequestHighlightOption={onRequestHighlightOption}
284+
>
285+
{(selectable) => (
286+
<span {...selectable.getRootProps()}>
287+
<input
288+
type="text"
289+
{...selectable.getTriggerProps({ onKeyDown })}
290+
{...selectable.getInputProps()}
291+
/>
292+
</span>
293+
)}
294+
</Selectable>
295+
)
296+
297+
cy.get('input[role$="combobox"]').as('input')
298+
299+
cy.get('@input').type('{downArrow}')
300+
cy.get('@input').type('{upArrow}')
301+
cy.get('@input').type('a')
302+
303+
cy.wrap(onRequestHighlightOption).should('have.been.calledTwice')
304+
cy.wrap(onKeyDown).should('have.been.calledThrice')
305+
})
306+
307+
it('getOptionProps() should allow supplemental onMouseOver behavior', async () => {
308+
const onMouseOver = cy.stub()
309+
const onRequestHighlightOption = cy.stub()
310+
311+
cy.mount(
312+
<Selectable
313+
isShowingOptions={true}
314+
onRequestHighlightOption={onRequestHighlightOption}
315+
>
316+
{(selectable) => (
317+
<span>
318+
<input type="text" {...selectable.getInputProps()} />
319+
<ul {...selectable.getListProps()}>
320+
{defaultOptions.map((opt) => (
321+
<li
322+
key={opt}
323+
{...selectable.getOptionProps({ id: opt, onMouseOver })}
324+
>
325+
{opt}
326+
</li>
327+
))}
328+
</ul>
329+
</span>
330+
)}
331+
</Selectable>
332+
)
333+
334+
cy.get('li').as('options')
335+
336+
cy.get('@options').eq(0).trigger('mouseover')
337+
cy.get('@options').eq(1).trigger('mouseover')
338+
339+
cy.wrap(onMouseOver).should('have.been.calledTwice')
340+
cy.wrap(onRequestHighlightOption).should('have.been.calledTwice')
341+
})
342+
})

package-lock.json

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/ui-selectable/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
"license": "MIT",
2525
"devDependencies": {
2626
"@instructure/ui-babel-preset": "10.11.0",
27-
"@instructure/ui-test-utils": "10.11.0"
27+
"@testing-library/jest-dom": "^6.6.3",
28+
"@testing-library/react": "^16.0.1",
29+
"@testing-library/user-event": "^14.5.2",
30+
"vitest": "^2.1.8"
2831
},
2932
"dependencies": {
3033
"@babel/runtime": "^7.26.0",

0 commit comments

Comments
 (0)