@jobber/components-native 0.47.3 → 0.48.1
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/package.json +2 -2
- package/dist/src/Select/Select.js +8 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/Select/Select.d.ts +5 -1
- package/package.json +2 -2
- package/src/AtlantisContext/AtlantisContext.test.tsx +1 -3
- package/src/Button/components/InternalButtonLoading/InternalButtonLoading.test.tsx +1 -3
- package/src/Checkbox/CheckboxGroup.test.tsx +3 -5
- package/src/Divider/Divider.test.tsx +1 -3
- package/src/Form/components/FormErrorBanner/FormErrorBanner.test.tsx +3 -4
- package/src/InputSearch/InputSearch.test.tsx +1 -7
- package/src/InputTime/InputTime.test.tsx +2 -7
- package/src/Select/Select.test.tsx +141 -173
- package/src/Select/Select.tsx +18 -1
- package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.test.tsx +2 -2
- package/src/Select/components/SelectInternalPicker/SelectInternalPicker.test.tsx +1 -2
|
@@ -64,6 +64,10 @@ export interface SelectProps {
|
|
|
64
64
|
* The validations that will mark this component as invalid
|
|
65
65
|
*/
|
|
66
66
|
readonly validations?: RegisterOptions;
|
|
67
|
+
/**
|
|
68
|
+
* Used to locate this view in end-to-end tests.
|
|
69
|
+
*/
|
|
70
|
+
readonly testID?: string;
|
|
67
71
|
}
|
|
68
|
-
export declare function Select({ value, defaultValue, onChange, children, placeholder, label, assistiveText, disabled, invalid, validations, accessibilityLabel, name, }: SelectProps): JSX.Element;
|
|
72
|
+
export declare function Select({ value, defaultValue, onChange, children, placeholder, label, assistiveText, disabled, invalid, validations, accessibilityLabel, name, testID, }: SelectProps): JSX.Element;
|
|
69
73
|
export declare function Option({ children }: SelectOption): JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jobber/components-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React Native implementation of Atlantis",
|
|
6
6
|
"repository": {
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"react-native-reanimated": "^2.17.0",
|
|
85
85
|
"react-native-safe-area-context": "^4.5.2"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "d8214fde2dedb50cebe48fe7967019660a1933bd"
|
|
88
88
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
2
|
import React, { PropsWithChildren } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { renderHook } from "@testing-library/react-hooks";
|
|
4
4
|
import {
|
|
5
5
|
AtlantisContext,
|
|
6
6
|
AtlantisContextProps,
|
|
@@ -8,8 +8,6 @@ import {
|
|
|
8
8
|
useAtlantisContext,
|
|
9
9
|
} from "./AtlantisContext";
|
|
10
10
|
|
|
11
|
-
afterEach(cleanup);
|
|
12
|
-
|
|
13
11
|
const providerValues: AtlantisContextProps = {
|
|
14
12
|
dateFormat: "MM/DD/YYYY",
|
|
15
13
|
timeFormat: "hh:mm a",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
3
|
import {
|
|
4
4
|
InternalButtonLoading,
|
|
5
5
|
darkPattern,
|
|
@@ -7,8 +7,6 @@ import {
|
|
|
7
7
|
} from "./InternalButtonLoading";
|
|
8
8
|
import { ButtonType, ButtonVariation } from "../../types";
|
|
9
9
|
|
|
10
|
-
afterEach(cleanup);
|
|
11
|
-
|
|
12
10
|
describe("Loading pattern", () => {
|
|
13
11
|
it.each<[string, ButtonType, ButtonVariation]>([
|
|
14
12
|
[lightPattern, "primary", "work"],
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import {
|
|
3
3
|
RenderAPI,
|
|
4
|
-
cleanup,
|
|
5
4
|
fireEvent,
|
|
6
5
|
render,
|
|
7
6
|
waitFor,
|
|
@@ -31,8 +30,6 @@ interface CheckboxGroupFormOnChangeHandlers {
|
|
|
31
30
|
all?: (data: CheckboxGroupState) => void;
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
afterEach(cleanup);
|
|
35
|
-
|
|
36
33
|
function setup(
|
|
37
34
|
label: string | undefined,
|
|
38
35
|
disabled?: boolean,
|
|
@@ -71,8 +68,8 @@ function SetupWithForm({
|
|
|
71
68
|
initialValues,
|
|
72
69
|
onChangeHandlers,
|
|
73
70
|
}: {
|
|
74
|
-
initialValues: CheckboxGroupFormData;
|
|
75
|
-
onChangeHandlers?: CheckboxGroupFormOnChangeHandlers;
|
|
71
|
+
readonly initialValues: CheckboxGroupFormData;
|
|
72
|
+
readonly onChangeHandlers?: CheckboxGroupFormOnChangeHandlers;
|
|
76
73
|
}): JSX.Element {
|
|
77
74
|
const formMethods = useForm({ defaultValues: initialValues });
|
|
78
75
|
|
|
@@ -178,6 +175,7 @@ describe("when all of the checkboxes in a group are checked", () => {
|
|
|
178
175
|
describe("when the parent checkbox does not have a label", () => {
|
|
179
176
|
it("does not render the parent checkbox", async () => {
|
|
180
177
|
const { checkboxGroup } = setup(undefined);
|
|
178
|
+
|
|
181
179
|
const findParentCheckbox = () => {
|
|
182
180
|
checkboxGroup.getByLabelText(parentCheckboxLabel);
|
|
183
181
|
};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
3
|
import { Divider } from "./Divider";
|
|
4
4
|
import { styles } from "./Divider.style";
|
|
5
5
|
|
|
6
|
-
afterEach(cleanup);
|
|
7
|
-
|
|
8
6
|
const dividerTestId = "Divider";
|
|
9
7
|
|
|
10
8
|
describe("Divider", () => {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
3
|
import { FormErrorBanner } from "./FormErrorBanner";
|
|
4
4
|
import { atlantisContextDefaultValues } from "../../../AtlantisContext";
|
|
5
5
|
import * as atlantisContext from "../../../AtlantisContext/AtlantisContext";
|
|
6
6
|
|
|
7
|
+
afterEach(jest.clearAllMocks);
|
|
8
|
+
|
|
7
9
|
describe("FormErrorBanner", () => {
|
|
8
10
|
const atlantisContextSpy = jest.spyOn(atlantisContext, "useAtlantisContext");
|
|
9
11
|
|
|
@@ -56,6 +58,3 @@ describe("FormErrorBanner", () => {
|
|
|
56
58
|
expect(queryByText(couldNotSavechanges)).toBeNull();
|
|
57
59
|
});
|
|
58
60
|
});
|
|
59
|
-
|
|
60
|
-
afterEach(jest.clearAllMocks);
|
|
61
|
-
afterEach(cleanup);
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
cleanup,
|
|
4
|
-
fireEvent,
|
|
5
|
-
render,
|
|
6
|
-
waitFor,
|
|
7
|
-
} from "@testing-library/react-native";
|
|
2
|
+
import { fireEvent, render, waitFor } from "@testing-library/react-native";
|
|
8
3
|
import { InputSearch } from "./InputSearch";
|
|
9
4
|
|
|
10
5
|
const accessibilityLabelSearch = "Search";
|
|
@@ -18,7 +13,6 @@ beforeEach(() => {
|
|
|
18
13
|
mockOnDebouncedChange.mockReset();
|
|
19
14
|
searchValue = "";
|
|
20
15
|
});
|
|
21
|
-
afterEach(cleanup);
|
|
22
16
|
|
|
23
17
|
function setup() {
|
|
24
18
|
return render(
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
cleanup,
|
|
4
|
-
fireEvent,
|
|
5
|
-
render,
|
|
6
|
-
waitFor,
|
|
7
|
-
} from "@testing-library/react-native";
|
|
2
|
+
import { fireEvent, render, waitFor } from "@testing-library/react-native";
|
|
8
3
|
import { Host } from "react-native-portalize";
|
|
9
4
|
import { FormProvider, useForm } from "react-hook-form";
|
|
10
5
|
import { InputTime } from "./InputTime";
|
|
@@ -12,7 +7,6 @@ import * as atlantisContext from "../AtlantisContext/AtlantisContext";
|
|
|
12
7
|
import { Button } from "../Button";
|
|
13
8
|
|
|
14
9
|
afterEach(() => {
|
|
15
|
-
cleanup();
|
|
16
10
|
jest.spyOn(atlantisContext, "useAtlantisContext").mockRestore();
|
|
17
11
|
});
|
|
18
12
|
|
|
@@ -192,6 +186,7 @@ const mockOnSubmit = jest.fn();
|
|
|
192
186
|
const saveButtonText = "Submit";
|
|
193
187
|
|
|
194
188
|
const requiredError = "This is required";
|
|
189
|
+
|
|
195
190
|
function SimpleFormWithProvider({ children, defaultValues }) {
|
|
196
191
|
const formMethods = useForm({
|
|
197
192
|
reValidateMode: "onChange",
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
RenderAPI,
|
|
4
|
-
cleanup,
|
|
5
|
-
fireEvent,
|
|
6
|
-
render,
|
|
7
|
-
} from "@testing-library/react-native";
|
|
2
|
+
import { RenderAPI, fireEvent, render } from "@testing-library/react-native";
|
|
8
3
|
import { tokens } from "@jobber/design/foundation";
|
|
9
4
|
import { AccessibilityInfo } from "react-native";
|
|
10
5
|
import { Option, Select } from ".";
|
|
@@ -19,7 +14,6 @@ beforeEach(() => {
|
|
|
19
14
|
});
|
|
20
15
|
|
|
21
16
|
afterEach(() => {
|
|
22
|
-
cleanup();
|
|
23
17
|
jest.resetAllMocks();
|
|
24
18
|
});
|
|
25
19
|
|
|
@@ -80,48 +74,6 @@ describe("Select", () => {
|
|
|
80
74
|
).toBeDefined();
|
|
81
75
|
});
|
|
82
76
|
|
|
83
|
-
describe("when invalid", () => {
|
|
84
|
-
const labelText = "labelText";
|
|
85
|
-
|
|
86
|
-
it("renders an invalid Select", () => {
|
|
87
|
-
const { getByText } = render(
|
|
88
|
-
<Select onChange={onChange} invalid={true} label={labelText}>
|
|
89
|
-
<Option value={"1"}>1</Option>
|
|
90
|
-
<Option value={"2"}>2</Option>
|
|
91
|
-
</Select>,
|
|
92
|
-
);
|
|
93
|
-
expect(
|
|
94
|
-
getByText(labelText, { includeHiddenElements: true }).props.style,
|
|
95
|
-
).toContainEqual({
|
|
96
|
-
color: tokens["color-critical"],
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("renders an invalid Select with placeholder", () => {
|
|
101
|
-
const placeholder = "Place me in the holder";
|
|
102
|
-
const { getByText } = render(
|
|
103
|
-
<Select
|
|
104
|
-
label={labelText}
|
|
105
|
-
onChange={onChange}
|
|
106
|
-
invalid={true}
|
|
107
|
-
placeholder={placeholder}
|
|
108
|
-
>
|
|
109
|
-
<Option value={"1"}>1</Option>
|
|
110
|
-
<Option value={"2"}>2</Option>
|
|
111
|
-
</Select>,
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
expect(
|
|
115
|
-
getByText(placeholder, { includeHiddenElements: true }),
|
|
116
|
-
).toBeDefined();
|
|
117
|
-
expect(
|
|
118
|
-
getByText(labelText, { includeHiddenElements: true }).props.style,
|
|
119
|
-
).toContainEqual({
|
|
120
|
-
color: tokens["color-critical"],
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
77
|
it("renders a disabled Select", () => {
|
|
126
78
|
const labelText = "labelText";
|
|
127
79
|
const { getByText } = render(
|
|
@@ -166,156 +118,172 @@ describe("Select", () => {
|
|
|
166
118
|
).toBeDefined();
|
|
167
119
|
});
|
|
168
120
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
121
|
+
it("renders a Select with custom testID", () => {
|
|
122
|
+
const testID = "testID";
|
|
123
|
+
const { getByTestId } = render(
|
|
124
|
+
<Select onChange={onChange} testID={testID}>
|
|
125
|
+
<Option value={"1"}>1</Option>
|
|
126
|
+
<Option value={"2"}>2</Option>
|
|
127
|
+
</Select>,
|
|
128
|
+
);
|
|
177
129
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
130
|
+
expect(getByTestId(`ATL-${testID}-Select`)).toBeDefined();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("renders an accessibilityLabel if provided", () => {
|
|
134
|
+
const { getByLabelText } = render(
|
|
135
|
+
<Select
|
|
136
|
+
onChange={onChange}
|
|
137
|
+
label="label"
|
|
138
|
+
accessibilityLabel="accessibilityLabel"
|
|
139
|
+
>
|
|
140
|
+
<Option value={"1"}>1</Option>
|
|
141
|
+
<Option value={"2"}>2</Option>
|
|
142
|
+
</Select>,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
expect(getByLabelText("accessibilityLabel")).toBeTruthy();
|
|
146
|
+
});
|
|
147
|
+
it("fires the onChange callback", () => {
|
|
148
|
+
const { getByTestId } = render(
|
|
149
|
+
<Select onChange={onChange} value={"2"}>
|
|
150
|
+
<Option value={"1"}>1</Option>
|
|
151
|
+
<Option value={"2"}>2</Option>
|
|
152
|
+
</Select>,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
const select = getByTestId("ATL-Select").findByType(SelectInternalPicker);
|
|
156
|
+
expect(select).toBeTruthy();
|
|
157
|
+
fireEvent(select, "onChange", "1");
|
|
158
|
+
expect(onChange).toHaveBeenCalledWith("1");
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("when Select is invalid", () => {
|
|
163
|
+
const labelText = "labelText";
|
|
164
|
+
|
|
165
|
+
it("renders an invalid Select", () => {
|
|
166
|
+
const { getByText } = render(
|
|
167
|
+
<Select onChange={onChange} invalid={true} label={labelText}>
|
|
168
|
+
<Option value={"1"}>1</Option>
|
|
169
|
+
<Option value={"2"}>2</Option>
|
|
170
|
+
</Select>,
|
|
171
|
+
);
|
|
172
|
+
expect(
|
|
173
|
+
getByText(labelText, { includeHiddenElements: true }).props.style,
|
|
174
|
+
).toContainEqual({
|
|
175
|
+
color: tokens["color-critical"],
|
|
182
176
|
});
|
|
183
177
|
});
|
|
184
178
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
179
|
+
it("renders an invalid Select with placeholder", () => {
|
|
180
|
+
const placeholder = "Place me in the holder";
|
|
181
|
+
const { getByText } = render(
|
|
182
|
+
<Select
|
|
183
|
+
label={labelText}
|
|
184
|
+
onChange={onChange}
|
|
185
|
+
invalid={true}
|
|
186
|
+
placeholder={placeholder}
|
|
187
|
+
>
|
|
188
|
+
<Option value={"1"}>1</Option>
|
|
189
|
+
<Option value={"2"}>2</Option>
|
|
190
|
+
</Select>,
|
|
191
|
+
);
|
|
193
192
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
193
|
+
expect(
|
|
194
|
+
getByText(placeholder, { includeHiddenElements: true }),
|
|
195
|
+
).toBeDefined();
|
|
196
|
+
expect(
|
|
197
|
+
getByText(labelText, { includeHiddenElements: true }).props.style,
|
|
198
|
+
).toContainEqual({
|
|
199
|
+
color: tokens["color-critical"],
|
|
197
200
|
});
|
|
201
|
+
});
|
|
202
|
+
});
|
|
198
203
|
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
describe("when validations are passed to the component", () => {
|
|
205
|
+
describe("validations fail", () => {
|
|
206
|
+
let tree: RenderAPI;
|
|
207
|
+
const labelText = "labelText";
|
|
208
|
+
const errorMsg = "Too short";
|
|
209
|
+
beforeEach(() => {
|
|
210
|
+
tree = render(
|
|
201
211
|
<Select
|
|
212
|
+
label={labelText}
|
|
202
213
|
onChange={onChange}
|
|
203
|
-
value={"
|
|
204
|
-
|
|
214
|
+
value={"Watermelon"}
|
|
215
|
+
validations={{
|
|
216
|
+
minLength: { value: 60, message: errorMsg },
|
|
217
|
+
}}
|
|
205
218
|
>
|
|
206
|
-
<Option value={"
|
|
207
|
-
<Option value={"
|
|
219
|
+
<Option value={"Apple"}>Apple</Option>
|
|
220
|
+
<Option value={"Watermelon"}>Watermelon</Option>
|
|
208
221
|
</Select>,
|
|
209
222
|
);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("renders the error message when there is an error", async () => {
|
|
226
|
+
const select = tree
|
|
227
|
+
.getByTestId("ATL-Select")
|
|
228
|
+
.findByType(SelectInternalPicker);
|
|
229
|
+
fireEvent(select, "onChange", "Apple");
|
|
230
|
+
expect(
|
|
231
|
+
await tree.findByText(errorMsg, { includeHiddenElements: true }),
|
|
232
|
+
).toBeTruthy();
|
|
233
|
+
});
|
|
210
234
|
|
|
235
|
+
it("shows the invalid colours", async () => {
|
|
236
|
+
const select = tree
|
|
237
|
+
.getByTestId("ATL-Select")
|
|
238
|
+
.findByType(SelectInternalPicker);
|
|
239
|
+
fireEvent(select, "onChange", "Apple");
|
|
211
240
|
expect(
|
|
212
|
-
|
|
213
|
-
|
|
241
|
+
(await tree.findByText(labelText, { includeHiddenElements: true }))
|
|
242
|
+
.props.style,
|
|
243
|
+
).toContainEqual({
|
|
244
|
+
color: tokens["color-critical"],
|
|
245
|
+
});
|
|
214
246
|
});
|
|
215
247
|
});
|
|
216
248
|
|
|
217
|
-
describe("
|
|
218
|
-
|
|
219
|
-
|
|
249
|
+
describe("validations passes", () => {
|
|
250
|
+
let tree: RenderAPI;
|
|
251
|
+
const labelText = "labelText";
|
|
252
|
+
const errorMsg = "Not too short";
|
|
253
|
+
beforeEach(() => {
|
|
254
|
+
tree = render(
|
|
220
255
|
<Select
|
|
256
|
+
label={labelText}
|
|
221
257
|
onChange={onChange}
|
|
222
|
-
|
|
223
|
-
|
|
258
|
+
value={"Watermelon"}
|
|
259
|
+
validations={{
|
|
260
|
+
minLength: { value: 4, message: errorMsg },
|
|
261
|
+
}}
|
|
224
262
|
>
|
|
225
|
-
<Option value={"
|
|
226
|
-
<Option value={"
|
|
263
|
+
<Option value={"Apple"}>Apple</Option>
|
|
264
|
+
<Option value={"Watermelon"}>Watermelon</Option>
|
|
227
265
|
</Select>,
|
|
228
266
|
);
|
|
229
|
-
|
|
230
|
-
expect(getByLabelText("accessibilityLabel")).toBeTruthy();
|
|
231
267
|
});
|
|
232
|
-
});
|
|
233
268
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
<Select
|
|
242
|
-
label={labelText}
|
|
243
|
-
onChange={onChange}
|
|
244
|
-
value={"Watermelon"}
|
|
245
|
-
validations={{
|
|
246
|
-
minLength: { value: 60, message: errorMsg },
|
|
247
|
-
}}
|
|
248
|
-
>
|
|
249
|
-
<Option value={"Apple"}>Apple</Option>
|
|
250
|
-
<Option value={"Watermelon"}>Watermelon</Option>
|
|
251
|
-
</Select>,
|
|
252
|
-
);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it("renders the error message when there is an error", async () => {
|
|
256
|
-
const select = tree
|
|
257
|
-
.getByTestId("ATL-Select")
|
|
258
|
-
.findByType(SelectInternalPicker);
|
|
259
|
-
fireEvent(select, "onChange", "Apple");
|
|
260
|
-
expect(
|
|
261
|
-
await tree.findByText(errorMsg, { includeHiddenElements: true }),
|
|
262
|
-
).toBeTruthy();
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it("shows the invalid colours", async () => {
|
|
266
|
-
const select = tree
|
|
267
|
-
.getByTestId("ATL-Select")
|
|
268
|
-
.findByType(SelectInternalPicker);
|
|
269
|
-
fireEvent(select, "onChange", "Apple");
|
|
270
|
-
expect(
|
|
271
|
-
(await tree.findByText(labelText, { includeHiddenElements: true }))
|
|
272
|
-
.props.style,
|
|
273
|
-
).toContainEqual({
|
|
274
|
-
color: tokens["color-critical"],
|
|
275
|
-
});
|
|
276
|
-
});
|
|
269
|
+
it("does not render any error messages", () => {
|
|
270
|
+
const select = tree
|
|
271
|
+
.getByTestId("ATL-Select")
|
|
272
|
+
.findByType(SelectInternalPicker);
|
|
273
|
+
expect(select).toBeTruthy();
|
|
274
|
+
fireEvent(select, "onChange", "Apple");
|
|
275
|
+
expect(tree.queryByText(errorMsg)).toBeNull();
|
|
277
276
|
});
|
|
278
277
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
value={"Watermelon"}
|
|
289
|
-
validations={{
|
|
290
|
-
minLength: { value: 4, message: errorMsg },
|
|
291
|
-
}}
|
|
292
|
-
>
|
|
293
|
-
<Option value={"Apple"}>Apple</Option>
|
|
294
|
-
<Option value={"Watermelon"}>Watermelon</Option>
|
|
295
|
-
</Select>,
|
|
296
|
-
);
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
it("does not render any error messages", () => {
|
|
300
|
-
const select = tree
|
|
301
|
-
.getByTestId("ATL-Select")
|
|
302
|
-
.findByType(SelectInternalPicker);
|
|
303
|
-
expect(select).toBeTruthy();
|
|
304
|
-
fireEvent(select, "onChange", "Apple");
|
|
305
|
-
expect(tree.queryByText(errorMsg)).toBeNull();
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it("has non-critical colours", () => {
|
|
309
|
-
const select = tree
|
|
310
|
-
.getByTestId("ATL-Select")
|
|
311
|
-
.findByType(SelectInternalPicker);
|
|
312
|
-
fireEvent(select, "onChange", "Apple");
|
|
313
|
-
expect(
|
|
314
|
-
tree.getByText(labelText, { includeHiddenElements: true }).props
|
|
315
|
-
.style,
|
|
316
|
-
).toContainEqual({
|
|
317
|
-
color: tokens["color-text--secondary"],
|
|
318
|
-
});
|
|
278
|
+
it("has non-critical colours", () => {
|
|
279
|
+
const select = tree
|
|
280
|
+
.getByTestId("ATL-Select")
|
|
281
|
+
.findByType(SelectInternalPicker);
|
|
282
|
+
fireEvent(select, "onChange", "Apple");
|
|
283
|
+
expect(
|
|
284
|
+
tree.getByText(labelText, { includeHiddenElements: true }).props.style,
|
|
285
|
+
).toContainEqual({
|
|
286
|
+
color: tokens["color-text--secondary"],
|
|
319
287
|
});
|
|
320
288
|
});
|
|
321
289
|
});
|
package/src/Select/Select.tsx
CHANGED
|
@@ -88,6 +88,11 @@ export interface SelectProps {
|
|
|
88
88
|
* The validations that will mark this component as invalid
|
|
89
89
|
*/
|
|
90
90
|
readonly validations?: RegisterOptions;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Used to locate this view in end-to-end tests.
|
|
94
|
+
*/
|
|
95
|
+
readonly testID?: string;
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
export function Select({
|
|
@@ -103,6 +108,7 @@ export function Select({
|
|
|
103
108
|
validations,
|
|
104
109
|
accessibilityLabel,
|
|
105
110
|
name,
|
|
111
|
+
testID,
|
|
106
112
|
}: SelectProps): JSX.Element {
|
|
107
113
|
const { field, error } = useFormController({
|
|
108
114
|
name,
|
|
@@ -129,7 +135,7 @@ export function Select({
|
|
|
129
135
|
}}
|
|
130
136
|
>
|
|
131
137
|
<View
|
|
132
|
-
testID=
|
|
138
|
+
testID={getTestID(testID)}
|
|
133
139
|
accessible={true}
|
|
134
140
|
accessibilityLabel={getA11yLabel()}
|
|
135
141
|
accessibilityValue={{ text: getValue() }}
|
|
@@ -187,6 +193,7 @@ export function Select({
|
|
|
187
193
|
function getA11yLabel(): string | undefined {
|
|
188
194
|
let text = [accessibilityLabel || label, assistiveText];
|
|
189
195
|
text = text.filter(Boolean);
|
|
196
|
+
|
|
190
197
|
return text.join(", ");
|
|
191
198
|
}
|
|
192
199
|
|
|
@@ -219,6 +226,7 @@ export function Select({
|
|
|
219
226
|
const options = getOptions();
|
|
220
227
|
|
|
221
228
|
const activeValue = options.find(option => option.isActive);
|
|
229
|
+
|
|
222
230
|
return activeValue?.label || placeholder || t("Select.emptyValue");
|
|
223
231
|
}
|
|
224
232
|
}
|
|
@@ -229,9 +237,18 @@ function getTextVariation({
|
|
|
229
237
|
}: Pick<SelectProps, "invalid" | "disabled">): TextVariation {
|
|
230
238
|
if (invalid) return "error";
|
|
231
239
|
if (disabled) return "disabled";
|
|
240
|
+
|
|
232
241
|
return "subdued";
|
|
233
242
|
}
|
|
234
243
|
|
|
244
|
+
function getTestID(testID?: string): string {
|
|
245
|
+
if (testID) {
|
|
246
|
+
return `ATL-${testID}-Select`;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return "ATL-Select";
|
|
250
|
+
}
|
|
251
|
+
|
|
235
252
|
export function Option({ children }: SelectOption): JSX.Element {
|
|
236
253
|
return <>{children}</>;
|
|
237
254
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { fireEvent, render } from "@testing-library/react-native";
|
|
3
3
|
import { AccessibilityInfo, View } from "react-native";
|
|
4
4
|
import { SelectDefaultPicker } from "./SelectDefaultPicker";
|
|
5
5
|
import { Text } from "../../../Text";
|
|
@@ -19,11 +19,11 @@ beforeEach(() => {
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
afterEach(() => {
|
|
22
|
-
cleanup();
|
|
23
22
|
jest.resetAllMocks();
|
|
24
23
|
});
|
|
25
24
|
|
|
26
25
|
const childText = "Click me";
|
|
26
|
+
|
|
27
27
|
function setup() {
|
|
28
28
|
return render(
|
|
29
29
|
<View testID="SelectDefaultPicker">
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { ElementType } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { fireEvent, render } from "@testing-library/react-native";
|
|
3
3
|
import { View } from "react-native";
|
|
4
4
|
import { SelectInternalPicker } from ".";
|
|
5
5
|
import { SelectInternalPickerProps } from "../../types";
|
|
@@ -19,7 +19,6 @@ jest.mock("@react-native-picker/picker", () => ({ Picker: MockPicker }));
|
|
|
19
19
|
MockPicker.Item = MockPickerItem;
|
|
20
20
|
|
|
21
21
|
afterEach(() => {
|
|
22
|
-
cleanup();
|
|
23
22
|
jest.resetAllMocks();
|
|
24
23
|
});
|
|
25
24
|
|