@jobber/components-native 0.38.0 → 0.40.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/src/AtlantisContext/AtlantisContext.js +2 -0
- package/dist/src/Form/Form.js +187 -0
- package/dist/src/Form/Form.style.js +33 -0
- package/dist/src/Form/components/FormActionBar/FormActionBar.js +21 -0
- package/dist/src/Form/components/FormActionBar/FormActionBar.style.js +5 -0
- package/dist/src/Form/components/FormActionBar/index.js +1 -0
- package/dist/src/Form/components/FormBody/FormBody.js +20 -0
- package/dist/src/Form/components/FormBody/FormBody.style.js +26 -0
- package/dist/src/Form/components/FormBody/index.js +1 -0
- package/dist/src/Form/components/FormCache/FormCache.js +34 -0
- package/dist/src/Form/components/FormErrorBanner/FormErrorBanner.js +21 -0
- package/dist/src/Form/components/FormErrorBanner/index.js +1 -0
- package/dist/src/Form/components/FormErrorBanner/messages.js +13 -0
- package/dist/src/Form/components/FormMask/FormMask.js +11 -0
- package/dist/src/Form/components/FormMask/FormMask.style.js +15 -0
- package/dist/src/Form/components/FormMask/index.js +1 -0
- package/dist/src/Form/components/FormMessage/FormMessage.js +48 -0
- package/dist/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.js +28 -0
- package/dist/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.style.js +17 -0
- package/dist/src/Form/components/FormMessage/components/InternalFormMessage/index.js +1 -0
- package/dist/src/Form/components/FormMessage/components/InternalFormMessage/messages.js +8 -0
- package/dist/src/Form/components/FormMessage/index.js +1 -0
- package/dist/src/Form/components/FormMessageBanner/FormMessageBanner.js +15 -0
- package/dist/src/Form/components/FormMessageBanner/index.js +1 -0
- package/dist/src/Form/components/FormSaveButton/FormSaveButton.js +69 -0
- package/dist/src/Form/components/FormSaveButton/index.js +1 -0
- package/dist/src/Form/components/FormSaveButton/messages.js +8 -0
- package/dist/src/Form/constants.js +2 -0
- package/dist/src/Form/context/AtlantisFormContext.js +16 -0
- package/dist/src/Form/context/index.js +1 -0
- package/dist/src/Form/context/types.js +1 -0
- package/dist/src/Form/hooks/useFormViewRefs.js +14 -0
- package/dist/src/Form/hooks/useInternalForm.js +37 -0
- package/dist/src/Form/hooks/useOfflineHandler.js +24 -0
- package/dist/src/Form/hooks/useSaveButtonPosition.js +25 -0
- package/dist/src/Form/hooks/useScreenInformation.js +15 -0
- package/dist/src/Form/hooks/useScrollToError/index.js +1 -0
- package/dist/src/Form/hooks/useScrollToError/useScrollToError.js +63 -0
- package/dist/src/Form/index.js +4 -0
- package/dist/src/Form/messages.js +28 -0
- package/dist/src/Form/types.js +10 -0
- package/dist/src/InputDate/InputDate.js +76 -0
- package/dist/src/InputDate/index.js +1 -0
- package/dist/src/InputDate/messages.js +8 -0
- package/dist/src/Menu/Menu.js +67 -0
- package/dist/src/Menu/Menu.style.js +6 -0
- package/dist/src/Menu/components/MenuOption/MenuOption.js +25 -0
- package/dist/src/Menu/components/MenuOption/MenuOption.style.js +10 -0
- package/dist/src/Menu/components/MenuOption/index.js +1 -0
- package/dist/src/Menu/components/Overlay/Overlay.js +9 -0
- package/dist/src/Menu/components/Overlay/Overlay.style.js +6 -0
- package/dist/src/Menu/components/Overlay/index.js +1 -0
- package/dist/src/Menu/index.js +1 -0
- package/dist/src/Menu/messages.js +8 -0
- package/dist/src/Menu/types.js +1 -0
- package/dist/src/Menu/utils.js +84 -0
- package/dist/src/index.js +3 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/AtlantisContext/AtlantisContext.d.ts +7 -1
- package/dist/types/src/Form/Form.d.ts +4 -0
- package/dist/types/src/Form/Form.style.d.ts +31 -0
- package/dist/types/src/Form/components/FormActionBar/FormActionBar.d.ts +13 -0
- package/dist/types/src/Form/components/FormActionBar/FormActionBar.style.d.ts +15 -0
- package/dist/types/src/Form/components/FormActionBar/index.d.ts +2 -0
- package/dist/types/src/Form/components/FormBody/FormBody.d.ts +10 -0
- package/dist/types/src/Form/components/FormBody/FormBody.style.d.ts +24 -0
- package/dist/types/src/Form/components/FormBody/index.d.ts +1 -0
- package/dist/types/src/Form/components/FormCache/FormCache.d.ts +10 -0
- package/dist/types/src/Form/components/FormErrorBanner/FormErrorBanner.d.ts +3 -0
- package/dist/types/src/Form/components/FormErrorBanner/index.d.ts +1 -0
- package/dist/types/src/Form/components/FormErrorBanner/messages.d.ts +12 -0
- package/dist/types/src/Form/components/FormMask/FormMask.d.ts +2 -0
- package/dist/types/src/Form/components/FormMask/FormMask.style.d.ts +13 -0
- package/dist/types/src/Form/components/FormMask/index.d.ts +1 -0
- package/dist/types/src/Form/components/FormMessage/FormMessage.d.ts +19 -0
- package/dist/types/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.d.ts +8 -0
- package/dist/types/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.style.d.ts +20 -0
- package/dist/types/src/Form/components/FormMessage/components/InternalFormMessage/index.d.ts +1 -0
- package/dist/types/src/Form/components/FormMessage/components/InternalFormMessage/messages.d.ts +7 -0
- package/dist/types/src/Form/components/FormMessage/index.d.ts +1 -0
- package/dist/types/src/Form/components/FormMessageBanner/FormMessageBanner.d.ts +7 -0
- package/dist/types/src/Form/components/FormMessageBanner/index.d.ts +1 -0
- package/dist/types/src/Form/components/FormSaveButton/FormSaveButton.d.ts +3 -0
- package/dist/types/src/Form/components/FormSaveButton/index.d.ts +1 -0
- package/dist/types/src/Form/components/FormSaveButton/messages.d.ts +7 -0
- package/dist/types/src/Form/constants.d.ts +2 -0
- package/dist/types/src/Form/context/AtlantisFormContext.d.ts +12 -0
- package/dist/types/src/Form/context/index.d.ts +2 -0
- package/dist/types/src/Form/context/types.d.ts +26 -0
- package/dist/types/src/Form/hooks/useFormViewRefs.d.ts +10 -0
- package/dist/types/src/Form/hooks/useInternalForm.d.ts +19 -0
- package/dist/types/src/Form/hooks/useOfflineHandler.d.ts +1 -0
- package/dist/types/src/Form/hooks/useSaveButtonPosition.d.ts +12 -0
- package/dist/types/src/Form/hooks/useScreenInformation.d.ts +8 -0
- package/dist/types/src/Form/hooks/useScrollToError/index.d.ts +1 -0
- package/dist/types/src/Form/hooks/useScrollToError/useScrollToError.d.ts +10 -0
- package/dist/types/src/Form/index.d.ts +5 -0
- package/dist/types/src/Form/messages.d.ts +27 -0
- package/dist/types/src/Form/types.d.ts +199 -0
- package/dist/types/src/InputDate/InputDate.d.ts +74 -0
- package/dist/types/src/InputDate/index.d.ts +1 -0
- package/dist/types/src/InputDate/messages.d.ts +7 -0
- package/dist/types/src/InputNumber/InputNumber.d.ts +1 -1
- package/dist/types/src/Menu/Menu.d.ts +3 -0
- package/dist/types/src/Menu/Menu.style.d.ts +18 -0
- package/dist/types/src/Menu/components/MenuOption/MenuOption.d.ts +3 -0
- package/dist/types/src/Menu/components/MenuOption/MenuOption.style.d.ts +8 -0
- package/dist/types/src/Menu/components/MenuOption/index.d.ts +1 -0
- package/dist/types/src/Menu/components/Overlay/Overlay.d.ts +3 -0
- package/dist/types/src/Menu/components/Overlay/Overlay.style.d.ts +12 -0
- package/dist/types/src/Menu/components/Overlay/index.d.ts +1 -0
- package/dist/types/src/Menu/index.d.ts +2 -0
- package/dist/types/src/Menu/messages.d.ts +7 -0
- package/dist/types/src/Menu/types.d.ts +22 -0
- package/dist/types/src/Menu/utils.d.ts +10 -0
- package/dist/types/src/index.d.ts +3 -0
- package/package.json +3 -2
- package/src/AtlantisContext/AtlantisContext.tsx +10 -1
- package/src/Form/Form.style.ts +34 -0
- package/src/Form/Form.test.tsx +588 -0
- package/src/Form/Form.tsx +296 -0
- package/src/Form/components/FormActionBar/FormActionBar.style.ts +11 -0
- package/src/Form/components/FormActionBar/FormActionBar.tsx +63 -0
- package/src/Form/components/FormActionBar/index.ts +2 -0
- package/src/Form/components/FormBody/FormBody.style.ts +27 -0
- package/src/Form/components/FormBody/FormBody.tsx +62 -0
- package/src/Form/components/FormBody/index.ts +1 -0
- package/src/Form/components/FormCache/FormCache.tsx +50 -0
- package/src/Form/components/FormErrorBanner/FormErrorBanner.test.tsx +124 -0
- package/src/Form/components/FormErrorBanner/FormErrorBanner.tsx +34 -0
- package/src/Form/components/FormErrorBanner/index.ts +1 -0
- package/src/Form/components/FormErrorBanner/messages.ts +14 -0
- package/src/Form/components/FormMask/FormMask.style.tsx +16 -0
- package/src/Form/components/FormMask/FormMask.tsx +19 -0
- package/src/Form/components/FormMask/index.ts +1 -0
- package/src/Form/components/FormMessage/FormMessage.test.tsx +72 -0
- package/src/Form/components/FormMessage/FormMessage.tsx +63 -0
- package/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.style.ts +18 -0
- package/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.tsx +55 -0
- package/src/Form/components/FormMessage/components/InternalFormMessage/index.ts +1 -0
- package/src/Form/components/FormMessage/components/InternalFormMessage/messages.ts +10 -0
- package/src/Form/components/FormMessage/index.ts +1 -0
- package/src/Form/components/FormMessageBanner/FormMessageBanner.test.tsx +27 -0
- package/src/Form/components/FormMessageBanner/FormMessageBanner.tsx +33 -0
- package/src/Form/components/FormMessageBanner/index.ts +1 -0
- package/src/Form/components/FormSaveButton/FormSaveButton.test.tsx +159 -0
- package/src/Form/components/FormSaveButton/FormSaveButton.tsx +103 -0
- package/src/Form/components/FormSaveButton/index.ts +1 -0
- package/src/Form/components/FormSaveButton/messages.ts +9 -0
- package/src/Form/constants.ts +2 -0
- package/src/Form/context/AtlantisFormContext.test.tsx +45 -0
- package/src/Form/context/AtlantisFormContext.tsx +21 -0
- package/src/Form/context/index.ts +5 -0
- package/src/Form/context/types.ts +34 -0
- package/src/Form/hooks/useFormViewRefs.ts +23 -0
- package/src/Form/hooks/useInternalForm.ts +99 -0
- package/src/Form/hooks/useOfflineHandler.ts +36 -0
- package/src/Form/hooks/useSaveButtonPosition.ts +52 -0
- package/src/Form/hooks/useScreenInformation.ts +25 -0
- package/src/Form/hooks/useScrollToError/index.ts +1 -0
- package/src/Form/hooks/useScrollToError/useScrollToError.test.tsx +103 -0
- package/src/Form/hooks/useScrollToError/useScrollToError.ts +102 -0
- package/src/Form/index.ts +13 -0
- package/src/Form/messages.ts +33 -0
- package/src/Form/types.ts +255 -0
- package/src/InputDate/InputDate.test.tsx +295 -0
- package/src/InputDate/InputDate.tsx +231 -0
- package/src/InputDate/index.ts +1 -0
- package/src/InputDate/messages.ts +9 -0
- package/src/InputNumber/InputNumber.tsx +1 -1
- package/src/Menu/Menu.style.ts +16 -0
- package/src/Menu/Menu.test.tsx +201 -0
- package/src/Menu/Menu.tsx +116 -0
- package/src/Menu/components/MenuOption/MenuOption.style.tsx +11 -0
- package/src/Menu/components/MenuOption/MenuOption.tsx +63 -0
- package/src/Menu/components/MenuOption/index.ts +1 -0
- package/src/Menu/components/Overlay/Overlay.style.ts +13 -0
- package/src/Menu/components/Overlay/Overlay.tsx +16 -0
- package/src/Menu/components/Overlay/index.ts +1 -0
- package/src/Menu/index.ts +6 -0
- package/src/Menu/messages.ts +9 -0
- package/src/Menu/types.ts +25 -0
- package/src/Menu/utils.ts +151 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { act, fireEvent, render, waitFor } from "@testing-library/react-native";
|
|
3
|
+
import { Alert, Keyboard } from "react-native";
|
|
4
|
+
import { useIntl } from "react-intl";
|
|
5
|
+
import { Host } from "react-native-portalize";
|
|
6
|
+
import { Form, FormBannerMessage, FormBannerMessageType } from ".";
|
|
7
|
+
import { messages as formErrorBannerMessages } from "./components/FormErrorBanner/messages";
|
|
8
|
+
import { messages } from "./components/FormSaveButton/messages";
|
|
9
|
+
import { messages as formMessages } from "./messages";
|
|
10
|
+
import { FormBannerErrors, FormSubmitErrorType } from "./types";
|
|
11
|
+
import { defaultValues as contextDefaultValue } from "../AtlantisContext";
|
|
12
|
+
import * as atlantisContext from "../AtlantisContext/AtlantisContext";
|
|
13
|
+
import { Text } from "../Text";
|
|
14
|
+
import { Checkbox } from "../Checkbox";
|
|
15
|
+
import { InputNumber } from "../InputNumber";
|
|
16
|
+
import { Switch } from "../Switch";
|
|
17
|
+
import { Option, Select } from "../Select";
|
|
18
|
+
import { InputText } from "../InputText";
|
|
19
|
+
|
|
20
|
+
jest.mock("lodash/debounce", () => {
|
|
21
|
+
return jest.fn(fn => {
|
|
22
|
+
fn.cancel = jest.fn();
|
|
23
|
+
return fn;
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const onSubmitMock = jest.fn().mockImplementation(() => {
|
|
28
|
+
return Promise.resolve(() => Promise.resolve());
|
|
29
|
+
});
|
|
30
|
+
const onSuccessMock = jest.fn();
|
|
31
|
+
const onErrorMock = jest.fn();
|
|
32
|
+
const onChangeMock = jest.fn();
|
|
33
|
+
const onChangeSelectMock = jest.fn();
|
|
34
|
+
const onChangeSwitchMock = jest.fn();
|
|
35
|
+
|
|
36
|
+
const mockScrollToPosition = jest.fn();
|
|
37
|
+
const mockScrollToTop = jest.fn();
|
|
38
|
+
|
|
39
|
+
jest.mock("./hooks/useFormViewRefs", () => ({
|
|
40
|
+
useFormViewRefs: () => {
|
|
41
|
+
return {
|
|
42
|
+
scrollViewRef: {
|
|
43
|
+
current: { scrollToPosition: mockScrollToPosition },
|
|
44
|
+
},
|
|
45
|
+
bottomViewRef: { current: {} },
|
|
46
|
+
scrollToTop: mockScrollToTop,
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
const bannerError = {
|
|
52
|
+
title: "My error",
|
|
53
|
+
messages: ["userError1", "userError2"],
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const noticeMessage = {
|
|
57
|
+
messageType: FormBannerMessageType.NoticeMessage,
|
|
58
|
+
message: "Take note of this information.",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const warningMessage = {
|
|
62
|
+
messageType: FormBannerMessageType.WarningMessage,
|
|
63
|
+
message: "Caution is warranted in this case.",
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const testInputTextName = "test";
|
|
67
|
+
const testInputTextNameExclude = "exclude";
|
|
68
|
+
const testInputTextPlaceholderExclude = "Test Exclude";
|
|
69
|
+
const testInputTextPlaceholder = "Test Input";
|
|
70
|
+
const testSelectName = "testSelect";
|
|
71
|
+
const testSwitchName = "testSwitch";
|
|
72
|
+
const testInputNumberName = "testNumber";
|
|
73
|
+
const testCheckboxName = "testCheckbox";
|
|
74
|
+
const switchLabel = "switchLabel";
|
|
75
|
+
const checkboxLabel = "checkboxLabel";
|
|
76
|
+
const selectLabel = "selectLabel";
|
|
77
|
+
const saveButtonText = messages.saveButton.defaultMessage;
|
|
78
|
+
|
|
79
|
+
const requiredInputText = "This field is required";
|
|
80
|
+
const minLengthText = "Test is too short";
|
|
81
|
+
|
|
82
|
+
interface FormFields {
|
|
83
|
+
[testInputTextName]: string;
|
|
84
|
+
[testSelectName]: string;
|
|
85
|
+
[testSwitchName]: boolean;
|
|
86
|
+
[testInputNumberName]: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface FormTestProps {
|
|
90
|
+
onSubmit: jest.Mock;
|
|
91
|
+
sendBannerErrors?: boolean;
|
|
92
|
+
sendNetworkErrors?: boolean;
|
|
93
|
+
saveLabel?: string;
|
|
94
|
+
renderStickySection?: (
|
|
95
|
+
onSubmit: () => void,
|
|
96
|
+
label: string | undefined,
|
|
97
|
+
isSubmitting: boolean,
|
|
98
|
+
) => JSX.Element;
|
|
99
|
+
initialLoading?: boolean;
|
|
100
|
+
initialValues?: FormFields;
|
|
101
|
+
bannerMessages?: FormBannerMessage[];
|
|
102
|
+
localCacheKey?: string;
|
|
103
|
+
localCacheExclude?: string[];
|
|
104
|
+
localCacheId?: string[] | string;
|
|
105
|
+
onBeforeSubmit?: jest.Mock;
|
|
106
|
+
renderFooter?: React.ReactNode;
|
|
107
|
+
saveButtonOffset?: number;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function FormTest(props: FormTestProps) {
|
|
111
|
+
return <MockForm {...props} />;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function MockForm({
|
|
115
|
+
onSubmit,
|
|
116
|
+
sendBannerErrors = false,
|
|
117
|
+
sendNetworkErrors = false,
|
|
118
|
+
saveLabel,
|
|
119
|
+
renderStickySection,
|
|
120
|
+
initialLoading = false,
|
|
121
|
+
initialValues = undefined,
|
|
122
|
+
bannerMessages,
|
|
123
|
+
localCacheKey,
|
|
124
|
+
localCacheExclude,
|
|
125
|
+
onBeforeSubmit,
|
|
126
|
+
localCacheId,
|
|
127
|
+
renderFooter,
|
|
128
|
+
saveButtonOffset,
|
|
129
|
+
}: FormTestProps) {
|
|
130
|
+
const formErrors: FormBannerErrors = {};
|
|
131
|
+
if (sendBannerErrors) {
|
|
132
|
+
formErrors.bannerError = bannerError;
|
|
133
|
+
}
|
|
134
|
+
if (sendNetworkErrors) {
|
|
135
|
+
formErrors.networkError = "Ouch";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<Host>
|
|
140
|
+
<Form
|
|
141
|
+
onSubmit={onSubmit}
|
|
142
|
+
onSubmitError={onErrorMock}
|
|
143
|
+
onSubmitSuccess={onSuccessMock}
|
|
144
|
+
bannerErrors={formErrors}
|
|
145
|
+
bannerMessages={bannerMessages}
|
|
146
|
+
saveButtonLabel={saveLabel}
|
|
147
|
+
renderStickySection={renderStickySection}
|
|
148
|
+
initialLoading={initialLoading}
|
|
149
|
+
initialValues={initialValues}
|
|
150
|
+
localCacheKey={localCacheKey}
|
|
151
|
+
localCacheExclude={localCacheExclude}
|
|
152
|
+
localCacheId={localCacheId}
|
|
153
|
+
onBeforeSubmit={onBeforeSubmit}
|
|
154
|
+
renderFooter={renderFooter}
|
|
155
|
+
saveButtonOffset={saveButtonOffset}
|
|
156
|
+
>
|
|
157
|
+
<InputText
|
|
158
|
+
name={testInputTextName}
|
|
159
|
+
placeholder={testInputTextPlaceholder}
|
|
160
|
+
onChangeText={onChangeMock}
|
|
161
|
+
accessibilityLabel={testInputTextPlaceholder}
|
|
162
|
+
validations={{
|
|
163
|
+
required: requiredInputText,
|
|
164
|
+
minLength: { value: 3, message: minLengthText },
|
|
165
|
+
}}
|
|
166
|
+
/>
|
|
167
|
+
{Array.isArray(localCacheExclude) && localCacheExclude.length > 0 && (
|
|
168
|
+
<InputText
|
|
169
|
+
name={testInputTextNameExclude}
|
|
170
|
+
placeholder={testInputTextPlaceholderExclude}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
<Select
|
|
174
|
+
onChange={onChangeSelectMock}
|
|
175
|
+
label={selectLabel}
|
|
176
|
+
name={testSelectName}
|
|
177
|
+
>
|
|
178
|
+
<Option value={"1"}>1</Option>
|
|
179
|
+
<Option value={"2"}>2</Option>
|
|
180
|
+
</Select>
|
|
181
|
+
<Switch
|
|
182
|
+
name={testSwitchName}
|
|
183
|
+
label="Test Switch"
|
|
184
|
+
accessibilityLabel={switchLabel}
|
|
185
|
+
onValueChange={onChangeSwitchMock}
|
|
186
|
+
/>
|
|
187
|
+
<InputNumber name={testInputNumberName} placeholder="Test Num" />
|
|
188
|
+
<Checkbox name={testCheckboxName} accessibilityLabel={checkboxLabel} />
|
|
189
|
+
</Form>
|
|
190
|
+
</Host>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const testPresetValues = {
|
|
195
|
+
[testInputTextName]: "PresetValueTestText",
|
|
196
|
+
[testSelectName]: "2",
|
|
197
|
+
[testSwitchName]: true,
|
|
198
|
+
[testInputNumberName]: 123454321,
|
|
199
|
+
[testCheckboxName]: true,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
async function wait(milliseconds = 0): Promise<void> {
|
|
203
|
+
await new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
afterEach(() => {
|
|
207
|
+
jest.clearAllMocks();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe("Form", () => {
|
|
211
|
+
describe("Initial Load", () => {
|
|
212
|
+
it("should show activity indicator", () => {
|
|
213
|
+
const { getByLabelText } = render(
|
|
214
|
+
<FormTest initialLoading={true} onSubmit={onSubmitMock} />,
|
|
215
|
+
);
|
|
216
|
+
expect(
|
|
217
|
+
getByLabelText(formMessages.loadingA11YLabel.defaultMessage),
|
|
218
|
+
).toBeTruthy();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("should be populated with provided initialValues", () => {
|
|
222
|
+
const { getByDisplayValue, getByLabelText } = render(
|
|
223
|
+
<FormTest initialValues={testPresetValues} onSubmit={onSubmitMock} />,
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
expect(
|
|
227
|
+
getByDisplayValue(testPresetValues[testInputTextName]),
|
|
228
|
+
).toBeDefined();
|
|
229
|
+
expect(
|
|
230
|
+
getByDisplayValue(testPresetValues[testInputNumberName].toString()),
|
|
231
|
+
).toBeDefined();
|
|
232
|
+
expect(getByLabelText(switchLabel).props.value).toEqual(true);
|
|
233
|
+
expect(
|
|
234
|
+
getByLabelText(checkboxLabel).props.accessibilityState.checked,
|
|
235
|
+
).toEqual(true);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe("Save", () => {
|
|
240
|
+
it("renders the save button of the form", () => {
|
|
241
|
+
const { getByLabelText } = render(<FormTest onSubmit={onSubmitMock} />);
|
|
242
|
+
|
|
243
|
+
const saveButton = getByLabelText(saveButtonText);
|
|
244
|
+
expect(saveButton).toBeTruthy();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("displays relevant validation errors when trying to save the form", async () => {
|
|
248
|
+
const { getByLabelText, getAllByText } = render(
|
|
249
|
+
<FormTest onSubmit={onSubmitMock} />,
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
const saveButton = getByLabelText(saveButtonText);
|
|
253
|
+
await waitFor(() => {
|
|
254
|
+
fireEvent.press(saveButton);
|
|
255
|
+
});
|
|
256
|
+
expect(
|
|
257
|
+
getAllByText(requiredInputText, { includeHiddenElements: true }),
|
|
258
|
+
).toBeDefined();
|
|
259
|
+
|
|
260
|
+
const newValue = "A";
|
|
261
|
+
|
|
262
|
+
await waitFor(() => {
|
|
263
|
+
fireEvent.changeText(
|
|
264
|
+
getByLabelText(testInputTextPlaceholder),
|
|
265
|
+
newValue,
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
expect(
|
|
269
|
+
getAllByText(minLengthText, { includeHiddenElements: true }),
|
|
270
|
+
).toBeDefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should submit correct create form data", async () => {
|
|
274
|
+
const { getByLabelText, getByText } = render(
|
|
275
|
+
<FormTest onSubmit={onSubmitMock} />,
|
|
276
|
+
);
|
|
277
|
+
const saveButton = getByLabelText(saveButtonText);
|
|
278
|
+
|
|
279
|
+
const newValue = "New Value";
|
|
280
|
+
fireEvent.changeText(getByLabelText(testInputTextPlaceholder), newValue);
|
|
281
|
+
expect(onChangeMock).toHaveBeenCalled();
|
|
282
|
+
|
|
283
|
+
fireEvent(getByLabelText(switchLabel), "onValueChange", true);
|
|
284
|
+
expect(onChangeSwitchMock).toHaveBeenCalled();
|
|
285
|
+
|
|
286
|
+
fireEvent(
|
|
287
|
+
getByText(selectLabel, { includeHiddenElements: true }),
|
|
288
|
+
"onChange",
|
|
289
|
+
"2",
|
|
290
|
+
);
|
|
291
|
+
expect(onChangeSelectMock).toHaveBeenCalled();
|
|
292
|
+
|
|
293
|
+
fireEvent.press(saveButton);
|
|
294
|
+
|
|
295
|
+
await waitFor(() => {
|
|
296
|
+
expect(onSubmitMock).toHaveBeenCalledWith({
|
|
297
|
+
[testInputTextName]: newValue,
|
|
298
|
+
[testSelectName]: "2",
|
|
299
|
+
[testSwitchName]: true,
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should dismiss keyboard when form is saved", async () => {
|
|
305
|
+
const keyboardDismissSpy = jest.spyOn(Keyboard, "dismiss");
|
|
306
|
+
const { getByLabelText } = render(<FormTest onSubmit={onSubmitMock} />);
|
|
307
|
+
|
|
308
|
+
const newValue = "New Value";
|
|
309
|
+
fireEvent.changeText(getByLabelText(testInputTextPlaceholder), newValue);
|
|
310
|
+
|
|
311
|
+
const saveButton = getByLabelText(saveButtonText);
|
|
312
|
+
fireEvent.press(saveButton);
|
|
313
|
+
|
|
314
|
+
await waitFor(() => {
|
|
315
|
+
expect(onSubmitMock).toHaveBeenCalled();
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
expect(keyboardDismissSpy).toHaveBeenCalled();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("renders a save button with a custom label if provided", () => {
|
|
322
|
+
const customSaveButtonText = "MySave";
|
|
323
|
+
const { getByLabelText } = render(
|
|
324
|
+
<FormTest onSubmit={onSubmitMock} saveLabel={customSaveButtonText} />,
|
|
325
|
+
);
|
|
326
|
+
const saveButton = getByLabelText(customSaveButtonText);
|
|
327
|
+
expect(saveButton).toBeTruthy();
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it("renders a custom sticky component if provided", () => {
|
|
331
|
+
const customSaveButtonText = "CheckboxOverload";
|
|
332
|
+
const { getByLabelText } = render(
|
|
333
|
+
<FormTest
|
|
334
|
+
onSubmit={onSubmitMock}
|
|
335
|
+
saveLabel={customSaveButtonText}
|
|
336
|
+
renderStickySection={(onSubmit, label) => (
|
|
337
|
+
<Checkbox
|
|
338
|
+
checked={false}
|
|
339
|
+
name={label}
|
|
340
|
+
accessibilityLabel={label}
|
|
341
|
+
onChange={onSubmit}
|
|
342
|
+
/>
|
|
343
|
+
)}
|
|
344
|
+
/>,
|
|
345
|
+
);
|
|
346
|
+
const overrideCheckbox = getByLabelText(customSaveButtonText);
|
|
347
|
+
expect(overrideCheckbox).toBeTruthy();
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
describe("Submitting", () => {
|
|
352
|
+
it("should show submission spinner when submitting form data", async () => {
|
|
353
|
+
const timeoutSubmit = jest.fn().mockImplementation(() => {
|
|
354
|
+
return new Promise(res =>
|
|
355
|
+
setTimeout(() => res(() => Promise.resolve()), 1000),
|
|
356
|
+
);
|
|
357
|
+
});
|
|
358
|
+
const { getByLabelText } = await waitFor(() =>
|
|
359
|
+
render(<FormTest onSubmit={timeoutSubmit} />),
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
const saveButton = getByLabelText(saveButtonText);
|
|
363
|
+
fireEvent.press(saveButton);
|
|
364
|
+
|
|
365
|
+
expect(
|
|
366
|
+
getByLabelText(formMessages.loadingA11YLabel.defaultMessage),
|
|
367
|
+
).toBeTruthy();
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it("should call beforeSubmit if one is provided", async () => {
|
|
371
|
+
const beforeSubmitMock = jest.fn().mockImplementation(() => {
|
|
372
|
+
return Promise.resolve(true);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
const { getByLabelText } = render(
|
|
376
|
+
<FormTest onSubmit={onSubmitMock} onBeforeSubmit={beforeSubmitMock} />,
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
const newValue = "New Value";
|
|
380
|
+
fireEvent.changeText(getByLabelText(testInputTextPlaceholder), newValue);
|
|
381
|
+
|
|
382
|
+
const saveButton = getByLabelText(saveButtonText);
|
|
383
|
+
fireEvent.press(saveButton);
|
|
384
|
+
|
|
385
|
+
await waitFor(() => {
|
|
386
|
+
expect(beforeSubmitMock).toHaveBeenCalled();
|
|
387
|
+
expect(onSubmitMock).toHaveBeenCalled();
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("does not submit if beforeSubmit returns false", async () => {
|
|
392
|
+
const beforeSubmitMock = jest.fn().mockImplementation(() => {
|
|
393
|
+
return Promise.resolve(false);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const { getByLabelText } = render(
|
|
397
|
+
<FormTest onSubmit={onSubmitMock} onBeforeSubmit={beforeSubmitMock} />,
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
const newValue = "New Value";
|
|
401
|
+
fireEvent.changeText(getByLabelText(testInputTextPlaceholder), newValue);
|
|
402
|
+
|
|
403
|
+
const saveButton = getByLabelText(saveButtonText);
|
|
404
|
+
fireEvent.press(saveButton);
|
|
405
|
+
|
|
406
|
+
await waitFor(() => {
|
|
407
|
+
expect(beforeSubmitMock).toHaveBeenCalled();
|
|
408
|
+
expect(onSubmitMock).not.toHaveBeenCalled();
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
describe("While offline", () => {
|
|
412
|
+
const mockSubmit = jest.fn().mockImplementation(() =>
|
|
413
|
+
Promise.reject({
|
|
414
|
+
errorType: FormSubmitErrorType.NetworkError,
|
|
415
|
+
}),
|
|
416
|
+
);
|
|
417
|
+
const setup = () => {
|
|
418
|
+
const view = render(
|
|
419
|
+
<FormTest sendNetworkErrors={true} onSubmit={mockSubmit} />,
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
const { getByLabelText } = view;
|
|
423
|
+
|
|
424
|
+
const newValue = "New Value";
|
|
425
|
+
fireEvent.changeText(
|
|
426
|
+
getByLabelText(testInputTextPlaceholder),
|
|
427
|
+
newValue,
|
|
428
|
+
);
|
|
429
|
+
fireEvent.press(getByLabelText(saveButtonText));
|
|
430
|
+
return view;
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
it("should show offline alert when attempting to save while offline", async () => {
|
|
434
|
+
const alertSpy = jest.spyOn(Alert, "alert");
|
|
435
|
+
const { formatMessage } = useIntl();
|
|
436
|
+
setup();
|
|
437
|
+
|
|
438
|
+
await act(wait);
|
|
439
|
+
expect(alertSpy).toHaveBeenCalledTimes(1);
|
|
440
|
+
expect(alertSpy).toHaveBeenCalledWith(
|
|
441
|
+
formatMessage(formMessages.unavailableNetworkTitle),
|
|
442
|
+
formatMessage(formMessages.unavailableNetworkMessage),
|
|
443
|
+
expect.anything(),
|
|
444
|
+
);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it("Submits Form on successful retry", async () => {
|
|
448
|
+
const alertSpy = jest.spyOn(Alert, "alert");
|
|
449
|
+
setup();
|
|
450
|
+
await act(wait);
|
|
451
|
+
const alertActions = alertSpy.mock.calls[0][2];
|
|
452
|
+
const retryAction = alertActions?.find(
|
|
453
|
+
action =>
|
|
454
|
+
action.text === formMessages.retryAlertButton.defaultMessage,
|
|
455
|
+
);
|
|
456
|
+
mockSubmit.mockImplementationOnce(() => Promise.resolve());
|
|
457
|
+
retryAction?.onPress?.();
|
|
458
|
+
|
|
459
|
+
await act(wait);
|
|
460
|
+
expect(alertSpy).toHaveBeenCalledTimes(1);
|
|
461
|
+
expect(onSuccessMock).toHaveBeenCalled();
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it("reshows an Alert on unsuccessful retry", async () => {
|
|
465
|
+
const alertSpy = jest.spyOn(Alert, "alert");
|
|
466
|
+
setup();
|
|
467
|
+
await act(wait);
|
|
468
|
+
const alertActions = alertSpy.mock.calls[0][2];
|
|
469
|
+
const retryAction = alertActions?.find(
|
|
470
|
+
action =>
|
|
471
|
+
action.text === formMessages.retryAlertButton.defaultMessage,
|
|
472
|
+
);
|
|
473
|
+
retryAction?.onPress?.();
|
|
474
|
+
|
|
475
|
+
await act(wait);
|
|
476
|
+
expect(alertSpy).toHaveBeenCalledTimes(2);
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
describe("Error Banner", () => {
|
|
482
|
+
const atlantisContextSpy = jest.spyOn(
|
|
483
|
+
atlantisContext,
|
|
484
|
+
"useAtlantisContext",
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
atlantisContextSpy.mockReturnValue({
|
|
488
|
+
...contextDefaultValue,
|
|
489
|
+
isOnline: false,
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it("renders Offline Banner when disconnected", async () => {
|
|
493
|
+
const { getByText } = render(<FormTest onSubmit={onSubmitMock} />);
|
|
494
|
+
const { formatMessage } = useIntl();
|
|
495
|
+
|
|
496
|
+
expect(
|
|
497
|
+
getByText(formatMessage(formErrorBannerMessages.offlineError)),
|
|
498
|
+
).toBeDefined();
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it("does not render Offline Banner when connected", async () => {
|
|
502
|
+
atlantisContextSpy.mockReturnValue({
|
|
503
|
+
...contextDefaultValue,
|
|
504
|
+
isOnline: true,
|
|
505
|
+
});
|
|
506
|
+
const { queryByText } = render(<FormTest onSubmit={onSubmitMock} />);
|
|
507
|
+
const { formatMessage } = useIntl();
|
|
508
|
+
|
|
509
|
+
expect(
|
|
510
|
+
queryByText(formatMessage(formErrorBannerMessages.offlineError)),
|
|
511
|
+
).toBeNull();
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it("renders user errors when provided", async () => {
|
|
515
|
+
const { getByText } = render(
|
|
516
|
+
<FormTest onSubmit={onSubmitMock} sendBannerErrors={true} />,
|
|
517
|
+
);
|
|
518
|
+
const expectedErrors = bannerError.messages;
|
|
519
|
+
|
|
520
|
+
expect(getByText(new RegExp(expectedErrors[0]))).toBeTruthy();
|
|
521
|
+
expect(getByText(new RegExp(expectedErrors[1]))).toBeTruthy();
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
it("does not render user errors when not provided", async () => {
|
|
525
|
+
const { queryByText } = render(<FormTest onSubmit={onSubmitMock} />);
|
|
526
|
+
|
|
527
|
+
const expectedErrors = bannerError.messages;
|
|
528
|
+
|
|
529
|
+
expect(queryByText(expectedErrors[0])).toBeNull();
|
|
530
|
+
expect(queryByText(expectedErrors[1])).toBeNull();
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
describe("Message Banner", () => {
|
|
535
|
+
it.each([
|
|
536
|
+
[FormBannerMessageType.NoticeMessage, noticeMessage],
|
|
537
|
+
[FormBannerMessageType.WarningMessage, warningMessage],
|
|
538
|
+
])("renders a %s when provided", async (_messageType, message) => {
|
|
539
|
+
const { getByText } = render(
|
|
540
|
+
<FormTest onSubmit={onSubmitMock} bannerMessages={[message]} />,
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
expect(getByText(message.message)).toBeDefined();
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
it("renders multiple messages when provided", async () => {
|
|
547
|
+
const { getByText } = render(
|
|
548
|
+
<FormTest
|
|
549
|
+
onSubmit={onSubmitMock}
|
|
550
|
+
bannerMessages={[noticeMessage, warningMessage]}
|
|
551
|
+
/>,
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
expect(getByText(noticeMessage.message)).toBeDefined();
|
|
555
|
+
expect(getByText(warningMessage.message)).toBeDefined();
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
describe("Render footer", () => {
|
|
560
|
+
it("render a footer when provided", () => {
|
|
561
|
+
const footerMessage = "Hello, I'm a footer!";
|
|
562
|
+
const { getByText } = render(
|
|
563
|
+
<FormTest
|
|
564
|
+
onSubmit={onSubmitMock}
|
|
565
|
+
renderFooter={<Text>{footerMessage}</Text>}
|
|
566
|
+
/>,
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
expect(getByText(footerMessage)).toBeDefined();
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
describe("Safe Area", () => {
|
|
574
|
+
it("does render a safe area when there's a saveButtonOffset is provided", () => {
|
|
575
|
+
const { getByTestId } = render(<FormTest onSubmit={onSubmitMock} />);
|
|
576
|
+
|
|
577
|
+
expect(getByTestId("ATL-FormSafeArea")).toBeDefined();
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
it("does NOT render a safe area when there's a saveButtonOffset is provided", () => {
|
|
581
|
+
const { queryByTestId } = render(
|
|
582
|
+
<FormTest onSubmit={onSubmitMock} saveButtonOffset={30} />,
|
|
583
|
+
);
|
|
584
|
+
|
|
585
|
+
expect(queryByTestId("ATL-FormSafeArea")).toBeNull();
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
});
|