@jobber/components-native 0.30.0 → 0.31.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.
Files changed (71) hide show
  1. package/README.md +3 -0
  2. package/dist/src/Select/Select.js +79 -0
  3. package/dist/src/Select/Select.style.js +45 -0
  4. package/dist/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.js +30 -0
  5. package/dist/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.js +16 -0
  6. package/dist/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.style.js +29 -0
  7. package/dist/src/Select/components/SelectDefaultPicker/index.js +1 -0
  8. package/dist/src/Select/components/SelectDefaultPicker/messages.js +8 -0
  9. package/dist/src/Select/components/SelectIOSPicker/SelectIOSPicker.js +2 -0
  10. package/dist/src/Select/components/SelectIOSPicker/index.js +1 -0
  11. package/dist/src/Select/components/SelectInternalPicker/SelectInternalPicker.js +14 -0
  12. package/dist/src/Select/components/SelectInternalPicker/index.js +1 -0
  13. package/dist/src/Select/components/SelectInternalPicker/utils.js +13 -0
  14. package/dist/src/Select/components/SelectPressable/SelectPressable.js +15 -0
  15. package/dist/src/Select/components/SelectPressable/SelectPressable.style.js +7 -0
  16. package/dist/src/Select/components/SelectPressable/index.js +1 -0
  17. package/dist/src/Select/index.js +1 -0
  18. package/dist/src/Select/messages.js +13 -0
  19. package/dist/src/Select/types.js +1 -0
  20. package/dist/src/index.js +1 -0
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/dist/types/src/Select/Select.d.ts +69 -0
  23. package/dist/types/src/Select/Select.style.d.ts +56 -0
  24. package/dist/types/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.d.ts +5 -0
  25. package/dist/types/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.d.ts +5 -0
  26. package/dist/types/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.style.d.ts +30 -0
  27. package/dist/types/src/Select/components/SelectDefaultPicker/index.d.ts +1 -0
  28. package/dist/types/src/Select/components/SelectDefaultPicker/messages.d.ts +7 -0
  29. package/dist/types/src/Select/components/SelectIOSPicker/SelectIOSPicker.d.ts +10 -0
  30. package/dist/types/src/Select/components/SelectIOSPicker/index.d.ts +1 -0
  31. package/dist/types/src/Select/components/SelectInternalPicker/SelectInternalPicker.d.ts +3 -0
  32. package/dist/types/src/Select/components/SelectInternalPicker/index.d.ts +1 -0
  33. package/dist/types/src/Select/components/SelectInternalPicker/utils.d.ts +3 -0
  34. package/dist/types/src/Select/components/SelectPressable/SelectPressable.d.ts +11 -0
  35. package/dist/types/src/Select/components/SelectPressable/SelectPressable.style.d.ts +5 -0
  36. package/dist/types/src/Select/components/SelectPressable/index.d.ts +1 -0
  37. package/dist/types/src/Select/index.d.ts +1 -0
  38. package/dist/types/src/Select/messages.d.ts +12 -0
  39. package/dist/types/src/Select/types.d.ts +38 -0
  40. package/dist/types/src/index.d.ts +1 -0
  41. package/ios/ComponentsNative-Bridging-Header.h +2 -0
  42. package/ios/ComponentsNative.xcodeproj/project.pbxproj +303 -0
  43. package/ios/Picker/ATLFallBackPickerView.swift +13 -0
  44. package/ios/Picker/ATLPickerOption.swift +44 -0
  45. package/ios/Picker/ATLPickerView.swift +61 -0
  46. package/ios/Picker/RCTATLPickerManager.m +26 -0
  47. package/ios/Picker/RCTATLPickerManager.swift +25 -0
  48. package/jobber-components-native.podspec +35 -0
  49. package/package.json +18 -3
  50. package/src/Select/Select.style.ts +51 -0
  51. package/src/Select/Select.test.tsx +323 -0
  52. package/src/Select/Select.tsx +240 -0
  53. package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.tsx +64 -0
  54. package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.style.ts +30 -0
  55. package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.test.tsx +76 -0
  56. package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.tsx +45 -0
  57. package/src/Select/components/SelectDefaultPicker/index.ts +1 -0
  58. package/src/Select/components/SelectDefaultPicker/messages.ts +9 -0
  59. package/src/Select/components/SelectIOSPicker/SelectIOSPicker.tsx +16 -0
  60. package/src/Select/components/SelectIOSPicker/index.ts +1 -0
  61. package/src/Select/components/SelectInternalPicker/SelectInternalPicker.test.tsx +100 -0
  62. package/src/Select/components/SelectInternalPicker/SelectInternalPicker.tsx +33 -0
  63. package/src/Select/components/SelectInternalPicker/index.ts +1 -0
  64. package/src/Select/components/SelectInternalPicker/utils.ts +20 -0
  65. package/src/Select/components/SelectPressable/SelectPressable.style.ts +8 -0
  66. package/src/Select/components/SelectPressable/SelectPressable.tsx +32 -0
  67. package/src/Select/components/SelectPressable/index.ts +1 -0
  68. package/src/Select/index.ts +1 -0
  69. package/src/Select/messages.ts +14 -0
  70. package/src/Select/types.ts +46 -0
  71. package/src/index.ts +1 -0
