@ksp-gonogo/ui-kit 0.1.0 → 0.2.0-rc.10
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/LICENSE +21 -596
- package/README.md +151 -0
- package/dist/chunk-G3PMV62Z.js +36 -0
- package/dist/chunk-G3PMV62Z.js.map +1 -0
- package/dist/chunk-KPESGDJJ.js +8611 -0
- package/dist/chunk-KPESGDJJ.js.map +1 -0
- package/dist/chunk-SHAX2WJJ.js +18 -0
- package/dist/chunk-SHAX2WJJ.js.map +1 -0
- package/dist/dist-JSEJWZKX.js +546 -0
- package/dist/dist-JSEJWZKX.js.map +1 -0
- package/dist/gridUnits.d.ts +34 -0
- package/dist/gridUnits.js +14 -0
- package/dist/gridUnits.js.map +1 -0
- package/dist/guards.d.ts +110 -0
- package/dist/guards.js +171 -0
- package/dist/guards.js.map +1 -0
- package/dist/index.d.ts +9318 -25
- package/dist/index.js +8098 -28
- package/dist/index.js.map +1 -1
- package/dist/magic-string.es-J7BYFTTJ.js +1309 -0
- package/dist/magic-string.es-J7BYFTTJ.js.map +1 -0
- package/dist/testing.d.ts +470 -0
- package/dist/testing.js +16747 -0
- package/dist/testing.js.map +1 -0
- package/dist/tokens.css +1063 -29
- package/dist/units-Cl-8ZdJc.d.ts +270 -0
- package/package.json +57 -15
- package/dist/ActionButton.d.ts +0 -18
- package/dist/ActionButton.d.ts.map +0 -1
- package/dist/ActionButton.js +0 -56
- package/dist/ActionButton.js.map +0 -1
- package/dist/Badge.d.ts +0 -15
- package/dist/Badge.d.ts.map +0 -1
- package/dist/Badge.js +0 -60
- package/dist/Badge.js.map +0 -1
- package/dist/Box.d.ts +0 -19
- package/dist/Box.d.ts.map +0 -1
- package/dist/Box.js +0 -27
- package/dist/Box.js.map +0 -1
- package/dist/Card.d.ts +0 -11
- package/dist/Card.d.ts.map +0 -1
- package/dist/Card.js +0 -13
- package/dist/Card.js.map +0 -1
- package/dist/Cluster.d.ts +0 -18
- package/dist/Cluster.d.ts.map +0 -1
- package/dist/Cluster.js +0 -24
- package/dist/Cluster.js.map +0 -1
- package/dist/EmptyState.d.ts +0 -16
- package/dist/EmptyState.d.ts.map +0 -1
- package/dist/EmptyState.js +0 -37
- package/dist/EmptyState.js.map +0 -1
- package/dist/GonogoTokens.d.ts +0 -16
- package/dist/GonogoTokens.d.ts.map +0 -1
- package/dist/GonogoTokens.js +0 -108
- package/dist/GonogoTokens.js.map +0 -1
- package/dist/Grid.d.ts +0 -25
- package/dist/Grid.d.ts.map +0 -1
- package/dist/Grid.js +0 -23
- package/dist/Grid.js.map +0 -1
- package/dist/Inline.d.ts +0 -20
- package/dist/Inline.d.ts.map +0 -1
- package/dist/Inline.js +0 -17
- package/dist/Inline.js.map +0 -1
- package/dist/Panel.d.ts +0 -14
- package/dist/Panel.d.ts.map +0 -1
- package/dist/Panel.js +0 -145
- package/dist/Panel.js.map +0 -1
- package/dist/ProgressBar.d.ts +0 -15
- package/dist/ProgressBar.d.ts.map +0 -1
- package/dist/ProgressBar.js +0 -31
- package/dist/ProgressBar.js.map +0 -1
- package/dist/Readout.d.ts +0 -35
- package/dist/Readout.d.ts.map +0 -1
- package/dist/Readout.js +0 -114
- package/dist/Readout.js.map +0 -1
- package/dist/Row.d.ts +0 -22
- package/dist/Row.d.ts.map +0 -1
- package/dist/Row.js +0 -32
- package/dist/Row.js.map +0 -1
- package/dist/Section.d.ts +0 -15
- package/dist/Section.d.ts.map +0 -1
- package/dist/Section.js +0 -21
- package/dist/Section.js.map +0 -1
- package/dist/Spinner.d.ts +0 -18
- package/dist/Spinner.d.ts.map +0 -1
- package/dist/Spinner.js +0 -22
- package/dist/Spinner.js.map +0 -1
- package/dist/Stack.d.ts +0 -15
- package/dist/Stack.d.ts.map +0 -1
- package/dist/Stack.js +0 -17
- package/dist/Stack.js.map +0 -1
- package/dist/StatusIndicator.d.ts +0 -27
- package/dist/StatusIndicator.d.ts.map +0 -1
- package/dist/StatusIndicator.js +0 -78
- package/dist/StatusIndicator.js.map +0 -1
- package/dist/Truncate.d.ts +0 -7
- package/dist/Truncate.d.ts.map +0 -1
- package/dist/Truncate.js +0 -14
- package/dist/Truncate.js.map +0 -1
- package/dist/Value.d.ts +0 -24
- package/dist/Value.d.ts.map +0 -1
- package/dist/Value.js +0 -42
- package/dist/Value.js.map +0 -1
- package/dist/WidgetHeader.d.ts +0 -16
- package/dist/WidgetHeader.d.ts.map +0 -1
- package/dist/WidgetHeader.js +0 -40
- package/dist/WidgetHeader.js.map +0 -1
- package/dist/defaultDarkTheme.d.ts +0 -16
- package/dist/defaultDarkTheme.d.ts.map +0 -1
- package/dist/defaultDarkTheme.js +0 -96
- package/dist/defaultDarkTheme.js.map +0 -1
- package/dist/format.d.ts +0 -11
- package/dist/format.d.ts.map +0 -1
- package/dist/format.js +0 -12
- package/dist/format.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/science/ScienceExperimentRow.d.ts +0 -43
- package/dist/science/ScienceExperimentRow.d.ts.map +0 -1
- package/dist/science/ScienceExperimentRow.js +0 -61
- package/dist/science/ScienceExperimentRow.js.map +0 -1
- package/dist/test/axe.d.ts +0 -3
- package/dist/test/axe.d.ts.map +0 -1
- package/dist/test/axe.js +0 -5
- package/dist/test/axe.js.map +0 -1
- package/dist/test/setup.d.ts +0 -2
- package/dist/test/setup.d.ts.map +0 -1
- package/dist/test/setup.js +0 -12
- package/dist/test/setup.js.map +0 -1
- package/dist/theme.d.ts +0 -116
- package/dist/theme.d.ts.map +0 -1
- package/dist/theme.js +0 -15
- package/dist/theme.js.map +0 -1
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { F as FormatQuantityOptions } from './units-Cl-8ZdJc.js';
|
|
2
|
+
import { RenderHookOptions, RenderHookResult, RenderOptions, RenderResult } from '@ksp-gonogo/sitrep-sdk/testing';
|
|
3
|
+
import { ReactElement, JSXElementConstructor, ReactNode } from 'react';
|
|
4
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
|
+
import { ComponentDefinition } from '@ksp-gonogo/sitrep-sdk';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A checkered-flag test for framed pictures: paint a pattern of square cells
|
|
9
|
+
* into a box and ask what a cell looks like on screen, with no pixels involved.
|
|
10
|
+
*
|
|
11
|
+
* Three different faults make a framed picture look wrong, and they are easy to
|
|
12
|
+
* mistake for each other by eye:
|
|
13
|
+
*
|
|
14
|
+
* - **distortion**: the picture is scaled by different amounts per axis, so a
|
|
15
|
+
* square cell renders as a rectangle
|
|
16
|
+
* - **cropping**: cells stay square, but some of them are painted outside the
|
|
17
|
+
* box and lost off its edge
|
|
18
|
+
* - **field of view**: cells stay square and nothing is cut off, but the source
|
|
19
|
+
* was rendered showing a different grid than the one intended, so more or
|
|
20
|
+
* fewer cells are visible
|
|
21
|
+
*
|
|
22
|
+
* jsdom lays nothing out, so this is geometry rather than measurement: the
|
|
23
|
+
* caller supplies the box it gave the picture, and the fit comes from the
|
|
24
|
+
* element (see {@link fitOf}) or is stated.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* A pattern of square cells, `cols` wide and `rows` high. Either may be fractional.
|
|
28
|
+
*
|
|
29
|
+
* @category Testing
|
|
30
|
+
*/
|
|
31
|
+
interface CheckerGrid {
|
|
32
|
+
cols: number;
|
|
33
|
+
rows: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The `object-fit` values that scale a picture to its box.
|
|
37
|
+
*
|
|
38
|
+
* @category Testing
|
|
39
|
+
*/
|
|
40
|
+
type CheckerFit = "fill" | "contain" | "cover";
|
|
41
|
+
/**
|
|
42
|
+
* How a {@link CheckerGrid} lands in a box under a given fit, in CSS px.
|
|
43
|
+
*
|
|
44
|
+
* @category Testing
|
|
45
|
+
*/
|
|
46
|
+
interface CheckerPaint {
|
|
47
|
+
/** The grid the source picture carries. */
|
|
48
|
+
grid: CheckerGrid;
|
|
49
|
+
fit: CheckerFit;
|
|
50
|
+
box: {
|
|
51
|
+
width: number;
|
|
52
|
+
height: number;
|
|
53
|
+
};
|
|
54
|
+
/** The painted picture's own size, which exceeds `box` on a cropped axis and falls short of it on a letterboxed one. */
|
|
55
|
+
painted: {
|
|
56
|
+
width: number;
|
|
57
|
+
height: number;
|
|
58
|
+
};
|
|
59
|
+
cellWidth: number;
|
|
60
|
+
cellHeight: number;
|
|
61
|
+
/** Cells visible inside the box per axis, never more than the grid holds. */
|
|
62
|
+
visible: CheckerGrid;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* One of the three ways a framed picture goes wrong. `distortion` renders a
|
|
66
|
+
* square cell as a rectangle; `cropping` keeps cells square and loses some
|
|
67
|
+
* off the box's edge; `field-of-view` keeps cells square and whole but shows a
|
|
68
|
+
* different grid from the one intended.
|
|
69
|
+
*
|
|
70
|
+
* @category Testing
|
|
71
|
+
*/
|
|
72
|
+
type FramingFault = "distortion" | "cropping" | "field-of-view";
|
|
73
|
+
/**
|
|
74
|
+
* Relative slack on every comparison, 1%. A box floored to whole pixels to fit a
|
|
75
|
+
* feed's aspect sits a fraction of a percent off it, which is not a fault; a
|
|
76
|
+
* real distortion is far larger.
|
|
77
|
+
*
|
|
78
|
+
* @category Testing
|
|
79
|
+
*/
|
|
80
|
+
declare const CHECKER_TOLERANCE = 0.01;
|
|
81
|
+
/**
|
|
82
|
+
* Paint `grid` into `box` under `fit`, centred as `object-position` defaults.
|
|
83
|
+
* The source's pixel size never matters: every supported fit scales it to the
|
|
84
|
+
* box, so only its shape does, and that is the grid's.
|
|
85
|
+
*
|
|
86
|
+
* @category Testing
|
|
87
|
+
*/
|
|
88
|
+
declare function paintChecker(grid: CheckerGrid, box: {
|
|
89
|
+
width: number;
|
|
90
|
+
height: number;
|
|
91
|
+
}, fit: CheckerFit): CheckerPaint;
|
|
92
|
+
/**
|
|
93
|
+
* Every {@link FramingFault} `paint` shows.
|
|
94
|
+
* `intended` is the grid the picture was meant to carry (a camera's own
|
|
95
|
+
* aspect, say); without it a field-of-view change cannot be told from a
|
|
96
|
+
* faithful picture, so it is never reported.
|
|
97
|
+
*
|
|
98
|
+
* @category Testing
|
|
99
|
+
*/
|
|
100
|
+
declare function framingFaults(paint: CheckerPaint, intended?: CheckerGrid): FramingFault[];
|
|
101
|
+
/**
|
|
102
|
+
* The fit an element paints its picture with. An `<svg>` takes it from its
|
|
103
|
+
* `preserveAspectRatio` (`none` fills, `slice` covers, anything else
|
|
104
|
+
* contains); every other element from its `object-fit`, which is `fill` unless
|
|
105
|
+
* set, and `contain` on a `<video>`, whose user-agent style says so. Throws for
|
|
106
|
+
* an `<svg>` with no `viewBox`, which does not scale its content at all, and
|
|
107
|
+
* for `none` or `scale-down`, which depend on a pixel size the checker does not
|
|
108
|
+
* have.
|
|
109
|
+
*
|
|
110
|
+
* @category Testing
|
|
111
|
+
*/
|
|
112
|
+
declare function fitOf(element: Element): CheckerFit;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Asserts that a component's live region is in the document, empty, before its
|
|
116
|
+
* first message, and that the same element is still there holding the message
|
|
117
|
+
* afterwards.
|
|
118
|
+
*
|
|
119
|
+
* Assistive tech announces a CHANGE to a region it already knows. A region
|
|
120
|
+
* inserted together with its words is often never announced, and a test that
|
|
121
|
+
* only looks at the final DOM cannot see that: the words are there either way.
|
|
122
|
+
* Call this with `container` rendered in the state that has nothing to say, and
|
|
123
|
+
* `reveal` doing whatever makes the component say something (a rerender, a
|
|
124
|
+
* store write, a click). Rendering the region only once it has content, as
|
|
125
|
+
* `{message && <span role="status">{message}</span>}` does, fails the first
|
|
126
|
+
* check; keeping the region mounted for as long as the thing it reports on is
|
|
127
|
+
* on screen passes.
|
|
128
|
+
*
|
|
129
|
+
* `region` narrows which live region is under test when a component carries
|
|
130
|
+
* several, as a selector. It defaults to every `aria-live` element and every
|
|
131
|
+
* `status`, `log` and `alert` role under `container`.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```tsx
|
|
135
|
+
* const { container, rerender } = render(<Outcome entries={[]} />);
|
|
136
|
+
* await expectLiveRegionPrimed(container, () =>
|
|
137
|
+
* rerender(<Outcome entries={[sent]} />),
|
|
138
|
+
* );
|
|
139
|
+
* ```
|
|
140
|
+
*
|
|
141
|
+
* @category Testing
|
|
142
|
+
*/
|
|
143
|
+
declare function expectLiveRegionPrimed(container: HTMLElement, reveal: () => void | Promise<void>, region?: string): Promise<HTMLElement[]>;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The accessibility smoke assertion for a widget test: runs `axe` over
|
|
147
|
+
* `container` (an element or a selector) and fails on any violation.
|
|
148
|
+
*
|
|
149
|
+
* The whole check runs inside `act`, so a widget with a clock or a
|
|
150
|
+
* subscription that keeps updating while `axe` walks the DOM raises no act
|
|
151
|
+
* warning. Call this rather than `axe` directly. Needs `jest-axe` installed as
|
|
152
|
+
* a dev dependency of your own; it is loaded on first use.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```tsx
|
|
156
|
+
* import { expectNoA11yViolations, renderWidget } from "@ksp-gonogo/ui-kit/testing";
|
|
157
|
+
*
|
|
158
|
+
* it("has no accessibility violations", async () => {
|
|
159
|
+
* const { container } = renderWidget("my-gauge");
|
|
160
|
+
* await expectNoA11yViolations(container);
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @category Testing
|
|
165
|
+
*/
|
|
166
|
+
declare function expectNoA11yViolations(container: Element | string): Promise<void>;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Why a drawn held mark fails to tell an operator what it means:
|
|
170
|
+
* `silent` where nothing a screen reader hears names its grade, `no-hover`
|
|
171
|
+
* where the hover does not, and `no-as-of` where the hover leaves out the
|
|
172
|
+
* instant the spoken words give.
|
|
173
|
+
*
|
|
174
|
+
* @category Testing
|
|
175
|
+
*/
|
|
176
|
+
type HeldMarkFault = "silent" | "no-hover" | "no-as-of";
|
|
177
|
+
/**
|
|
178
|
+
* One held mark that does not announce itself, with a short description of
|
|
179
|
+
* where it was drawn.
|
|
180
|
+
*
|
|
181
|
+
* @category Testing
|
|
182
|
+
*/
|
|
183
|
+
interface UnannouncedHeldMark {
|
|
184
|
+
mark: Element;
|
|
185
|
+
fault: HeldMarkFault;
|
|
186
|
+
where: string;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Every held mark (`[data-held-mark]`) under `root` that does not say what it
|
|
190
|
+
* means: its grade's word to a screen reader and on hover, with the hover
|
|
191
|
+
* naming the same "as of" instant the spoken words do.
|
|
192
|
+
*
|
|
193
|
+
* Keyed on the mark rather than the figure, so a mark drawn by hand outside any
|
|
194
|
+
* kit primitive is still asked about.
|
|
195
|
+
*
|
|
196
|
+
* @category Testing
|
|
197
|
+
*/
|
|
198
|
+
declare function unannouncedHeldMarks(root?: ParentNode): UnannouncedHeldMark[];
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* The sdk's themed `render` (from `@ksp-gonogo/sitrep-sdk/testing`), with a
|
|
202
|
+
* command rail mounted above it, for a component under test that dispatches
|
|
203
|
+
* through `useCommand` but is not a registered widget. A dev build throws on a
|
|
204
|
+
* dispatch with no rail mounted. A caller's own `wrapper` nests inside the
|
|
205
|
+
* rail. For a registered widget use {@link renderWidget}, which carries one.
|
|
206
|
+
*
|
|
207
|
+
* @category Testing
|
|
208
|
+
*/
|
|
209
|
+
declare function renderWithRail(ui: ReactElement, options?: RenderOptions): RenderResult;
|
|
210
|
+
/**
|
|
211
|
+
* The sdk's `renderHook`, with the same command rail as {@link renderWithRail},
|
|
212
|
+
* for a hook under test that calls `useCommand`.
|
|
213
|
+
*
|
|
214
|
+
* @category Testing
|
|
215
|
+
*/
|
|
216
|
+
declare function renderHookWithRail<Result, Props>(callback: (initialProps: Props) => Result, options?: RenderHookOptions<Props>): RenderHookResult<Result, Props>;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Options for {@link renderWidget}.
|
|
220
|
+
*
|
|
221
|
+
* @category Testing
|
|
222
|
+
*/
|
|
223
|
+
interface RenderWidgetOptions {
|
|
224
|
+
/**
|
|
225
|
+
* The dashboard instance id, what the widget sees as
|
|
226
|
+
* `DashboardItemContext`'s `instanceId` and as its own `id` prop.
|
|
227
|
+
*/
|
|
228
|
+
instanceId?: string;
|
|
229
|
+
/** Per-instance config, the widget's `config` prop. */
|
|
230
|
+
config?: Record<string, unknown>;
|
|
231
|
+
/** Grid units, the `w`/`h` props a responsive widget reads. */
|
|
232
|
+
w?: number;
|
|
233
|
+
/** Grid units, the widget's `h` prop. */
|
|
234
|
+
h?: number;
|
|
235
|
+
/** The widget's `onConfigChange`. Defaults to a no-op. */
|
|
236
|
+
onConfigChange?: (config: Record<string, unknown>) => void;
|
|
237
|
+
/**
|
|
238
|
+
* Mounted outside the dashboard stack, where the app mounts the equivalent:
|
|
239
|
+
* a stream fixture's `Provider` belongs above the widget host, because the
|
|
240
|
+
* host's own hooks read telemetry through it.
|
|
241
|
+
*/
|
|
242
|
+
wrapper?: JSXElementConstructor<{
|
|
243
|
+
children: ReactNode;
|
|
244
|
+
}>;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* The provider stack the dashboard puts around every widget, in the same
|
|
248
|
+
* order, for a registered widget id: the command rail, the panel status store,
|
|
249
|
+
* the widget's instance and metadata, augment settings and contributions.
|
|
250
|
+
* {@link renderWidget} uses it; use it directly to wrap a tree of your own.
|
|
251
|
+
*
|
|
252
|
+
* It omits three things the dashboard also wraps a widget in, because each
|
|
253
|
+
* would make a test quieter rather than truer:
|
|
254
|
+
*
|
|
255
|
+
* - an error boundary, which turns a throw into a fallback UI. In a test a
|
|
256
|
+
* throw should reach the test
|
|
257
|
+
* - the requires guard, which hides a widget whose `requires` domain is absent.
|
|
258
|
+
* A test asserting on a widget's contents wants the widget, not the gate;
|
|
259
|
+
* test the gate by asserting on `def.requires` directly
|
|
260
|
+
* - the alarm-status bridge, which folds firing alarms into the status store.
|
|
261
|
+
* It needs an alarm host, which is app-side, and it renders nothing
|
|
262
|
+
*
|
|
263
|
+
* @category Testing
|
|
264
|
+
*/
|
|
265
|
+
declare function WidgetHost({ widgetId, instanceId, children, }: {
|
|
266
|
+
/** The registered widget id, which the stack is built from. */
|
|
267
|
+
widgetId: string;
|
|
268
|
+
/** Defaults to `<widgetId>-test`, matching `renderWidget`. */
|
|
269
|
+
instanceId?: string;
|
|
270
|
+
children: ReactNode;
|
|
271
|
+
}): react_jsx_runtime.JSX.Element;
|
|
272
|
+
/**
|
|
273
|
+
* The same stack as {@link WidgetHost}, given the component definition rather
|
|
274
|
+
* than an id to look one up by: for a harness previewing an augment against a
|
|
275
|
+
* synthetic host definition.
|
|
276
|
+
*
|
|
277
|
+
* @category Testing
|
|
278
|
+
*/
|
|
279
|
+
declare function WidgetHostFor({ def, instanceId, children, }: {
|
|
280
|
+
def: ComponentDefinition;
|
|
281
|
+
instanceId: string;
|
|
282
|
+
children: ReactNode;
|
|
283
|
+
}): react_jsx_runtime.JSX.Element;
|
|
284
|
+
/**
|
|
285
|
+
* Render a widget the way the dashboard does: by its registered id, inside the
|
|
286
|
+
* provider stack the dashboard puts around one ({@link WidgetHost}). A bare
|
|
287
|
+
* `render` omits that stack, so for instance a `Panel` status badge would never
|
|
288
|
+
* appear. The widget must already be registered, so import its module first;
|
|
289
|
+
* an unknown id throws and lists the registered ones.
|
|
290
|
+
*
|
|
291
|
+
* Returns the `RenderResult` of `@ksp-gonogo/sitrep-sdk/testing`'s `render`. A
|
|
292
|
+
* widget with unusual needs drops to `render` and builds its own scaffolding.
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```tsx
|
|
296
|
+
* import { screen } from "@ksp-gonogo/sitrep-sdk/testing";
|
|
297
|
+
* import { renderWidget } from "@ksp-gonogo/ui-kit/testing";
|
|
298
|
+
* import { expect, it } from "vitest";
|
|
299
|
+
* import "./MyGauge"; // registers "my-gauge" on load
|
|
300
|
+
*
|
|
301
|
+
* it("shows its label", () => {
|
|
302
|
+
* renderWidget("my-gauge", { config: { label: "Apoapsis" }, w: 4, h: 3 });
|
|
303
|
+
* expect(screen.getByText("Apoapsis")).toBeTruthy();
|
|
304
|
+
* });
|
|
305
|
+
* ```
|
|
306
|
+
*
|
|
307
|
+
* @category Testing
|
|
308
|
+
*/
|
|
309
|
+
declare function renderWidget(widgetId: string, options?: RenderWidgetOptions): RenderResult;
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Testing helpers for the readouts this kit renders, published as
|
|
313
|
+
* `@ksp-gonogo/ui-kit/testing` (separate from the root so a runtime bundle
|
|
314
|
+
* never pulls testing code in). `<Unit>` splits a readout into a number, a
|
|
315
|
+
* symbol and a hidden spoken word, so `getByText("12.4 km")` finds nothing;
|
|
316
|
+
* these read it back.
|
|
317
|
+
*
|
|
318
|
+
* `renderWidget` mounts a widget inside the dashboard's provider stack, which is
|
|
319
|
+
* made of this package's providers. `renderWithRail`/`renderHookWithRail` are
|
|
320
|
+
* the bare equivalent, the sdk's themed `render`/`renderHook` with a command
|
|
321
|
+
* rail mounted above it, for a component or hook under test that is not a
|
|
322
|
+
* registered widget but still dispatches through `useCommand`. Named apart
|
|
323
|
+
* from the sdk's own `render`/`renderHook` rather than shadowing them, since
|
|
324
|
+
* both packages are published. Neither re-exports the sdk's testing entry
|
|
325
|
+
* wholesale: an Uplink's setup takes a host from the sdk and a provider stack
|
|
326
|
+
* from here.
|
|
327
|
+
*/
|
|
328
|
+
/**
|
|
329
|
+
* What a sighted reader sees, with the screen-reader words removed:
|
|
330
|
+
* `textContent` of a `<Unit>` reads "12.4 km kilometres", this reads
|
|
331
|
+
* "12.4 km". Assert on `textContent`, or `getByText("kilometres")`, when the
|
|
332
|
+
* announcement is under test.
|
|
333
|
+
*
|
|
334
|
+
* Defaults to `document.body`. The thin space between a number and its symbol
|
|
335
|
+
* is normalised to an ordinary space.
|
|
336
|
+
*
|
|
337
|
+
* @category Testing
|
|
338
|
+
*/
|
|
339
|
+
declare function visibleText(container?: HTMLElement): string;
|
|
340
|
+
/** The shape a matcher reports back to its test framework. */
|
|
341
|
+
interface MatcherResult {
|
|
342
|
+
pass: boolean;
|
|
343
|
+
message: () => string;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* `expect(container).toShowQuantity(value("m", 12400))`.
|
|
347
|
+
*
|
|
348
|
+
* Asserts that a quantity is on screen without naming how it is spelled: it
|
|
349
|
+
* formats through `writeQuantity`, the same ladder `<Unit>` renders with, so it
|
|
350
|
+
* survives a change to where metres hand off to kilometres. For the same
|
|
351
|
+
* reason it cannot catch a formatting bug. To pin the exact spelling, assert
|
|
352
|
+
* the literal:
|
|
353
|
+
*
|
|
354
|
+
* ```ts
|
|
355
|
+
* expect(visibleText()).toContain("12.4 km");
|
|
356
|
+
* ```
|
|
357
|
+
*
|
|
358
|
+
* Register it once, in a setup file:
|
|
359
|
+
*
|
|
360
|
+
* ```ts
|
|
361
|
+
* import { expect } from "vitest";
|
|
362
|
+
* import { unitMatchers } from "@ksp-gonogo/ui-kit/testing";
|
|
363
|
+
* expect.extend(unitMatchers);
|
|
364
|
+
* ```
|
|
365
|
+
*
|
|
366
|
+
* @category Testing
|
|
367
|
+
*/
|
|
368
|
+
declare const unitMatchers: {
|
|
369
|
+
toShowQuantity(received: HTMLElement | undefined, quantity: {
|
|
370
|
+
magnitude: number;
|
|
371
|
+
unit: string;
|
|
372
|
+
} | null | undefined, opts?: FormatQuantityOptions): MatcherResult;
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
* Type augmentation for the matcher above, for a Vitest consumer to merge
|
|
376
|
+
* explicitly (importing this module never changes `expect` types on its own):
|
|
377
|
+
*
|
|
378
|
+
* ```ts
|
|
379
|
+
* declare module "vitest" {
|
|
380
|
+
* interface Assertion<T> extends UnitMatchers<T> {}
|
|
381
|
+
* }
|
|
382
|
+
* ```
|
|
383
|
+
*
|
|
384
|
+
* @category Testing
|
|
385
|
+
*/
|
|
386
|
+
interface UnitMatchers<Result = unknown> {
|
|
387
|
+
toShowQuantity(quantity: {
|
|
388
|
+
magnitude: number;
|
|
389
|
+
unit: string;
|
|
390
|
+
} | null | undefined, opts?: FormatQuantityOptions): Result;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Every element under `container` that carries the kit's {@link Tooltip} with
|
|
395
|
+
* this text, a string matched whole or a pattern matched anywhere. The tip is
|
|
396
|
+
* the `data-tooltip` attribute, present whether or not the tip is open, so a
|
|
397
|
+
* test reads what an element would say without hovering it.
|
|
398
|
+
*
|
|
399
|
+
* @category Testing
|
|
400
|
+
*/
|
|
401
|
+
declare function getAllByTip(container: ParentNode, text: string | RegExp): HTMLElement[];
|
|
402
|
+
/**
|
|
403
|
+
* The one element under `container` carrying this tip, or `null`; throws when
|
|
404
|
+
* more than one does.
|
|
405
|
+
*
|
|
406
|
+
* @category Testing
|
|
407
|
+
*/
|
|
408
|
+
declare function queryByTip(container: ParentNode, text: string | RegExp): HTMLElement | null;
|
|
409
|
+
/**
|
|
410
|
+
* The one element under `container` carrying this tip; throws when there is
|
|
411
|
+
* none or more than one.
|
|
412
|
+
*
|
|
413
|
+
* @category Testing
|
|
414
|
+
*/
|
|
415
|
+
declare function getByTip(container: ParentNode, text: string | RegExp): HTMLElement;
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* One observation of `target` at the given size, as a complete
|
|
419
|
+
* `ResizeObserverEntry` with every box filled. jsdom lays nothing out, so a
|
|
420
|
+
* self-sizing component otherwise renders at zero.
|
|
421
|
+
*
|
|
422
|
+
* @category Testing
|
|
423
|
+
*/
|
|
424
|
+
declare function resizeObservation(target: Element, size: {
|
|
425
|
+
width: number;
|
|
426
|
+
height: number;
|
|
427
|
+
}): ResizeObserverEntry;
|
|
428
|
+
/**
|
|
429
|
+
* Install a `ResizeObserver` that reports one fixed size to everything observed,
|
|
430
|
+
* and return the uninstall. `deliver` fires the callback during `observe`
|
|
431
|
+
* (`"sync"`, the default), or on a macrotask for a component that must not see
|
|
432
|
+
* a size during its own mount.
|
|
433
|
+
*
|
|
434
|
+
* The returned function is the only way to uninstall: `vi.unstubAllGlobals()`
|
|
435
|
+
* does not undo it, and installing either observer while one is live throws.
|
|
436
|
+
* Installing once at module scope and never restoring is fine.
|
|
437
|
+
*
|
|
438
|
+
* @category Testing
|
|
439
|
+
*/
|
|
440
|
+
declare function installFixedSizeResizeObserver(options: {
|
|
441
|
+
width: number;
|
|
442
|
+
height: number;
|
|
443
|
+
deliver?: "sync" | "macrotask";
|
|
444
|
+
}): () => void;
|
|
445
|
+
/**
|
|
446
|
+
* A `ResizeObserver` a test drives by hand: see {@link installDrivableResizeObserver}.
|
|
447
|
+
*
|
|
448
|
+
* @category Testing
|
|
449
|
+
*/
|
|
450
|
+
interface DrivableResizeObservers {
|
|
451
|
+
/** Deliver one observation of `target` at `size` to every observer watching it. */
|
|
452
|
+
resize(target: Element, size: {
|
|
453
|
+
width: number;
|
|
454
|
+
height: number;
|
|
455
|
+
}): void;
|
|
456
|
+
/** Restore the previous `ResizeObserver`. The only way to uninstall. */
|
|
457
|
+
uninstall(): void;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Install a `ResizeObserver` whose observations a test delivers itself, for a
|
|
461
|
+
* component whose behaviour is the response to a size change. `resize` reaches
|
|
462
|
+
* only observers watching the element, so a component that never subscribed
|
|
463
|
+
* cannot pass. Installing either observer while one is live throws; call
|
|
464
|
+
* `uninstall` when done, or install once at module scope.
|
|
465
|
+
*
|
|
466
|
+
* @category Testing
|
|
467
|
+
*/
|
|
468
|
+
declare function installDrivableResizeObserver(): DrivableResizeObservers;
|
|
469
|
+
|
|
470
|
+
export { CHECKER_TOLERANCE, type CheckerFit, type CheckerGrid, type CheckerPaint, type DrivableResizeObservers, type FramingFault, type HeldMarkFault, type RenderWidgetOptions, type UnannouncedHeldMark, type UnitMatchers, WidgetHost, WidgetHostFor, expectLiveRegionPrimed, expectNoA11yViolations, fitOf, framingFaults, getAllByTip, getByTip, installDrivableResizeObserver, installFixedSizeResizeObserver, paintChecker, queryByTip, renderHookWithRail, renderWidget, renderWithRail, resizeObservation, unannouncedHeldMarks, unitMatchers, visibleText };
|