Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit 2305659

Browse files
committed
test: add test for autocomplete
1 parent fb261a8 commit 2305659

File tree

15 files changed

+473
-13
lines changed

15 files changed

+473
-13
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
describe('forms/Auto Completes', () => {
2+
beforeEach(() => {
3+
cy.visit('/auto-completes');
4+
});
5+
6+
it('rendered properly', () => {
7+
cy.contains('h2[data-cy=auto-completes]', 'Auto Completes');
8+
cy.get('div[data-cy=auto-complete-0]').as('firstAutoComplete');
9+
10+
cy.get('@firstAutoComplete').find('[data-id="activator"]').should('be.exist');
11+
cy.get('@firstAutoComplete').find('span[class*=_label_]').should('contain.text', 'Select');
12+
13+
cy.get('div[role=menu]').should('not.exist');
14+
15+
cy.get('@firstAutoComplete').find('[data-id="activator"]').click();
16+
17+
cy.get('div[role=menu]').should('be.visible');
18+
cy.get('div[role=menu] button:first-child').click();
19+
20+
cy.get('@firstAutoComplete').find('div[class*=_value_]').should('contain.text', 'Germany');
21+
});
22+
});

example/src/views/AutoCompleteView.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ const autoCompletePrimitive = ref<AutoCompleteProps<string>[]>([
227227
>
228228
<RuiAutoComplete
229229
v-model="item.value"
230+
clearable
230231
auto-select-first
231232
v-bind="objectOmit(item, ['value'])"
232233
:data-cy="`auto-complete-${i}`"
@@ -247,6 +248,7 @@ const autoCompletePrimitive = ref<AutoCompleteProps<string>[]>([
247248
>
248249
<RuiAutoComplete
249250
v-model="item.value"
251+
clearable
250252
auto-select-first
251253
v-bind="objectOmit(item, ['value'])"
252254
:data-cy="`auto-complete-custom-${i}`"
@@ -287,6 +289,7 @@ const autoCompletePrimitive = ref<AutoCompleteProps<string>[]>([
287289
>
288290
<RuiAutoComplete
289291
v-model="autoCompleteProp.value"
292+
clearable
290293
auto-select-first
291294
v-bind="objectOmit(autoCompleteProp, ['value'])"
292295
:data-cy="`auto-complete-custom-inner-${i}`"
@@ -322,6 +325,7 @@ const autoCompletePrimitive = ref<AutoCompleteProps<string>[]>([
322325
>
323326
<RuiAutoComplete
324327
v-model="item.value"
328+
clearable
325329
auto-select-first
326330
v-bind="objectOmit(item, ['value'])"
327331
:append-width="1.5"
@@ -352,6 +356,7 @@ const autoCompletePrimitive = ref<AutoCompleteProps<string>[]>([
352356
>
353357
<RuiAutoComplete
354358
v-model="item.value"
359+
clearable
355360
auto-select-first
356361
return-primitive
357362
v-bind="objectOmit(item, ['value'])"
@@ -382,6 +387,7 @@ const autoCompletePrimitive = ref<AutoCompleteProps<string>[]>([
382387
>
383388
<RuiAutoComplete
384389
v-model="item.value"
390+
clearable
385391
auto-select-first
386392
v-bind="objectOmit(item, ['value'])"
387393
:append-width="1.5"

example/src/views/MenuView.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ const menuSelectPrimitive = ref<MenuSelectProps<string>[]>([
343343
>
344344
<RuiMenuSelect
345345
v-model="menu.value"
346+
clearable
346347
v-bind="objectOmit(menu, ['value'])"
347348
:data-cy="`select-menu-${i}`"
348349
/>
@@ -362,6 +363,7 @@ const menuSelectPrimitive = ref<MenuSelectProps<string>[]>([
362363
>
363364
<RuiMenuSelect
364365
v-model="menu.value"
366+
clearable
365367
v-bind="objectOmit(menu, ['value'])"
366368
:data-cy="`select-menu-custom-${i}`"
367369
>
@@ -401,10 +403,10 @@ const menuSelectPrimitive = ref<MenuSelectProps<string>[]>([
401403
>
402404
<RuiMenuSelect
403405
v-model="menu.value"
406+
clearable
404407
v-bind="objectOmit(menu, ['value'])"
405408
:data-cy="`select-menu-custom-inner-${i}`"
406409
:item-height="menu.dense ? undefined : 80"
407-
clearable
408410
:label-class="menu.dense ? undefined : 'h-20'"
409411
variant="outlined"
410412
>
@@ -436,6 +438,7 @@ const menuSelectPrimitive = ref<MenuSelectProps<string>[]>([
436438
>
437439
<RuiMenuSelect
438440
v-model="menu.value"
441+
clearable
439442
v-bind="objectOmit(menu, ['value'])"
440443
:append-width="1.5"
441444
:data-cy="`select-menu-custom-options-${i}`"
@@ -465,6 +468,7 @@ const menuSelectPrimitive = ref<MenuSelectProps<string>[]>([
465468
>
466469
<RuiMenuSelect
467470
v-model="menu.value"
471+
clearable
468472
v-bind="objectOmit(menu, ['value'])"
469473
:append-width="1.5"
470474
:data-cy="`select-menu-custom-options-${i}`"
@@ -493,6 +497,7 @@ const menuSelectPrimitive = ref<MenuSelectProps<string>[]>([
493497
>
494498
<RuiMenuSelect
495499
v-model="menu.value"
500+
clearable
496501
v-bind="objectOmit(menu, ['value'])"
497502
:append-width="1.5"
498503
:data-cy="`select-menu-readonly-${i}`"

src/components/chips/Chip.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ const style: ComputedRef<Partial<CSSStyleDeclaration>> = computed(() => {
8080
[css.readonly]: !clickable,
8181
},
8282
]"
83+
class="rui-chip"
8384
:style="style"
8485
role="button"
8586
tabindex="0"
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import { describe, expect, it, vi } from 'vitest';
2+
import { mount } from '@vue/test-utils';
3+
import Vue from 'vue';
4+
import AutoComplete from '@/components/forms/auto-complete/RuiAutoComplete.vue';
5+
import { TeleportPlugin } from '@/components/overlays/teleport-container';
6+
7+
interface SelectOption { id: string; label: string }
8+
9+
Vue.use(TeleportPlugin);
10+
11+
function createWrapper(options?: any) {
12+
return mount(AutoComplete, options);
13+
}
14+
15+
describe('autocomplete', () => {
16+
const options: SelectOption[] = [
17+
{ id: '1', label: 'Germany' },
18+
{ id: '2', label: 'Nigeria' },
19+
{ id: '3', label: 'Greece' },
20+
{ id: '4', label: 'Indonesia' },
21+
{ id: '5', label: 'Spain' },
22+
{ id: '6', label: 'India' },
23+
{ id: '7', label: 'France' },
24+
{ id: '8', label: 'England' },
25+
...[...new Array(50).keys()].map(index => ({
26+
id: `${index + 9}`,
27+
label: `${index + 9}`,
28+
})),
29+
];
30+
31+
it('renders properly', () => {
32+
const wrapper = createWrapper({
33+
propsData: {
34+
keyAttr: 'id',
35+
options,
36+
textAttr: 'label',
37+
value: null,
38+
},
39+
});
40+
41+
expect(wrapper.get('div[data-id="activator"]').classes()).toEqual(
42+
expect.arrayContaining([expect.stringMatching(/_activator_/)]),
43+
);
44+
expect(wrapper.find('div[data-id="activator"] span[class*=label]').exists()).toBeTruthy();
45+
expect(wrapper.find('span > svg').exists()).toBeTruthy();
46+
});
47+
48+
it('passes props correctly', async () => {
49+
const wrapper = createWrapper({
50+
propsData: {
51+
disabled: true,
52+
keyAttr: 'id',
53+
options,
54+
textAttr: 'label',
55+
value: options[4].id,
56+
},
57+
});
58+
expect(wrapper.find('div[data-id=activator][tabindex=-1]').exists()).toBeTruthy();
59+
expect(wrapper.find('div[data-id=activator][tabindex=-1]').text()).toMatch('Spain');
60+
});
61+
62+
it('works with primitive options', () => {
63+
const wrapper = createWrapper({
64+
propsData: {
65+
keyAttr: 'id',
66+
options: options.map(item => item.label),
67+
textAttr: 'label',
68+
value: options[4].label,
69+
},
70+
});
71+
expect(wrapper.find('div[data-id=activator]').text()).toMatch('Spain');
72+
});
73+
74+
it('value passed and emitted properly', async () => {
75+
const wrapper = createWrapper({
76+
propsData: {
77+
autoSelectFirst: true,
78+
keyAttr: 'id',
79+
options,
80+
textAttr: 'label',
81+
},
82+
});
83+
84+
// Open Menu Select
85+
await wrapper.find('[data-id=activator]').trigger('click');
86+
await vi.delay();
87+
await nextTick();
88+
89+
expect(document.body.querySelector('div[role=menu]')).toBeTruthy();
90+
91+
const selectedIndex = 4;
92+
let highlightedItemButton = document.body.querySelector(`button:first-child`) as HTMLButtonElement;
93+
expect(highlightedItemButton.classList).toContain('highlighted');
94+
95+
const buttonToSelect = document.body.querySelector(`button:nth-child(${selectedIndex})`) as HTMLButtonElement;
96+
buttonToSelect?.click();
97+
expect(wrapper.emitted().input!.at(-1)![0]).toBe(selectedIndex.toString());
98+
99+
await vi.delay();
100+
expect(document.body.querySelector('div[role=menu]')).toBeFalsy();
101+
102+
// Open Menu Select
103+
await wrapper.find('[data-id=activator]').trigger('click');
104+
await vi.delay();
105+
await nextTick();
106+
107+
expect(document.body.querySelector('div[role=menu]')).toBeTruthy();
108+
109+
await nextTick();
110+
111+
highlightedItemButton = document.body.querySelector(`button:nth-child(${selectedIndex})`) as HTMLButtonElement;
112+
expect(highlightedItemButton.classList).toContain('highlighted');
113+
114+
await wrapper.find('[data-id=activator]').trigger('keydown.down');
115+
116+
highlightedItemButton = document.body.querySelector(`button:nth-child(${selectedIndex + 1})`) as HTMLButtonElement;
117+
expect(highlightedItemButton.classList).toContain('highlighted');
118+
119+
await wrapper.find('[data-id=activator]').trigger('keydown.up');
120+
await wrapper.find('[data-id=activator]').trigger('keydown.up');
121+
122+
const newSelectedIndex = selectedIndex - 1;
123+
124+
highlightedItemButton = document.body.querySelector(`button:nth-child(${newSelectedIndex})`) as HTMLButtonElement;
125+
expect(highlightedItemButton.classList).toContain('highlighted');
126+
127+
await wrapper.find('[data-id=activator]').trigger('keydown.enter');
128+
expect(wrapper.emitted().input!.at(-1)![0]).toBe(newSelectedIndex.toString());
129+
});
130+
131+
it('multiple value', async () => {
132+
const wrapper = createWrapper({
133+
propsData: {
134+
autoSelectFirst: true,
135+
keyAttr: 'id',
136+
options,
137+
textAttr: 'label',
138+
value: ['7', '8'],
139+
},
140+
});
141+
142+
expect(wrapper.find('div[data-id=activator]').exists()).toBeTruthy();
143+
let chips = wrapper.find('div[data-id=activator]').findAll('.rui-chip');
144+
expect(chips).toHaveLength(2);
145+
expect(chips.at(0).text()).toBe('France');
146+
expect(chips.at(1).text()).toBe('England');
147+
148+
// Add India
149+
await wrapper.find('input').setValue('India');
150+
await vi.delay();
151+
152+
expect(document.body.querySelectorAll('button').length).toBe(1);
153+
const itemButton = document.body.querySelector('button')!;
154+
expect(itemButton.innerHTML).toContain('India');
155+
itemButton.click();
156+
157+
let newValue = ['7', '8', '6'];
158+
expect(wrapper.emitted().input!.at(-1)![0]).toEqual(newValue);
159+
160+
await wrapper.setProps({
161+
value: newValue,
162+
});
163+
164+
chips = wrapper.find('div[data-id=activator]').findAll('.rui-chip');
165+
expect(chips).toHaveLength(3);
166+
expect(chips.at(0).text()).toBe('India');
167+
expect(chips.at(1).text()).toBe('France');
168+
expect(chips.at(2).text()).toBe('England');
169+
170+
// Delete England
171+
await chips.at(2).find('button[type="button"]').trigger('click');
172+
await nextTick();
173+
174+
newValue = ['6', '7'];
175+
expect(wrapper.emitted().input!.at(-1)![0]).toEqual(newValue);
176+
});
177+
});

0 commit comments

Comments
 (0)