@happyvertical/smrt-ui 0.53.1 → 0.53.2

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.
Files changed (205) hide show
  1. package/package.json +3 -3
  2. package/dist/actions/__tests__/ripple.test.js +0 -82
  3. package/dist/actions/__tests__/swipe-dismiss.test.js +0 -69
  4. package/dist/components/calendar/__tests__/CalendarView.test.js +0 -226
  5. package/dist/components/calendar/__tests__/calendar-model.test.js +0 -138
  6. package/dist/components/chat/__tests__/chat-primitives.test.js +0 -118
  7. package/dist/components/data/__tests__/CollectionList.test.js +0 -37
  8. package/dist/components/data/__tests__/DataTable.test.js +0 -807
  9. package/dist/components/data/__tests__/DataTableConformance.test.js +0 -212
  10. package/dist/components/data/__tests__/DataTableController.test.js +0 -371
  11. package/dist/components/data/__tests__/DataTableIdentity.test.js +0 -29
  12. package/dist/components/data/__tests__/DataTableLayout.test.js +0 -195
  13. package/dist/components/data/__tests__/DataTablePerformance.test.js +0 -21
  14. package/dist/components/data/__tests__/DataTableResponsive.test.js +0 -80
  15. package/dist/components/data/__tests__/DataTableVirtualization.test.js +0 -80
  16. package/dist/components/data/__tests__/DataTableVirtualizationComponent.test.js +0 -255
  17. package/dist/components/data/__tests__/SortableHeader.test.js +0 -101
  18. package/dist/components/data/__tests__/data-surface.test.js +0 -746
  19. package/dist/components/data/__tests__/data-table-helpers.test.js +0 -36
  20. package/dist/components/data/__tests__/data-table-surface.test.js +0 -49
  21. package/dist/components/data/__tests__/link-step-surface.test.js +0 -172
  22. package/dist/components/data/__tests__/list-sort-state.svelte.test.js +0 -71
  23. package/dist/components/data/__tests__/list-sort.test.js +0 -91
  24. package/dist/components/data/__tests__/mounted-data-surface.test.js +0 -794
  25. package/dist/components/data/__tests__/responsive-table.fixture.svelte +0 -29
  26. package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts +0 -7
  27. package/dist/components/data/__tests__/responsive-table.fixture.svelte.d.ts.map +0 -1
  28. package/dist/components/data/__tests__/surface-navigation.test.js +0 -121
  29. package/dist/components/display/__tests__/ConfidenceBadge.test.js +0 -109
  30. package/dist/components/display/__tests__/CurrencyDisplay.test.js +0 -304
  31. package/dist/components/display/__tests__/CurrencyDisplayI18nHarness.svelte +0 -20
  32. package/dist/components/display/__tests__/CurrencyDisplayI18nHarness.svelte.d.ts +0 -19
  33. package/dist/components/display/__tests__/CurrencyDisplayI18nHarness.svelte.d.ts.map +0 -1
  34. package/dist/components/display/__tests__/CurrencyDisplaySsrHarness.svelte +0 -7
  35. package/dist/components/display/__tests__/CurrencyDisplaySsrHarness.svelte.d.ts +0 -19
  36. package/dist/components/display/__tests__/CurrencyDisplaySsrHarness.svelte.d.ts.map +0 -1
  37. package/dist/components/display/__tests__/DateDisplay.test.js +0 -195
  38. package/dist/components/display/__tests__/Icon.test.js +0 -223
  39. package/dist/components/display/__tests__/StatusBadge.test.js +0 -191
  40. package/dist/components/feedback/__tests__/ConfirmDialog.test.js +0 -181
  41. package/dist/components/feedback/__tests__/LoadingOverlay.test.js +0 -113
  42. package/dist/components/feedback/__tests__/Modal.test.js +0 -72
  43. package/dist/components/feedback/__tests__/PhoneSheet.test.js +0 -101
  44. package/dist/components/feedback/__tests__/ProgressBar.test.js +0 -89
  45. package/dist/components/feedback/__tests__/WorkingStrip.test.js +0 -172
  46. package/dist/components/feedback/__tests__/confirm-message.fixture.svelte +0 -9
  47. package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts +0 -19
  48. package/dist/components/feedback/__tests__/confirm-message.fixture.svelte.d.ts.map +0 -1
  49. package/dist/components/feedback/__tests__/toast.test.js +0 -190
  50. package/dist/components/forms/__tests__/CameraCapture.test.js +0 -504
  51. package/dist/components/forms/__tests__/Combobox.test.js +0 -354
  52. package/dist/components/forms/__tests__/ControlHitArea.test.js +0 -73
  53. package/dist/components/forms/__tests__/DictationButton.test.js +0 -176
  54. package/dist/components/forms/__tests__/Fieldset.test.js +0 -37
  55. package/dist/components/forms/__tests__/Form.test.js +0 -201
  56. package/dist/components/forms/__tests__/FormActionBar.test.js +0 -22
  57. package/dist/components/forms/__tests__/FormGroup.test.js +0 -48
  58. package/dist/components/forms/__tests__/Input.test.js +0 -49
  59. package/dist/components/forms/__tests__/Listbox.test.js +0 -303
  60. package/dist/components/forms/__tests__/MultiSelect.test.js +0 -281
  61. package/dist/components/forms/__tests__/SearchInput.test.js +0 -92
  62. package/dist/components/forms/__tests__/Select.test.js +0 -37
  63. package/dist/components/forms/__tests__/SignaturePad.test.js +0 -338
  64. package/dist/components/forms/__tests__/StagedControlReview.test.js +0 -702
  65. package/dist/components/forms/__tests__/Textarea.test.js +0 -39
  66. package/dist/components/forms/__tests__/Toggle.test.js +0 -87
  67. package/dist/components/forms/__tests__/camera-capture-session.test.js +0 -207
  68. package/dist/components/forms/__tests__/capture-form-retry.test.js +0 -166
  69. package/dist/components/forms/__tests__/capture-form.fixture.svelte +0 -38
  70. package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts +0 -10
  71. package/dist/components/forms/__tests__/capture-form.fixture.svelte.d.ts.map +0 -1
  72. package/dist/components/forms/__tests__/capture-test-env.d.ts +0 -70
  73. package/dist/components/forms/__tests__/capture-test-env.d.ts.map +0 -1
  74. package/dist/components/forms/__tests__/capture-test-env.js +0 -122
  75. package/dist/components/forms/__tests__/capture-touch.fixture.svelte +0 -15
  76. package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts +0 -8
  77. package/dist/components/forms/__tests__/capture-touch.fixture.svelte.d.ts.map +0 -1
  78. package/dist/components/forms/__tests__/combobox-form.fixture.svelte +0 -29
  79. package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts +0 -14
  80. package/dist/components/forms/__tests__/combobox-form.fixture.svelte.d.ts.map +0 -1
  81. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte +0 -19
  82. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts +0 -11
  83. package/dist/components/forms/__tests__/combobox-labels.fixture.svelte.d.ts.map +0 -1
  84. package/dist/components/forms/__tests__/composite-controls.fixture.svelte +0 -47
  85. package/dist/components/forms/__tests__/composite-controls.fixture.svelte.d.ts +0 -12
  86. package/dist/components/forms/__tests__/composite-controls.fixture.svelte.d.ts.map +0 -1
  87. package/dist/components/forms/__tests__/composite-controls.test.js +0 -128
  88. package/dist/components/forms/__tests__/composite-registration.fixture.svelte +0 -29
  89. package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts +0 -8
  90. package/dist/components/forms/__tests__/composite-registration.fixture.svelte.d.ts.map +0 -1
  91. package/dist/components/forms/__tests__/composite-user-edit.fixture.svelte +0 -41
  92. package/dist/components/forms/__tests__/composite-user-edit.fixture.svelte.d.ts +0 -13
  93. package/dist/components/forms/__tests__/composite-user-edit.fixture.svelte.d.ts.map +0 -1
  94. package/dist/components/forms/__tests__/control-interaction.test.js +0 -3421
  95. package/dist/components/forms/__tests__/control-proposals.test.js +0 -63
  96. package/dist/components/forms/__tests__/core-controls.fixture.svelte +0 -50
  97. package/dist/components/forms/__tests__/core-controls.fixture.svelte.d.ts +0 -9
  98. package/dist/components/forms/__tests__/core-controls.fixture.svelte.d.ts.map +0 -1
  99. package/dist/components/forms/__tests__/core-controls.test.js +0 -311
  100. package/dist/components/forms/__tests__/decimal-sliders.fixture.svelte +0 -25
  101. package/dist/components/forms/__tests__/decimal-sliders.fixture.svelte.d.ts +0 -8
  102. package/dist/components/forms/__tests__/decimal-sliders.fixture.svelte.d.ts.map +0 -1
  103. package/dist/components/forms/__tests__/dictation-recording.test.js +0 -582
  104. package/dist/components/forms/__tests__/dictation.test.js +0 -486
  105. package/dist/components/forms/__tests__/form-attachment.fixture.svelte +0 -28
  106. package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts +0 -11
  107. package/dist/components/forms/__tests__/form-attachment.fixture.svelte.d.ts.map +0 -1
  108. package/dist/components/forms/__tests__/form-group-input.fixture.svelte +0 -16
  109. package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts +0 -9
  110. package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts.map +0 -1
  111. package/dist/components/forms/__tests__/form-retry-form.fixture.svelte +0 -31
  112. package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts +0 -13
  113. package/dist/components/forms/__tests__/form-retry-form.fixture.svelte.d.ts.map +0 -1
  114. package/dist/components/forms/__tests__/form-retry-form.test.js +0 -107
  115. package/dist/components/forms/__tests__/hidden-controls-form-retry.test.js +0 -69
  116. package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte +0 -29
  117. package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts +0 -9
  118. package/dist/components/forms/__tests__/hidden-controls-form.fixture.svelte.d.ts.map +0 -1
  119. package/dist/components/forms/__tests__/listbox-form.fixture.svelte +0 -27
  120. package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts +0 -13
  121. package/dist/components/forms/__tests__/listbox-form.fixture.svelte.d.ts.map +0 -1
  122. package/dist/components/forms/__tests__/long-press.test.js +0 -175
  123. package/dist/components/forms/__tests__/multiselect-form.fixture.svelte +0 -27
  124. package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts +0 -13
  125. package/dist/components/forms/__tests__/multiselect-form.fixture.svelte.d.ts.map +0 -1
  126. package/dist/components/forms/__tests__/native-file-field.test.js +0 -177
  127. package/dist/components/forms/__tests__/place-picker.fixture.svelte +0 -33
  128. package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts +0 -12
  129. package/dist/components/forms/__tests__/place-picker.fixture.svelte.d.ts.map +0 -1
  130. package/dist/components/forms/__tests__/segmented-posting.fixture.svelte +0 -28
  131. package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts +0 -12
  132. package/dist/components/forms/__tests__/segmented-posting.fixture.svelte.d.ts.map +0 -1
  133. package/dist/components/forms/__tests__/segmented-posting.test.js +0 -92
  134. package/dist/components/forms/__tests__/select-interaction.fixture.svelte +0 -25
  135. package/dist/components/forms/__tests__/select-interaction.fixture.svelte.d.ts +0 -9
  136. package/dist/components/forms/__tests__/select-interaction.fixture.svelte.d.ts.map +0 -1
  137. package/dist/components/forms/__tests__/signature-pad-logic.test.js +0 -54
  138. package/dist/components/forms/__tests__/staged-review-fieldset.fixture.svelte +0 -21
  139. package/dist/components/forms/__tests__/staged-review-fieldset.fixture.svelte.d.ts +0 -8
  140. package/dist/components/forms/__tests__/staged-review-fieldset.fixture.svelte.d.ts.map +0 -1
  141. package/dist/components/forms/__tests__/staged-review-outer-fieldset.fixture.svelte +0 -23
  142. package/dist/components/forms/__tests__/staged-review-outer-fieldset.fixture.svelte.d.ts +0 -8
  143. package/dist/components/forms/__tests__/staged-review-outer-fieldset.fixture.svelte.d.ts.map +0 -1
  144. package/dist/components/forms/__tests__/staged-review.fixture.svelte +0 -56
  145. package/dist/components/forms/__tests__/staged-review.fixture.svelte.d.ts +0 -12
  146. package/dist/components/forms/__tests__/staged-review.fixture.svelte.d.ts.map +0 -1
  147. package/dist/components/forms/__tests__/touch-density.fixture.svelte +0 -34
  148. package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts +0 -8
  149. package/dist/components/forms/__tests__/touch-density.fixture.svelte.d.ts.map +0 -1
  150. package/dist/components/forms/__tests__/touch-density.test.js +0 -66
  151. package/dist/components/forms/form-retry/__tests__/boundaries.test.js +0 -23
  152. package/dist/components/forms/form-retry/__tests__/content-digest.test.js +0 -70
  153. package/dist/components/forms/form-retry/__tests__/controller.test.js +0 -802
  154. package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts +0 -82
  155. package/dist/components/forms/form-retry/__tests__/fake-kit.d.ts.map +0 -1
  156. package/dist/components/forms/form-retry/__tests__/fake-kit.js +0 -180
  157. package/dist/components/forms/form-retry/__tests__/form-draft.test.js +0 -169
  158. package/dist/components/forms/form-retry/__tests__/ssr.test.js +0 -37
  159. package/dist/components/forms/form-retry/__tests__/storage.d.ts +0 -26
  160. package/dist/components/forms/form-retry/__tests__/storage.d.ts.map +0 -1
  161. package/dist/components/forms/form-retry/__tests__/storage.js +0 -63
  162. package/dist/components/forms/form-retry/__tests__/submission-key.test.js +0 -236
  163. package/dist/components/forms/form-retry/__tests__/submitted-draft.test.js +0 -334
  164. package/dist/components/layout/__tests__/Container.test.js +0 -62
  165. package/dist/components/layout/__tests__/EmptyState.test.js +0 -83
  166. package/dist/components/layout/__tests__/Footer.test.js +0 -50
  167. package/dist/components/layout/__tests__/Grid.test.js +0 -121
  168. package/dist/components/layout/__tests__/Header.test.js +0 -48
  169. package/dist/components/layout/__tests__/Masthead.test.js +0 -93
  170. package/dist/components/layout/__tests__/PageHeader.test.js +0 -166
  171. package/dist/components/layout/__tests__/SummaryCard.test.js +0 -104
  172. package/dist/components/nav/__tests__/FilterChips.test.js +0 -94
  173. package/dist/components/nav/__tests__/LinkTabs.test.js +0 -117
  174. package/dist/components/nav/__tests__/Tabs.test.js +0 -128
  175. package/dist/components/roles/__tests__/RoleSelector.test.js +0 -134
  176. package/dist/components/ui/__tests__/Badge.test.js +0 -76
  177. package/dist/components/ui/__tests__/Button.test.js +0 -166
  178. package/dist/components/ui/__tests__/Card.test.js +0 -103
  179. package/dist/components/ui/__tests__/IconToggle.test.js +0 -59
  180. package/dist/components/ui/__tests__/IconToggleGroup.test.js +0 -30
  181. package/dist/components/ui/__tests__/Pagination.test.js +0 -113
  182. package/dist/components/ui/__tests__/Popover.test.js +0 -44
  183. package/dist/components/ui/__tests__/dropdown-popover-icon.test.js +0 -125
  184. package/dist/components/ui/__tests__/gap-primitives-interactive.test.js +0 -112
  185. package/dist/components/ui/__tests__/gap-primitives.test.js +0 -84
  186. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte +0 -13
  187. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte.d.ts +0 -19
  188. package/dist/components/ui/__tests__/interaction-primitives.fixture.svelte.d.ts.map +0 -1
  189. package/dist/components/ui/__tests__/interaction-primitives.test.js +0 -31
  190. package/dist/components/ui/__tests__/phone-touch-targets.test.js +0 -39
  191. package/dist/i18n/__tests__/i18n.test.js +0 -74
  192. package/dist/i18n/__tests__/render-parity.spec.js +0 -37
  193. package/dist/svelte/__tests__/playground.test.js +0 -20
  194. package/dist/themes/__tests__/control-boundary-contrast.test.js +0 -112
  195. package/dist/themes/__tests__/create-theme.test.js +0 -79
  196. package/dist/themes/__tests__/css-generator.test.js +0 -129
  197. package/dist/themes/__tests__/happyvertical-theme.test.js +0 -231
  198. package/dist/themes/__tests__/registry.test.js +0 -43
  199. package/dist/themes/__tests__/styles-lockstep.test.js +0 -32
  200. package/dist/themes/__tests__/theme-provider.test.js +0 -147
  201. package/dist/themes/__tests__/theme-script.test.js +0 -130
  202. package/dist/themes/__tests__/token-aliases.test.js +0 -178
  203. package/dist/utils/forms/__tests__/formatters.test.js +0 -27
  204. package/dist/utils/theme/__tests__/color.test.js +0 -89
  205. package/dist/utils/theme/__tests__/typography.test.js +0 -11