@@ -0,0 +1,61 @@
1
+ //
2
+ // PickerView.swift
3
+ // @jobber/components-native
4
+ //
5
+ // Created by Darryl Tec on 2022-07-21.
6
+ // Copyright © 2022 Octopusapp Inc. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+
11
+ import UIKit
12
+ @available(iOS 14.0, *)
13
+ @objc(ATLPickerView)
14
+ class ATLPickerView: UIButton {
15
+ override init(frame: CGRect) {
16
+ super.init(frame: frame)
17
+ }
18
+ private var _hasSelectedValue: Bool = false;
19
+ private var _options: [UIAction] = [];
20
+
21
+ @objc var onOptionPress: RCTDirectEventBlock?
22
+ @objc func sendButtonAction(_ action: UIAction) {
23
+ if let onPress = onOptionPress {
24
+ onPress(["event": action.identifier.rawValue])
25
+ }
26
+ }
27
+
28
+ @objc var options: [NSDictionary]? {
29
+ didSet {
30
+ guard let options = self.options else {
31
+ return
32
+ }
33
+ _options.removeAll()
34
+ options.forEach { menuAction in
35
+ let opt = ATLPickerOption(details: menuAction)
36
+ _hasSelectedValue = opt.isActive
37
+ _options.append(opt.createUIAction({action in self.sendButtonAction(action)}))
38
+ }
39
+ self.setup()
40
+ }
41
+ }
42
+
43
+ func setup () {
44
+ let menu = UIMenu(title: "", identifier: nil, options: .displayInline, children: _options)
45
+
46
+ self.menu = menu
47
+ self.showsMenuAsPrimaryAction = true
48
+ if #available(iOS 15.0, *) {
49
+ self.setTitleColor(UIColor.clear, for: .normal)
50
+ self.changesSelectionAsPrimaryAction = true
51
+ }
52
+ }
53
+
54
+ override func reactSetFrame(_ frame: CGRect) {
55
+ super.reactSetFrame(frame);
56
+ };
57
+
58
+ required init?(coder aDecoder: NSCoder) {
59
+ fatalError("init(coder:) has not been implemented")
60
+ }
61
+ }
@@ -0,0 +1,26 @@
1
+ //
2
+ // RCTPickerManager.m
3
+ // Jobber
4
+ //
5
+ // Created by Darryl Tec on 2022-07-21.
6
+ // Copyright © 2022 Octopusapp Inc. All rights reserved.
7
+ //
8
+
9
+ #import <Foundation/Foundation.h>
10
+
11
+ #import <React/RCTBridgeModule.h>
12
+ #import <React/RCTViewManager.h>
13
+
14
+ @interface RCT_EXTERN_MODULE(RCTATLPicker, RCTViewManager)
15
+
16
+ /**
17
+ * Options the user can choose
18
+ */
19
+ RCT_EXPORT_VIEW_PROPERTY(options, NSArray)
20
+
21
+ /**
22
+ * Callback when one of the option is pressed
23
+ */
24
+ RCT_EXPORT_VIEW_PROPERTY(onOptionPress, RCTDirectEventBlock)
25
+
26
+ @end
@@ -0,0 +1,25 @@
1
+ //
2
+ // RCTPickerManager.swift
3
+ // @jobber/components-native
4
+ //
5
+ // Created by Darryl Tec on 2022-07-21.
6
+ // Copyright © 2022 Octopusapp Inc. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+
11
+ @objc(RCTATLPicker)
12
+ class RCTATLPickerManager: RCTViewManager {
13
+
14
+ override static func requiresMainQueueSetup() -> Bool {
15
+ return true
16
+ }
17
+
18
+ override func view() -> UIView! {
19
+ if #available(iOS 14.0, *) {
20
+ return ATLPickerView();
21
+ } else {
22
+ return ATLFallBackPickerView()
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,35 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = "jobber-components-native"
8
+ s.version = package["version"]
9
+ s.summary = package["description"]
10
+ s.homepage = package["homepage"]
11
+ s.license = package["license"]
12
+ s.authors = package["author"]
13
+
14
+ s.platforms = { :ios => "11.0" }
15
+ s.source = { :git => "https://github.com/MichaelParadis/jobber-components-native.git", :tag => "#{s.version}" }
16
+
17
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
18
+
19
+ s.dependency "React-Core"
20
+
21
+ # Don't install the dependencies when we run `pod install` in the old architecture.
22
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
23
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
24
+ s.pod_target_xcconfig = {
25
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
26
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
27
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
28
+ }
29
+ s.dependency "React-Codegen"
30
+ s.dependency "RCT-Folly"
31
+ s.dependency "RCTRequired"
32
+ s.dependency "RCTTypeSafety"
33
+ s.dependency "ReactCommon/turbomodule/core"
34
+ end
35
+ end
package/package.json CHANGED
@@ -1,7 +1,17 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "license": "MIT",
5
+ "description": "React Native implementation of Atlantis",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/GetJobber/atlantis.git"
9
+ },
10
+ "author": "The Frends",
11
+ "bugs": {
12
+ "url": "https://github.com/GetJobber/atlantis/issues"
13
+ },
14
+ "homepage": "https://github.com/GetJobber/atlantis#readme",
5
15
  "main": "dist/src/index.js",
6
16
  "module": "dist/src/index.js",
7
17
  "types": "dist/types/src/index.d.ts",
@@ -10,7 +20,11 @@
10
20
  "src",
11
21
  "!**/__tests__",
12
22
  "!**/__fixtures__",
13
- "!**/__mocks__"
23
+ "!**/__mocks__",
24
+ "ios",
25
+ "cpp",
26
+ "*.podspec",
27
+ "!ios/build"
14
28
  ],
