@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.
- package/README.md +3 -0
- package/dist/src/Select/Select.js +79 -0
- package/dist/src/Select/Select.style.js +45 -0
- package/dist/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.js +30 -0
- package/dist/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.js +16 -0
- package/dist/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.style.js +29 -0
- package/dist/src/Select/components/SelectDefaultPicker/index.js +1 -0
- package/dist/src/Select/components/SelectDefaultPicker/messages.js +8 -0
- package/dist/src/Select/components/SelectIOSPicker/SelectIOSPicker.js +2 -0
- package/dist/src/Select/components/SelectIOSPicker/index.js +1 -0
- package/dist/src/Select/components/SelectInternalPicker/SelectInternalPicker.js +14 -0
- package/dist/src/Select/components/SelectInternalPicker/index.js +1 -0
- package/dist/src/Select/components/SelectInternalPicker/utils.js +13 -0
- package/dist/src/Select/components/SelectPressable/SelectPressable.js +15 -0
- package/dist/src/Select/components/SelectPressable/SelectPressable.style.js +7 -0
- package/dist/src/Select/components/SelectPressable/index.js +1 -0
- package/dist/src/Select/index.js +1 -0
- package/dist/src/Select/messages.js +13 -0
- package/dist/src/Select/types.js +1 -0
- package/dist/src/index.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/Select/Select.d.ts +69 -0
- package/dist/types/src/Select/Select.style.d.ts +56 -0
- package/dist/types/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.d.ts +5 -0
- package/dist/types/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.d.ts +5 -0
- package/dist/types/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.style.d.ts +30 -0
- package/dist/types/src/Select/components/SelectDefaultPicker/index.d.ts +1 -0
- package/dist/types/src/Select/components/SelectDefaultPicker/messages.d.ts +7 -0
- package/dist/types/src/Select/components/SelectIOSPicker/SelectIOSPicker.d.ts +10 -0
- package/dist/types/src/Select/components/SelectIOSPicker/index.d.ts +1 -0
- package/dist/types/src/Select/components/SelectInternalPicker/SelectInternalPicker.d.ts +3 -0
- package/dist/types/src/Select/components/SelectInternalPicker/index.d.ts +1 -0
- package/dist/types/src/Select/components/SelectInternalPicker/utils.d.ts +3 -0
- package/dist/types/src/Select/components/SelectPressable/SelectPressable.d.ts +11 -0
- package/dist/types/src/Select/components/SelectPressable/SelectPressable.style.d.ts +5 -0
- package/dist/types/src/Select/components/SelectPressable/index.d.ts +1 -0
- package/dist/types/src/Select/index.d.ts +1 -0
- package/dist/types/src/Select/messages.d.ts +12 -0
- package/dist/types/src/Select/types.d.ts +38 -0
- package/dist/types/src/index.d.ts +1 -0
- package/ios/ComponentsNative-Bridging-Header.h +2 -0
- package/ios/ComponentsNative.xcodeproj/project.pbxproj +303 -0
- package/ios/Picker/ATLFallBackPickerView.swift +13 -0
- package/ios/Picker/ATLPickerOption.swift +44 -0
- package/ios/Picker/ATLPickerView.swift +61 -0
- package/ios/Picker/RCTATLPickerManager.m +26 -0
- package/ios/Picker/RCTATLPickerManager.swift +25 -0
- package/jobber-components-native.podspec +35 -0
- package/package.json +18 -3
- package/src/Select/Select.style.ts +51 -0
- package/src/Select/Select.test.tsx +323 -0
- package/src/Select/Select.tsx +240 -0
- package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.tsx +64 -0
- package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.style.ts +30 -0
- package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.test.tsx +76 -0
- package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.tsx +45 -0
- package/src/Select/components/SelectDefaultPicker/index.ts +1 -0
- package/src/Select/components/SelectDefaultPicker/messages.ts +9 -0
- package/src/Select/components/SelectIOSPicker/SelectIOSPicker.tsx +16 -0
- package/src/Select/components/SelectIOSPicker/index.ts +1 -0
- package/src/Select/components/SelectInternalPicker/SelectInternalPicker.test.tsx +100 -0
- package/src/Select/components/SelectInternalPicker/SelectInternalPicker.tsx +33 -0
- package/src/Select/components/SelectInternalPicker/index.ts +1 -0
- package/src/Select/components/SelectInternalPicker/utils.ts +20 -0
- package/src/Select/components/SelectPressable/SelectPressable.style.ts +8 -0
- package/src/Select/components/SelectPressable/SelectPressable.tsx +32 -0
- package/src/Select/components/SelectPressable/index.ts +1 -0
- package/src/Select/index.ts +1 -0
- package/src/Select/messages.ts +14 -0
- package/src/Select/types.ts +46 -0
- 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.
|
|
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": "
|
|
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
|
+
});
|