@getmicdrop/svelte-components 5.5.1 → 5.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/calendar/AboutShow/AboutShow.spec.d.ts +2 -0
- package/dist/calendar/AboutShow/AboutShow.spec.d.ts.map +1 -0
- package/dist/calendar/AboutShow/AboutShow.spec.js +791 -0
- package/dist/calendar/AboutShow/AboutShow.svelte +172 -172
- package/dist/calendar/Calendar/MiniMonthCalendar.spec.d.ts +2 -0
- package/dist/calendar/Calendar/MiniMonthCalendar.spec.d.ts.map +1 -0
- package/dist/calendar/Calendar/MiniMonthCalendar.spec.js +1191 -0
- package/dist/calendar/Calendar/MiniMonthCalendar.svelte +782 -782
- package/dist/calendar/FAQs/FAQs.spec.d.ts +2 -0
- package/dist/calendar/FAQs/FAQs.spec.d.ts.map +1 -0
- package/dist/calendar/FAQs/FAQs.spec.js +238 -0
- package/dist/calendar/FAQs/FAQs.svelte +75 -75
- package/dist/calendar/MonthSwitcher/MonthSwitcher.spec.d.ts +2 -0
- package/dist/calendar/MonthSwitcher/MonthSwitcher.spec.d.ts.map +1 -0
- package/dist/calendar/MonthSwitcher/MonthSwitcher.spec.js +420 -0
- package/dist/calendar/MonthSwitcher/MonthSwitcher.svelte +126 -126
- package/dist/calendar/OrderSummary/OrderSummary.spec.d.ts +2 -0
- package/dist/calendar/OrderSummary/OrderSummary.spec.d.ts.map +1 -0
- package/dist/calendar/OrderSummary/OrderSummary.spec.js +808 -0
- package/dist/calendar/OrderSummary/OrderSummary.svelte +367 -367
- package/dist/calendar/PublicCard/PublicCard.spec.d.ts +2 -0
- package/dist/calendar/PublicCard/PublicCard.spec.d.ts.map +1 -0
- package/dist/calendar/PublicCard/PublicCard.spec.js +301 -0
- package/dist/calendar/PublicCard/PublicCard.svelte +134 -134
- package/dist/calendar/ShowCard/ShowCard.spec.d.ts +2 -0
- package/dist/calendar/ShowCard/ShowCard.spec.d.ts.map +1 -0
- package/dist/calendar/ShowCard/ShowCard.spec.js +714 -0
- package/dist/calendar/ShowCard/ShowCard.svelte +157 -157
- package/dist/calendar/ShowTimeCard/ShowTimeCard.spec.d.ts +2 -0
- package/dist/calendar/ShowTimeCard/ShowTimeCard.spec.d.ts.map +1 -0
- package/dist/calendar/ShowTimeCard/ShowTimeCard.spec.js +241 -0
- package/dist/calendar/ShowTimeCard/ShowTimeCard.svelte +61 -61
- package/dist/components/Layout/Grid.svelte +4 -4
- package/dist/components/Layout/Section.spec.d.ts +2 -0
- package/dist/components/Layout/Section.spec.d.ts.map +1 -0
- package/dist/components/Layout/Section.spec.js +149 -0
- package/dist/components/Layout/Section.svelte +80 -80
- package/dist/components/Layout/Sidebar.spec.d.ts +2 -0
- package/dist/components/Layout/Sidebar.spec.d.ts.map +1 -0
- package/dist/components/Layout/Sidebar.spec.js +186 -0
- package/dist/components/Layout/Sidebar.svelte +108 -108
- package/dist/components/Layout/Stack.spec.js +3 -3
- package/dist/components/Layout/Stack.svelte +6 -6
- package/dist/constants/formOptions.spec.js +9 -5
- package/dist/constants/validation.js +91 -91
- package/dist/constants/validation.spec.js +64 -64
- package/dist/datetime/__tests__/format.test.js +1 -1
- package/dist/datetime/__tests__/parse.test.js +1 -1
- package/dist/datetime/__tests__/timezone.test.js +124 -2
- package/dist/datetime/parse.js +1 -1
- package/dist/forms/createFieldTracker.spec.d.ts +2 -0
- package/dist/forms/createFieldTracker.spec.d.ts.map +1 -0
- package/dist/forms/createFieldTracker.spec.js +343 -0
- package/dist/forms/createFormStore.spec.d.ts +2 -0
- package/dist/forms/createFormStore.spec.d.ts.map +1 -0
- package/dist/forms/createFormStore.spec.js +689 -0
- package/dist/forms/createFormStore.svelte.js +0 -1
- package/dist/index.d.ts +5 -112
- package/dist/index.js +40 -225
- package/dist/patterns/data/DataGrid.spec.d.ts +2 -0
- package/dist/patterns/data/DataGrid.spec.d.ts.map +1 -0
- package/dist/patterns/data/DataGrid.spec.js +159 -0
- package/dist/patterns/data/DataGrid.svelte +45 -45
- package/dist/patterns/data/DataList.spec.d.ts +2 -0
- package/dist/patterns/data/DataList.spec.d.ts.map +1 -0
- package/dist/patterns/data/DataList.spec.js +158 -0
- package/dist/patterns/data/DataList.svelte +24 -24
- package/dist/patterns/data/DataTable.spec.d.ts +2 -0
- package/dist/patterns/data/DataTable.spec.d.ts.map +1 -0
- package/dist/patterns/data/DataTable.spec.js +196 -0
- package/dist/patterns/data/DataTable.svelte +36 -36
- package/dist/patterns/forms/FormActions.spec.js +95 -88
- package/dist/patterns/forms/FormActions.stories.svelte +97 -97
- package/dist/patterns/forms/FormActions.svelte +46 -46
- package/dist/patterns/forms/FormGrid.spec.d.ts +2 -0
- package/dist/patterns/forms/FormGrid.spec.d.ts.map +1 -0
- package/dist/patterns/forms/FormGrid.spec.js +125 -0
- package/dist/patterns/forms/FormGrid.svelte +33 -33
- package/dist/patterns/forms/FormSection.spec.d.ts +2 -0
- package/dist/patterns/forms/FormSection.spec.d.ts.map +1 -0
- package/dist/patterns/forms/FormSection.spec.js +153 -0
- package/dist/patterns/forms/FormSection.svelte +32 -32
- package/dist/patterns/forms/FormValidationSummary.stories.svelte +83 -83
- package/dist/patterns/forms/FormValidationSummary.svelte +33 -33
- package/dist/patterns/layout/Sidebar.spec.d.ts +2 -0
- package/dist/patterns/layout/Sidebar.spec.d.ts.map +1 -0
- package/dist/patterns/layout/Sidebar.spec.js +159 -0
- package/dist/patterns/layout/Sidebar.svelte +39 -39
- package/dist/patterns/navigation/BottomNav.stories.svelte +117 -117
- package/dist/patterns/navigation/BottomNav.svelte +20 -20
- package/dist/patterns/navigation/Header.spec.js +33 -24
- package/dist/patterns/navigation/Header.stories.svelte +77 -77
- package/dist/patterns/navigation/Header.svelte +193 -193
- package/dist/patterns/page/PageHeader.spec.d.ts +2 -0
- package/dist/patterns/page/PageHeader.spec.d.ts.map +1 -0
- package/dist/patterns/page/PageHeader.spec.js +167 -0
- package/dist/patterns/page/PageHeader.svelte +18 -18
- package/dist/patterns/page/PageLayout.spec.d.ts +2 -0
- package/dist/patterns/page/PageLayout.spec.d.ts.map +1 -0
- package/dist/patterns/page/PageLayout.spec.js +145 -0
- package/dist/patterns/page/PageLayout.svelte +40 -40
- package/dist/patterns/page/PageLoader.spec.js +57 -54
- package/dist/patterns/page/PageLoader.stories.svelte +137 -137
- package/dist/patterns/page/PageLoader.svelte +24 -24
- package/dist/patterns/page/SectionHeader.spec.d.ts +2 -0
- package/dist/patterns/page/SectionHeader.spec.d.ts.map +1 -0
- package/dist/patterns/page/SectionHeader.spec.js +197 -0
- package/dist/patterns/page/SectionHeader.svelte +29 -29
- package/dist/presets/badges.js +112 -112
- package/dist/presets/badges.spec.d.ts +2 -0
- package/dist/presets/badges.spec.d.ts.map +1 -0
- package/dist/presets/badges.spec.js +172 -0
- package/dist/presets/buttons.js +76 -76
- package/dist/presets/buttons.spec.d.ts +2 -0
- package/dist/presets/buttons.spec.d.ts.map +1 -0
- package/dist/presets/buttons.spec.js +135 -0
- package/dist/presets/index.js +9 -9
- package/dist/primitives/Accordion/Accordion.spec.d.ts +2 -0
- package/dist/primitives/Accordion/Accordion.spec.d.ts.map +1 -0
- package/dist/primitives/Accordion/Accordion.spec.js +83 -0
- package/dist/primitives/Accordion/Accordion.stories.svelte +75 -75
- package/dist/primitives/Accordion/Accordion.svelte +42 -42
- package/dist/primitives/Accordion/AccordionItem.spec.d.ts +2 -0
- package/dist/primitives/Accordion/AccordionItem.spec.d.ts.map +1 -0
- package/dist/primitives/Accordion/AccordionItem.spec.js +661 -0
- package/dist/primitives/Accordion/AccordionItem.svelte +95 -95
- package/dist/primitives/Accordion/AccordionItemWrapper.test.svelte +107 -0
- package/dist/primitives/Accordion/AccordionItemWrapper.test.svelte.d.ts +35 -0
- package/dist/primitives/Accordion/AccordionItemWrapper.test.svelte.d.ts.map +1 -0
- package/dist/primitives/Alert/Alert.spec.js +173 -170
- package/dist/primitives/Alert/Alert.stories.svelte +88 -88
- package/dist/primitives/Alert/Alert.svelte +27 -27
- package/dist/primitives/Avatar/Avatar.spec.d.ts +2 -0
- package/dist/primitives/Avatar/Avatar.spec.d.ts.map +1 -0
- package/dist/primitives/Avatar/Avatar.spec.js +211 -0
- package/dist/primitives/Avatar/Avatar.stories.svelte +94 -94
- package/dist/primitives/Avatar/Avatar.svelte +66 -66
- package/dist/primitives/Badges/Badge.spec.js +144 -103
- package/dist/primitives/Badges/Badge.stories.svelte +86 -86
- package/dist/primitives/Badges/Badge.svelte +79 -79
- package/dist/primitives/BottomSheet/BottomSheet.spec.js +136 -127
- package/dist/primitives/BottomSheet/BottomSheet.stories.svelte +83 -83
- package/dist/primitives/BottomSheet/BottomSheet.svelte +100 -100
- package/dist/primitives/BottomSheet/BottomSheetWrapper.test.svelte +13 -0
- package/dist/primitives/BottomSheet/BottomSheetWrapper.test.svelte.d.ts +7 -0
- package/dist/primitives/BottomSheet/BottomSheetWrapper.test.svelte.d.ts.map +1 -0
- package/dist/primitives/Breadcrumb/Breadcrumb.spec.js +122 -120
- package/dist/primitives/Breadcrumb/Breadcrumb.stories.svelte +23 -23
- package/dist/primitives/Breadcrumb/Breadcrumb.svelte +89 -89
- package/dist/primitives/Button/Button.spec.js +223 -211
- package/dist/primitives/Button/Button.stories.svelte +76 -76
- package/dist/primitives/Button/Button.svelte +270 -270
- package/dist/primitives/Button/ButtonSaveDemo.spec.js +146 -48
- package/dist/primitives/Button/ButtonSaveDemo.svelte +25 -25
- package/dist/primitives/Button/ButtonVariantShowcase.spec.d.ts +2 -0
- package/dist/primitives/Button/ButtonVariantShowcase.spec.d.ts.map +1 -0
- package/dist/primitives/Button/ButtonVariantShowcase.spec.js +202 -0
- package/dist/primitives/Button/ButtonVariantShowcase.svelte +129 -129
- package/dist/primitives/Card.spec.js +49 -49
- package/dist/primitives/Card.stories.svelte +22 -22
- package/dist/primitives/Card.svelte +28 -28
- package/dist/primitives/Checkbox/Checkbox.spec.d.ts +2 -0
- package/dist/primitives/Checkbox/Checkbox.spec.d.ts.map +1 -0
- package/dist/primitives/Checkbox/Checkbox.spec.js +252 -0
- package/dist/primitives/Checkbox/Checkbox.stories.svelte +84 -84
- package/dist/primitives/Checkbox/Checkbox.svelte +88 -88
- package/dist/primitives/DarkModeToggle.spec.js +390 -357
- package/dist/primitives/DarkModeToggle.stories.svelte +57 -57
- package/dist/primitives/DarkModeToggle.svelte +136 -136
- package/dist/primitives/Drawer/Drawer.spec.d.ts +2 -0
- package/dist/primitives/Drawer/Drawer.spec.d.ts.map +1 -0
- package/dist/primitives/Drawer/Drawer.spec.js +212 -0
- package/dist/primitives/Drawer/Drawer.stories.svelte +80 -80
- package/dist/primitives/Drawer/Drawer.svelte +120 -120
- package/dist/primitives/Dropdown/Dropdown.spec.d.ts +2 -0
- package/dist/primitives/Dropdown/Dropdown.spec.d.ts.map +1 -0
- package/dist/primitives/Dropdown/Dropdown.spec.js +366 -0
- package/dist/primitives/Dropdown/Dropdown.stories.svelte +137 -137
- package/dist/primitives/Dropdown/Dropdown.svelte +14 -14
- package/dist/primitives/Dropdown/DropdownItem.spec.d.ts +2 -0
- package/dist/primitives/Dropdown/DropdownItem.spec.d.ts.map +1 -0
- package/dist/primitives/Dropdown/DropdownItem.spec.js +182 -0
- package/dist/primitives/Dropdown/DropdownItem.svelte +80 -80
- package/dist/primitives/Icons/ArrowLeft.svelte +8 -8
- package/dist/primitives/Icons/ArrowRight.svelte +8 -8
- package/dist/primitives/Icons/Availability.svelte +14 -14
- package/dist/primitives/Icons/Back.svelte +14 -14
- package/dist/primitives/Icons/CheckCircle.svelte +6 -6
- package/dist/primitives/Icons/CheckCircleOutline.svelte +15 -15
- package/dist/primitives/Icons/ChevronLeft.svelte +4 -4
- package/dist/primitives/Icons/ChevronRight.svelte +4 -4
- package/dist/primitives/Icons/Copy.svelte +15 -15
- package/dist/primitives/Icons/Cross.svelte +5 -5
- package/dist/primitives/Icons/DownArrow.svelte +8 -8
- package/dist/primitives/Icons/ErrorCircle.svelte +6 -6
- package/dist/primitives/Icons/FacebookIcon.svelte +2 -2
- package/dist/primitives/Icons/Home.svelte +15 -15
- package/dist/primitives/Icons/Icon.spec.js +169 -169
- package/dist/primitives/Icons/Icon.stories.svelte +100 -100
- package/dist/primitives/Icons/Icon.svelte +52 -52
- package/dist/primitives/Icons/IconGallery.stories.svelte +235 -235
- package/dist/primitives/Icons/Info.svelte +7 -7
- package/dist/primitives/Icons/InstagramIcon.svelte +4 -4
- package/dist/primitives/Icons/LogoInstagram.svelte +2 -2
- package/dist/primitives/Icons/Message.svelte +15 -15
- package/dist/primitives/Icons/MoonIcon.svelte +5 -5
- package/dist/primitives/Icons/More.svelte +21 -21
- package/dist/primitives/Icons/MoreHori.spec.js +61 -61
- package/dist/primitives/Icons/MoreHori.svelte +22 -22
- package/dist/primitives/Icons/Notification.svelte +14 -14
- package/dist/primitives/Icons/Payment.svelte +14 -14
- package/dist/primitives/Icons/Profile.svelte +21 -21
- package/dist/primitives/Icons/Reload.svelte +29 -29
- package/dist/primitives/Icons/Shows.svelte +21 -21
- package/dist/primitives/Icons/Signout.svelte +21 -21
- package/dist/primitives/Icons/SunIcon.svelte +8 -8
- package/dist/primitives/Icons/TiktokIcon.svelte +2 -2
- package/dist/primitives/Icons/TwitterIcon.svelte +2 -2
- package/dist/primitives/Icons/WarningIcon.spec.js +18 -18
- package/dist/primitives/Icons/WarningIcon.svelte +5 -5
- package/dist/primitives/Icons/iconTestUtils.spec.d.ts +2 -0
- package/dist/primitives/Icons/iconTestUtils.spec.d.ts.map +1 -0
- package/dist/primitives/Icons/iconTestUtils.spec.js +235 -0
- package/dist/primitives/Input/Input.spec.js +573 -573
- package/dist/primitives/Input/Input.stories.svelte +139 -139
- package/dist/primitives/Input/Input.svelte +384 -397
- package/dist/primitives/Input/Input.svelte.d.ts.map +1 -1
- package/dist/primitives/Input/Select.spec.js +212 -218
- package/dist/primitives/Input/Select.stories.svelte +112 -112
- package/dist/primitives/Input/Select.svelte +128 -128
- package/dist/primitives/Input/Textarea.spec.d.ts +2 -0
- package/dist/primitives/Input/Textarea.spec.d.ts.map +1 -0
- package/dist/primitives/Input/Textarea.spec.js +255 -0
- package/dist/primitives/Input/Textarea.stories.svelte +137 -137
- package/dist/primitives/Input/Textarea.svelte +35 -35
- package/dist/primitives/Label/Label.spec.d.ts +2 -0
- package/dist/primitives/Label/Label.spec.d.ts.map +1 -0
- package/dist/primitives/Label/Label.spec.js +157 -0
- package/dist/primitives/Label/Label.svelte +37 -37
- package/dist/primitives/Modal/Modal.spec.js +99 -95
- package/dist/primitives/Modal/Modal.stories.svelte +86 -86
- package/dist/primitives/Modal/Modal.svelte +158 -158
- package/dist/primitives/Modal/ModalTestWrapper.svelte +65 -0
- package/dist/primitives/Modal/ModalTestWrapper.svelte.d.ts +23 -0
- package/dist/primitives/Modal/ModalTestWrapper.svelte.d.ts.map +1 -0
- package/dist/primitives/NumberInput/NumberInput.spec.d.ts +2 -0
- package/dist/primitives/NumberInput/NumberInput.spec.d.ts.map +1 -0
- package/dist/primitives/NumberInput/NumberInput.spec.js +235 -0
- package/dist/primitives/NumberInput/NumberInput.svelte +106 -106
- package/dist/primitives/Pagination/Pagination.spec.d.ts +2 -0
- package/dist/primitives/Pagination/Pagination.spec.d.ts.map +1 -0
- package/dist/primitives/Pagination/Pagination.spec.js +266 -0
- package/dist/primitives/Pagination/Pagination.stories.svelte +76 -76
- package/dist/primitives/Pagination/Pagination.svelte +261 -261
- package/dist/primitives/Radio/Radio.spec.d.ts +2 -0
- package/dist/primitives/Radio/Radio.spec.d.ts.map +1 -0
- package/dist/primitives/Radio/Radio.spec.js +206 -0
- package/dist/primitives/Radio/Radio.stories.svelte +80 -80
- package/dist/primitives/Radio/Radio.svelte +67 -67
- package/dist/primitives/Skeleton/CardPlaceholder.spec.d.ts +2 -0
- package/dist/primitives/Skeleton/CardPlaceholder.spec.d.ts.map +1 -0
- package/dist/primitives/Skeleton/CardPlaceholder.spec.js +156 -0
- package/dist/primitives/Skeleton/CardPlaceholder.svelte +87 -87
- package/dist/primitives/Skeleton/ImagePlaceholder.spec.d.ts +2 -0
- package/dist/primitives/Skeleton/ImagePlaceholder.spec.d.ts.map +1 -0
- package/dist/primitives/Skeleton/ImagePlaceholder.spec.js +120 -0
- package/dist/primitives/Skeleton/ImagePlaceholder.svelte +59 -59
- package/dist/primitives/Skeleton/ListPlaceholder.spec.d.ts +2 -0
- package/dist/primitives/Skeleton/ListPlaceholder.spec.d.ts.map +1 -0
- package/dist/primitives/Skeleton/ListPlaceholder.spec.js +220 -0
- package/dist/primitives/Skeleton/ListPlaceholder.svelte +76 -76
- package/dist/primitives/Skeleton/Skeleton.spec.d.ts +2 -0
- package/dist/primitives/Skeleton/Skeleton.spec.d.ts.map +1 -0
- package/dist/primitives/Skeleton/Skeleton.spec.js +173 -0
- package/dist/primitives/Skeleton/Skeleton.stories.svelte +151 -151
- package/dist/primitives/Skeleton/Skeleton.svelte +26 -26
- package/dist/primitives/Spinner/Spinner.spec.js +71 -75
- package/dist/primitives/Spinner/Spinner.stories.svelte +29 -29
- package/dist/primitives/Spinner/Spinner.svelte +20 -20
- package/dist/primitives/Tabs/TabItem.spec.d.ts +2 -0
- package/dist/primitives/Tabs/TabItem.spec.d.ts.map +1 -0
- package/dist/primitives/Tabs/TabItem.spec.js +130 -0
- package/dist/primitives/Tabs/TabItem.svelte +49 -49
- package/dist/primitives/Tabs/Tabs.spec.d.ts +2 -0
- package/dist/primitives/Tabs/Tabs.spec.d.ts.map +1 -0
- package/dist/primitives/Tabs/Tabs.spec.js +295 -0
- package/dist/primitives/Tabs/Tabs.stories.svelte +112 -112
- package/dist/primitives/Tabs/Tabs.svelte +123 -123
- package/dist/primitives/Tabs/TabsWithItems.test.svelte +18 -0
- package/dist/primitives/Tabs/TabsWithItems.test.svelte.d.ts +16 -0
- package/dist/primitives/Tabs/TabsWithItems.test.svelte.d.ts.map +1 -0
- package/dist/primitives/Toggle.spec.js +143 -127
- package/dist/primitives/Toggle.stories.svelte +92 -92
- package/dist/primitives/Toggle.svelte +71 -71
- package/dist/primitives/Typography/Typography.spec.d.ts +2 -0
- package/dist/primitives/Typography/Typography.spec.d.ts.map +1 -0
- package/dist/primitives/Typography/Typography.spec.js +183 -0
- package/dist/primitives/Typography/Typography.svelte +53 -53
- package/dist/primitives/ValidationError.spec.js +103 -103
- package/dist/primitives/ValidationError.stories.svelte +69 -69
- package/dist/primitives/ValidationError.svelte +29 -29
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.js +3 -0
- package/dist/recipes/CropImage/CropImage.spec.js +208 -216
- package/dist/recipes/CropImage/CropImage.stories.svelte +104 -104
- package/dist/recipes/CropImage/CropImage.svelte +238 -238
- package/dist/recipes/ImageUploader/ImageUploader.spec.d.ts +2 -0
- package/dist/recipes/ImageUploader/ImageUploader.spec.d.ts.map +1 -0
- package/dist/recipes/ImageUploader/ImageUploader.spec.js +1351 -0
- package/dist/recipes/ImageUploader/ImageUploader.stories.svelte +125 -125
- package/dist/recipes/ImageUploader/ImageUploader.svelte +804 -804
- package/dist/recipes/SuperLogin/SuperLogin.spec.d.ts +2 -0
- package/dist/recipes/SuperLogin/SuperLogin.spec.d.ts.map +1 -0
- package/dist/recipes/SuperLogin/SuperLogin.spec.js +1436 -0
- package/dist/recipes/SuperLogin/SuperLogin.svelte +7 -6
- package/dist/recipes/SuperLogin/SuperLogin.svelte.d.ts.map +1 -1
- package/dist/recipes/Toaster/Toaster.stories.svelte +62 -62
- package/dist/recipes/feedback/EmptyState/EmptyState.spec.d.ts +2 -0
- package/dist/recipes/feedback/EmptyState/EmptyState.spec.d.ts.map +1 -0
- package/dist/recipes/feedback/EmptyState/EmptyState.spec.js +202 -0
- package/dist/recipes/feedback/EmptyState/EmptyState.svelte +1 -1
- package/dist/recipes/feedback/ErrorDisplay.spec.js +69 -69
- package/dist/recipes/feedback/ErrorDisplay.stories.svelte +101 -101
- package/dist/recipes/feedback/ErrorDisplay.svelte +1 -1
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.spec.js +133 -129
- package/dist/recipes/feedback/StatusIndicator/StatusIndicator.svelte +157 -157
- package/dist/recipes/fields/CheckboxField.spec.d.ts +2 -0
- package/dist/recipes/fields/CheckboxField.spec.d.ts.map +1 -0
- package/dist/recipes/fields/CheckboxField.spec.js +135 -0
- package/dist/recipes/fields/CheckboxField.svelte +85 -85
- package/dist/recipes/fields/FormField.spec.d.ts +2 -0
- package/dist/recipes/fields/FormField.spec.d.ts.map +1 -0
- package/dist/recipes/fields/FormField.spec.js +159 -0
- package/dist/recipes/fields/FormField.svelte +58 -58
- package/dist/recipes/fields/RadioGroup.spec.d.ts +2 -0
- package/dist/recipes/fields/RadioGroup.spec.d.ts.map +1 -0
- package/dist/recipes/fields/RadioGroup.spec.js +199 -0
- package/dist/recipes/fields/RadioGroup.svelte +95 -95
- package/dist/recipes/fields/SelectField.spec.d.ts +2 -0
- package/dist/recipes/fields/SelectField.spec.d.ts.map +1 -0
- package/dist/recipes/fields/SelectField.spec.js +188 -0
- package/dist/recipes/fields/SelectField.svelte +80 -80
- package/dist/recipes/fields/TextareaField.spec.d.ts +2 -0
- package/dist/recipes/fields/TextareaField.spec.d.ts.map +1 -0
- package/dist/recipes/fields/TextareaField.spec.js +205 -0
- package/dist/recipes/fields/TextareaField.svelte +97 -97
- package/dist/recipes/fields/ToggleField.spec.d.ts +2 -0
- package/dist/recipes/fields/ToggleField.spec.d.ts.map +1 -0
- package/dist/recipes/fields/ToggleField.spec.js +153 -0
- package/dist/recipes/fields/ToggleField.svelte +60 -60
- package/dist/recipes/fields/index.js +7 -7
- package/dist/recipes/inputs/MultiSelect.spec.js +258 -257
- package/dist/recipes/inputs/MultiSelect.stories.svelte +133 -133
- package/dist/recipes/inputs/MultiSelect.svelte +256 -249
- package/dist/recipes/inputs/MultiSelect.svelte.d.ts +2 -0
- package/dist/recipes/inputs/MultiSelect.svelte.d.ts.map +1 -1
- package/dist/recipes/inputs/OTPInput.spec.js +251 -238
- package/dist/recipes/inputs/OTPInput.stories.svelte +162 -162
- package/dist/recipes/inputs/OTPInput.svelte +29 -29
- package/dist/recipes/inputs/PasswordInput.spec.d.ts +2 -0
- package/dist/recipes/inputs/PasswordInput.spec.d.ts.map +1 -0
- package/dist/recipes/inputs/PasswordInput.spec.js +410 -0
- package/dist/recipes/inputs/PasswordInput.svelte +22 -22
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.spec.js +245 -165
- package/dist/recipes/inputs/PasswordStrengthIndicator/PasswordStrengthIndicator.svelte +43 -43
- package/dist/recipes/inputs/PasswordStrengthIndicator/TestWrapper.svelte +71 -0
- package/dist/recipes/inputs/PasswordStrengthIndicator/TestWrapper.svelte.d.ts +9 -0
- package/dist/recipes/inputs/PasswordStrengthIndicator/TestWrapper.svelte.d.ts.map +1 -0
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.spec.js +1139 -193
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.stories.svelte +123 -123
- package/dist/recipes/inputs/PlaceAutocomplete/PlaceAutocomplete.svelte +326 -326
- package/dist/recipes/inputs/Search.spec.d.ts +2 -0
- package/dist/recipes/inputs/Search.spec.d.ts.map +1 -0
- package/dist/recipes/inputs/Search.spec.js +177 -0
- package/dist/recipes/inputs/Search.svelte +37 -37
- package/dist/recipes/inputs/SelectDropdown.spec.d.ts +2 -0
- package/dist/recipes/inputs/SelectDropdown.spec.d.ts.map +1 -0
- package/dist/recipes/inputs/SelectDropdown.spec.js +512 -0
- package/dist/recipes/inputs/SelectDropdown.svelte +57 -57
- package/dist/recipes/modals/AlertModal.spec.d.ts +2 -0
- package/dist/recipes/modals/AlertModal.spec.d.ts.map +1 -0
- package/dist/recipes/modals/AlertModal.spec.js +432 -0
- package/dist/recipes/modals/AlertModal.svelte +130 -130
- package/dist/recipes/modals/ConfirmationModal.spec.js +206 -191
- package/dist/recipes/modals/ConfirmationModal.stories.svelte +119 -119
- package/dist/recipes/modals/ConfirmationModal.svelte +152 -152
- package/dist/recipes/modals/InputModal.spec.d.ts +2 -0
- package/dist/recipes/modals/InputModal.spec.d.ts.map +1 -0
- package/dist/recipes/modals/InputModal.spec.js +872 -0
- package/dist/recipes/modals/InputModal.svelte +182 -182
- package/dist/recipes/modals/ModalStateManager.spec.js +100 -100
- package/dist/recipes/modals/ModalStateManager.svelte +77 -77
- package/dist/recipes/modals/ModalTestWrapper.spec.d.ts +2 -0
- package/dist/recipes/modals/ModalTestWrapper.spec.d.ts.map +1 -0
- package/dist/recipes/modals/ModalTestWrapper.spec.js +502 -0
- package/dist/recipes/modals/ModalTestWrapper.svelte +65 -65
- package/dist/recipes/modals/StatusModal.spec.d.ts +2 -0
- package/dist/recipes/modals/StatusModal.spec.d.ts.map +1 -0
- package/dist/recipes/modals/StatusModal.spec.js +599 -0
- package/dist/recipes/modals/StatusModal.svelte +206 -206
- package/dist/services/EventService.js +75 -75
- package/dist/services/EventService.spec.js +217 -217
- package/dist/services/ShowService.spec.js +345 -342
- package/dist/stores/auth.js +36 -36
- package/dist/stores/auth.spec.js +139 -139
- package/dist/stores/toaster.js +13 -13
- package/dist/stories/ButtonAuditDashboard.spec.d.ts +2 -0
- package/dist/stories/ButtonAuditDashboard.spec.d.ts.map +1 -0
- package/dist/stories/ButtonAuditDashboard.spec.js +913 -0
- package/dist/stories/ButtonAuditReview.spec.d.ts +2 -0
- package/dist/stories/ButtonAuditReview.spec.d.ts.map +1 -0
- package/dist/stories/ButtonAuditReview.spec.js +422 -0
- package/dist/stories/ButtonAuditReview.stories.svelte +14 -14
- package/dist/stories/ButtonAuditReview.svelte +427 -427
- package/dist/stories/ButtonGridView.spec.d.ts +2 -0
- package/dist/stories/ButtonGridView.spec.d.ts.map +1 -0
- package/dist/stories/ButtonGridView.spec.js +667 -0
- package/dist/stories/ButtonShowcase.spec.d.ts +2 -0
- package/dist/stories/ButtonShowcase.spec.d.ts.map +1 -0
- package/dist/stories/ButtonShowcase.spec.js +499 -0
- package/dist/stories/PatternsGallery.spec.d.ts +2 -0
- package/dist/stories/PatternsGallery.spec.d.ts.map +1 -0
- package/dist/stories/PatternsGallery.spec.js +514 -0
- package/dist/stories/PatternsGallery.stories.svelte +19 -19
- package/dist/stories/PatternsGallery.svelte +206 -206
- package/dist/stories/PrimitivesGallery.spec.d.ts +2 -0
- package/dist/stories/PrimitivesGallery.spec.d.ts.map +1 -0
- package/dist/stories/PrimitivesGallery.spec.js +813 -0
- package/dist/stories/PrimitivesGallery.stories.svelte +19 -19
- package/dist/stories/PrimitivesGallery.svelte +725 -725
- package/dist/stories/RecipesGallery.spec.d.ts +2 -0
- package/dist/stories/RecipesGallery.spec.d.ts.map +1 -0
- package/dist/stories/RecipesGallery.spec.js +299 -0
- package/dist/stories/RecipesGallery.stories.svelte +19 -19
- package/dist/stories/RecipesGallery.svelte +271 -271
- package/dist/stories/button-audit-manifest.json +11186 -11186
- package/dist/stripe/useStripeTheme.spec.d.ts +2 -0
- package/dist/stripe/useStripeTheme.spec.d.ts.map +1 -0
- package/dist/stripe/useStripeTheme.spec.js +793 -0
- package/dist/tailwind/preset.cjs +82 -82
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +6 -5
- package/dist/telemetry.spec.js +495 -12
- package/dist/tokens/__tests__/colors.test.d.ts +2 -0
- package/dist/tokens/__tests__/colors.test.d.ts.map +1 -0
- package/dist/tokens/__tests__/colors.test.js +152 -0
- package/dist/tokens/__tests__/radius.test.d.ts +2 -0
- package/dist/tokens/__tests__/radius.test.d.ts.map +1 -0
- package/dist/tokens/__tests__/radius.test.js +118 -0
- package/dist/tokens/__tests__/shadows.test.d.ts +2 -0
- package/dist/tokens/__tests__/shadows.test.d.ts.map +1 -0
- package/dist/tokens/__tests__/shadows.test.js +105 -0
- package/dist/tokens/__tests__/spacing.test.js +11 -8
- package/dist/tokens/__tests__/typography.test.d.ts +2 -0
- package/dist/tokens/__tests__/typography.test.d.ts.map +1 -0
- package/dist/tokens/__tests__/typography.test.js +156 -0
- package/dist/tokens/__tests__/z-index.test.d.ts +2 -0
- package/dist/tokens/__tests__/z-index.test.d.ts.map +1 -0
- package/dist/tokens/__tests__/z-index.test.js +121 -0
- package/dist/tokens/tokens.css +87 -87
- package/dist/utils/apiConfig.spec.js +102 -1
- package/dist/utils/formatters.spec.d.ts +2 -0
- package/dist/utils/formatters.spec.d.ts.map +1 -0
- package/dist/utils/formatters.spec.js +82 -0
- package/dist/utils/transitions.d.ts +24 -0
- package/dist/utils/transitions.d.ts.map +1 -0
- package/dist/utils/transitions.js +62 -0
- package/dist/utils/transitions.spec.d.ts +2 -0
- package/dist/utils/transitions.spec.d.ts.map +1 -0
- package/dist/utils/transitions.spec.js +130 -0
- package/dist/utils/utils.js +354 -354
- package/package.json +288 -283
|
@@ -1,300 +1,1246 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
vi.mock('../../lib/config.js', () => ({
|
|
6
|
-
PUBLIC_GOOGLE_MAPS_API_KEY: 'mock-api-key',
|
|
7
|
-
}));
|
|
1
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { expect, describe, test, vi, beforeEach, afterEach } from 'vitest';
|
|
4
|
+
import PlaceAutocomplete from './PlaceAutocomplete.svelte';
|
|
8
5
|
|
|
9
6
|
// Mock Google Maps API
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{
|
|
14
|
-
placePrediction: {
|
|
15
|
-
text: { toString: () => 'Los Angeles, CA, USA' },
|
|
16
|
-
types: ['locality', 'political'],
|
|
17
|
-
toPlace: vi.fn().mockReturnValue({
|
|
18
|
-
fetchFields: vi.fn().mockResolvedValue({}),
|
|
19
|
-
toJSON: vi.fn().mockReturnValue({
|
|
20
|
-
text: 'Los Angeles, CA, USA',
|
|
21
|
-
formattedAddress: '123 Main St, Los Angeles, CA 90012',
|
|
22
|
-
}),
|
|
23
|
-
}),
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
placePrediction: {
|
|
28
|
-
text: { toString: () => 'Long Beach, CA, USA' },
|
|
29
|
-
types: ['locality', 'political'],
|
|
30
|
-
toPlace: vi.fn().mockReturnValue({
|
|
31
|
-
fetchFields: vi.fn().mockResolvedValue({}),
|
|
32
|
-
toJSON: vi.fn().mockReturnValue({
|
|
33
|
-
text: 'Long Beach, CA, USA',
|
|
34
|
-
formattedAddress: '456 Beach St, Long Beach, CA 90801',
|
|
35
|
-
}),
|
|
36
|
-
}),
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
});
|
|
7
|
+
const mockAutocompleteSuggestion = {
|
|
8
|
+
fetchAutocompleteSuggestions: vi.fn(),
|
|
9
|
+
};
|
|
41
10
|
|
|
11
|
+
const mockAutocompleteSessionToken = vi.fn();
|
|
12
|
+
|
|
13
|
+
const mockLoader = {
|
|
14
|
+
importLibrary: vi.fn().mockResolvedValue({
|
|
15
|
+
AutocompleteSessionToken: mockAutocompleteSessionToken,
|
|
16
|
+
AutocompleteSuggestion: mockAutocompleteSuggestion,
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Mock the Google Maps Loader
|
|
42
21
|
vi.mock('@googlemaps/js-api-loader', () => ({
|
|
43
|
-
Loader: vi.fn().mockImplementation(() =>
|
|
44
|
-
importLibrary: vi.fn().mockResolvedValue({
|
|
45
|
-
AutocompleteSessionToken: mockAutocompleteSessionToken,
|
|
46
|
-
AutocompleteSuggestion: {
|
|
47
|
-
fetchAutocompleteSuggestions: mockFetchAutocompleteSuggestions,
|
|
48
|
-
},
|
|
49
|
-
}),
|
|
50
|
-
})),
|
|
22
|
+
Loader: vi.fn().mockImplementation(() => mockLoader),
|
|
51
23
|
}));
|
|
52
24
|
|
|
53
|
-
|
|
54
|
-
|
|
25
|
+
// Mock config
|
|
26
|
+
vi.mock('$lib/config.js', () => ({
|
|
27
|
+
PUBLIC_GOOGLE_MAPS_API_KEY: 'test-api-key',
|
|
28
|
+
}));
|
|
55
29
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
30
|
+
function setupTest(props = {}) {
|
|
31
|
+
const user = userEvent.setup();
|
|
32
|
+
const result = render(PlaceAutocomplete, { props });
|
|
33
|
+
return { user, container: result.container };
|
|
34
|
+
}
|
|
60
35
|
|
|
36
|
+
describe('PlaceAutocomplete Component', () => {
|
|
61
37
|
beforeEach(() => {
|
|
62
38
|
vi.clearAllMocks();
|
|
39
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
40
|
+
suggestions: [],
|
|
41
|
+
});
|
|
63
42
|
});
|
|
64
43
|
|
|
65
44
|
afterEach(() => {
|
|
66
|
-
|
|
45
|
+
vi.clearAllMocks();
|
|
67
46
|
});
|
|
68
47
|
|
|
69
|
-
describe('
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
48
|
+
describe('Rendering', () => {
|
|
49
|
+
test('renders input element', () => {
|
|
50
|
+
setupTest();
|
|
51
|
+
const input = screen.getByRole('textbox');
|
|
52
|
+
expect(input).toBeInTheDocument();
|
|
73
53
|
});
|
|
74
54
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
55
|
+
test('renders with default placeholder', async () => {
|
|
56
|
+
setupTest();
|
|
57
|
+
await waitFor(() => {
|
|
58
|
+
const input = screen.getByRole('textbox');
|
|
59
|
+
expect(input).toHaveAttribute('placeholder', 'Search for location...');
|
|
60
|
+
});
|
|
79
61
|
});
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
63
|
+
test('renders with custom placeholder', () => {
|
|
64
|
+
setupTest({ placeholder: 'Find a venue...' });
|
|
65
|
+
const input = screen.getByRole('textbox');
|
|
66
|
+
expect(input).toHaveAttribute('placeholder', 'Find a venue...');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('renders search icon', () => {
|
|
70
|
+
const { container } = setupTest();
|
|
71
|
+
const icon = container.querySelector('svg');
|
|
72
|
+
expect(icon).toBeInTheDocument();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('applies wrapper styles correctly', () => {
|
|
76
|
+
const { container } = setupTest();
|
|
77
|
+
const wrapper = container.querySelector('.relative.rounded-lg');
|
|
78
|
+
expect(wrapper).toBeInTheDocument();
|
|
87
79
|
});
|
|
88
80
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
test('input has correct name attribute', () => {
|
|
82
|
+
setupTest();
|
|
83
|
+
const input = screen.getByRole('textbox');
|
|
84
|
+
expect(input).toHaveAttribute('name', 'location');
|
|
92
85
|
});
|
|
93
86
|
});
|
|
94
87
|
|
|
95
|
-
describe('
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
88
|
+
describe('Initial Value', () => {
|
|
89
|
+
test('displays initial value', async () => {
|
|
90
|
+
setupTest({ initialValue: 'New York, NY' });
|
|
91
|
+
await waitFor(() => {
|
|
92
|
+
const input = screen.getByRole('textbox');
|
|
93
|
+
expect(input.value).toBe('New York, NY');
|
|
99
94
|
});
|
|
100
|
-
const input = container.querySelector('input');
|
|
101
|
-
expect(input?.value).toBe('New York, NY');
|
|
102
95
|
});
|
|
103
96
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const input = container.querySelector('input');
|
|
109
|
-
expect(input?.disabled).toBe(true);
|
|
97
|
+
test('does not display value when initialValue is empty', () => {
|
|
98
|
+
setupTest({ initialValue: '' });
|
|
99
|
+
const input = screen.getByRole('textbox');
|
|
100
|
+
expect(input.value).toBe('');
|
|
110
101
|
});
|
|
102
|
+
});
|
|
111
103
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
expect(input?.placeholder).toContain('city, state');
|
|
104
|
+
describe('Disabled State', () => {
|
|
105
|
+
test('input can be disabled', () => {
|
|
106
|
+
setupTest({ disabled: true });
|
|
107
|
+
const input = screen.getByRole('textbox');
|
|
108
|
+
expect(input).toBeDisabled();
|
|
118
109
|
});
|
|
119
110
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
test('input is enabled by default', () => {
|
|
112
|
+
setupTest();
|
|
113
|
+
const input = screen.getByRole('textbox');
|
|
114
|
+
expect(input).not.toBeDisabled();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('applies disabled opacity class', () => {
|
|
118
|
+
setupTest({ disabled: true });
|
|
119
|
+
const input = screen.getByRole('textbox');
|
|
120
|
+
expect(input).toHaveClass('disabled:opacity-50');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('Animation', () => {
|
|
125
|
+
test('applies animation class when animateFocus is true', () => {
|
|
126
|
+
const { container } = setupTest({ animateFocus: true });
|
|
127
|
+
const wrapper = container.querySelector('.transition-transform');
|
|
128
|
+
expect(wrapper).toBeInTheDocument();
|
|
129
|
+
expect(wrapper).toHaveClass('focus-within:scale-[1.01]');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('does not apply animation when animateFocus is false', () => {
|
|
133
|
+
const { container } = setupTest({ animateFocus: false });
|
|
134
|
+
const wrapper = container.querySelector('.transition-transform');
|
|
135
|
+
expect(wrapper).not.toBeInTheDocument();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('does not apply animation when disabled', () => {
|
|
139
|
+
const { container } = setupTest({ animateFocus: true, disabled: true });
|
|
140
|
+
const wrapper = container.querySelector('.transition-transform');
|
|
141
|
+
expect(wrapper).not.toBeInTheDocument();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('Mode Variants', () => {
|
|
146
|
+
test('default mode is full', () => {
|
|
147
|
+
setupTest();
|
|
148
|
+
const input = screen.getByRole('textbox');
|
|
149
|
+
expect(input).toHaveAttribute('placeholder', 'Search for location...');
|
|
125
150
|
});
|
|
126
151
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
152
|
+
test('cityState mode updates placeholder', async () => {
|
|
153
|
+
setupTest({ mode: 'cityState' });
|
|
154
|
+
await waitFor(() => {
|
|
155
|
+
const input = screen.getByRole('textbox');
|
|
156
|
+
expect(input).toHaveAttribute('placeholder', 'Search for city, state...');
|
|
130
157
|
});
|
|
131
|
-
|
|
132
|
-
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('cityState mode with custom placeholder keeps custom value', () => {
|
|
161
|
+
setupTest({ mode: 'cityState', placeholder: 'Custom placeholder' });
|
|
162
|
+
const input = screen.getByRole('textbox');
|
|
163
|
+
expect(input).toHaveAttribute('placeholder', 'Custom placeholder');
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('Autocomplete Attribute', () => {
|
|
168
|
+
test('has autocomplete off by default', () => {
|
|
169
|
+
setupTest();
|
|
170
|
+
const input = screen.getByRole('textbox');
|
|
171
|
+
expect(input).toHaveAttribute('autocomplete', 'off');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('can set autocomplete to on', () => {
|
|
175
|
+
setupTest({ autocomplete: 'on' });
|
|
176
|
+
const input = screen.getByRole('textbox');
|
|
177
|
+
expect(input).toHaveAttribute('autocomplete', 'on');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('User Input', () => {
|
|
182
|
+
test('updates input value on typing', async () => {
|
|
183
|
+
const { user } = setupTest();
|
|
184
|
+
const input = screen.getByRole('textbox');
|
|
185
|
+
|
|
186
|
+
await user.type(input, 'Los Angeles');
|
|
187
|
+
expect(input.value).toBe('Los Angeles');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('clears input when empty value is typed', async () => {
|
|
191
|
+
const { user } = setupTest({ initialValue: 'Test' });
|
|
192
|
+
const input = screen.getByRole('textbox');
|
|
193
|
+
|
|
194
|
+
await user.clear(input);
|
|
195
|
+
expect(input.value).toBe('');
|
|
133
196
|
});
|
|
134
197
|
});
|
|
135
198
|
|
|
136
|
-
describe('
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
|
|
199
|
+
describe('Autocomplete Suggestions', () => {
|
|
200
|
+
test('displays suggestions when typing', async () => {
|
|
201
|
+
const mockSuggestions = [
|
|
202
|
+
{
|
|
203
|
+
placePrediction: {
|
|
204
|
+
text: { toString: () => 'Los Angeles, CA, USA' },
|
|
205
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
placePrediction: {
|
|
210
|
+
text: { toString: () => 'Los Angeles County, CA, USA' },
|
|
211
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
];
|
|
140
215
|
|
|
141
|
-
|
|
142
|
-
|
|
216
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
217
|
+
suggestions: mockSuggestions,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const { user } = setupTest();
|
|
221
|
+
const input = screen.getByRole('textbox');
|
|
222
|
+
|
|
223
|
+
await user.type(input, 'Los Angeles');
|
|
224
|
+
|
|
225
|
+
await waitFor(() => {
|
|
226
|
+
const options = screen.getByRole('list', { id: 'options' });
|
|
227
|
+
expect(options).toBeInTheDocument();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('does not display suggestions list when results are empty', async () => {
|
|
232
|
+
const { user } = setupTest();
|
|
233
|
+
const input = screen.getByRole('textbox');
|
|
234
|
+
|
|
235
|
+
await user.type(input, 'xyz');
|
|
236
|
+
|
|
237
|
+
const options = screen.queryByRole('list');
|
|
238
|
+
expect(options).not.toBeInTheDocument();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('filters cityState results correctly', async () => {
|
|
242
|
+
const mockSuggestions = [
|
|
243
|
+
{
|
|
244
|
+
placePrediction: {
|
|
245
|
+
text: { toString: () => 'Los Angeles, CA, USA' },
|
|
246
|
+
types: ['locality', 'political'],
|
|
247
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
placePrediction: {
|
|
252
|
+
text: { toString: () => 'California, USA' },
|
|
253
|
+
types: ['administrative_area_level_1', 'political'],
|
|
254
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
placePrediction: {
|
|
259
|
+
text: { toString: () => 'Van Nuys, Los Angeles, CA, USA' },
|
|
260
|
+
types: ['sublocality', 'political'],
|
|
261
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
267
|
+
suggestions: mockSuggestions,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const { user } = setupTest({ mode: 'cityState' });
|
|
271
|
+
const input = screen.getByRole('textbox');
|
|
272
|
+
|
|
273
|
+
await user.type(input, 'Los Angeles');
|
|
274
|
+
|
|
275
|
+
await waitFor(() => {
|
|
276
|
+
const buttons = screen.getAllByRole('button');
|
|
277
|
+
// Should have 2 results: Los Angeles and Van Nuys (not California)
|
|
278
|
+
expect(buttons).toHaveLength(2);
|
|
279
|
+
});
|
|
143
280
|
});
|
|
144
281
|
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
282
|
+
test('formats cityState results to show first two parts', async () => {
|
|
283
|
+
const mockSuggestions = [
|
|
284
|
+
{
|
|
285
|
+
placePrediction: {
|
|
286
|
+
text: { toString: () => 'Los Angeles, CA, USA' },
|
|
287
|
+
types: ['locality'],
|
|
288
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
294
|
+
suggestions: mockSuggestions,
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
const { user } = setupTest({ mode: 'cityState' });
|
|
298
|
+
const input = screen.getByRole('textbox');
|
|
299
|
+
|
|
300
|
+
await user.type(input, 'Los Angeles');
|
|
148
301
|
|
|
149
|
-
await
|
|
150
|
-
|
|
151
|
-
|
|
302
|
+
await waitFor(() => {
|
|
303
|
+
const button = screen.getByText('Los Angeles, CA');
|
|
304
|
+
expect(button).toBeInTheDocument();
|
|
305
|
+
});
|
|
152
306
|
});
|
|
153
307
|
});
|
|
154
308
|
|
|
155
309
|
describe('Keyboard Navigation', () => {
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
310
|
+
beforeEach(() => {
|
|
311
|
+
const mockSuggestions = [
|
|
312
|
+
{
|
|
313
|
+
placePrediction: {
|
|
314
|
+
text: { toString: () => 'Result 1' },
|
|
315
|
+
toPlace: () => ({
|
|
316
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
317
|
+
toJSON: () => ({ text: 'Result 1' }),
|
|
318
|
+
}),
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
placePrediction: {
|
|
323
|
+
text: { toString: () => 'Result 2' },
|
|
324
|
+
toPlace: () => ({
|
|
325
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
326
|
+
toJSON: () => ({ text: 'Result 2' }),
|
|
327
|
+
}),
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
placePrediction: {
|
|
332
|
+
text: { toString: () => 'Result 3' },
|
|
333
|
+
toPlace: () => ({
|
|
334
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
335
|
+
toJSON: () => ({ text: 'Result 3' }),
|
|
336
|
+
}),
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
];
|
|
159
340
|
|
|
160
|
-
|
|
161
|
-
|
|
341
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
342
|
+
suggestions: mockSuggestions,
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test('ArrowDown highlights first suggestion', async () => {
|
|
347
|
+
const { user, container } = setupTest();
|
|
348
|
+
const input = screen.getByRole('textbox');
|
|
349
|
+
|
|
350
|
+
await user.type(input, 'Test');
|
|
351
|
+
|
|
352
|
+
await waitFor(() => {
|
|
353
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
357
|
+
|
|
358
|
+
await waitFor(() => {
|
|
359
|
+
const highlighted = container.querySelector('.bg-gray-100');
|
|
360
|
+
expect(highlighted).toBeInTheDocument();
|
|
361
|
+
});
|
|
162
362
|
});
|
|
163
363
|
|
|
164
|
-
|
|
165
|
-
const { container } =
|
|
166
|
-
const input =
|
|
364
|
+
test('ArrowDown cycles through suggestions', async () => {
|
|
365
|
+
const { user, container } = setupTest();
|
|
366
|
+
const input = screen.getByRole('textbox');
|
|
367
|
+
|
|
368
|
+
await user.type(input, 'Test');
|
|
369
|
+
|
|
370
|
+
await waitFor(() => {
|
|
371
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Press down three times
|
|
375
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
376
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
377
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
167
378
|
|
|
379
|
+
// Should cycle back to first
|
|
168
380
|
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
169
|
-
|
|
381
|
+
|
|
382
|
+
const highlighted = container.querySelectorAll('.bg-gray-100');
|
|
383
|
+
expect(highlighted.length).toBeGreaterThan(0);
|
|
170
384
|
});
|
|
171
385
|
|
|
172
|
-
|
|
173
|
-
const { container } =
|
|
174
|
-
const input =
|
|
386
|
+
test('ArrowUp highlights last suggestion when none selected', async () => {
|
|
387
|
+
const { user, container } = setupTest();
|
|
388
|
+
const input = screen.getByRole('textbox');
|
|
389
|
+
|
|
390
|
+
await user.type(input, 'Test');
|
|
175
391
|
|
|
392
|
+
await waitFor(() => {
|
|
393
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
await fireEvent.keyDown(input, { key: 'ArrowUp' });
|
|
397
|
+
|
|
398
|
+
const highlighted = container.querySelector('.bg-gray-100');
|
|
399
|
+
expect(highlighted).toBeInTheDocument();
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test('ArrowUp moves selection upward', async () => {
|
|
403
|
+
const { user, container } = setupTest();
|
|
404
|
+
const input = screen.getByRole('textbox');
|
|
405
|
+
|
|
406
|
+
await user.type(input, 'Test');
|
|
407
|
+
|
|
408
|
+
await waitFor(() => {
|
|
409
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// Go down twice, then up once
|
|
413
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
414
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
176
415
|
await fireEvent.keyDown(input, { key: 'ArrowUp' });
|
|
177
|
-
|
|
416
|
+
|
|
417
|
+
// Should be on first suggestion - check the li element
|
|
418
|
+
await waitFor(() => {
|
|
419
|
+
const highlighted = container.querySelector('li.bg-gray-100');
|
|
420
|
+
expect(highlighted).toBeInTheDocument();
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
test('Enter selects highlighted suggestion', async () => {
|
|
425
|
+
const onResponse = vi.fn();
|
|
426
|
+
const { user } = setupTest({ onResponse });
|
|
427
|
+
const input = screen.getByRole('textbox');
|
|
428
|
+
|
|
429
|
+
await user.type(input, 'Test');
|
|
430
|
+
|
|
431
|
+
await waitFor(() => {
|
|
432
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
436
|
+
await fireEvent.keyDown(input, { key: 'Enter' });
|
|
437
|
+
|
|
438
|
+
await waitFor(() => {
|
|
439
|
+
expect(onResponse).toHaveBeenCalled();
|
|
440
|
+
});
|
|
178
441
|
});
|
|
179
442
|
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
const
|
|
443
|
+
test('Enter does nothing when no suggestion is highlighted', async () => {
|
|
444
|
+
const onResponse = vi.fn();
|
|
445
|
+
const { user } = setupTest({ onResponse });
|
|
446
|
+
const input = screen.getByRole('textbox');
|
|
447
|
+
|
|
448
|
+
await user.type(input, 'Test');
|
|
449
|
+
|
|
450
|
+
await waitFor(() => {
|
|
451
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
452
|
+
});
|
|
183
453
|
|
|
184
454
|
await fireEvent.keyDown(input, { key: 'Enter' });
|
|
185
|
-
|
|
455
|
+
|
|
456
|
+
expect(onResponse).not.toHaveBeenCalled();
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
test('Escape clears results', async () => {
|
|
460
|
+
const { user } = setupTest();
|
|
461
|
+
const input = screen.getByRole('textbox');
|
|
462
|
+
|
|
463
|
+
await user.type(input, 'Test');
|
|
464
|
+
|
|
465
|
+
await waitFor(() => {
|
|
466
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
await fireEvent.keyDown(input, { key: 'Escape' });
|
|
470
|
+
|
|
471
|
+
await waitFor(() => {
|
|
472
|
+
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
test('keyboard navigation does nothing when no results', async () => {
|
|
477
|
+
const { user } = setupTest();
|
|
478
|
+
const input = screen.getByRole('textbox');
|
|
479
|
+
|
|
480
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
481
|
+
await fireEvent.keyDown(input, { key: 'ArrowUp' });
|
|
482
|
+
await fireEvent.keyDown(input, { key: 'Enter' });
|
|
483
|
+
|
|
484
|
+
// Should not throw error
|
|
485
|
+
expect(input).toBeInTheDocument();
|
|
186
486
|
});
|
|
187
487
|
});
|
|
188
488
|
|
|
189
|
-
describe('
|
|
190
|
-
|
|
489
|
+
describe('Place Selection', () => {
|
|
490
|
+
test('clicking suggestion calls onResponse', async () => {
|
|
191
491
|
const onResponse = vi.fn();
|
|
192
|
-
const
|
|
193
|
-
|
|
492
|
+
const mockPlace = {
|
|
493
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
494
|
+
toJSON: () => ({ formattedAddress: '123 Main St', text: 'Test Place' }),
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
const mockSuggestions = [
|
|
498
|
+
{
|
|
499
|
+
placePrediction: {
|
|
500
|
+
text: { toString: () => 'Test Place' },
|
|
501
|
+
toPlace: () => mockPlace,
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
];
|
|
505
|
+
|
|
506
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
507
|
+
suggestions: mockSuggestions,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
const { user } = setupTest({ onResponse });
|
|
511
|
+
const input = screen.getByRole('textbox');
|
|
512
|
+
|
|
513
|
+
await user.type(input, 'Test');
|
|
514
|
+
|
|
515
|
+
await waitFor(() => {
|
|
516
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
const button = screen.getByRole('button', { name: /Test Place/i });
|
|
520
|
+
await fireEvent.click(button);
|
|
521
|
+
|
|
522
|
+
await waitFor(() => {
|
|
523
|
+
expect(onResponse).toHaveBeenCalledWith(
|
|
524
|
+
expect.objectContaining({ text: 'Test Place' })
|
|
525
|
+
);
|
|
194
526
|
});
|
|
195
|
-
expect(container).toBeDefined();
|
|
196
527
|
});
|
|
197
528
|
|
|
198
|
-
|
|
529
|
+
test('selecting place updates input value', async () => {
|
|
530
|
+
const mockPlace = {
|
|
531
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
532
|
+
toJSON: () => ({ text: 'Selected Place' }),
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
const mockSuggestions = [
|
|
536
|
+
{
|
|
537
|
+
placePrediction: {
|
|
538
|
+
text: { toString: () => 'Selected Place' },
|
|
539
|
+
toPlace: () => mockPlace,
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
];
|
|
543
|
+
|
|
544
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
545
|
+
suggestions: mockSuggestions,
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
const { user } = setupTest();
|
|
549
|
+
const input = screen.getByRole('textbox');
|
|
550
|
+
|
|
551
|
+
await user.type(input, 'Test');
|
|
552
|
+
|
|
553
|
+
await waitFor(() => {
|
|
554
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
const button = screen.getByRole('button');
|
|
558
|
+
await fireEvent.click(button);
|
|
559
|
+
|
|
560
|
+
await waitFor(() => {
|
|
561
|
+
expect(input.value).toBe('Selected Place');
|
|
562
|
+
});
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test('selecting place clears results list', async () => {
|
|
566
|
+
const mockPlace = {
|
|
567
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
568
|
+
toJSON: () => ({ text: 'Selected Place' }),
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
const mockSuggestions = [
|
|
572
|
+
{
|
|
573
|
+
placePrediction: {
|
|
574
|
+
text: { toString: () => 'Selected Place' },
|
|
575
|
+
toPlace: () => mockPlace,
|
|
576
|
+
},
|
|
577
|
+
},
|
|
578
|
+
];
|
|
579
|
+
|
|
580
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
581
|
+
suggestions: mockSuggestions,
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
const { user } = setupTest();
|
|
585
|
+
const input = screen.getByRole('textbox');
|
|
586
|
+
|
|
587
|
+
await user.type(input, 'Test');
|
|
588
|
+
|
|
589
|
+
await waitFor(() => {
|
|
590
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
const button = screen.getByRole('button');
|
|
594
|
+
await fireEvent.click(button);
|
|
595
|
+
|
|
596
|
+
await waitFor(() => {
|
|
597
|
+
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
test('uses originalText for cityState mode', async () => {
|
|
602
|
+
const onResponse = vi.fn();
|
|
603
|
+
const mockPlace = {
|
|
604
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
605
|
+
toJSON: () => ({ text: 'Los Angeles, CA' }),
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
const mockSuggestions = [
|
|
609
|
+
{
|
|
610
|
+
placePrediction: {
|
|
611
|
+
text: { toString: () => 'Los Angeles, CA, USA' },
|
|
612
|
+
types: ['locality'],
|
|
613
|
+
toPlace: () => mockPlace,
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
];
|
|
617
|
+
|
|
618
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
619
|
+
suggestions: mockSuggestions,
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
const { user } = setupTest({ mode: 'cityState', onResponse });
|
|
623
|
+
const input = screen.getByRole('textbox');
|
|
624
|
+
|
|
625
|
+
await user.type(input, 'Los Angeles');
|
|
626
|
+
|
|
627
|
+
await waitFor(() => {
|
|
628
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
const button = screen.getByRole('button');
|
|
632
|
+
await fireEvent.click(button);
|
|
633
|
+
|
|
634
|
+
await waitFor(() => {
|
|
635
|
+
expect(input.value).toBe('Los Angeles, CA');
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
describe('Click Outside', () => {
|
|
641
|
+
test('clicking outside clears results', async () => {
|
|
642
|
+
const mockSuggestions = [
|
|
643
|
+
{
|
|
644
|
+
placePrediction: {
|
|
645
|
+
text: { toString: () => 'Test Place' },
|
|
646
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
];
|
|
650
|
+
|
|
651
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
652
|
+
suggestions: mockSuggestions,
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const { user } = setupTest();
|
|
656
|
+
const input = screen.getByRole('textbox');
|
|
657
|
+
|
|
658
|
+
await user.type(input, 'Test');
|
|
659
|
+
|
|
660
|
+
await waitFor(() => {
|
|
661
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
// Click outside
|
|
665
|
+
await fireEvent.click(document.body);
|
|
666
|
+
|
|
667
|
+
await waitFor(() => {
|
|
668
|
+
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
|
669
|
+
});
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
test('clicking inside does not clear results', async () => {
|
|
673
|
+
const mockSuggestions = [
|
|
674
|
+
{
|
|
675
|
+
placePrediction: {
|
|
676
|
+
text: { toString: () => 'Test Place' },
|
|
677
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
678
|
+
},
|
|
679
|
+
},
|
|
680
|
+
];
|
|
681
|
+
|
|
682
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
683
|
+
suggestions: mockSuggestions,
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
const { user, container } = setupTest();
|
|
687
|
+
const input = screen.getByRole('textbox');
|
|
688
|
+
|
|
689
|
+
await user.type(input, 'Test');
|
|
690
|
+
|
|
691
|
+
await waitFor(() => {
|
|
692
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// Click on the input itself
|
|
696
|
+
await fireEvent.click(input);
|
|
697
|
+
|
|
698
|
+
// Results should still be visible
|
|
699
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
700
|
+
});
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
describe('Error Handling', () => {
|
|
704
|
+
test('calls onError when API request fails', async () => {
|
|
199
705
|
const onError = vi.fn();
|
|
200
|
-
|
|
201
|
-
|
|
706
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockRejectedValue(
|
|
707
|
+
new Error('API Error')
|
|
708
|
+
);
|
|
709
|
+
|
|
710
|
+
const { user } = setupTest({ onError });
|
|
711
|
+
const input = screen.getByRole('textbox');
|
|
712
|
+
|
|
713
|
+
await user.type(input, 'Test');
|
|
714
|
+
|
|
715
|
+
await waitFor(() => {
|
|
716
|
+
expect(onError).toHaveBeenCalledWith(expect.stringContaining('API Error'));
|
|
202
717
|
});
|
|
203
|
-
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
test('calls onError when place selection fails', async () => {
|
|
721
|
+
const onError = vi.fn();
|
|
722
|
+
const mockPlace = {
|
|
723
|
+
fetchFields: vi.fn().mockRejectedValue(new Error('Fetch Error')),
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
const mockSuggestions = [
|
|
727
|
+
{
|
|
728
|
+
placePrediction: {
|
|
729
|
+
text: { toString: () => 'Test Place' },
|
|
730
|
+
toPlace: () => mockPlace,
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
];
|
|
734
|
+
|
|
735
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
736
|
+
suggestions: mockSuggestions,
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
const { user } = setupTest({ onError });
|
|
740
|
+
const input = screen.getByRole('textbox');
|
|
741
|
+
|
|
742
|
+
await user.type(input, 'Test');
|
|
743
|
+
|
|
744
|
+
await waitFor(() => {
|
|
745
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
const button = screen.getByRole('button');
|
|
749
|
+
await fireEvent.click(button);
|
|
750
|
+
|
|
751
|
+
await waitFor(() => {
|
|
752
|
+
expect(onError).toHaveBeenCalledWith(expect.stringContaining('Fetch Error'));
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
test('handles missing API key gracefully', async () => {
|
|
757
|
+
const onError = vi.fn();
|
|
758
|
+
|
|
759
|
+
// This test verifies the component handles initialization properly
|
|
760
|
+
setupTest({ onError });
|
|
761
|
+
|
|
762
|
+
// Component should initialize without throwing
|
|
763
|
+
const input = screen.getByRole('textbox');
|
|
764
|
+
expect(input).toBeInTheDocument();
|
|
204
765
|
});
|
|
205
766
|
});
|
|
206
767
|
|
|
207
|
-
describe('
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
|
|
768
|
+
describe('Keyboard Hints', () => {
|
|
769
|
+
test('displays keyboard hints when results are visible', async () => {
|
|
770
|
+
const mockSuggestions = [
|
|
771
|
+
{
|
|
772
|
+
placePrediction: {
|
|
773
|
+
text: { toString: () => 'Test Place' },
|
|
774
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
775
|
+
},
|
|
776
|
+
},
|
|
777
|
+
];
|
|
778
|
+
|
|
779
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
780
|
+
suggestions: mockSuggestions,
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
const { user, container } = setupTest();
|
|
784
|
+
const input = screen.getByRole('textbox');
|
|
785
|
+
|
|
786
|
+
await user.type(input, 'Test');
|
|
787
|
+
|
|
788
|
+
await waitFor(() => {
|
|
789
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
// Check for keyboard hints
|
|
793
|
+
const hints = container.querySelectorAll('kbd');
|
|
794
|
+
expect(hints.length).toBeGreaterThan(0);
|
|
211
795
|
});
|
|
212
796
|
|
|
213
|
-
|
|
214
|
-
const { container } =
|
|
215
|
-
|
|
797
|
+
test('does not display hints when no results', () => {
|
|
798
|
+
const { container } = setupTest();
|
|
799
|
+
const hints = container.querySelectorAll('kbd');
|
|
800
|
+
expect(hints.length).toBe(0);
|
|
216
801
|
});
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
describe('Fetch Fields Configuration', () => {
|
|
805
|
+
test('uses default fetch fields', async () => {
|
|
806
|
+
const mockPlace = {
|
|
807
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
808
|
+
toJSON: () => ({ text: 'Test' }),
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
const mockSuggestions = [
|
|
812
|
+
{
|
|
813
|
+
placePrediction: {
|
|
814
|
+
text: { toString: () => 'Test' },
|
|
815
|
+
toPlace: () => mockPlace,
|
|
816
|
+
},
|
|
817
|
+
},
|
|
818
|
+
];
|
|
819
|
+
|
|
820
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
821
|
+
suggestions: mockSuggestions,
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
const { user } = setupTest();
|
|
825
|
+
const input = screen.getByRole('textbox');
|
|
826
|
+
|
|
827
|
+
await user.type(input, 'Test');
|
|
828
|
+
|
|
829
|
+
await waitFor(() => {
|
|
830
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
const button = screen.getByRole('button');
|
|
834
|
+
await fireEvent.click(button);
|
|
835
|
+
|
|
836
|
+
await waitFor(() => {
|
|
837
|
+
expect(mockPlace.fetchFields).toHaveBeenCalledWith({
|
|
838
|
+
fields: ['formattedAddress', 'addressComponents'],
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
test('uses custom fetch fields', async () => {
|
|
844
|
+
const mockPlace = {
|
|
845
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
846
|
+
toJSON: () => ({ text: 'Test' }),
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
const mockSuggestions = [
|
|
850
|
+
{
|
|
851
|
+
placePrediction: {
|
|
852
|
+
text: { toString: () => 'Test' },
|
|
853
|
+
toPlace: () => mockPlace,
|
|
854
|
+
},
|
|
855
|
+
},
|
|
856
|
+
];
|
|
857
|
+
|
|
858
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
859
|
+
suggestions: mockSuggestions,
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
const { user } = setupTest({ fetchFields: ['location', 'displayName'] });
|
|
863
|
+
const input = screen.getByRole('textbox');
|
|
864
|
+
|
|
865
|
+
await user.type(input, 'Test');
|
|
866
|
+
|
|
867
|
+
await waitFor(() => {
|
|
868
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
const button = screen.getByRole('button');
|
|
872
|
+
await fireEvent.click(button);
|
|
217
873
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
874
|
+
await waitFor(() => {
|
|
875
|
+
expect(mockPlace.fetchFields).toHaveBeenCalledWith({
|
|
876
|
+
fields: ['location', 'displayName'],
|
|
877
|
+
});
|
|
878
|
+
});
|
|
221
879
|
});
|
|
880
|
+
});
|
|
222
881
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
882
|
+
describe('Language and Region', () => {
|
|
883
|
+
test('uses default language and region', async () => {
|
|
884
|
+
const { user } = setupTest();
|
|
885
|
+
const input = screen.getByRole('textbox');
|
|
886
|
+
|
|
887
|
+
await user.type(input, 'Test');
|
|
888
|
+
|
|
889
|
+
await waitFor(() => {
|
|
890
|
+
expect(mockAutocompleteSuggestion.fetchAutocompleteSuggestions).toHaveBeenCalledWith(
|
|
891
|
+
expect.objectContaining({
|
|
892
|
+
language: 'en-US',
|
|
893
|
+
region: 'US',
|
|
894
|
+
})
|
|
895
|
+
);
|
|
226
896
|
});
|
|
227
|
-
expect(container.querySelector('.place-animate-focus')).toBeDefined();
|
|
228
897
|
});
|
|
229
898
|
|
|
230
|
-
|
|
231
|
-
const {
|
|
232
|
-
|
|
899
|
+
test('uses custom language and region', async () => {
|
|
900
|
+
const { user } = setupTest({ language: 'es-ES', region: 'ES' });
|
|
901
|
+
const input = screen.getByRole('textbox');
|
|
902
|
+
|
|
903
|
+
await user.type(input, 'Test');
|
|
904
|
+
|
|
905
|
+
await waitFor(() => {
|
|
906
|
+
expect(mockAutocompleteSuggestion.fetchAutocompleteSuggestions).toHaveBeenCalledWith(
|
|
907
|
+
expect.objectContaining({
|
|
908
|
+
language: 'es-ES',
|
|
909
|
+
region: 'ES',
|
|
910
|
+
})
|
|
911
|
+
);
|
|
233
912
|
});
|
|
234
|
-
expect(container.querySelector('.place-animate-focus')).toBeNull();
|
|
235
913
|
});
|
|
236
914
|
});
|
|
237
915
|
|
|
238
|
-
describe('
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
916
|
+
describe('Input Styling', () => {
|
|
917
|
+
test('has correct base classes', () => {
|
|
918
|
+
setupTest();
|
|
919
|
+
const input = screen.getByRole('textbox');
|
|
920
|
+
expect(input).toHaveClass('block');
|
|
921
|
+
expect(input).toHaveClass('w-full');
|
|
922
|
+
expect(input).toHaveClass('rounded-lg');
|
|
923
|
+
expect(input).toHaveClass('bg-gray-50');
|
|
924
|
+
expect(input).toHaveClass('border');
|
|
925
|
+
expect(input).toHaveClass('border-gray-300');
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
test('has focus styles', () => {
|
|
929
|
+
setupTest();
|
|
930
|
+
const input = screen.getByRole('textbox');
|
|
931
|
+
expect(input).toHaveClass('focus:ring-blue-500');
|
|
932
|
+
expect(input).toHaveClass('focus:border-blue-500');
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
test('has hover styles', () => {
|
|
936
|
+
setupTest();
|
|
937
|
+
const input = screen.getByRole('textbox');
|
|
938
|
+
expect(input).toHaveClass('hover:border-blue-500');
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
test('icon has correct positioning', () => {
|
|
942
|
+
const { container } = setupTest();
|
|
943
|
+
const iconContainer = container.querySelector('.pointer-events-none.absolute');
|
|
944
|
+
expect(iconContainer).toBeInTheDocument();
|
|
945
|
+
expect(iconContainer).toHaveClass('inset-y-0');
|
|
946
|
+
expect(iconContainer).toHaveClass('left-0');
|
|
947
|
+
});
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
describe('Results List Styling', () => {
|
|
951
|
+
test('results list has correct styling', async () => {
|
|
952
|
+
const mockSuggestions = [
|
|
953
|
+
{
|
|
954
|
+
placePrediction: {
|
|
955
|
+
text: { toString: () => 'Test Place' },
|
|
956
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
957
|
+
},
|
|
958
|
+
},
|
|
959
|
+
];
|
|
960
|
+
|
|
961
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
962
|
+
suggestions: mockSuggestions,
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
const { user } = setupTest();
|
|
966
|
+
const input = screen.getByRole('textbox');
|
|
967
|
+
|
|
968
|
+
await user.type(input, 'Test');
|
|
969
|
+
|
|
970
|
+
await waitFor(() => {
|
|
971
|
+
const list = screen.getByRole('list');
|
|
972
|
+
expect(list).toHaveClass('absolute');
|
|
973
|
+
expect(list).toHaveClass('top-full');
|
|
974
|
+
expect(list).toHaveClass('rounded-lg');
|
|
975
|
+
expect(list).toHaveClass('shadow-lg');
|
|
976
|
+
expect(list).toHaveClass('bg-white');
|
|
242
977
|
});
|
|
243
|
-
expect(container).toBeDefined();
|
|
244
978
|
});
|
|
245
979
|
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
|
|
980
|
+
test('result items have hover styling', async () => {
|
|
981
|
+
const mockSuggestions = [
|
|
982
|
+
{
|
|
983
|
+
placePrediction: {
|
|
984
|
+
text: { toString: () => 'Test Place' },
|
|
985
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
986
|
+
},
|
|
987
|
+
},
|
|
988
|
+
];
|
|
989
|
+
|
|
990
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
991
|
+
suggestions: mockSuggestions,
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
const { user, container } = setupTest();
|
|
995
|
+
const input = screen.getByRole('textbox');
|
|
996
|
+
|
|
997
|
+
await user.type(input, 'Test');
|
|
998
|
+
|
|
999
|
+
await waitFor(() => {
|
|
1000
|
+
const listItem = container.querySelector('li');
|
|
1001
|
+
expect(listItem).toHaveClass('cursor-pointer');
|
|
1002
|
+
expect(listItem).toHaveClass('transition-colors');
|
|
249
1003
|
});
|
|
250
|
-
const input = container.querySelector('input');
|
|
251
|
-
expect(input?.placeholder).toContain('city, state');
|
|
252
1004
|
});
|
|
253
1005
|
});
|
|
254
1006
|
|
|
255
|
-
describe('
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
1007
|
+
describe('Multiple Suggestions', () => {
|
|
1008
|
+
test('displays all suggestions', async () => {
|
|
1009
|
+
const mockSuggestions = [
|
|
1010
|
+
{
|
|
1011
|
+
placePrediction: {
|
|
1012
|
+
text: { toString: () => 'Result 1' },
|
|
1013
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1014
|
+
},
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
placePrediction: {
|
|
1018
|
+
text: { toString: () => 'Result 2' },
|
|
1019
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1020
|
+
},
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
placePrediction: {
|
|
1024
|
+
text: { toString: () => 'Result 3' },
|
|
1025
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1026
|
+
},
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
placePrediction: {
|
|
1030
|
+
text: { toString: () => 'Result 4' },
|
|
1031
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1032
|
+
},
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
placePrediction: {
|
|
1036
|
+
text: { toString: () => 'Result 5' },
|
|
1037
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1038
|
+
},
|
|
1039
|
+
},
|
|
1040
|
+
];
|
|
1041
|
+
|
|
1042
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
1043
|
+
suggestions: mockSuggestions,
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
const { user } = setupTest();
|
|
1047
|
+
const input = screen.getByRole('textbox');
|
|
1048
|
+
|
|
1049
|
+
await user.type(input, 'Test');
|
|
1050
|
+
|
|
1051
|
+
await waitFor(() => {
|
|
1052
|
+
const buttons = screen.getAllByRole('button');
|
|
1053
|
+
expect(buttons).toHaveLength(5);
|
|
1054
|
+
});
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
test('each suggestion has correct id attribute', async () => {
|
|
1058
|
+
const mockSuggestions = [
|
|
1059
|
+
{
|
|
1060
|
+
placePrediction: {
|
|
1061
|
+
text: { toString: () => 'Result 1' },
|
|
1062
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1063
|
+
},
|
|
1064
|
+
},
|
|
1065
|
+
{
|
|
1066
|
+
placePrediction: {
|
|
1067
|
+
text: { toString: () => 'Result 2' },
|
|
1068
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1069
|
+
},
|
|
1070
|
+
},
|
|
1071
|
+
];
|
|
1072
|
+
|
|
1073
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
1074
|
+
suggestions: mockSuggestions,
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
const { user, container } = setupTest();
|
|
1078
|
+
const input = screen.getByRole('textbox');
|
|
1079
|
+
|
|
1080
|
+
await user.type(input, 'Test');
|
|
1081
|
+
|
|
1082
|
+
await waitFor(() => {
|
|
1083
|
+
expect(container.querySelector('#option-1')).toBeInTheDocument();
|
|
1084
|
+
expect(container.querySelector('#option-2')).toBeInTheDocument();
|
|
260
1085
|
});
|
|
261
|
-
expect(container).toBeDefined();
|
|
262
1086
|
});
|
|
263
1087
|
});
|
|
264
1088
|
|
|
265
|
-
describe('
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
1089
|
+
describe('Integration Tests', () => {
|
|
1090
|
+
test('complete flow: type, navigate, select', async () => {
|
|
1091
|
+
const onResponse = vi.fn();
|
|
1092
|
+
const mockPlace = {
|
|
1093
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
1094
|
+
toJSON: () => ({ text: 'Final Selection', formattedAddress: '123 Main St' }),
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
const mockSuggestions = [
|
|
1098
|
+
{
|
|
1099
|
+
placePrediction: {
|
|
1100
|
+
text: { toString: () => 'Result 1' },
|
|
1101
|
+
toPlace: () => mockPlace,
|
|
1102
|
+
},
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
placePrediction: {
|
|
1106
|
+
text: { toString: () => 'Final Selection' },
|
|
1107
|
+
toPlace: () => mockPlace,
|
|
1108
|
+
},
|
|
1109
|
+
},
|
|
1110
|
+
];
|
|
1111
|
+
|
|
1112
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
1113
|
+
suggestions: mockSuggestions,
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
const { user } = setupTest({ onResponse });
|
|
1117
|
+
const input = screen.getByRole('textbox');
|
|
1118
|
+
|
|
1119
|
+
// Type to get suggestions
|
|
1120
|
+
await user.type(input, 'Test');
|
|
1121
|
+
|
|
1122
|
+
await waitFor(() => {
|
|
1123
|
+
expect(screen.getByRole('list')).toBeInTheDocument();
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
// Navigate down to second item
|
|
1127
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
1128
|
+
await fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
1129
|
+
|
|
1130
|
+
// Select with Enter
|
|
1131
|
+
await fireEvent.keyDown(input, { key: 'Enter' });
|
|
1132
|
+
|
|
272
1133
|
await waitFor(() => {
|
|
273
|
-
expect(
|
|
1134
|
+
expect(onResponse).toHaveBeenCalledWith(
|
|
1135
|
+
expect.objectContaining({ text: 'Final Selection' })
|
|
1136
|
+
);
|
|
1137
|
+
expect(input.value).toBe('Final Selection');
|
|
1138
|
+
expect(screen.queryByRole('list')).not.toBeInTheDocument();
|
|
1139
|
+
});
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
test('complete flow with cityState mode', async () => {
|
|
1143
|
+
const onResponse = vi.fn();
|
|
1144
|
+
const mockPlace = {
|
|
1145
|
+
fetchFields: vi.fn().mockResolvedValue({}),
|
|
1146
|
+
toJSON: () => ({ text: 'Los Angeles, CA' }),
|
|
1147
|
+
};
|
|
1148
|
+
|
|
1149
|
+
const mockSuggestions = [
|
|
1150
|
+
{
|
|
1151
|
+
placePrediction: {
|
|
1152
|
+
text: { toString: () => 'Los Angeles, CA, USA' },
|
|
1153
|
+
types: ['locality'],
|
|
1154
|
+
toPlace: () => mockPlace,
|
|
1155
|
+
},
|
|
1156
|
+
},
|
|
1157
|
+
];
|
|
1158
|
+
|
|
1159
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
1160
|
+
suggestions: mockSuggestions,
|
|
1161
|
+
});
|
|
1162
|
+
|
|
1163
|
+
const { user } = setupTest({ mode: 'cityState', onResponse });
|
|
1164
|
+
const input = screen.getByRole('textbox');
|
|
1165
|
+
|
|
1166
|
+
await user.type(input, 'Los Angeles');
|
|
1167
|
+
|
|
1168
|
+
await waitFor(() => {
|
|
1169
|
+
expect(screen.getByText('Los Angeles, CA')).toBeInTheDocument();
|
|
1170
|
+
});
|
|
1171
|
+
|
|
1172
|
+
const button = screen.getByRole('button');
|
|
1173
|
+
await fireEvent.click(button);
|
|
1174
|
+
|
|
1175
|
+
await waitFor(() => {
|
|
1176
|
+
expect(input.value).toBe('Los Angeles, CA');
|
|
1177
|
+
expect(onResponse).toHaveBeenCalled();
|
|
274
1178
|
});
|
|
275
1179
|
});
|
|
276
1180
|
});
|
|
277
1181
|
|
|
278
|
-
describe('
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
1182
|
+
describe('Accessibility', () => {
|
|
1183
|
+
test('input has aria-controls attribute', () => {
|
|
1184
|
+
setupTest();
|
|
1185
|
+
const input = screen.getByRole('textbox');
|
|
1186
|
+
expect(input).toHaveAttribute('aria-controls', 'options');
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1189
|
+
test('results list has correct id', async () => {
|
|
1190
|
+
const mockSuggestions = [
|
|
1191
|
+
{
|
|
1192
|
+
placePrediction: {
|
|
1193
|
+
text: { toString: () => 'Test Place' },
|
|
1194
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1195
|
+
},
|
|
1196
|
+
},
|
|
1197
|
+
];
|
|
1198
|
+
|
|
1199
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
1200
|
+
suggestions: mockSuggestions,
|
|
1201
|
+
});
|
|
1202
|
+
|
|
1203
|
+
const { user } = setupTest();
|
|
1204
|
+
const input = screen.getByRole('textbox');
|
|
1205
|
+
|
|
1206
|
+
await user.type(input, 'Test');
|
|
1207
|
+
|
|
1208
|
+
await waitFor(() => {
|
|
1209
|
+
const list = screen.getByRole('list');
|
|
1210
|
+
expect(list).toHaveAttribute('id', 'options');
|
|
282
1211
|
});
|
|
283
|
-
|
|
284
|
-
const input = container.querySelector('input');
|
|
285
|
-
expect(input?.value).toBe('San Francisco, CA');
|
|
286
1212
|
});
|
|
287
1213
|
|
|
288
|
-
|
|
289
|
-
const
|
|
290
|
-
|
|
1214
|
+
test('suggestion buttons have correct tabindex', async () => {
|
|
1215
|
+
const mockSuggestions = [
|
|
1216
|
+
{
|
|
1217
|
+
placePrediction: {
|
|
1218
|
+
text: { toString: () => 'Result 1' },
|
|
1219
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1220
|
+
},
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
placePrediction: {
|
|
1224
|
+
text: { toString: () => 'Result 2' },
|
|
1225
|
+
toPlace: () => ({ fetchFields: vi.fn() }),
|
|
1226
|
+
},
|
|
1227
|
+
},
|
|
1228
|
+
];
|
|
1229
|
+
|
|
1230
|
+
mockAutocompleteSuggestion.fetchAutocompleteSuggestions.mockResolvedValue({
|
|
1231
|
+
suggestions: mockSuggestions,
|
|
291
1232
|
});
|
|
292
1233
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
1234
|
+
const { user } = setupTest();
|
|
1235
|
+
const input = screen.getByRole('textbox');
|
|
1236
|
+
|
|
1237
|
+
await user.type(input, 'Test');
|
|
1238
|
+
|
|
1239
|
+
await waitFor(() => {
|
|
1240
|
+
const buttons = screen.getAllByRole('button');
|
|
1241
|
+
expect(buttons[0]).toHaveAttribute('tabindex', '1');
|
|
1242
|
+
expect(buttons[1]).toHaveAttribute('tabindex', '2');
|
|
1243
|
+
});
|
|
298
1244
|
});
|
|
299
1245
|
});
|
|
300
1246
|
});
|