@terreno/ui 0.9.3 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Banner.js +2 -2
- package/dist/Banner.js.map +1 -1
- package/dist/Common.d.ts +6 -10
- package/dist/Common.js.map +1 -1
- package/dist/ConsentHistory.d.ts +2 -1
- package/dist/DataTable.js +4 -2
- package/dist/DataTable.js.map +1 -1
- package/dist/DateUtilities.js +16 -7
- package/dist/DateUtilities.js.map +1 -1
- package/dist/DraggableList.d.ts +5 -4
- package/dist/DraggableList.js.map +1 -1
- package/dist/Icon.js +0 -3
- package/dist/Icon.js.map +1 -1
- package/dist/PasswordField.d.ts +1 -1
- package/dist/PasswordField.js.map +1 -1
- package/dist/TextFieldNumberActionSheet.d.ts +1 -1
- package/dist/Toast.d.ts +1 -1
- package/dist/Toast.js +2 -2
- package/dist/Toast.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/package.json +2 -1
- package/src/ActionSheet.test.tsx +262 -3
- package/src/AddressField.test.tsx +50 -0
- package/src/Banner.test.tsx +22 -0
- package/src/Banner.tsx +2 -2
- package/src/Box.test.tsx +218 -0
- package/src/Button.test.tsx +71 -0
- package/src/Common.ts +11 -9
- package/src/ConsentFormScreen.test.tsx +167 -0
- package/src/ConsentHistory.tsx +1 -1
- package/src/ConsentNavigator.test.tsx +210 -4
- package/src/DataTable.tsx +15 -15
- package/src/DateUtilities.test.ts +34 -16
- package/src/DateUtilities.tsx +24 -13
- package/src/DecimalRangeActionSheet.test.tsx +53 -2
- package/src/DraggableList.tsx +5 -5
- package/src/EmailField.test.tsx +81 -0
- package/src/EmojiSelector.test.tsx +262 -1
- package/src/ErrorBoundary.test.tsx +52 -1
- package/src/HeightActionSheet.test.tsx +57 -2
- package/src/Icon.tsx +0 -3
- package/src/InfoModalIcon.test.tsx +16 -0
- package/src/InfoTooltipButton.test.tsx +53 -1
- package/src/MobileAddressAutoComplete.test.tsx +137 -7
- package/src/Modal.test.tsx +188 -0
- package/src/NumberPickerActionSheet.test.tsx +59 -2
- package/src/OpenAPIContext.test.tsx +184 -3
- package/src/Page.test.tsx +162 -1
- package/src/Pagination.test.tsx +16 -0
- package/src/PasswordField.tsx +1 -1
- package/src/PhoneNumberField.test.tsx +46 -9
- package/src/PickerSelect.test.tsx +230 -0
- package/src/SegmentedControl.test.tsx +38 -0
- package/src/SelectBadge.test.tsx +52 -1
- package/src/SideDrawer.test.tsx +69 -0
- package/src/Signature.test.tsx +42 -5
- package/src/SignatureField.test.tsx +35 -0
- package/src/Slider.test.tsx +59 -0
- package/src/Spinner.test.tsx +6 -0
- package/src/SplitPage.test.tsx +228 -2
- package/src/TapToEdit.test.tsx +171 -1
- package/src/TerrenoProvider.test.tsx +42 -2
- package/src/TextFieldNumberActionSheet.tsx +1 -1
- package/src/Theme.test.tsx +118 -28
- package/src/Toast.test.tsx +95 -2
- package/src/Toast.tsx +3 -3
- package/src/Tooltip.test.tsx +204 -1
- package/src/UnifiedAddressAutoComplete.test.tsx +38 -19
- package/src/UserInactivity.test.tsx +73 -1
- package/src/Utilities.test.tsx +190 -2
- package/src/WebAddressAutocomplete.test.tsx +148 -1
- package/src/__snapshots__/ActionSheet.test.tsx.snap +1736 -0
- package/src/__snapshots__/Button.test.tsx.snap +68 -0
- package/src/__snapshots__/EmojiSelector.test.tsx.snap +1363 -0
- package/src/__snapshots__/InfoTooltipButton.test.tsx.snap +72 -3
- package/src/__snapshots__/MobileAddressAutoComplete.test.tsx.snap +60 -9
- package/src/__snapshots__/Modal.test.tsx.snap +181 -0
- package/src/__snapshots__/Page.test.tsx.snap +48 -2
- package/src/__snapshots__/PhoneNumberField.test.tsx.snap +0 -93
- package/src/__snapshots__/PickerSelect.test.tsx.snap +706 -0
- package/src/__snapshots__/SideDrawer.test.tsx.snap +533 -1399
- package/src/__snapshots__/Signature.test.tsx.snap +0 -3
- package/src/__snapshots__/SplitPage.test.tsx.snap +970 -0
- package/src/__snapshots__/UnifiedAddressAutoComplete.test.tsx.snap +220 -4
- package/src/__snapshots__/WebAddressAutocomplete.test.tsx.snap +93 -0
- package/src/bunSetup.ts +204 -121
- package/src/index.tsx +2 -2
- package/src/table/TableHeaderCell.test.tsx +142 -0
- package/src/table/TableRow.test.tsx +33 -0
- package/src/table/__snapshots__/TableRow.test.tsx.snap +403 -0
- package/src/table/tableContext.test.tsx +96 -0
- package/src/test-utils.tsx +1 -1
- package/src/useConsentForms.test.ts +130 -0
- package/src/useSubmitConsent.test.ts +64 -0
package/src/ActionSheet.test.tsx
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import {describe, expect, it} from "bun:test";
|
|
2
|
-
import {render} from "@testing-library/react-native";
|
|
1
|
+
import {beforeAll, describe, expect, it, mock} from "bun:test";
|
|
2
|
+
import {act, render} from "@testing-library/react-native";
|
|
3
3
|
import {createRef} from "react";
|
|
4
4
|
import {Text} from "react-native";
|
|
5
5
|
|
|
6
|
-
import {ActionSheet, getDeviceHeight, getElevation} from "./ActionSheet";
|
|
6
|
+
import {ActionSheet, getDeviceHeight, getElevation, waitAsync} from "./ActionSheet";
|
|
7
7
|
import {ThemeProvider} from "./Theme";
|
|
8
8
|
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
(global as any).requestAnimationFrame = (callback: FrameRequestCallback) => {
|
|
11
|
+
return setTimeout(() => callback(Date.now()), 0) as unknown as number;
|
|
12
|
+
};
|
|
13
|
+
(global as any).cancelAnimationFrame = (id: number) => {
|
|
14
|
+
clearTimeout(id);
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
9
18
|
describe("ActionSheet", () => {
|
|
10
19
|
it("component is defined", () => {
|
|
11
20
|
expect(ActionSheet).toBeDefined();
|
|
@@ -48,6 +57,249 @@ describe("ActionSheet", () => {
|
|
|
48
57
|
expect(toJSON()).toMatchSnapshot();
|
|
49
58
|
});
|
|
50
59
|
|
|
60
|
+
it("show() sets modalVisible to true", () => {
|
|
61
|
+
const ref = createRef<ActionSheet>();
|
|
62
|
+
render(
|
|
63
|
+
<ThemeProvider>
|
|
64
|
+
<ActionSheet ref={ref}>
|
|
65
|
+
<Text>Content</Text>
|
|
66
|
+
</ActionSheet>
|
|
67
|
+
</ThemeProvider>
|
|
68
|
+
);
|
|
69
|
+
act(() => {
|
|
70
|
+
ref.current?.show();
|
|
71
|
+
});
|
|
72
|
+
expect(ref.current?.state.modalVisible).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("show() followed by hide() calls hide animation path", () => {
|
|
76
|
+
const ref = createRef<ActionSheet>();
|
|
77
|
+
render(
|
|
78
|
+
<ThemeProvider>
|
|
79
|
+
<ActionSheet closeAnimationDuration={1} ref={ref}>
|
|
80
|
+
<Text>Content</Text>
|
|
81
|
+
</ActionSheet>
|
|
82
|
+
</ThemeProvider>
|
|
83
|
+
);
|
|
84
|
+
act(() => {
|
|
85
|
+
ref.current?.show();
|
|
86
|
+
});
|
|
87
|
+
expect(ref.current?.state.modalVisible).toBe(true);
|
|
88
|
+
act(() => {
|
|
89
|
+
ref.current?.hide();
|
|
90
|
+
});
|
|
91
|
+
// hide() does not immediately flip modalVisible (it animates first)
|
|
92
|
+
expect(ref.current).toBeTruthy();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("setModalVisible does nothing when state already matches", () => {
|
|
96
|
+
const ref = createRef<ActionSheet>();
|
|
97
|
+
render(
|
|
98
|
+
<ThemeProvider>
|
|
99
|
+
<ActionSheet ref={ref}>
|
|
100
|
+
<Text>Content</Text>
|
|
101
|
+
</ActionSheet>
|
|
102
|
+
</ThemeProvider>
|
|
103
|
+
);
|
|
104
|
+
// modal starts hidden, call hide again (setModalVisible(false)) - state stays hidden
|
|
105
|
+
act(() => {
|
|
106
|
+
ref.current?.hide();
|
|
107
|
+
});
|
|
108
|
+
expect(ref.current?.state.modalVisible).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("snapToOffset does not throw when called before layout", () => {
|
|
112
|
+
const ref = createRef<ActionSheet>();
|
|
113
|
+
render(
|
|
114
|
+
<ThemeProvider>
|
|
115
|
+
<ActionSheet ref={ref}>
|
|
116
|
+
<Text>Content</Text>
|
|
117
|
+
</ActionSheet>
|
|
118
|
+
</ThemeProvider>
|
|
119
|
+
);
|
|
120
|
+
expect(() => ref.current?.snapToOffset(100)).not.toThrow();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("renders with elevation prop", () => {
|
|
124
|
+
const ref = createRef<ActionSheet>();
|
|
125
|
+
const {toJSON} = render(
|
|
126
|
+
<ThemeProvider>
|
|
127
|
+
<ActionSheet elevation={10} ref={ref}>
|
|
128
|
+
<Text>Elevated</Text>
|
|
129
|
+
</ActionSheet>
|
|
130
|
+
</ThemeProvider>
|
|
131
|
+
);
|
|
132
|
+
expect(toJSON()).toMatchSnapshot();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("renders with indicator color", () => {
|
|
136
|
+
const ref = createRef<ActionSheet>();
|
|
137
|
+
const {toJSON} = render(
|
|
138
|
+
<ThemeProvider>
|
|
139
|
+
<ActionSheet indicatorColor="red" ref={ref}>
|
|
140
|
+
<Text>Indicator</Text>
|
|
141
|
+
</ActionSheet>
|
|
142
|
+
</ThemeProvider>
|
|
143
|
+
);
|
|
144
|
+
expect(toJSON()).toMatchSnapshot();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("renders with initialOffsetFromBottom", () => {
|
|
148
|
+
const ref = createRef<ActionSheet>();
|
|
149
|
+
const {toJSON} = render(
|
|
150
|
+
<ThemeProvider>
|
|
151
|
+
<ActionSheet initialOffsetFromBottom={0.5} ref={ref}>
|
|
152
|
+
<Text>Offset</Text>
|
|
153
|
+
</ActionSheet>
|
|
154
|
+
</ThemeProvider>
|
|
155
|
+
);
|
|
156
|
+
expect(toJSON()).toMatchSnapshot();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("renders with bottomOffset", () => {
|
|
160
|
+
const ref = createRef<ActionSheet>();
|
|
161
|
+
const {toJSON} = render(
|
|
162
|
+
<ThemeProvider>
|
|
163
|
+
<ActionSheet bottomOffset={20} ref={ref}>
|
|
164
|
+
<Text>Bottom</Text>
|
|
165
|
+
</ActionSheet>
|
|
166
|
+
</ThemeProvider>
|
|
167
|
+
);
|
|
168
|
+
expect(toJSON()).toMatchSnapshot();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("renders with closable=false and persistent", () => {
|
|
172
|
+
const ref = createRef<ActionSheet>();
|
|
173
|
+
const {toJSON} = render(
|
|
174
|
+
<ThemeProvider>
|
|
175
|
+
<ActionSheet closable={false} ref={ref}>
|
|
176
|
+
<Text>Persistent</Text>
|
|
177
|
+
</ActionSheet>
|
|
178
|
+
</ThemeProvider>
|
|
179
|
+
);
|
|
180
|
+
expect(toJSON()).toMatchSnapshot();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("renders with custom containerStyle", () => {
|
|
184
|
+
const ref = createRef<ActionSheet>();
|
|
185
|
+
const {toJSON} = render(
|
|
186
|
+
<ThemeProvider>
|
|
187
|
+
<ActionSheet containerStyle={{backgroundColor: "blue"}} ref={ref}>
|
|
188
|
+
<Text>Styled</Text>
|
|
189
|
+
</ActionSheet>
|
|
190
|
+
</ThemeProvider>
|
|
191
|
+
);
|
|
192
|
+
expect(toJSON()).toMatchSnapshot();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("invokes onOpen when modal is shown", () => {
|
|
196
|
+
const ref = createRef<ActionSheet>();
|
|
197
|
+
const handleOpen = mock(() => {});
|
|
198
|
+
render(
|
|
199
|
+
<ThemeProvider>
|
|
200
|
+
<ActionSheet onOpen={handleOpen} ref={ref}>
|
|
201
|
+
<Text>Open</Text>
|
|
202
|
+
</ActionSheet>
|
|
203
|
+
</ThemeProvider>
|
|
204
|
+
);
|
|
205
|
+
act(() => {
|
|
206
|
+
ref.current?.show();
|
|
207
|
+
});
|
|
208
|
+
expect(ref.current?.state.modalVisible).toBe(true);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("_onRequestClose hides modal when closeOnPressBack is true", () => {
|
|
212
|
+
const ref = createRef<ActionSheet>();
|
|
213
|
+
render(
|
|
214
|
+
<ThemeProvider>
|
|
215
|
+
<ActionSheet closeAnimationDuration={1} closeOnPressBack ref={ref}>
|
|
216
|
+
<Text>Close</Text>
|
|
217
|
+
</ActionSheet>
|
|
218
|
+
</ThemeProvider>
|
|
219
|
+
);
|
|
220
|
+
act(() => {
|
|
221
|
+
ref.current?.show();
|
|
222
|
+
});
|
|
223
|
+
expect(() => (ref.current as any)._onRequestClose()).not.toThrow();
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("_onTouchBackdrop hides modal when closeOnTouchBackdrop is true", () => {
|
|
227
|
+
const ref = createRef<ActionSheet>();
|
|
228
|
+
render(
|
|
229
|
+
<ThemeProvider>
|
|
230
|
+
<ActionSheet closeAnimationDuration={1} closeOnTouchBackdrop ref={ref}>
|
|
231
|
+
<Text>Backdrop</Text>
|
|
232
|
+
</ActionSheet>
|
|
233
|
+
</ThemeProvider>
|
|
234
|
+
);
|
|
235
|
+
act(() => {
|
|
236
|
+
ref.current?.show();
|
|
237
|
+
});
|
|
238
|
+
expect(() => (ref.current as any)._onTouchBackdrop()).not.toThrow();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("_onRequestClose does not hide when closeOnPressBack is false", () => {
|
|
242
|
+
const ref = createRef<ActionSheet>();
|
|
243
|
+
render(
|
|
244
|
+
<ThemeProvider>
|
|
245
|
+
<ActionSheet closeOnPressBack={false} ref={ref}>
|
|
246
|
+
<Text>NoClose</Text>
|
|
247
|
+
</ActionSheet>
|
|
248
|
+
</ThemeProvider>
|
|
249
|
+
);
|
|
250
|
+
act(() => {
|
|
251
|
+
ref.current?.show();
|
|
252
|
+
});
|
|
253
|
+
(ref.current as any)._onRequestClose();
|
|
254
|
+
expect(ref.current?.state.modalVisible).toBe(true);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it("_onTouchBackdrop does not hide when closeOnTouchBackdrop is false", () => {
|
|
258
|
+
const ref = createRef<ActionSheet>();
|
|
259
|
+
render(
|
|
260
|
+
<ThemeProvider>
|
|
261
|
+
<ActionSheet closeOnTouchBackdrop={false} ref={ref}>
|
|
262
|
+
<Text>NoBackdrop</Text>
|
|
263
|
+
</ActionSheet>
|
|
264
|
+
</ThemeProvider>
|
|
265
|
+
);
|
|
266
|
+
act(() => {
|
|
267
|
+
ref.current?.show();
|
|
268
|
+
});
|
|
269
|
+
(ref.current as any)._onTouchBackdrop();
|
|
270
|
+
expect(ref.current?.state.modalVisible).toBe(true);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("_onScroll does not throw", () => {
|
|
274
|
+
const ref = createRef<ActionSheet>();
|
|
275
|
+
render(
|
|
276
|
+
<ThemeProvider>
|
|
277
|
+
<ActionSheet ref={ref}>
|
|
278
|
+
<Text>Scroll</Text>
|
|
279
|
+
</ActionSheet>
|
|
280
|
+
</ThemeProvider>
|
|
281
|
+
);
|
|
282
|
+
expect(() =>
|
|
283
|
+
(ref.current as any)._onScroll({
|
|
284
|
+
nativeEvent: {contentOffset: {x: 0, y: 10}},
|
|
285
|
+
})
|
|
286
|
+
).not.toThrow();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("_onTouchStart and _onTouchMove do not throw", () => {
|
|
290
|
+
const ref = createRef<ActionSheet>();
|
|
291
|
+
render(
|
|
292
|
+
<ThemeProvider>
|
|
293
|
+
<ActionSheet ref={ref}>
|
|
294
|
+
<Text>Touch</Text>
|
|
295
|
+
</ActionSheet>
|
|
296
|
+
</ThemeProvider>
|
|
297
|
+
);
|
|
298
|
+
expect(() => (ref.current as any)._onTouchStart()).not.toThrow();
|
|
299
|
+
expect(() => (ref.current as any)._onTouchMove()).not.toThrow();
|
|
300
|
+
expect(() => (ref.current as any)._onTouchEnd()).not.toThrow();
|
|
301
|
+
});
|
|
302
|
+
|
|
51
303
|
describe("getDeviceHeight", () => {
|
|
52
304
|
it("returns a number", () => {
|
|
53
305
|
const height = getDeviceHeight(false);
|
|
@@ -74,4 +326,11 @@ describe("ActionSheet", () => {
|
|
|
74
326
|
expect(result).toHaveProperty("boxShadow");
|
|
75
327
|
});
|
|
76
328
|
});
|
|
329
|
+
|
|
330
|
+
describe("waitAsync", () => {
|
|
331
|
+
it("resolves after the specified time", async () => {
|
|
332
|
+
const result = await waitAsync(1);
|
|
333
|
+
expect(result).toBeNull();
|
|
334
|
+
});
|
|
335
|
+
});
|
|
77
336
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {afterEach, beforeEach, describe, expect, it, mock} from "bun:test";
|
|
2
2
|
import {fireEvent} from "@testing-library/react-native";
|
|
3
|
+
import type {ReactTestInstance} from "react-test-renderer";
|
|
3
4
|
|
|
4
5
|
import {AddressField} from "./AddressField";
|
|
5
6
|
import {renderWithTheme} from "./test-utils";
|
|
@@ -117,4 +118,53 @@ describe("AddressField", () => {
|
|
|
117
118
|
expect(address1Input.props.accessibilityState.disabled).toBe(true);
|
|
118
119
|
expect(cityInput.props.accessibilityState.disabled).toBe(true);
|
|
119
120
|
});
|
|
121
|
+
|
|
122
|
+
it("calls onChange when address2 changes", () => {
|
|
123
|
+
const {getByTestId} = renderWithTheme(
|
|
124
|
+
<AddressField {...defaultProps} onBlur={mockOnBlur} onChange={mockOnChange} />
|
|
125
|
+
);
|
|
126
|
+
fireEvent.changeText(getByTestId("test-address-address2"), "Suite 500");
|
|
127
|
+
expect(mockOnChange).toHaveBeenCalledWith({...defaultValue, address2: "Suite 500"});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("calls onChange when countyName and countyCode change", () => {
|
|
131
|
+
const {getByTestId} = renderWithTheme(
|
|
132
|
+
<AddressField {...defaultProps} includeCounty onBlur={mockOnBlur} onChange={mockOnChange} />
|
|
133
|
+
);
|
|
134
|
+
fireEvent.changeText(getByTestId("test-address-county"), "Clark");
|
|
135
|
+
expect(mockOnChange).toHaveBeenCalledWith({...defaultValue, countyName: "Clark"});
|
|
136
|
+
fireEvent.changeText(getByTestId("test-address-county-code"), "999");
|
|
137
|
+
expect(mockOnChange).toHaveBeenCalledWith({...defaultValue, countyCode: "999"});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("renders without throwing when value is undefined", () => {
|
|
141
|
+
expect(() =>
|
|
142
|
+
renderWithTheme(
|
|
143
|
+
<AddressField onBlur={mockOnBlur} onChange={mockOnChange} testID="no-value" />
|
|
144
|
+
)
|
|
145
|
+
).not.toThrow();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("invokes autocomplete callbacks with merged values", () => {
|
|
149
|
+
const {UNSAFE_getAllByProps} = renderWithTheme(
|
|
150
|
+
<AddressField {...defaultProps} onBlur={mockOnBlur} onChange={mockOnChange} />
|
|
151
|
+
);
|
|
152
|
+
const autocompletes = UNSAFE_getAllByProps({}).filter(
|
|
153
|
+
(el: ReactTestInstance) =>
|
|
154
|
+
typeof el.props?.handleAutoCompleteChange === "function" &&
|
|
155
|
+
typeof el.props?.handleAddressChange === "function"
|
|
156
|
+
);
|
|
157
|
+
expect(autocompletes.length).toBeGreaterThan(0);
|
|
158
|
+
const ac = autocompletes[0];
|
|
159
|
+
// Trigger handleAddressChange for address1
|
|
160
|
+
ac.props.handleAddressChange("456 Oak Ave");
|
|
161
|
+
expect(mockOnChange).toHaveBeenCalledWith({...defaultValue, address1: "456 Oak Ave"});
|
|
162
|
+
// Trigger handleAutoCompleteChange with a new address object
|
|
163
|
+
ac.props.handleAutoCompleteChange({city: "Chicago", state: "IL"});
|
|
164
|
+
expect(mockOnChange).toHaveBeenCalledWith({
|
|
165
|
+
...defaultValue,
|
|
166
|
+
city: "Chicago",
|
|
167
|
+
state: "IL",
|
|
168
|
+
});
|
|
169
|
+
});
|
|
120
170
|
});
|
package/src/Banner.test.tsx
CHANGED
|
@@ -103,4 +103,26 @@ describe("Banner", () => {
|
|
|
103
103
|
expect(handleClick).toHaveBeenCalled();
|
|
104
104
|
});
|
|
105
105
|
});
|
|
106
|
+
|
|
107
|
+
it("invokes buttonOnClick when icon button is pressed", async () => {
|
|
108
|
+
const handleClick = mock(() => Promise.resolve());
|
|
109
|
+
const {getByText} = renderWithTheme(
|
|
110
|
+
<Banner
|
|
111
|
+
buttonIconName="arrow-right"
|
|
112
|
+
buttonOnClick={handleClick}
|
|
113
|
+
buttonText="Go"
|
|
114
|
+
id="test-icon-banner"
|
|
115
|
+
text="Banner"
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
await act(async () => {
|
|
120
|
+
fireEvent.press(getByText("Go"));
|
|
121
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
await waitFor(() => {
|
|
125
|
+
expect(handleClick).toHaveBeenCalled();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
106
128
|
});
|
package/src/Banner.tsx
CHANGED
|
@@ -86,9 +86,9 @@ const BannerButton = ({
|
|
|
86
86
|
);
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
const getKey = (id: string): string => {
|
|
90
90
|
return `@TerrenoUI:${id}`;
|
|
91
|
-
}
|
|
91
|
+
};
|
|
92
92
|
|
|
93
93
|
export const hideBanner = (id: string): Promise<void> => {
|
|
94
94
|
console.debug(`[banner] Hiding ${getKey(id)} `);
|
package/src/Box.test.tsx
CHANGED
|
@@ -659,4 +659,222 @@ describe("Box", () => {
|
|
|
659
659
|
expect(component.toJSON()).toMatchSnapshot();
|
|
660
660
|
});
|
|
661
661
|
});
|
|
662
|
+
|
|
663
|
+
describe("edge case warnings and fallbacks", () => {
|
|
664
|
+
it("returns empty style when border prop is falsy", () => {
|
|
665
|
+
const {root} = renderWithTheme(<Box border={undefined as any} />);
|
|
666
|
+
expect(root).toBeTruthy();
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
it("returns empty style when borderBottom prop is falsy", () => {
|
|
670
|
+
const {root} = renderWithTheme(<Box borderBottom={undefined as any} />);
|
|
671
|
+
expect(root).toBeTruthy();
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
it("returns empty style when borderLeft prop is falsy", () => {
|
|
675
|
+
const {root} = renderWithTheme(<Box borderLeft={undefined as any} />);
|
|
676
|
+
expect(root).toBeTruthy();
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it("returns empty style when borderRight prop is falsy", () => {
|
|
680
|
+
const {root} = renderWithTheme(<Box borderRight={undefined as any} />);
|
|
681
|
+
expect(root).toBeTruthy();
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
it("returns empty style when borderTop prop is falsy", () => {
|
|
685
|
+
const {root} = renderWithTheme(<Box borderTop={undefined as any} />);
|
|
686
|
+
expect(root).toBeTruthy();
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
it("warns when invalid height value is provided", () => {
|
|
690
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
691
|
+
renderWithTheme(<Box height={"abc" as any} />);
|
|
692
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
693
|
+
warnSpy.mockRestore();
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it("warns when invalid maxHeight value is provided", () => {
|
|
697
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
698
|
+
renderWithTheme(<Box maxHeight={"xyz" as any} />);
|
|
699
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
700
|
+
warnSpy.mockRestore();
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
it("warns when invalid maxWidth value is provided", () => {
|
|
704
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
705
|
+
renderWithTheme(<Box maxWidth={"abc" as any} />);
|
|
706
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
707
|
+
warnSpy.mockRestore();
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
it("warns when invalid minHeight value is provided", () => {
|
|
711
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
712
|
+
renderWithTheme(<Box minHeight={"abc" as any} />);
|
|
713
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
714
|
+
warnSpy.mockRestore();
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
it("warns when invalid minWidth value is provided", () => {
|
|
718
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
719
|
+
renderWithTheme(<Box minWidth={"abc" as any} />);
|
|
720
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
721
|
+
warnSpy.mockRestore();
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
it("warns when invalid width value is provided", () => {
|
|
725
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
726
|
+
renderWithTheme(<Box width={"abc" as any} />);
|
|
727
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
728
|
+
warnSpy.mockRestore();
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
it("applies mdDirection only when mediaQuery is md+", () => {
|
|
732
|
+
const {root} = renderWithTheme(<Box mdDirection="row" />);
|
|
733
|
+
expect(root).toBeTruthy();
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
it("applies lgDirection only when mediaQuery is lg", () => {
|
|
737
|
+
const {root} = renderWithTheme(<Box lgDirection="column" />);
|
|
738
|
+
expect(root).toBeTruthy();
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
it("applies width with border adds 4 pixels", () => {
|
|
742
|
+
const {root} = renderWithTheme(<Box border="default" width={100} />);
|
|
743
|
+
const view = root.findByType("View");
|
|
744
|
+
expect(view.props.style.width).toBe(104);
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
it("applies height with border adds 4 pixels", () => {
|
|
748
|
+
const {root} = renderWithTheme(<Box border="default" height={80} />);
|
|
749
|
+
const view = root.findByType("View");
|
|
750
|
+
expect(view.props.style.height).toBe(84);
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
it("warns when wrap is combined with alignItems on native", () => {
|
|
754
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
755
|
+
renderWithTheme(<Box alignItems="center" wrap />);
|
|
756
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
757
|
+
warnSpy.mockRestore();
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
it("applies dangerouslySetInlineStyle overrides", () => {
|
|
761
|
+
const {root} = renderWithTheme(
|
|
762
|
+
<Box dangerouslySetInlineStyle={{__style: {backgroundColor: "red"}}} />
|
|
763
|
+
);
|
|
764
|
+
const view = root.findByType("View");
|
|
765
|
+
expect(view.props.style.backgroundColor).toBe("red");
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
it("handles rounding='circle' with width/height", () => {
|
|
769
|
+
const {root} = renderWithTheme(<Box height={40} rounding="circle" width={40} />);
|
|
770
|
+
const view = root.findByType("View");
|
|
771
|
+
expect(view.props.style.borderRadius).toBe(40);
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
it("warns when rounding='circle' without width/height", () => {
|
|
775
|
+
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
776
|
+
renderWithTheme(<Box rounding="circle" />);
|
|
777
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
778
|
+
warnSpy.mockRestore();
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
it("applies shadow on ios/web", () => {
|
|
782
|
+
const {root} = renderWithTheme(<Box shadow />);
|
|
783
|
+
const view = root.findByType("View");
|
|
784
|
+
expect(view.props.style.boxShadow).toBeDefined();
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
it("applies overflow='scroll'", () => {
|
|
788
|
+
const {root} = renderWithTheme(<Box overflow="scroll" />);
|
|
789
|
+
const view = root.findByType("View");
|
|
790
|
+
expect(view.props.style.overflow).toBe("scroll");
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
it("applies overflow='scrollY'", () => {
|
|
794
|
+
const {root} = renderWithTheme(<Box overflow="scrollY" />);
|
|
795
|
+
const view = root.findByType("View");
|
|
796
|
+
expect(view.props.style.overflow).toBe("scroll");
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
it("applies position='absolute'", () => {
|
|
800
|
+
const {root} = renderWithTheme(<Box position="absolute" />);
|
|
801
|
+
const view = root.findByType("View");
|
|
802
|
+
expect(view.props.style.position).toBe("absolute");
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
it("applies zIndex", () => {
|
|
806
|
+
const {root} = renderWithTheme(<Box zIndex={10} />);
|
|
807
|
+
const view = root.findByType("View");
|
|
808
|
+
expect(view.props.style.zIndex).toBe(10);
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
it("applies top/left/right/bottom offsets", () => {
|
|
812
|
+
const {root} = renderWithTheme(<Box bottom left position="absolute" right top />);
|
|
813
|
+
const view = root.findByType("View");
|
|
814
|
+
expect(view.props.style.top).toBe(0);
|
|
815
|
+
expect(view.props.style.left).toBe(0);
|
|
816
|
+
expect(view.props.style.right).toBe(0);
|
|
817
|
+
expect(view.props.style.bottom).toBe(0);
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
it("fires onScroll when scroll is enabled", async () => {
|
|
821
|
+
const onScroll = mock(() => {});
|
|
822
|
+
const {root} = renderWithTheme(
|
|
823
|
+
<Box onScroll={onScroll} scroll>
|
|
824
|
+
<Text>Scrollable</Text>
|
|
825
|
+
</Box>
|
|
826
|
+
);
|
|
827
|
+
const scrollView = root.findByType("ScrollView" as any);
|
|
828
|
+
await act(async () => {
|
|
829
|
+
scrollView.props.onScroll?.({nativeEvent: {contentOffset: {y: 100}}});
|
|
830
|
+
});
|
|
831
|
+
expect(onScroll).toHaveBeenCalledWith(100);
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
it("invokes onHoverStart/onHoverEnd callbacks", async () => {
|
|
835
|
+
const onHoverStart = mock(() => {});
|
|
836
|
+
const onHoverEnd = mock(() => {});
|
|
837
|
+
const {root} = renderWithTheme(
|
|
838
|
+
<Box onHoverEnd={onHoverEnd} onHoverStart={onHoverStart}>
|
|
839
|
+
<Text>Hover</Text>
|
|
840
|
+
</Box>
|
|
841
|
+
);
|
|
842
|
+
const view = root.findByType("View");
|
|
843
|
+
await act(async () => {
|
|
844
|
+
await view.props.onPointerEnter?.();
|
|
845
|
+
});
|
|
846
|
+
await act(async () => {
|
|
847
|
+
await view.props.onPointerLeave?.();
|
|
848
|
+
});
|
|
849
|
+
expect(onHoverStart).toHaveBeenCalled();
|
|
850
|
+
expect(onHoverEnd).toHaveBeenCalled();
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
it("exposes scrollTo and scrollToEnd through ref", () => {
|
|
854
|
+
const ref = React.createRef<any>();
|
|
855
|
+
renderWithTheme(
|
|
856
|
+
<Box ref={ref} scroll>
|
|
857
|
+
<Text>Content</Text>
|
|
858
|
+
</Box>
|
|
859
|
+
);
|
|
860
|
+
expect(typeof ref.current?.scrollTo).toBe("function");
|
|
861
|
+
expect(typeof ref.current?.scrollToEnd).toBe("function");
|
|
862
|
+
// Call them to cover the function bodies
|
|
863
|
+
ref.current?.scrollTo(100);
|
|
864
|
+
ref.current?.scrollToEnd();
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
it("invokes onClick with haptic feedback", async () => {
|
|
868
|
+
const onClick = mock(() => Promise.resolve());
|
|
869
|
+
const {getByLabelText} = renderWithTheme(
|
|
870
|
+
<Box accessibilityHint="" accessibilityLabel="Press" onClick={onClick}>
|
|
871
|
+
<Text>Click</Text>
|
|
872
|
+
</Box>
|
|
873
|
+
);
|
|
874
|
+
await act(async () => {
|
|
875
|
+
fireEvent.press(getByLabelText("Press"));
|
|
876
|
+
});
|
|
877
|
+
expect(onClick).toHaveBeenCalled();
|
|
878
|
+
});
|
|
879
|
+
});
|
|
662
880
|
});
|
package/src/Button.test.tsx
CHANGED
|
@@ -157,4 +157,75 @@ describe("Button", () => {
|
|
|
157
157
|
const {getByLabelText} = renderWithTheme(<Button onClick={() => {}} text="Accessible" />);
|
|
158
158
|
expect(getByLabelText("Accessible")).toBeTruthy();
|
|
159
159
|
});
|
|
160
|
+
|
|
161
|
+
it("invokes onClick when confirmation primary button is pressed", async () => {
|
|
162
|
+
const handleClick = mock(() => Promise.resolve());
|
|
163
|
+
const {getByText, queryByText} = renderWithTheme(
|
|
164
|
+
<Button
|
|
165
|
+
confirmationText="Confirm action?"
|
|
166
|
+
modalTitle="Confirm Title"
|
|
167
|
+
onClick={handleClick}
|
|
168
|
+
text="Press Me"
|
|
169
|
+
withConfirmation
|
|
170
|
+
/>
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
await act(async () => {
|
|
174
|
+
fireEvent.press(getByText("Press Me"));
|
|
175
|
+
await new Promise((resolve) => setTimeout(resolve, 600));
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Wait for confirmation modal
|
|
179
|
+
await waitFor(
|
|
180
|
+
() => {
|
|
181
|
+
expect(queryByText("Confirm Title")).toBeTruthy();
|
|
182
|
+
},
|
|
183
|
+
{timeout: 2000}
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
await act(async () => {
|
|
187
|
+
fireEvent.press(getByText("Confirm"));
|
|
188
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await waitFor(() => {
|
|
192
|
+
expect(handleClick).toHaveBeenCalled();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("dismisses confirmation modal when secondary button is pressed", async () => {
|
|
197
|
+
const handleClick = mock(() => Promise.resolve());
|
|
198
|
+
const {getByText, queryByText} = renderWithTheme(
|
|
199
|
+
<Button
|
|
200
|
+
confirmationText="Confirm action?"
|
|
201
|
+
modalTitle="Confirm Title"
|
|
202
|
+
onClick={handleClick}
|
|
203
|
+
text="Press Me"
|
|
204
|
+
withConfirmation
|
|
205
|
+
/>
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
await act(async () => {
|
|
209
|
+
fireEvent.press(getByText("Press Me"));
|
|
210
|
+
await new Promise((resolve) => setTimeout(resolve, 600));
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
await waitFor(
|
|
214
|
+
() => {
|
|
215
|
+
expect(queryByText("Cancel")).toBeTruthy();
|
|
216
|
+
},
|
|
217
|
+
{timeout: 2000}
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Cancel does not throw and does not invoke onClick
|
|
221
|
+
expect(() => fireEvent.press(getByText("Cancel"))).not.toThrow();
|
|
222
|
+
expect(handleClick).not.toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("renders with tooltip on desktop (wrapped in Tooltip)", () => {
|
|
226
|
+
const {toJSON} = renderWithTheme(
|
|
227
|
+
<Button onClick={() => {}} text="Hover me" tooltipText="Tooltip text" />
|
|
228
|
+
);
|
|
229
|
+
expect(toJSON()).toMatchSnapshot();
|
|
230
|
+
});
|
|
160
231
|
});
|