@happyvertical/smrt-svelte 0.53.1 → 0.53.3
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/package.json +15 -15
- package/dist/__tests__/app-state.test.js +0 -156
- package/dist/__tests__/data-surface-bridge.test.js +0 -351
- package/dist/__tests__/provider-mode-harness.svelte +0 -14
- package/dist/__tests__/provider-mode-harness.svelte.d.ts +0 -11
- package/dist/__tests__/provider-mode-harness.svelte.d.ts.map +0 -1
- package/dist/__tests__/provider-mode-probe.svelte +0 -13
- package/dist/__tests__/provider-mode-probe.svelte.d.ts +0 -8
- package/dist/__tests__/provider-mode-probe.svelte.d.ts.map +0 -1
- package/dist/__tests__/provider-webmcp-harness.svelte +0 -14
- package/dist/__tests__/provider-webmcp-harness.svelte.d.ts +0 -8
- package/dist/__tests__/provider-webmcp-harness.svelte.d.ts.map +0 -1
- package/dist/__tests__/success-never-text.test.js +0 -100
- package/dist/__tests__/warm-clients.test.js +0 -186
- package/dist/browser-ai/adapters/llm/bitgpu-inference-backend.test.js +0 -464
- package/dist/browser-ai/adapters/llm/webllm-inference-backend.test.js +0 -646
- package/dist/browser-ai/adapters/stt/browser-speech.test.js +0 -113
- package/dist/browser-ai/adapters/stt/dictation-source.test.js +0 -52
- package/dist/browser-ai/svelte/components/__tests__/ModelStatusControl.test.js +0 -172
- package/dist/components/board/__tests__/Board.test.js +0 -498
- package/dist/components/board/__tests__/BoardSsrHarness.svelte +0 -30
- package/dist/components/board/__tests__/BoardSsrHarness.svelte.d.ts +0 -19
- package/dist/components/board/__tests__/BoardSsrHarness.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/AddressInput.behavior.test.js +0 -216
- package/dist/components/forms/__tests__/CheckboxInput.test.js +0 -92
- package/dist/components/forms/__tests__/DateRangeInput.behavior.test.js +0 -135
- package/dist/components/forms/__tests__/DateTimeInput.behavior.test.js +0 -113
- package/dist/components/forms/__tests__/FileUpload.error-alert.test.js +0 -37
- package/dist/components/forms/__tests__/FileUpload.native-form.test.js +0 -249
- package/dist/components/forms/__tests__/FileUpload.test.js +0 -90
- package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte +0 -24
- package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte.d.ts +0 -10
- package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/Form.behavior.test.js +0 -137
- package/dist/components/forms/__tests__/Form.extraction.test.js +0 -68
- package/dist/components/forms/__tests__/Form.stt-error.test.js +0 -57
- package/dist/components/forms/__tests__/Form.test.js +0 -86
- package/dist/components/forms/__tests__/Form.ui-controls.test.js +0 -119
- package/dist/components/forms/__tests__/Form.webmcp.test.js +0 -2336
- package/dist/components/forms/__tests__/FormMicButton.test.js +0 -92
- package/dist/components/forms/__tests__/FormScope.test.js +0 -39
- package/dist/components/forms/__tests__/MeasurementInput.behavior.test.js +0 -129
- package/dist/components/forms/__tests__/MoneyInput.behavior.test.js +0 -124
- package/dist/components/forms/__tests__/NumberInput.behavior.test.js +0 -151
- package/dist/components/forms/__tests__/PhoneInput.behavior.test.js +0 -96
- package/dist/components/forms/__tests__/SearchInput.test.js +0 -79
- package/dist/components/forms/__tests__/SelectInput.behavior.test.js +0 -132
- package/dist/components/forms/__tests__/TextInput.behavior.test.js +0 -131
- package/dist/components/forms/__tests__/TextareaInput.behavior.test.js +0 -96
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte +0 -30
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte.d.ts +0 -7
- package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte +0 -19
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte.d.ts +0 -9
- package/dist/components/forms/__tests__/async-validation-form.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte +0 -21
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte.d.ts +0 -8
- package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/composite-inputs-a11y.test.js +0 -69
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte +0 -27
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte.d.ts +0 -9
- package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte +0 -48
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte.d.ts +0 -10
- package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte +0 -26
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte.d.ts +0 -13
- package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte +0 -52
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte.d.ts +0 -16
- package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-scope.fixture.svelte +0 -30
- package/dist/components/forms/__tests__/form-scope.fixture.svelte.d.ts +0 -10
- package/dist/components/forms/__tests__/form-scope.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +0 -158
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +0 -51
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte +0 -24
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte.d.ts +0 -11
- package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte +0 -105
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts +0 -42
- package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte +0 -84
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte.d.ts +0 -14
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte +0 -44
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte.d.ts +0 -9
- package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/mic-keyboard-a11y.test.js +0 -74
- package/dist/components/forms/__tests__/policy-field.fixture.svelte +0 -35
- package/dist/components/forms/__tests__/policy-field.fixture.svelte.d.ts +0 -8
- package/dist/components/forms/__tests__/policy-field.fixture.svelte.d.ts.map +0 -1
- package/dist/components/forms/__tests__/rich-inputs-a11y.test.js +0 -87
- package/dist/components/settings/__tests__/SettingsCatalog.test.js +0 -69
- package/dist/components/settings/__tests__/catalog.test.js +0 -46
- package/dist/components/workspace/__tests__/AdminShell.responsive.test.js +0 -597
- package/dist/components/workspace/__tests__/AdminShell.test.js +0 -572
- package/dist/components/workspace/__tests__/RoleShell.test.js +0 -772
- package/dist/components/workspace/__tests__/TenantNav.test.js +0 -208
- package/dist/components/workspace/__tests__/WorkspaceAccountMenu.test.js +0 -79
- package/dist/components/workspace/__tests__/WorkspaceShell.test.js +0 -630
- package/dist/components/workspace/__tests__/admin-shell-header-overflow.test.js +0 -25
- package/dist/components/workspace/__tests__/admin-shell-hotkeys.test.js +0 -34
- package/dist/components/workspace/__tests__/admin-shell-mobile.test.js +0 -217
- package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte +0 -52
- package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte.d.ts +0 -23
- package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/admin-shell-page-contracts.test.js +0 -30
- package/dist/components/workspace/__tests__/admin-shell-responsive-state.test.js +0 -184
- package/dist/components/workspace/__tests__/admin-shell-settings.test.js +0 -25
- package/dist/components/workspace/__tests__/admin-shell-state.test.js +0 -286
- package/dist/components/workspace/__tests__/admin-shell-theme-hooks.test.js +0 -36
- package/dist/components/workspace/__tests__/breadcrumbs-helpers.test.js +0 -141
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte +0 -45
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts +0 -21
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/define-tools-dock.test.js +0 -1188
- package/dist/components/workspace/__tests__/harness.svelte +0 -25
- package/dist/components/workspace/__tests__/harness.svelte.d.ts +0 -14
- package/dist/components/workspace/__tests__/harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/index.test.js +0 -28
- package/dist/components/workspace/__tests__/legacy-index.test.js +0 -9
- package/dist/components/workspace/__tests__/manifest-nav-helpers.test.js +0 -24
- package/dist/components/workspace/__tests__/manifest-nav.test.js +0 -599
- package/dist/components/workspace/__tests__/nav-helpers.test.js +0 -95
- package/dist/components/workspace/__tests__/render-harness.svelte +0 -66
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts +0 -32
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/render-tools-dock.test.js +0 -260
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte +0 -58
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts +0 -16
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte +0 -41
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts +0 -13
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/shell-chrome-components.test.js +0 -108
- package/dist/components/workspace/__tests__/system-feed.test.js +0 -327
- package/dist/components/workspace/__tests__/test-icon.svelte +0 -17
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts +0 -19
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte +0 -38
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts +0 -22
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts +0 -66
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.js +0 -115
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts +0 -15
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.js +0 -7
- package/dist/components/workspace/__tests__/typed-tool-fixture.test.js +0 -115
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte +0 -9
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts +0 -19
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/use-harness.svelte +0 -23
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts +0 -8
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/__tests__/use-tools-dock.test.js +0 -33
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte +0 -43
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts +0 -11
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts.map +0 -1
- package/dist/components/workspace/server/__tests__/compose-availability.test.js +0 -383
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts +0 -78
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts.map +0 -1
- package/dist/components/workspace/server/__tests__/typed-context-fixture.js +0 -104
- package/dist/hooks/__tests__/stt-consumer.fixture.svelte +0 -25
- package/dist/hooks/__tests__/stt-consumer.fixture.svelte.d.ts +0 -15
- package/dist/hooks/__tests__/stt-consumer.fixture.svelte.d.ts.map +0 -1
- package/dist/hooks/__tests__/stt-ownership-harness.svelte +0 -42
- package/dist/hooks/__tests__/stt-ownership-harness.svelte.d.ts +0 -20
- package/dist/hooks/__tests__/stt-ownership-harness.svelte.d.ts.map +0 -1
- package/dist/hooks/__tests__/useSTT-ownership.test.js +0 -102
- package/dist/i18n/__tests__/server.spec.js +0 -57
- package/dist/internal/logger.test.js +0 -54
- package/dist/provider-mode.test.js +0 -86
- package/dist/provider-webmcp.test.js +0 -244
- package/dist/state/__tests__/app-state-ai-lifecycle.test.js +0 -240
- package/dist/state/__tests__/warm-clients.test.js +0 -40
- package/dist/web/__tests__/activity-feed-harness.svelte +0 -32
- package/dist/web/__tests__/activity-feed-harness.svelte.d.ts +0 -18
- package/dist/web/__tests__/activity-feed-harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/activity-feed.integration.svelte.test.js +0 -190
- package/dist/web/__tests__/activity-feed.svelte.test.js +0 -235
- package/dist/web/__tests__/assistant-dock.integration.svelte.test.js +0 -204
- package/dist/web/__tests__/data-surface-conformance.integration.svelte.test.js +0 -1392
- package/dist/web/__tests__/harness.svelte +0 -25
- package/dist/web/__tests__/harness.svelte.d.ts +0 -15
- package/dist/web/__tests__/harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/list-data-surface.fixture.svelte +0 -59
- package/dist/web/__tests__/list-data-surface.fixture.svelte.d.ts +0 -14
- package/dist/web/__tests__/list-data-surface.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/list-data-surface.svelte.test.js +0 -106
- package/dist/web/__tests__/list-data-surface.test.js +0 -651
- package/dist/web/__tests__/list-sort-surface.fixture.svelte +0 -41
- package/dist/web/__tests__/list-sort-surface.fixture.svelte.d.ts +0 -15
- package/dist/web/__tests__/list-sort-surface.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/list-sort-surface.svelte.test.js +0 -59
- package/dist/web/__tests__/live-collection.svelte.test.js +0 -185
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte +0 -43
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte.d.ts +0 -13
- package/dist/web/__tests__/provider-ui-registry.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/provider-ui-registry.test.js +0 -235
- package/dist/web/__tests__/remote-query-harness.svelte +0 -27
- package/dist/web/__tests__/remote-query-harness.svelte.d.ts +0 -11
- package/dist/web/__tests__/remote-query-harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/remote-query.svelte.test.js +0 -101
- package/dist/web/__tests__/surfaces.child.fixture.svelte +0 -69
- package/dist/web/__tests__/surfaces.child.fixture.svelte.d.ts +0 -16
- package/dist/web/__tests__/surfaces.child.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/surfaces.fixture.svelte +0 -26
- package/dist/web/__tests__/surfaces.fixture.svelte.d.ts +0 -18
- package/dist/web/__tests__/surfaces.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/surfaces.svelte.test.js +0 -140
- package/dist/web/__tests__/update-available-harness.svelte +0 -46
- package/dist/web/__tests__/update-available-harness.svelte.d.ts +0 -22
- package/dist/web/__tests__/update-available-harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/update-available.svelte.test.js +0 -137
- package/dist/web/__tests__/view-intent-provider.fixture.svelte +0 -28
- package/dist/web/__tests__/view-intent-provider.fixture.svelte.d.ts +0 -13
- package/dist/web/__tests__/view-intent-provider.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/view-intent.fixture.svelte +0 -33
- package/dist/web/__tests__/view-intent.fixture.svelte.d.ts +0 -15
- package/dist/web/__tests__/view-intent.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/view-intent.intents.d.ts +0 -14
- package/dist/web/__tests__/view-intent.intents.d.ts.map +0 -1
- package/dist/web/__tests__/view-intent.intents.js +0 -38
- package/dist/web/__tests__/view-intent.svelte.test.js +0 -244
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte +0 -73
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts +0 -8
- package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-composed.fixture.svelte +0 -52
- package/dist/web/__tests__/webmcp-composed.fixture.svelte.d.ts +0 -12
- package/dist/web/__tests__/webmcp-composed.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-composed.integration.svelte.test.js +0 -251
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte +0 -16
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte.d.ts +0 -19
- package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte +0 -11
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte.d.ts +0 -8
- package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte +0 -20
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte.d.ts +0 -7
- package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte +0 -14
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte.d.ts +0 -19
- package/dist/web/__tests__/webmcp-harness-unannotated.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-harness.svelte +0 -18
- package/dist/web/__tests__/webmcp-harness.svelte.d.ts +0 -7
- package/dist/web/__tests__/webmcp-harness.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte +0 -13
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte.d.ts +0 -19
- package/dist/web/__tests__/webmcp-ssr.fixture.svelte.d.ts.map +0 -1
- package/dist/web/__tests__/webmcp-ui.test.js +0 -723
- package/dist/web/__tests__/webmcp.test.js +0 -234
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Behavior tests for AddressInput (Sweep S11, #1416).
|
|
3
|
-
*
|
|
4
|
-
* Exercises the sub-field wiring: typing/selecting each field composes a
|
|
5
|
-
* Partial<AddressValue> emitted via onchange, the `fields` prop gates which
|
|
6
|
-
* sub-fields render (and thus which keys appear in the composed value),
|
|
7
|
-
* province/country selects populate from options, and the error prop marks
|
|
8
|
-
* every field invalid with a single linked alert. useAppState (default mode)
|
|
9
|
-
* is mocked since the hook throws outside a <Provider>.
|
|
10
|
-
*/
|
|
11
|
-
import { expectNoA11yViolations } from '@happyvertical/smrt-ui/test-support/a11y';
|
|
12
|
-
import { fireEvent, render, screen } from '@testing-library/svelte';
|
|
13
|
-
import userEvent from '@testing-library/user-event';
|
|
14
|
-
import { tick } from 'svelte';
|
|
15
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
16
|
-
const formCapture = vi.hoisted(() => ({
|
|
17
|
-
field: undefined,
|
|
18
|
-
}));
|
|
19
|
-
vi.mock('../../../hooks/useAppState.svelte.js', () => ({
|
|
20
|
-
useAppState: () => ({ state: { mode: 'default' }, setMode: vi.fn() }),
|
|
21
|
-
}));
|
|
22
|
-
vi.mock('../../../state/form-context.js', () => ({
|
|
23
|
-
tryGetFormContext: () => ({
|
|
24
|
-
registerField: (field) => {
|
|
25
|
-
formCapture.field = field;
|
|
26
|
-
},
|
|
27
|
-
}),
|
|
28
|
-
}));
|
|
29
|
-
import AddressInput from '../AddressInput.svelte';
|
|
30
|
-
describe('AddressInput — behavior', () => {
|
|
31
|
-
it('typing the street composes a value including the street', async () => {
|
|
32
|
-
const onchange = vi.fn();
|
|
33
|
-
render(AddressInput, {
|
|
34
|
-
props: { name: 'addr', label: 'Address', onchange },
|
|
35
|
-
});
|
|
36
|
-
await userEvent.type(screen.getByLabelText('Street Address'), '123 Main St');
|
|
37
|
-
expect(onchange).toHaveBeenLastCalledWith(expect.objectContaining({ street: '123 Main St' }));
|
|
38
|
-
});
|
|
39
|
-
it('typing the city updates the composed value', async () => {
|
|
40
|
-
const onchange = vi.fn();
|
|
41
|
-
render(AddressInput, {
|
|
42
|
-
props: { name: 'addr', label: 'Address', onchange },
|
|
43
|
-
});
|
|
44
|
-
await userEvent.type(screen.getByLabelText('City'), 'Toronto');
|
|
45
|
-
expect(onchange).toHaveBeenLastCalledWith(expect.objectContaining({ city: 'Toronto' }));
|
|
46
|
-
});
|
|
47
|
-
it('selecting a province emits its value code', async () => {
|
|
48
|
-
const onchange = vi.fn();
|
|
49
|
-
render(AddressInput, {
|
|
50
|
-
props: { name: 'addr', label: 'Address', onchange },
|
|
51
|
-
});
|
|
52
|
-
await userEvent.selectOptions(screen.getByLabelText('Province/State'), 'ON');
|
|
53
|
-
expect(onchange).toHaveBeenLastCalledWith(expect.objectContaining({ province: 'ON' }));
|
|
54
|
-
});
|
|
55
|
-
it('selecting a country emits its value code', async () => {
|
|
56
|
-
const onchange = vi.fn();
|
|
57
|
-
render(AddressInput, {
|
|
58
|
-
props: { name: 'addr', label: 'Address', onchange },
|
|
59
|
-
});
|
|
60
|
-
await userEvent.selectOptions(screen.getByLabelText('Country'), 'US');
|
|
61
|
-
expect(onchange).toHaveBeenLastCalledWith(expect.objectContaining({ country: 'US' }));
|
|
62
|
-
});
|
|
63
|
-
it('defaults the country to CA', () => {
|
|
64
|
-
render(AddressInput, { props: { name: 'addr', label: 'Address' } });
|
|
65
|
-
expect(screen.getByLabelText('Country')).toHaveValue('CA');
|
|
66
|
-
});
|
|
67
|
-
it('composes a complete address object across all fields', async () => {
|
|
68
|
-
const onchange = vi.fn();
|
|
69
|
-
render(AddressInput, {
|
|
70
|
-
props: { name: 'addr', label: 'Address', onchange },
|
|
71
|
-
});
|
|
72
|
-
await userEvent.type(screen.getByLabelText('Postal/ZIP Code'), 'M5V 2T6');
|
|
73
|
-
expect(onchange).toHaveBeenLastCalledWith(expect.objectContaining({
|
|
74
|
-
street: '',
|
|
75
|
-
city: '',
|
|
76
|
-
province: '',
|
|
77
|
-
postalCode: 'M5V 2T6',
|
|
78
|
-
country: 'CA',
|
|
79
|
-
}));
|
|
80
|
-
});
|
|
81
|
-
it('only emits keys for the fields it was told to render', async () => {
|
|
82
|
-
const onchange = vi.fn();
|
|
83
|
-
render(AddressInput, {
|
|
84
|
-
props: {
|
|
85
|
-
name: 'addr',
|
|
86
|
-
label: 'Address',
|
|
87
|
-
fields: ['city', 'country'],
|
|
88
|
-
onchange,
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
expect(screen.queryByLabelText('Street Address')).toBeNull();
|
|
92
|
-
expect(screen.queryByLabelText('Postal/ZIP Code')).toBeNull();
|
|
93
|
-
await userEvent.type(screen.getByLabelText('City'), 'Ottawa');
|
|
94
|
-
const composed = onchange.mock.calls.at(-1)?.[0];
|
|
95
|
-
expect(Object.keys(composed).sort()).toEqual(['city', 'country']);
|
|
96
|
-
expect(composed.city).toBe('Ottawa');
|
|
97
|
-
});
|
|
98
|
-
it('seeds sub-fields from the bound value object', () => {
|
|
99
|
-
render(AddressInput, {
|
|
100
|
-
props: {
|
|
101
|
-
name: 'addr',
|
|
102
|
-
label: 'Address',
|
|
103
|
-
value: { city: 'Calgary', province: 'AB', country: 'CA' },
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
expect(screen.getByLabelText('City')).toHaveValue('Calgary');
|
|
107
|
-
expect(screen.getByLabelText('Province/State')).toHaveValue('AB');
|
|
108
|
-
});
|
|
109
|
-
it('renders the province and country option sets', () => {
|
|
110
|
-
render(AddressInput, { props: { name: 'addr', label: 'Address' } });
|
|
111
|
-
const provinces = screen.getByLabelText('Province/State');
|
|
112
|
-
expect(provinces.querySelector('option[value="QC"]')?.textContent).toBe('Quebec');
|
|
113
|
-
const countries = screen.getByLabelText('Country');
|
|
114
|
-
expect(countries.querySelector('option[value="US"]')?.textContent).toBe('United States');
|
|
115
|
-
});
|
|
116
|
-
it('parses spoken countries only from the live configured options', async () => {
|
|
117
|
-
const onchange = vi.fn();
|
|
118
|
-
render(AddressInput, {
|
|
119
|
-
props: {
|
|
120
|
-
name: 'addr',
|
|
121
|
-
label: 'Address',
|
|
122
|
-
fields: ['country'],
|
|
123
|
-
countries: [{ value: 'FR', label: 'France' }],
|
|
124
|
-
onchange,
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
await tick();
|
|
128
|
-
const field = formCapture.field;
|
|
129
|
-
if (!field)
|
|
130
|
-
throw new Error('AddressInput did not register its field');
|
|
131
|
-
field.setValue('Canada');
|
|
132
|
-
expect(onchange).not.toHaveBeenCalled();
|
|
133
|
-
expect(field.getValue()).toEqual({ country: 'FR' });
|
|
134
|
-
field.setValue('France');
|
|
135
|
-
expect(onchange).toHaveBeenLastCalledWith({ country: 'FR' });
|
|
136
|
-
field.setValue('FR');
|
|
137
|
-
expect(onchange).toHaveBeenLastCalledWith({ country: 'FR' });
|
|
138
|
-
});
|
|
139
|
-
it('retains spoken Canada and United States defaults', async () => {
|
|
140
|
-
const onchange = vi.fn();
|
|
141
|
-
render(AddressInput, {
|
|
142
|
-
props: {
|
|
143
|
-
name: 'addr',
|
|
144
|
-
label: 'Address',
|
|
145
|
-
fields: ['country'],
|
|
146
|
-
onchange,
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
await tick();
|
|
150
|
-
const field = formCapture.field;
|
|
151
|
-
if (!field)
|
|
152
|
-
throw new Error('AddressInput did not register its field');
|
|
153
|
-
field.setValue('Canada');
|
|
154
|
-
expect(onchange).toHaveBeenLastCalledWith({ country: 'CA' });
|
|
155
|
-
field.setValue('United States');
|
|
156
|
-
expect(onchange).toHaveBeenLastCalledWith({ country: 'US' });
|
|
157
|
-
});
|
|
158
|
-
it('accepts valid incremental setters for a required address', async () => {
|
|
159
|
-
const onchange = vi.fn();
|
|
160
|
-
render(AddressInput, {
|
|
161
|
-
props: {
|
|
162
|
-
name: 'addr',
|
|
163
|
-
label: 'Address',
|
|
164
|
-
required: true,
|
|
165
|
-
countries: [{ value: 'FR', label: 'France' }],
|
|
166
|
-
onchange,
|
|
167
|
-
},
|
|
168
|
-
});
|
|
169
|
-
await tick();
|
|
170
|
-
const field = formCapture.field;
|
|
171
|
-
if (!field)
|
|
172
|
-
throw new Error('AddressInput did not register its field');
|
|
173
|
-
field.setValue({ city: 'Paris' });
|
|
174
|
-
expect(onchange).toHaveBeenLastCalledWith({
|
|
175
|
-
street: '',
|
|
176
|
-
city: 'Paris',
|
|
177
|
-
province: '',
|
|
178
|
-
postalCode: '',
|
|
179
|
-
country: 'FR',
|
|
180
|
-
});
|
|
181
|
-
expect(field.validateValue?.({ city: 'Paris' })).toBe(false);
|
|
182
|
-
expect(field.validate?.()).toBe(false);
|
|
183
|
-
expect(field.webMcpSchema).toMatchObject({
|
|
184
|
-
required: ['street', 'city', 'province', 'postalCode', 'country'],
|
|
185
|
-
});
|
|
186
|
-
field.setValue('France');
|
|
187
|
-
expect(onchange).toHaveBeenLastCalledWith(expect.objectContaining({ city: 'Paris', country: 'FR' }));
|
|
188
|
-
onchange.mockClear();
|
|
189
|
-
field.setValue({ country: 'CA' });
|
|
190
|
-
expect(onchange).not.toHaveBeenCalled();
|
|
191
|
-
expect(field.getValue()).toEqual({
|
|
192
|
-
street: '',
|
|
193
|
-
city: 'Paris',
|
|
194
|
-
province: '',
|
|
195
|
-
postalCode: '',
|
|
196
|
-
country: 'FR',
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
it('marks every field invalid and links one alert when error is set', () => {
|
|
200
|
-
render(AddressInput, {
|
|
201
|
-
props: { name: 'addr', label: 'Address', error: 'Address required' },
|
|
202
|
-
});
|
|
203
|
-
const street = screen.getByLabelText('Street Address');
|
|
204
|
-
expect(street).toHaveAttribute('aria-invalid', 'true');
|
|
205
|
-
expect(street).toHaveAttribute('aria-describedby', 'addr-error');
|
|
206
|
-
const err = document.getElementById('addr-error');
|
|
207
|
-
expect(err).toHaveTextContent('Address required');
|
|
208
|
-
expect(err).toHaveAttribute('role', 'alert');
|
|
209
|
-
});
|
|
210
|
-
it('is axe-clean with all fields labelled', async () => {
|
|
211
|
-
const { container } = render(AddressInput, {
|
|
212
|
-
props: { name: 'addr', label: 'Address' },
|
|
213
|
-
});
|
|
214
|
-
await expectNoA11yViolations(container);
|
|
215
|
-
});
|
|
216
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Component test for CheckboxInput (Sweep S11, #1416).
|
|
3
|
-
*
|
|
4
|
-
* Follows the golden pattern (src/components/ui/__tests__/Button.test.ts).
|
|
5
|
-
* CheckboxInput calls `useAppState` (throws outside a <Provider>), so we mock it
|
|
6
|
-
* to a stub default mode. Its form-context lookup uses `getContext` and safely
|
|
7
|
-
* returns undefined outside a provider, so no further stubbing is needed.
|
|
8
|
-
*/
|
|
9
|
-
import { expectNoA11yViolations } from '@happyvertical/smrt-ui/test-support/a11y';
|
|
10
|
-
import { render, screen } from '@testing-library/svelte';
|
|
11
|
-
import userEvent from '@testing-library/user-event';
|
|
12
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
13
|
-
vi.mock('../../../hooks/useAppState.svelte.js', () => ({
|
|
14
|
-
useAppState: () => ({ state: { mode: 'default' }, setMode: vi.fn() }),
|
|
15
|
-
}));
|
|
16
|
-
import CheckboxInput from '../CheckboxInput.svelte';
|
|
17
|
-
describe('CheckboxInput', () => {
|
|
18
|
-
it('renders a checkbox labelled by its label, wired via for/id', () => {
|
|
19
|
-
render(CheckboxInput, { props: { name: 'terms', label: 'Accept terms' } });
|
|
20
|
-
const checkbox = screen.getByRole('checkbox', { name: 'Accept terms' });
|
|
21
|
-
expect(checkbox).toBeInTheDocument();
|
|
22
|
-
expect(checkbox).toHaveAttribute('id', 'terms');
|
|
23
|
-
expect(checkbox).not.toBeChecked();
|
|
24
|
-
});
|
|
25
|
-
it('reflects the checked prop', () => {
|
|
26
|
-
render(CheckboxInput, {
|
|
27
|
-
props: { name: 'terms', label: 'Accept terms', checked: true },
|
|
28
|
-
});
|
|
29
|
-
expect(screen.getByRole('checkbox', { name: 'Accept terms' })).toBeChecked();
|
|
30
|
-
});
|
|
31
|
-
it('reflects the disabled prop', () => {
|
|
32
|
-
render(CheckboxInput, {
|
|
33
|
-
props: { name: 'terms', label: 'Accept terms', disabled: true },
|
|
34
|
-
});
|
|
35
|
-
expect(screen.getByRole('checkbox', { name: 'Accept terms' })).toBeDisabled();
|
|
36
|
-
});
|
|
37
|
-
it('reflects the required prop (and marks the label with *)', () => {
|
|
38
|
-
render(CheckboxInput, {
|
|
39
|
-
props: { name: 'terms', label: 'Accept terms', required: true },
|
|
40
|
-
});
|
|
41
|
-
// Required appends a "*" to the visible label, so the accessible name is "Accept terms*".
|
|
42
|
-
expect(screen.getByRole('checkbox', { name: 'Accept terms*' })).toBeRequired();
|
|
43
|
-
});
|
|
44
|
-
it('toggles checked and fires onchange when clicked', async () => {
|
|
45
|
-
const onchange = vi.fn();
|
|
46
|
-
render(CheckboxInput, {
|
|
47
|
-
props: { name: 'terms', label: 'Accept terms', onchange },
|
|
48
|
-
});
|
|
49
|
-
const checkbox = screen.getByRole('checkbox', { name: 'Accept terms' });
|
|
50
|
-
await userEvent.click(checkbox);
|
|
51
|
-
expect(checkbox).toBeChecked();
|
|
52
|
-
expect(onchange).toHaveBeenCalledWith(true);
|
|
53
|
-
await userEvent.click(checkbox);
|
|
54
|
-
expect(checkbox).not.toBeChecked();
|
|
55
|
-
expect(onchange).toHaveBeenLastCalledWith(false);
|
|
56
|
-
});
|
|
57
|
-
it('toggles when its label text is clicked', async () => {
|
|
58
|
-
const onchange = vi.fn();
|
|
59
|
-
render(CheckboxInput, {
|
|
60
|
-
props: { name: 'terms', label: 'Accept terms', onchange },
|
|
61
|
-
});
|
|
62
|
-
await userEvent.click(screen.getByText('Accept terms'));
|
|
63
|
-
expect(screen.getByRole('checkbox', { name: 'Accept terms' })).toBeChecked();
|
|
64
|
-
expect(onchange).toHaveBeenCalledWith(true);
|
|
65
|
-
});
|
|
66
|
-
it('does not fire onchange when disabled', async () => {
|
|
67
|
-
const onchange = vi.fn();
|
|
68
|
-
render(CheckboxInput, {
|
|
69
|
-
props: { name: 'terms', label: 'Accept terms', disabled: true, onchange },
|
|
70
|
-
});
|
|
71
|
-
await userEvent.click(screen.getByRole('checkbox', { name: 'Accept terms' }));
|
|
72
|
-
expect(onchange).not.toHaveBeenCalled();
|
|
73
|
-
});
|
|
74
|
-
it('is axe-clean with a label', async () => {
|
|
75
|
-
const { container } = render(CheckboxInput, {
|
|
76
|
-
props: { name: 'newsletter', label: 'Subscribe to the newsletter' },
|
|
77
|
-
});
|
|
78
|
-
await expectNoA11yViolations(container);
|
|
79
|
-
});
|
|
80
|
-
it('is axe-clean when checked, required, and disabled', async () => {
|
|
81
|
-
const { container } = render(CheckboxInput, {
|
|
82
|
-
props: {
|
|
83
|
-
name: 'newsletter',
|
|
84
|
-
label: 'Subscribe to the newsletter',
|
|
85
|
-
checked: true,
|
|
86
|
-
required: true,
|
|
87
|
-
disabled: true,
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
await expectNoA11yViolations(container);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Behavior tests for DateRangeInput (Sweep S11, #1416).
|
|
3
|
-
*
|
|
4
|
-
* In default mode the component renders two native date pickers (Start / End)
|
|
5
|
-
* with cross-linked min/max, emits a { startDate, endDate } range via
|
|
6
|
-
* onchange, and validates start <= end. The hooks throw outside a <Provider>,
|
|
7
|
-
* so useAppState (default mode) + useSTT (stub) are mocked.
|
|
8
|
-
*/
|
|
9
|
-
import { expectNoA11yViolations } from '@happyvertical/smrt-ui/test-support/a11y';
|
|
10
|
-
import { fireEvent, render, screen } from '@testing-library/svelte';
|
|
11
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
12
|
-
vi.mock('../../../hooks/useAppState.svelte.js', () => ({
|
|
13
|
-
useAppState: () => ({ state: { mode: 'default' }, setMode: vi.fn() }),
|
|
14
|
-
}));
|
|
15
|
-
vi.mock('../../../hooks/useSTT.svelte.js', () => ({
|
|
16
|
-
useSTT: () => ({
|
|
17
|
-
isListening: false,
|
|
18
|
-
isInitializing: false,
|
|
19
|
-
isReady: false,
|
|
20
|
-
adapterType: null,
|
|
21
|
-
downloadProgress: 0,
|
|
22
|
-
lastResult: '',
|
|
23
|
-
initialize: vi.fn(),
|
|
24
|
-
start: vi.fn(),
|
|
25
|
-
stop: vi.fn(),
|
|
26
|
-
}),
|
|
27
|
-
}));
|
|
28
|
-
import DateRangeInput from '../DateRangeInput.svelte';
|
|
29
|
-
describe('DateRangeInput — behavior', () => {
|
|
30
|
-
it('renders labelled Start and End date pickers', () => {
|
|
31
|
-
render(DateRangeInput, { props: { name: 'range', label: 'Dates' } });
|
|
32
|
-
expect(screen.getByLabelText('Start')).toHaveAttribute('type', 'date');
|
|
33
|
-
expect(screen.getByLabelText('End')).toHaveAttribute('type', 'date');
|
|
34
|
-
});
|
|
35
|
-
it('setting the start date emits the range with the new start', async () => {
|
|
36
|
-
const onchange = vi.fn();
|
|
37
|
-
render(DateRangeInput, {
|
|
38
|
-
props: { name: 'range', label: 'Dates', onchange },
|
|
39
|
-
});
|
|
40
|
-
await fireEvent.change(screen.getByLabelText('Start'), {
|
|
41
|
-
target: { value: '2024-01-10' },
|
|
42
|
-
});
|
|
43
|
-
expect(onchange).toHaveBeenLastCalledWith({
|
|
44
|
-
startDate: '2024-01-10',
|
|
45
|
-
endDate: '',
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
it('setting both dates emits the full range', async () => {
|
|
49
|
-
const onchange = vi.fn();
|
|
50
|
-
render(DateRangeInput, {
|
|
51
|
-
props: {
|
|
52
|
-
name: 'range',
|
|
53
|
-
label: 'Dates',
|
|
54
|
-
startDate: '2024-01-10',
|
|
55
|
-
onchange,
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
await fireEvent.change(screen.getByLabelText('End'), {
|
|
59
|
-
target: { value: '2024-03-20' },
|
|
60
|
-
});
|
|
61
|
-
expect(onchange).toHaveBeenLastCalledWith({
|
|
62
|
-
startDate: '2024-01-10',
|
|
63
|
-
endDate: '2024-03-20',
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
it('flags an end-before-start range as invalid with a linked alert', () => {
|
|
67
|
-
render(DateRangeInput, {
|
|
68
|
-
props: {
|
|
69
|
-
name: 'range',
|
|
70
|
-
label: 'Dates',
|
|
71
|
-
startDate: '2024-05-01',
|
|
72
|
-
endDate: '2024-01-01',
|
|
73
|
-
},
|
|
74
|
-
});
|
|
75
|
-
const start = screen.getByLabelText('Start');
|
|
76
|
-
expect(start).toHaveAttribute('aria-invalid', 'true');
|
|
77
|
-
expect(start).toHaveAttribute('aria-describedby', 'range-error');
|
|
78
|
-
const err = document.getElementById('range-error');
|
|
79
|
-
expect(err).toHaveAttribute('role', 'alert');
|
|
80
|
-
expect(err).toHaveTextContent('End date must be after start date');
|
|
81
|
-
});
|
|
82
|
-
it('treats start <= end as a valid range (no error)', () => {
|
|
83
|
-
render(DateRangeInput, {
|
|
84
|
-
props: {
|
|
85
|
-
name: 'range',
|
|
86
|
-
label: 'Dates',
|
|
87
|
-
startDate: '2024-01-01',
|
|
88
|
-
endDate: '2024-05-01',
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
expect(screen.getByLabelText('Start')).not.toHaveAttribute('aria-invalid');
|
|
92
|
-
expect(document.getElementById('range-error')).toBeNull();
|
|
93
|
-
});
|
|
94
|
-
it('caps the start picker max at the chosen end date', () => {
|
|
95
|
-
render(DateRangeInput, {
|
|
96
|
-
props: { name: 'range', label: 'Dates', endDate: '2024-03-20' },
|
|
97
|
-
});
|
|
98
|
-
expect(screen.getByLabelText('Start')).toHaveAttribute('max', '2024-03-20');
|
|
99
|
-
});
|
|
100
|
-
it('floors the end picker min at the chosen start date', () => {
|
|
101
|
-
render(DateRangeInput, {
|
|
102
|
-
props: { name: 'range', label: 'Dates', startDate: '2024-01-10' },
|
|
103
|
-
});
|
|
104
|
-
expect(screen.getByLabelText('End')).toHaveAttribute('min', '2024-01-10');
|
|
105
|
-
});
|
|
106
|
-
it('mirrors the dates into hidden submission inputs', async () => {
|
|
107
|
-
const { container } = render(DateRangeInput, {
|
|
108
|
-
props: { name: 'range', label: 'Dates', startDate: '2024-01-10' },
|
|
109
|
-
});
|
|
110
|
-
await fireEvent.change(screen.getByLabelText('End'), {
|
|
111
|
-
target: { value: '2024-03-20' },
|
|
112
|
-
});
|
|
113
|
-
expect(container.querySelector('input[name="range_start"]')).toHaveValue('2024-01-10');
|
|
114
|
-
expect(container.querySelector('input[name="range_end"]')).toHaveValue('2024-03-20');
|
|
115
|
-
});
|
|
116
|
-
it('renders an explicit error prop as a linked alert', () => {
|
|
117
|
-
render(DateRangeInput, {
|
|
118
|
-
props: { name: 'range', label: 'Dates', error: 'Pick a range' },
|
|
119
|
-
});
|
|
120
|
-
const err = document.getElementById('range-error');
|
|
121
|
-
expect(err).toHaveTextContent('Pick a range');
|
|
122
|
-
expect(err).toHaveAttribute('role', 'alert');
|
|
123
|
-
});
|
|
124
|
-
it('is axe-clean in a labelled + error state', async () => {
|
|
125
|
-
const { container } = render(DateRangeInput, {
|
|
126
|
-
props: {
|
|
127
|
-
name: 'range',
|
|
128
|
-
label: 'Dates',
|
|
129
|
-
startDate: '2024-05-01',
|
|
130
|
-
endDate: '2024-01-01',
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
await expectNoA11yViolations(container);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Behavior tests for DateTimeInput (Sweep S11, #1416).
|
|
3
|
-
*
|
|
4
|
-
* In default (non-smrt) mode the component renders a native date /
|
|
5
|
-
* datetime-local picker, echoes the picked value through onchange, and
|
|
6
|
-
* formats the bound ISO value for display via Intl. The hooks throw outside a
|
|
7
|
-
* <Provider>, so useAppState (default mode) + useSTT (stub) are mocked.
|
|
8
|
-
*
|
|
9
|
-
* Date assertions are timezone/locale-robust: for date-only the component
|
|
10
|
-
* parses YYYY-MM-DD into a *local* Date, so we derive the expected display the
|
|
11
|
-
* same way (new Date(y, m-1, d).toLocaleDateString) rather than hardcoding.
|
|
12
|
-
*/
|
|
13
|
-
import { expectNoA11yViolations } from '@happyvertical/smrt-ui/test-support/a11y';
|
|
14
|
-
import { fireEvent, render, screen } from '@testing-library/svelte';
|
|
15
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
16
|
-
vi.mock('../../../hooks/useAppState.svelte.js', () => ({
|
|
17
|
-
useAppState: () => ({ state: { mode: 'default' }, setMode: vi.fn() }),
|
|
18
|
-
}));
|
|
19
|
-
vi.mock('../../../hooks/useSTT.svelte.js', () => ({
|
|
20
|
-
useSTT: () => ({
|
|
21
|
-
isListening: false,
|
|
22
|
-
isInitializing: false,
|
|
23
|
-
isReady: false,
|
|
24
|
-
adapterType: null,
|
|
25
|
-
downloadProgress: 0,
|
|
26
|
-
lastResult: '',
|
|
27
|
-
initialize: vi.fn(),
|
|
28
|
-
start: vi.fn(),
|
|
29
|
-
stop: vi.fn(),
|
|
30
|
-
}),
|
|
31
|
-
}));
|
|
32
|
-
import DateTimeInput from '../DateTimeInput.svelte';
|
|
33
|
-
import dateTimeInputSource from '../DateTimeInput.svelte?raw';
|
|
34
|
-
describe('DateTimeInput — behavior', () => {
|
|
35
|
-
it('allows its native input to shrink inside a narrow form track', () => {
|
|
36
|
-
const { container } = render(DateTimeInput, {
|
|
37
|
-
props: { name: 'when', label: 'When' },
|
|
38
|
-
});
|
|
39
|
-
container.style.width = '80px';
|
|
40
|
-
const input = screen.getByLabelText('When');
|
|
41
|
-
expect(input).toHaveClass('smrt-input');
|
|
42
|
-
expect(dateTimeInputSource).toMatch(/\.smrt-input\s*\{[^}]*box-sizing:\s*border-box;[^}]*min-width:\s*0;[^}]*width:\s*100%;/);
|
|
43
|
-
});
|
|
44
|
-
it('renders a datetime-local input when includeTime is true (default)', () => {
|
|
45
|
-
render(DateTimeInput, { props: { name: 'when', label: 'When' } });
|
|
46
|
-
expect(screen.getByLabelText('When')).toHaveAttribute('type', 'datetime-local');
|
|
47
|
-
});
|
|
48
|
-
it('renders a date input when includeTime is false', () => {
|
|
49
|
-
render(DateTimeInput, {
|
|
50
|
-
props: { name: 'when', label: 'When', includeTime: false },
|
|
51
|
-
});
|
|
52
|
-
expect(screen.getByLabelText('When')).toHaveAttribute('type', 'date');
|
|
53
|
-
});
|
|
54
|
-
it('emits the picked date value via onchange', async () => {
|
|
55
|
-
const onchange = vi.fn();
|
|
56
|
-
render(DateTimeInput, {
|
|
57
|
-
props: { name: 'when', label: 'When', includeTime: false, onchange },
|
|
58
|
-
});
|
|
59
|
-
const input = screen.getByLabelText('When');
|
|
60
|
-
await fireEvent.change(input, { target: { value: '2024-03-15' } });
|
|
61
|
-
expect(onchange).toHaveBeenLastCalledWith('2024-03-15');
|
|
62
|
-
});
|
|
63
|
-
it('emits a datetime-local value through onchange unchanged', async () => {
|
|
64
|
-
const onchange = vi.fn();
|
|
65
|
-
render(DateTimeInput, {
|
|
66
|
-
props: { name: 'when', label: 'When', onchange },
|
|
67
|
-
});
|
|
68
|
-
const input = screen.getByLabelText('When');
|
|
69
|
-
await fireEvent.change(input, { target: { value: '2024-03-15T13:30' } });
|
|
70
|
-
expect(onchange).toHaveBeenLastCalledWith('2024-03-15T13:30');
|
|
71
|
-
});
|
|
72
|
-
it('seeds the native input with the bound ISO value', () => {
|
|
73
|
-
render(DateTimeInput, {
|
|
74
|
-
props: {
|
|
75
|
-
name: 'when',
|
|
76
|
-
label: 'When',
|
|
77
|
-
includeTime: false,
|
|
78
|
-
value: '1990-06-18',
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
expect(screen.getByLabelText('When')).toHaveValue('1990-06-18');
|
|
82
|
-
});
|
|
83
|
-
it('clearing the picker emits an empty string', async () => {
|
|
84
|
-
const onchange = vi.fn();
|
|
85
|
-
render(DateTimeInput, {
|
|
86
|
-
props: {
|
|
87
|
-
name: 'when',
|
|
88
|
-
label: 'When',
|
|
89
|
-
includeTime: false,
|
|
90
|
-
value: '2024-03-15',
|
|
91
|
-
onchange,
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
const input = screen.getByLabelText('When');
|
|
95
|
-
await fireEvent.change(input, { target: { value: '' } });
|
|
96
|
-
expect(onchange).toHaveBeenLastCalledWith('');
|
|
97
|
-
});
|
|
98
|
-
it('uses a date-aware placeholder for date-only mode', () => {
|
|
99
|
-
render(DateTimeInput, {
|
|
100
|
-
props: { name: 'when', label: 'When', includeTime: false },
|
|
101
|
-
});
|
|
102
|
-
// default mode native input has no placeholder attribute; the prop default
|
|
103
|
-
// still reflects includeTime — assert via the smrt-mode path being absent
|
|
104
|
-
// and the input rendering as a plain date control.
|
|
105
|
-
expect(screen.getByLabelText('When')).toHaveAttribute('type', 'date');
|
|
106
|
-
});
|
|
107
|
-
it('is axe-clean in a labelled state', async () => {
|
|
108
|
-
const { container } = render(DateTimeInput, {
|
|
109
|
-
props: { name: 'when', label: 'When', value: '2024-03-15T09:00' },
|
|
110
|
-
});
|
|
111
|
-
await expectNoA11yViolations(container);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Regression: FileUpload validation errors are announced (C7).
|
|
3
|
-
*
|
|
4
|
-
* The error `<p>` was a plain element, so async reject errors (wrong type /
|
|
5
|
-
* oversize) were not surfaced to screen readers — unlike Form/TextInput which
|
|
6
|
-
* announce. The fix makes it a live region (role="alert" + aria-live).
|
|
7
|
-
*/
|
|
8
|
-
import { render, screen, waitFor } from '@testing-library/svelte';
|
|
9
|
-
import userEvent from '@testing-library/user-event';
|
|
10
|
-
import { describe, expect, it } from 'vitest';
|
|
11
|
-
import FileUpload from '../FileUpload.svelte';
|
|
12
|
-
function fileInput(container) {
|
|
13
|
-
const input = container.querySelector('input[type="file"]');
|
|
14
|
-
if (!input)
|
|
15
|
-
throw new Error('file input not found');
|
|
16
|
-
return input;
|
|
17
|
-
}
|
|
18
|
-
describe('FileUpload — error live region (C7)', () => {
|
|
19
|
-
it('announces a max-size error via role="alert"', async () => {
|
|
20
|
-
const { container } = render(FileUpload, {
|
|
21
|
-
// maxSize forces a validation error without an `accept` filter (which
|
|
22
|
-
// userEvent.upload would otherwise apply before the file reaches the
|
|
23
|
-
// component, suppressing the error path under test).
|
|
24
|
-
props: { label: 'Upload', maxSize: 4 },
|
|
25
|
-
});
|
|
26
|
-
const big = new File(['way too many bytes'], 'big.bin', {
|
|
27
|
-
type: 'application/octet-stream',
|
|
28
|
-
});
|
|
29
|
-
await userEvent.upload(fileInput(container), big);
|
|
30
|
-
await waitFor(() => {
|
|
31
|
-
const alert = screen.getByRole('alert');
|
|
32
|
-
expect(alert).toBeInTheDocument();
|
|
33
|
-
expect(alert).toHaveAttribute('aria-live');
|
|
34
|
-
expect(alert.textContent).toMatch(/maximum size/i);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
});
|