15
29
  "scripts": {
16
30
  "clean": "rm -rf dist/* tsconfig.tsbuildinfo",
@@ -22,6 +36,7 @@
22
36
  },
23
37
  "dependencies": {
24
38
  "@jobber/design": "^0.41.3",
39
+ "@react-native-picker/picker": "^2.4.10",
25
40
  "lodash.chunk": "^4.2.0",
26
41
  "lodash.debounce": "^4.0.8",
27
42
  "lodash.identity": "^3.0.0",
@@ -57,5 +72,5 @@
57
72
  "react": "^18",
58
73
  "react-native": ">=0.69.2"
59
74
  },
60
- "gitHead": "362d0d3914aa440bcbb40f9eed388d447cd205e0"
75
+ "gitHead": "af99db94db46063487cedd6ddb3200674c9ce8e9"
61
76
  }
@@ -0,0 +1,51 @@
1
+ import { StyleSheet } from "react-native";
2
+ import { commonInputStyles } from "../InputFieldWrapper";
3
+ import { tokens } from "../utils/design";
4
+
5
+ export const styles = StyleSheet.create({
6
+ container: StyleSheet.flatten([
7
+ commonInputStyles.container,
8
+ {
9
+ flexDirection: "column",
10
+ justifyContent: "flex-end",
11
+ minHeight: tokens["space-largest"] + tokens["border-base"],
12
+ },
13
+ ]),
14
+
15
+ input: StyleSheet.flatten([
16
+ commonInputStyles.input,
17
+ {
18
+ flexDirection: "row",
19
+ flexGrow: 0,
20
+ paddingBottom: tokens["space-smaller"],
21
+ minHeight: 0,
22
+ minWidth: "100%",
23
+ },
24
+ ]),
25
+
26
+ value: {
27
+ flexGrow: 1,
28
+ flexShrink: 1,
29
+ },
30
+
31
+ icon: {
32
+ flexGrow: 0,
33
+ flexShrink: 0,
34
+ },
35
+
36
+ invalid: {
37
+ color: tokens["color-critical"],
38
+ borderColor: tokens["color-critical"],
39
+ },
40
+
41
+ errorMessageWrapperIcon: {
42
+ flex: 0,
43
+ flexBasis: "auto",
44
+ paddingTop: tokens["space-minuscule"],
45
+ paddingRight: tokens["space-smaller"],
46
+ },
47
+ messageWrapper: {
48
+ paddingTop: tokens["space-smaller"],
49
+ flexDirection: "row",
50
+ },
51
+ });
@@ -0,0 +1,323 @@
1
+ import React from "react";
2
+ import {
3
+ RenderAPI,
4
+ cleanup,
5
+ fireEvent,
6
+ render,
7
+ } from "@testing-library/react-native";
8
+ import { tokens } from "@jobber/design/foundation";
9
+ import { AccessibilityInfo } from "react-native";
10
+ import { Option, Select } from ".";
11
+ import { messages } from "./messages";
12
+ import { SelectInternalPicker } from "./components/SelectInternalPicker";
13
+
14
+ const A11yInfoSpy = jest.spyOn(AccessibilityInfo, "isScreenReaderEnabled");
15
+
16
+ const onChange = jest.fn();
17
+
18
+ beforeEach(() => {
19
+ A11yInfoSpy.mockImplementation(() => Promise.resolve(false));
20
+ });
21
+
22
+ afterEach(() => {
23
+ cleanup();
24
+ jest.resetAllMocks();
25
+ });
26
+
27
+ describe("Select", () => {
28
+ it("renders a Select", () => {
29
+ const component = render(
30
+ <Select onChange={onChange}>
31
+ <Option value={"one"}>one</Option>
32
+ <Option value={"2"}>2</Option>
33
+ </Select>,
34
+ );
35
+ expect(component.getByTestId("arrowDown")).toBeDefined();
36
+ expect(
37
+ component.getByText(messages.emptyValue.defaultMessage, {
38
+ includeHiddenElements: true,
39
+ }),
40
+ ).toBeDefined();
41
+ });
42
+
43
+ it("renders a Select with a label", () => {
44
+ const label = "Press me";
45
+ const { getByText } = render(
46
+ <Select onChange={onChange} label={label}>
47
+ <Option value={"1"}>1</Option>
48
+ <Option value={"2"}>2</Option>
49
+ </Select>,
50
+ );
51
+
52
+ expect(getByText(label, { includeHiddenElements: true })).toBeDefined();
53
+ });
54
+
55
+ it("renders a Select with a placeholder", () => {
56
+ const placeholder = "I am a placeholder";
57
+ const { getByText } = render(
58
+ <Select onChange={onChange} placeholder={placeholder}>
59
+ <Option value={"1"}>1</Option>
60
+ <Option value={"2"}>2</Option>
61
+ </Select>,
62
+ );
63
+
64
+ expect(
65
+ getByText(placeholder, { includeHiddenElements: true }),
66
+ ).toBeDefined();
67
+ });
68
+
69
+ it("renders a Select with assistive text", () => {
70
+ const assistiveText = "You need to pick something";
71
+ const { getByText } = render(
72
+ <Select onChange={onChange} assistiveText={assistiveText}>
73
+ <Option value={"1"}>1</Option>
74
+ <Option value={"2"}>2</Option>
75
+ </Select>,
76
+ );
77
+ expect(
78
+ getByText(assistiveText, { includeHiddenElements: true }),
79
+ ).toBeDefined();
80
+ });
81
+
82
+ describe("when invalid", () => {
83
+ const labelText = "labelText";
84
+
85
+ it("renders an invalid Select", () => {
86
+ const { getByText } = render(
87
+ <Select onChange={onChange} invalid={true} label={labelText}>
88
+ <Option value={"1"}>1</Option>
89
+ <Option value={"2"}>2</Option>
90
+ </Select>,
91
+ );
92
+ expect(
93
+ getByText(labelText, { includeHiddenElements: true }).props.style,
94
+ ).toContainEqual({
95
+ color: tokens["color-critical"],
96
+ });
97
+ });
98
+
99
+ it("renders an invalid Select with placeholder", () => {
100
+ const placeholder = "Place me in the holder";
101
+ const { getByText } = render(
102
+ <Select
103
+ label={labelText}
104
+ onChange={onChange}
105
+ invalid={true}
106
+ placeholder={placeholder}
107
+ >
108
+ <Option value={"1"}>1</Option>
109
+ <Option value={"2"}>2</Option>
110
+ </Select>,
111
+ );
112
+
113
+ expect(
114
+ getByText(placeholder, { includeHiddenElements: true }),
115
+ ).toBeDefined();
116
+ expect(
117
+ getByText(labelText, { includeHiddenElements: true }).props.style,
118
+ ).toContainEqual({
119
+ color: tokens["color-critical"],
120
+ });
121
+ });
122
+ });
123
+
124
+ it("renders a disabled Select", () => {
125
+ const labelText = "labelText";
126
+ const { getByText } = render(
127
+ <Select label={labelText} onChange={onChange} disabled={true}>
128
+ <Option value={"1"}>1</Option>
129
+ <Option value={"2"}>2</Option>
130
+ </Select>,
131
+ );
132
+ expect(
133
+ getByText(labelText, { includeHiddenElements: true }).props.style,
134
+ ).toContainEqual({
135
+ color: tokens["color-disabled"],
136
+ });
137
+ });
138
+
139
+ it("renders a Select with a value provided", () => {
140
+ const expectedValue = "That should be me";
141
+ const { getByText } = render(
142
+ <Select onChange={onChange} value={"2"}>
143
+ <Option value={"1"}>1</Option>
144
+ <Option value={"2"}>{expectedValue}</Option>
145
+ </Select>,
146
+ );
147
+
148
+ expect(
149
+ getByText(expectedValue, { includeHiddenElements: true }),
150
+ ).toBeDefined();
151
+ });
152
+
153
+ it("renders a Select with a defaultValue provided", () => {
154
+ const expectedValue = "It's the 3rd value";
155
+ const { getByText } = render(
156
+ <Select onChange={onChange} defaultValue={"3"}>
157
+ <Option value={"1"}>1</Option>
158
+ <Option value={"2"}>2</Option>
159
+ <Option value={"3"}>{expectedValue}</Option>
160
+ </Select>,
161
+ );
162
+
163
+ expect(
164
+ getByText(expectedValue, { includeHiddenElements: true }),
165
+ ).toBeDefined();
166
+ });
167
+
168
+ describe("fires the onChange callback", () => {
169
+ it("fires", () => {
170
+ const { getByTestId } = render(
171
+ <Select onChange={onChange} value={"2"}>
172
+ <Option value={"1"}>1</Option>
173
+ <Option value={"2"}>2</Option>
174
+ </Select>,
175
+ );
176
+
177
+ const select = getByTestId("ATL-Select").findByType(SelectInternalPicker);
178
+ expect(select).toBeTruthy();
179
+ fireEvent(select, "onChange", "1");
180
+ expect(onChange).toHaveBeenCalledWith("1");
181
+ });
182
+ });
183
+
184
+ describe("Invalid value", () => {
185
+ it("renders with the empty value option", () => {
186
+ const { getByText } = render(
187
+ <Select onChange={onChange} value={"invalid"}>
188
+ <Option value={"first"}>first</Option>
189
+ <Option value={"2"}>2</Option>
190
+ </Select>,
191
+ );
192
+
193
+ expect(
194
+ getByText(messages.emptyValue.defaultMessage, {
195
+ includeHiddenElements: true,
196
+ }),
197
+ ).toBeDefined();
198
+ });
199
+
200
+ it("renders with the placeholder", () => {
201
+ const { getByText } = render(
202
+ <Select
203
+ onChange={onChange}
204
+ value={"invalid"}
205
+ placeholder={"Make a selection"}
206
+ >
207
+ <Option value={"1"}>1</Option>
208
+ <Option value={"2"}>2</Option>
209
+ </Select>,
210
+ );
211
+
212
+ expect(
213
+ getByText("Make a selection", { includeHiddenElements: true }),
214
+ ).toBeDefined();
215
+ });
216
+ });
217
+
218
+ describe("accessibilityLabel", () => {
219
+ it("uses accessibilityLabel if specified", () => {
220
+ const { getByLabelText } = render(
221
+ <Select
222
+ onChange={onChange}
223
+ label="label"
224
+ accessibilityLabel="accessibilityLabel"
225
+ >
226
+ <Option value={"1"}>1</Option>
227
+ <Option value={"2"}>2</Option>
228
+ </Select>,
229
+ );
230
+
231
+ expect(getByLabelText("accessibilityLabel")).toBeTruthy();
232
+ });
233
+ });
234
+
235
+ describe("when validations are passed to the component", () => {
236
+ describe("validations fail", () => {
237
+ let tree: RenderAPI;
238
+ const labelText = "labelText";
239
+ const errorMsg = "Too short";
240
+ beforeEach(() => {
241
+ tree = render(
242
+ <Select
243
+ label={labelText}
244
+ onChange={onChange}
245
+ value={"Watermelon"}
246
+ validations={{
247
+ minLength: { value: 60, message: errorMsg },
248
+ }}
249
+ >
250
+ <Option value={"Apple"}>Apple</Option>
251
+ <Option value={"Watermelon"}>Watermelon</Option>
252
+ </Select>,
253
+ );
254
+ });
255
+
256
+ it("renders the error message when there is an error", async () => {
257
+ const select = tree
258
+ .getByTestId("ATL-Select")
259
+ .findByType(SelectInternalPicker);
260
+ fireEvent(select, "onChange", "Apple");
261
+ expect(
262
+ await tree.findByText(errorMsg, { includeHiddenElements: true }),
263
+ ).toBeTruthy();
264
+ });
265
+
266
+ it("shows the invalid colours", async () => {
267
+ const select = tree
268
+ .getByTestId("ATL-Select")
269
+ .findByType(SelectInternalPicker);
270
+ fireEvent(select, "onChange", "Apple");
271
+ expect(
272
+ (await tree.findByText(labelText, { includeHiddenElements: true }))
273
+ .props.style,
274
+ ).toContainEqual({
275
+ color: tokens["color-critical"],
276
+ });
277
+ });
278
+ });
279
+
280
+ describe("validations passes", () => {
281
+ let tree: RenderAPI;
282
+ const labelText = "labelText";
283
+ const errorMsg = "Not too short";
284
+ beforeEach(() => {
285
+ tree = render(
286
+ <Select
287
+ label={labelText}
288
+ onChange={onChange}
289
+ value={"Watermelon"}
290
+ validations={{
291
+ minLength: { value: 4, message: errorMsg },
292
+ }}
293
+ >
294
+ <Option value={"Apple"}>Apple</Option>
295
+ <Option value={"Watermelon"}>Watermelon</Option>
296
+ </Select>,
297
+ );
298
+ });
299
+
300
+ it("does not render any error messages", () => {
301
+ const select = tree
302
+ .getByTestId("ATL-Select")
303
+ .findByType(SelectInternalPicker);
304
+ expect(select).toBeTruthy();
305
+ fireEvent(select, "onChange", "Apple");
306
+ expect(tree.queryByText(errorMsg)).toBeNull();
307
+ });
308
+
309
+ it("has non-critical colours", () => {
310
+ const select = tree
311
+ .getByTestId("ATL-Select")
312
+ .findByType(SelectInternalPicker);
313
+ fireEvent(select, "onChange", "Apple");
314
+ expect(
315
+ tree.getByText(labelText, { includeHiddenElements: true }).props
316
+ .style,
317
+ ).toContainEqual({
318
+ color: tokens["color-text--secondary"],
319
+ });
320
+ });
321
+ });
322
+ });
323
+ });