Skip to content

Commit 2a38c83

Browse files
Merge pull request #345 from thejackshelton/add-headless-autocomplete
autocomplete tests, attempted fix at website build, disabled support for autocomplete
2 parents b4c8e5a + a70b6e8 commit 2a38c83

File tree

8 files changed

+198
-150
lines changed

8 files changed

+198
-150
lines changed

apps/website/src/_state/component-statuses.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export const componentsStatuses: ComponentKitsStatuses = {
4040
},
4141
headless: {
4242
Accordion: 'Planned',
43+
Autocomplete: 'Draft',
4344
Carousel: 'Planned',
4445
Popover: 'Planned',
4546
Select: 'Draft',

apps/website/src/routes/docs/headless/(components)/autocomplete/examples.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ export const Example01 = component$(() => {
2727
return (
2828
<PreviewCodeExample>
2929
<div q:slot="actualComponent">
30-
<AutocompleteRoot class="relative text-white">
31-
<AutocompleteLabel class="text-inherit font-semibold">
30+
<AutocompleteRoot class="relative">
31+
<AutocompleteLabel class=" font-semibold dark:text-white text-[#333333]">
3232
Personal Trainers ⚡
3333
</AutocompleteLabel>
3434
<AutocompleteTrigger class="bg-[#1f2532] flex items-center rounded-sm border-[#7d95b3] border-[1px] relative">
35-
<AutocompleteInput class="w-44 bg-inherit px-2 pr-6" />
35+
<AutocompleteInput class="w-44 bg-inherit px-2 pr-6 text-white" />
3636
<AutocompleteButton class="w-6 h-6 group absolute right-0">
3737
<svg
3838
xmlns="http://www.w3.org/2000/svg"
@@ -47,7 +47,7 @@ export const Example01 = component$(() => {
4747
</svg>
4848
</AutocompleteButton>
4949
</AutocompleteTrigger>
50-
<AutocompleteListbox class="w-full bg-[#1f2532] px-4 py-2 mt-2 rounded-sm border-[#7d95b3] border-[1px]">
50+
<AutocompleteListbox class="text-white w-full bg-[#1f2532] px-4 py-2 mt-2 rounded-sm border-[#7d95b3] border-[1px]">
5151
{trainers.map((trainer, index) => (
5252
<AutocompleteOption
5353
optionValue={trainer}

apps/website/src/routes/docs/headless/(components)/select/examples.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ export const Example01 = component$(() => {
1515
return (
1616
<PreviewCodeExample>
1717
<div q:slot="actualComponent">
18-
<SelectRoot class="dark:bg-gray-700">
19-
<SelectLabel class="text-white font-semibold ml-2">
18+
<SelectRoot>
19+
<SelectLabel class=" font-semibold ml-2 text-[#333333] dark:text-white">
2020
Qwik Fruits
2121
</SelectLabel>
2222
<SelectTrigger class="flex justify-between items-center px-8 bg-[#1f2532] border-[#7d95b3] border-[1px] rounded-md p-4 group peer">

packages/kit-headless/src/components/Autocomplete/autocomplete.spec.tsx

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
AutocompleteListbox,
99
AutocompleteOption,
1010
} from './autocomplete';
11-
import './autocompleteTest.css';
1211

1312
const fruits = [
1413
'Apple',
@@ -133,15 +132,19 @@ describe('Autocomplete', () => {
133132
cy.checkA11yForComponent();
134133
});
135134

136-
it('Should open the listbox and aria-expanded is true on the button', () => {
135+
it(`GIVEN a button is present that controls the visibility of a listbox
136+
WHEN the button is clicked,
137+
THEN the listbox should open and the attribute 'aria-expanded' on the button should be set to 'true'.`, () => {
137138
cy.mount(<RegularAutocomplete />);
138139

139140
cy.get('button').click().should('have.attr', 'aria-expanded', 'true');
140141

141142
cy.findByRole('listbox').should('be.visible');
142143
});
143144

144-
it('Should close the listbox and aria-expanded is false on the button', () => {
145+
it(`GIVEN a button is present that controls the visibility of a listbox, and the listbox is currently open,
146+
WHEN the button is clicked,
147+
THEN the listbox should close and the attribute 'aria-expanded' on the button should be set to 'false'.`, () => {
145148
cy.mount(<RegularAutocomplete />);
146149

147150
cy.get('button')
@@ -152,15 +155,69 @@ describe('Autocomplete', () => {
152155
cy.findByRole('listbox').should('not.exist');
153156
});
154157

155-
it('Should input a value and the listbox should open', () => {
158+
it(`GIVEN an open listbox
159+
WHEN the user presses the 'Escape' key,
160+
THEN the listbox should close and the attribute 'aria-expanded' on the button should be set to 'false'.`, () => {
161+
cy.mount(<RegularAutocomplete />);
162+
163+
cy.get('button').click();
164+
165+
cy.findByRole('listbox');
166+
167+
cy.get('body').type(`{esc}`);
168+
169+
cy.findByRole('listbox').should('not.exist');
170+
});
171+
172+
it(`GIVEN a focused option in a listbox,
173+
WHEN the user presses the 'Home' key,
174+
THEN the first option in the listbox should be focused.`, () => {
175+
cy.mount(<RegularAutocomplete />);
176+
177+
cy.get('button').click();
178+
179+
cy.findByRole('option', { name: 'Yuzu' }).focus().type(`{home}`);
180+
181+
cy.get('li').first().should('have.focus');
182+
});
183+
184+
it(`GIVEN a focused option in a listbox,
185+
WHEN the user presses the 'End' key,
186+
THEN the last option in the listbox should be focused.`, () => {
187+
cy.mount(<RegularAutocomplete />);
188+
189+
cy.get('button').click();
190+
191+
cy.findByRole('option', { name: 'Apricot' }).focus().type(`{end}`);
192+
193+
cy.get('li').last().should('have.focus');
194+
});
195+
196+
it(`GIVEN selected text in an input field,
197+
WHEN the user presses the 'Delete' key,
198+
THEN the text within the input field should be removed.`, () => {
199+
cy.mount(<RegularAutocomplete />);
200+
201+
cy.get('input')
202+
.type(`Here's some text!`)
203+
.type(`{selectall}`)
204+
.type(`{del}`)
205+
.should('have.value', '');
206+
});
207+
208+
it(`GIVEN an input field is present that is connected to a listbox,
209+
WHEN a value is entered into the input field,
210+
THEN the listbox should open.`, () => {
156211
cy.mount(<RegularAutocomplete />);
157212

158213
cy.get('input').type(`Ap`);
159214

160215
cy.findByRole('listbox').should('be.visible');
161216
});
162217

163-
it('Should input a value and select a value, with the input value as the option', () => {
218+
it(`GIVEN an input field is present that is connected to a listbox,
219+
WHEN a value is entered into the input field, and an option matching the input value is selected from the listbox,
220+
THEN the selected value should populate the input field.`, () => {
164221
cy.mount(<RegularAutocomplete />);
165222

166223
cy.get('input').type(`Ap`);
@@ -172,7 +229,9 @@ describe('Autocomplete', () => {
172229
cy.get('input').should('have.value', 'Apple');
173230
});
174231

175-
it('Should close the listbox when a value is selected', () => {
232+
it(`GIVEN a listbox is open and populated with selectable options,
233+
WHEN a value is selected from the listbox,
234+
THEN the listbox should close.`, () => {
176235
cy.mount(<RegularAutocomplete />);
177236

178237
cy.get('input').type(`Ap`);
@@ -184,7 +243,9 @@ describe('Autocomplete', () => {
184243
cy.findByRole('listbox').should('not.exist');
185244
});
186245

187-
it('Should focus the first filtered option when the down arrow is prssed', () => {
246+
it(`GIVEN a listbox is open and populated with filtered options,
247+
WHEN the down arrow key is pressed,
248+
THEN the first filtered option in the listbox should receive focus.`, () => {
188249
cy.mount(<RegularAutocomplete />);
189250

190251
cy.get('input').type(`Ba`);
@@ -196,23 +257,26 @@ describe('Autocomplete', () => {
196257
cy.get('li').filter(':visible').first().should('have.focus');
197258
});
198259

199-
it('Should select an option using the enter key, closing the listbox', () => {
260+
it(`GIVEN a listbox is open and an option is in focus,
261+
WHEN the enter key is pressed,
262+
THEN the focused option should be selected and the listbox should close.`, () => {
200263
cy.mount(<RegularAutocomplete />);
201264

202-
cy.get('input').type(`Ba`);
265+
cy.get('button').click();
203266

204267
cy.findByRole('listbox').should('be.visible');
205268

206-
cy.get('input').type(`{downarrow}`);
269+
cy.findByRole('option', { name: 'Guava' }).focus().type(`{enter}`);
207270

208-
cy.get('li').filter(':visible').first().type(`{enter}`);
209-
210-
cy.get('input').should('have.value', 'Banana');
271+
cy.get('input').should('have.value', 'Guava');
211272

212273
cy.findByRole('listbox').should('not.exist');
213274
});
214275

215-
it('Should go down an option and back up, using the up & down arrow keys', () => {
276+
it(`GIVEN a listbox is open and populated with selectable options,
277+
WHEN the down arrow key is pressed,
278+
THEN focus should move to the next option in the list,
279+
`, () => {
216280
cy.mount(<RegularAutocomplete />);
217281

218282
cy.get('input').type(`A`);
@@ -221,12 +285,22 @@ describe('Autocomplete', () => {
221285

222286
cy.get('input').type(`{downarrow}`);
223287

224-
cy.get('li').filter(':visible').first().type(`{downarrow}`);
288+
cy.findByRole('option', { name: 'Apple' }).focus().type(`{downarrow}`);
225289

226290
// grabs the 2nd element because the index is 1
227291
cy.get('li').filter(':visible').eq(1).should('have.focus');
292+
});
293+
294+
it(`GIVEN a listbox is open and populated with selectable options,
295+
WHEN the up arrow key is pressed,
296+
THEN focus should move back to the previous option in the list.`, () => {
297+
cy.mount(<RegularAutocomplete />);
298+
299+
cy.get('input').type(`A`);
300+
301+
cy.findByRole('listbox').should('be.visible');
228302

229-
cy.get('li').filter(':visible').eq(1).type(`{uparrow}`);
303+
cy.findByRole('option', { name: 'Apricot' }).focus().type(`{uparrow}`);
230304

231305
cy.get('li').filter(':visible').first().should('have.focus');
232306
});

packages/kit-headless/src/components/Autocomplete/autocomplete.stories.tsx

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -139,60 +139,6 @@ const RegularAutocomplete = () => (
139139
))}
140140
</AutocompleteListbox>
141141
</AutocompleteRoot>
142-
{/* <AutocompleteRoot style="width: fit-content">
143-
<AutocompleteLabel>Label</AutocompleteLabel>
144-
<AutocompleteTrigger>
145-
<AutocompleteInput />
146-
<AutocompleteButton>
147-
<svg
148-
xmlns="http://www.w3.org/2000/svg"
149-
viewBox="0 0 24 24"
150-
fill="none"
151-
stroke="currentColor"
152-
stroke-width="2"
153-
stroke-linecap="round"
154-
stroke-linejoin="round"
155-
style="width: 20px; height: 20px;"
156-
>
157-
<polyline points="6 9 12 15 18 9"></polyline>
158-
</svg>
159-
</AutocompleteButton>
160-
</AutocompleteTrigger>
161-
<AutocompleteListbox class="listboxStyle">
162-
{fruits.map((fruit, index) => (
163-
<AutocompleteOption optionValue={fruit} key={index}>
164-
{fruit}
165-
</AutocompleteOption>
166-
))}
167-
</AutocompleteListbox>
168-
</AutocompleteRoot>
169-
<AutocompleteRoot style="width: fit-content">
170-
<AutocompleteLabel>Label</AutocompleteLabel>
171-
<AutocompleteTrigger>
172-
<AutocompleteInput />
173-
<AutocompleteButton>
174-
<svg
175-
xmlns="http://www.w3.org/2000/svg"
176-
viewBox="0 0 24 24"
177-
fill="none"
178-
stroke="currentColor"
179-
stroke-width="2"
180-
stroke-linecap="round"
181-
stroke-linejoin="round"
182-
style="width: 20px; height: 20px;"
183-
>
184-
<polyline points="6 9 12 15 18 9"></polyline>
185-
</svg>
186-
</AutocompleteButton>
187-
</AutocompleteTrigger>
188-
<AutocompleteListbox class="listboxStyle">
189-
{fruits.map((fruit, index) => (
190-
<AutocompleteOption optionValue={fruit} key={index}>
191-
{fruit}
192-
</AutocompleteOption>
193-
))}
194-
</AutocompleteListbox>
195-
</AutocompleteRoot> */}
196142
</>
197143
);
198144

0 commit comments

Comments
 (0)