@@ -1,281 +0,0 @@
1
- import { render, screen } from '@testing-library/svelte';
2
- import userEvent from '@testing-library/user-event';
3
- import { tick } from 'svelte';
4
- import { describe, expect, it, vi } from 'vitest';
5
- import { createControlInteractionRegistry, executeLocalControlCommand, } from '../control-interaction.js';
6
- import MultiSelect from '../MultiSelect.svelte';
7
- import Fixture from './multiselect-form.fixture.svelte';
8
- function form() {
9
- return screen.getByRole('form', { name: 'Roles form' });
10
- }
11
- function data() {
12
- return new FormData(form());
13
- }
14
- async function open() {
15
- await userEvent.click(screen.getByRole('button', { name: /Roles/ }));
16
- }
17
- describe('MultiSelect native form values', () => {
18
- it('posts repeated values in selection order and removes deselected inputs', async () => {
19
- render(Fixture);
20
- await open();
21
- await userEvent.click(screen.getByRole('option', { name: 'Administrator' }));
22
- await userEvent.click(screen.getByRole('option', { name: 'Operator' }));
23
- expect(data().getAll('roles')).toEqual(['admin', '42']);
24
- await userEvent.click(screen.getByRole('option', { name: 'Administrator' }));
25
- expect(data().getAll('roles')).toEqual(['42']);
26
- await userEvent.click(screen.getByRole('option', { name: 'Disabled role' }));
27
- expect(data().getAll('roles')).toEqual(['42']);
28
- });
29
- it('posts canonical numeric selections from legacy strings', () => {
30
- render(Fixture, { props: { values: ['42'] } });
31
- expect(data().getAll('roles')).toEqual(['42']);
32
- });
33
- it('omits empty selections, empty names and unnamed controls', async () => {
34
- const { rerender } = render(Fixture);
35
- expect([...data()]).toEqual([]);
36
- await rerender({ values: [42], name: '' });
37
- expect([...data()]).toEqual([]);
38
- await rerender({ values: [42], unnamed: true });
39
- expect([...data()]).toEqual([]);
40
- });
41
- it.each([
42
- { disabled: true },
43
- { fieldsetDisabled: true },
44
- ])('omits disabled selections %j', (props) => {
45
- render(Fixture, { props: { ...props, values: [42, 'admin'] } });
46
- expect([...data()]).toEqual([]);
47
- });
48
- it('restores initial selected values on native reset', async () => {
49
- render(Fixture, { props: { values: [42] } });
50
- await open();
51
- await userEvent.click(screen.getByRole('option', { name: 'Administrator' }));
52
- form().reset();
53
- await settleReset();
54
- expect(data().getAll('roles')).toEqual(['42']);
55
- await open();
56
- expect(screen.getByRole('option', { name: 'Operator' })).toHaveAttribute('aria-selected', 'true');
57
- expect(screen.getByRole('option', { name: 'Administrator' })).toHaveAttribute('aria-selected', 'false');
58
- });
59
- it('preserves changed values when reset is canceled', async () => {
60
- render(Fixture);
61
- await open();
62
- await userEvent.click(screen.getByRole('option', { name: 'Operator' }));
63
- form().addEventListener('reset', (event) => event.preventDefault());
64
- form().reset();
65
- await settleReset();
66
- expect(data().getAll('roles')).toEqual(['42']);
67
- });
68
- it('preserves registry identity and posts only applied canonical values', async () => {
69
- const registry = createControlInteractionRegistry({
70
- isLocalGesture: () => true,
71
- });
72
- render(Fixture, { props: { registry } });
73
- const identity = { formId: 'roles-form', controlId: 'roles' };
74
- await registry.execute({ action: 'stage', identity, value: ['42', 'admin'] }, { source: 'agent' });
75
- expect([...data()]).toEqual([]);
76
- await userEvent.click(screen.getByRole('button', { name: 'Apply valid changes' }));
77
- expect(data().getAll('roles')).toEqual(['42', 'admin']);
78
- expect(registry.get(identity)?.state.value).toEqual([42, 'admin']);
79
- });
80
- });
81
- async function settleReset() {
82
- await new Promise((resolve) => setTimeout(resolve));
83
- await tick();
84
- }
85
- describe('MultiSelect deferred native reset', () => {
86
- it('preserves a newer programmatic value before reset completion', async () => {
87
- const target = document.createElement('form');
88
- document.body.append(target);
89
- const view = render(MultiSelect, {
90
- target,
91
- props: {
92
- options: [
93
- { value: 42, label: 'Initial' },
94
- { value: 'other', label: 'Other' },
95
- { value: 'changed', label: 'Changed' },
96
- ],
97
- label: 'Choice',
98
- name: 'choice',
99
- values: [42],
100
- },
101
- });
102
- await view.rerender({ values: ['changed'] });
103
- target.reset();
104
- await view.rerender({ values: ['other'] });
105
- await settleReset();
106
- expect(new FormData(target).getAll('choice')).toEqual(['other']);
107
- await view.unmount();
108
- target.remove();
109
- });
110
- it('cancels pending completion when unmounted', async () => {
111
- const target = document.createElement('form');
112
- document.body.append(target);
113
- const onChange = vi.fn();
114
- const view = render(MultiSelect, {
115
- target,
116
- props: {
117
- options: [
118
- { value: 42, label: 'Initial' },
119
- { value: 'other', label: 'Other' },
120
- { value: 'changed', label: 'Changed' },
121
- ],
122
- label: 'Choice',
123
- name: 'choice',
124
- values: [42],
125
- onvalueschange: onChange,
126
- },
127
- });
128
- target.reset();
129
- await view.unmount();
130
- await settleReset();
131
- expect(onChange).not.toHaveBeenCalled();
132
- target.remove();
133
- });
134
- });
135
- describe('MultiSelect selected disabled option posting', () => {
136
- it('omits initially disabled selections and responds to dynamic disable without losing state', async () => {
137
- const target = document.createElement('form');
138
- document.body.append(target);
139
- const options = [
140
- { value: 42, label: 'Selected', disabled: true },
141
- { value: 'other', label: 'Other' },
142
- ];
143
- const view = render(MultiSelect, {
144
- target,
145
- props: {
146
- options,
147
- label: 'Choice',
148
- name: 'choice',
149
- values: [42, 'other'],
150
- },
151
- });
152
- expect(new FormData(target).getAll('choice')).toEqual(['other']);
153
- await view.rerender({
154
- options: options.map((option) => ({ ...option, disabled: false })),
155
- });
156
- expect(new FormData(target).getAll('choice')).toEqual(['42', 'other']);
157
- await view.rerender({ options });
158
- expect(new FormData(target).getAll('choice')).toEqual(['other']);
159
- await view.rerender({
160
- options: options.map((option) => ({ ...option, disabled: false })),
161
- });
162
- expect(new FormData(target).getAll('choice')).toEqual(['42', 'other']);
163
- await view.unmount();
164
- target.remove();
165
- });
166
- });
167
- describe('MultiSelect reset listener ordering', () => {
168
- it('honors cancellation from a later listener microtask', async () => {
169
- const target = document.createElement('form');
170
- document.body.append(target);
171
- const onChange = vi.fn();
172
- const view = render(MultiSelect, {
173
- target,
174
- props: {
175
- options: [
176
- { value: 42, label: 'Initial' },
177
- { value: 'changed', label: 'Changed' },
178
- ],
179
- label: 'Choice',
180
- name: 'choice',
181
- values: [42],
182
- onvalueschange: onChange,
183
- },
184
- });
185
- await view.rerender({ values: ['changed'] });
186
- target.addEventListener('reset', (event) => {
187
- queueMicrotask(() => event.preventDefault());
188
- });
189
- target.reset();
190
- await settleReset();
191
- expect(new FormData(target).getAll('choice')).toEqual(['changed']);
192
- expect(onChange).not.toHaveBeenCalled();
193
- await view.unmount();
194
- target.remove();
195
- });
196
- });
197
- function dispatchLocalCommand(registry, command) {
198
- const target = new EventTarget();
199
- let pending;
200
- target.addEventListener('click', (event) => {
201
- pending = executeLocalControlCommand(registry, command, event);
202
- }, { once: true });
203
- target.dispatchEvent(new Event('click'));
204
- if (!pending)
205
- throw new Error('local command handler did not run');
206
- return pending;
207
- }
208
- describe('MultiSelect reset registry currency', () => {
209
- it.each([
210
- false,
211
- true,
212
- ])('keeps staged proposal currency correct when cancellation is %s', async (cancel) => {
213
- const registry = createControlInteractionRegistry({
214
- isLocalGesture: () => true,
215
- });
216
- render(Fixture, { props: { ...{ values: [42] }, registry } });
217
- const identity = { formId: 'roles-form', controlId: 'roles' };
218
- const target = form();
219
- await open();
220
- await userEvent.click(screen.getByRole('option', { name: 'Administrator' }));
221
- expect((await registry.execute({ action: 'stage', identity, value: ['admin'] }, { source: 'agent' })).ok).toBe(true);
222
- if (cancel)
223
- target.addEventListener('reset', (event) => event.preventDefault());
224
- target.reset();
225
- await settleReset();
226
- expect(registry.get(identity)?.state.staged?.stale).toBe(!cancel);
227
- const applied = await dispatchLocalCommand(registry, {
228
- action: 'apply',
229
- identity,
230
- });
231
- expect(applied.ok).toBe(cancel);
232
- if (!cancel) {
233
- expect(applied.reason).toBe('staged_value_stale');
234
- expect(new FormData(target).getAll('roles')).toEqual(['42']);
235
- }
236
- });
237
- it.each([
238
- false,
239
- true,
240
- ])('preserves reset over an async local clear when cancellation is %s', async (cancel) => {
241
- let releasePolicy;
242
- let policyStarted;
243
- const blocked = new Promise((resolve) => {
244
- releasePolicy = resolve;
245
- });
246
- const started = new Promise((resolve) => {
247
- policyStarted = resolve;
248
- });
249
- const registry = createControlInteractionRegistry({
250
- isLocalGesture: () => true,
251
- policy: async (command) => {
252
- if (command.action === 'clear') {
253
- policyStarted();
254
- await blocked;
255
- }
256
- return { allowed: true };
257
- },
258
- });
259
- render(Fixture, { props: { ...{ values: [42] }, registry } });
260
- const identity = { formId: 'roles-form', controlId: 'roles' };
261
- const target = form();
262
- await open();
263
- await userEvent.click(screen.getByRole('option', { name: 'Administrator' }));
264
- const clearing = dispatchLocalCommand(registry, {
265
- action: 'clear',
266
- identity,
267
- });
268
- await started;
269
- if (cancel)
270
- target.addEventListener('reset', (event) => event.preventDefault());
271
- target.reset();
272
- await settleReset();
273
- releasePolicy();
274
- const result = await clearing;
275
- await tick();
276
- expect(result.ok).toBe(cancel);
277
- if (!cancel)
278
- expect(result.reason).toBe('staged_value_stale');
279
- expect(new FormData(target).getAll('roles')).toEqual(cancel ? [] : ['42']);
280
- });
281
- });
@@ -1,92 +0,0 @@
1
- import { render, screen } from '@testing-library/svelte';
2
- import userEvent from '@testing-library/user-event';
3
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { expectNoA11yViolations } from '../../../test-support/a11y';
5
- import SearchInput from '../SearchInput.svelte';
6
- describe('SearchInput', () => {
7
- beforeEach(() => vi.useFakeTimers({ shouldAdvanceTime: true }));
8
- afterEach(() => vi.useRealTimers());
9
- it('is a labelled search field in a search landmark', () => {
10
- render(SearchInput, {
11
- props: { value: '', onsearch: vi.fn(), placeholder: 'Search by title' },
12
- });
13
- expect(screen.getByRole('search')).toBeInTheDocument();
14
- expect(screen.getByRole('searchbox', { name: 'Search' })).toHaveAttribute('placeholder', 'Search by title');
15
- });
16
- it('searches once, trimmed and single-line, after the last key', async () => {
17
- const onsearch = vi.fn();
18
- const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
19
- render(SearchInput, { props: { value: '', onsearch, debounceMs: 300 } });
20
- await user.type(screen.getByRole('searchbox'), ' council hall ');
21
- expect(onsearch).not.toHaveBeenCalled();
22
- vi.advanceTimersByTime(300);
23
- expect(onsearch).toHaveBeenCalledTimes(1);
24
- expect(onsearch).toHaveBeenCalledWith('council hall');
25
- });
26
- it('searches at once on Enter', async () => {
27
- const onsearch = vi.fn();
28
- const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
29
- render(SearchInput, { props: { value: '', onsearch } });
30
- await user.type(screen.getByRole('searchbox'), 'roads{Enter}');
31
- expect(onsearch).toHaveBeenCalledWith('roads');
32
- });
33
- it('does not search for the search it is already showing', async () => {
34
- const onsearch = vi.fn();
35
- const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
36
- render(SearchInput, { props: { value: 'roads', onsearch } });
37
- await user.type(screen.getByRole('searchbox'), '{Enter}');
38
- expect(onsearch).not.toHaveBeenCalled();
39
- });
40
- it('clears with the x and focuses the field', async () => {
41
- const onsearch = vi.fn();
42
- const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
43
- render(SearchInput, { props: { value: 'roads', onsearch } });
44
- const field = screen.getByRole('searchbox');
45
- expect(field).toHaveValue('roads');
46
- await user.click(screen.getByRole('button', { name: 'Clear search' }));
47
- expect(onsearch).toHaveBeenCalledWith('');
48
- expect(field).toHaveValue('');
49
- expect(field).toHaveFocus();
50
- expect(screen.queryByRole('button', { name: 'Clear search' })).toBeNull();
51
- });
52
- it('follows the applied search when it changes from outside', async () => {
53
- const { rerender } = render(SearchInput, {
54
- props: { value: 'roads', onsearch: vi.fn() },
55
- });
56
- await rerender({ value: 'parks', onsearch: vi.fn() });
57
- expect(screen.getByRole('searchbox')).toHaveValue('parks');
58
- });
59
- it('inside a host form, Enter searches and never submits the host form', async () => {
60
- const onsearch = vi.fn();
61
- const onsubmit = vi.fn((event) => event.preventDefault());
62
- const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
63
- const host = document.createElement('form');
64
- host.addEventListener('submit', onsubmit);
65
- document.body.append(host);
66
- render(SearchInput, { target: host, props: { value: '', onsearch } });
67
- expect(host.querySelector('form')).toBeNull();
68
- await user.type(screen.getByRole('searchbox'), 'roads{Enter}');
69
- expect(onsearch).toHaveBeenCalledWith('roads');
70
- expect(onsubmit).not.toHaveBeenCalled();
71
- host.remove();
72
- });
73
- it('a value the host normalized differently does not swallow a later one', async () => {
74
- const onsearch = vi.fn();
75
- const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
76
- const view = render(SearchInput, { props: { value: '', onsearch } });
77
- await user.type(screen.getByRole('searchbox'), 'Roads{Enter}');
78
- expect(onsearch).toHaveBeenCalledWith('Roads');
79
- // The host applies its own normalization, then later navigates to the
80
- // exact text the box once sent: the box must follow both.
81
- await view.rerender({ value: 'roads', onsearch });
82
- expect(screen.getByRole('searchbox')).toHaveValue('roads');
83
- await view.rerender({ value: 'Roads', onsearch });
84
- expect(screen.getByRole('searchbox')).toHaveValue('Roads');
85
- });
86
- it('is axe-clean', async () => {
87
- const { container } = render(SearchInput, {
88
- props: { value: 'roads', onsearch: vi.fn() },
89
- });
90
- await expectNoA11yViolations(container);
91
- });
92
- });
@@ -1,37 +0,0 @@
1
- /**
2
- * Golden test for Select (Sweep L1, #1420).
3
- *
4
- * Select forwards aria attributes (so it can be labelled / error-associated)
5
- * and inherits id / describedby / invalid from a wrapping FormGroup via context.
6
- */
7
- import { render, screen } from '@testing-library/svelte';
8
- import { createRawSnippet } from 'svelte';
9
- import { describe, expect, it } from 'vitest';
10
- import { expectNoA11yViolations } from '../../../test-support/a11y';
11
- import Select from '../Select.svelte';
12
- function options() {
13
- return createRawSnippet(() => ({
14
- render: () => `<option value="a">A</option><option value="b">B</option>`,
15
- }));
16
- }
17
- describe('Select', () => {
18
- it('forwards aria-label / aria-describedby / aria-invalid', () => {
19
- render(Select, {
20
- props: {
21
- 'aria-label': 'Country',
22
- 'aria-describedby': 'country-hint',
23
- 'aria-invalid': 'true',
24
- children: options(),
25
- },
26
- });
27
- const select = screen.getByRole('combobox', { name: 'Country' });
28
- expect(select).toHaveAttribute('aria-describedby', 'country-hint');
29
- expect(select).toHaveAttribute('aria-invalid', 'true');
30
- });
31
- it('is axe-clean when labelled', async () => {
32
- const { container } = render(Select, {
33
- props: { 'aria-label': 'Country', children: options() },
34
- });
35
- await expectNoA11yViolations(container);
36
- });
37
- });