Skip to content

Commit 22d7575

Browse files
authored
Add SecureField introspection (#317)
1 parent b94da69 commit 22d7575

File tree

5 files changed

+181
-0
lines changed

5 files changed

+181
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ Changelog
33

44
## master
55

6+
- Added: `SecureField` introspection (#317)
7+
68
## [0.9.2]
79

810
- Fixed: occasionally wrong status bar style (#313)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ Introspection
118118
- [`ProgressView` with `.linear` style](https://swiftpackageindex.com/siteline/swiftui-introspect/master/documentation/swiftuiintrospect/progressviewwithlinearstyletype)
119119
- [`ScrollView`](https://swiftpackageindex.com/siteline/swiftui-introspect/master/documentation/swiftuiintrospect/scrollviewtype)
120120
- [`.searchable`](https://swiftpackageindex.com/siteline/swiftui-introspect/master/documentation/swiftuiintrospect/searchfieldtype)
121+
- [`SecureField`](https://swiftpackageindex.com/siteline/swiftui-introspect/master/documentation/swiftuiintrospect/securefieldtype)
121122
- [`.sheet`](https://swiftpackageindex.com/siteline/swiftui-introspect/master/documentation/swiftuiintrospect/sheettype)
122123
- [`SignInWithAppleButton`](https://swiftpackageindex.com/siteline/swiftui-introspect/master/documentation/swiftuiintrospect/SignInWithAppleButtonType)
123124
- [`Slider`](https://swiftpackageindex.com/siteline/swiftui-introspect/master/documentation/swiftuiintrospect/slidertype)
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import SwiftUI
2+
3+
/// An abstract representation of the `SecureField` type in SwiftUI.
4+
///
5+
/// ### iOS
6+
///
7+
/// ```swift
8+
/// struct ContentView: View {
9+
/// @State var text = "Lorem ipsum"
10+
///
11+
/// var body: some View {
12+
/// SecureField("Secure Field", text: $text)
13+
/// .introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17)) {
14+
/// print(type(of: $0)) // UISecureField
15+
/// }
16+
/// }
17+
/// }
18+
/// ```
19+
///
20+
/// ### tvOS
21+
///
22+
/// ```swift
23+
/// struct ContentView: View {
24+
/// @State var text = "Lorem ipsum"
25+
///
26+
/// var body: some View {
27+
/// SecureField("Secure Field", text: $text)
28+
/// .introspect(.secureField, on: .tvOS(.v13, .v14, .v15, .v16, .v17)) {
29+
/// print(type(of: $0)) // UISecureField
30+
/// }
31+
/// }
32+
/// }
33+
/// ```
34+
///
35+
/// ### macOS
36+
///
37+
/// ```swift
38+
/// struct ContentView: View {
39+
/// @State var text = "Lorem ipsum"
40+
///
41+
/// var body: some View {
42+
/// SecureField("Secure Field", text: $text)
43+
/// .introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) {
44+
/// print(type(of: $0)) // NSSecureField
45+
/// }
46+
/// }
47+
/// }
48+
/// ```
49+
public struct SecureFieldType: IntrospectableViewType {}
50+
51+
extension IntrospectableViewType where Self == SecureFieldType {
52+
public static var secureField: Self { .init() }
53+
}
54+
55+
#if canImport(UIKit)
56+
extension iOSViewVersion<SecureFieldType, UITextField> {
57+
public static let v13 = Self(for: .v13)
58+
public static let v14 = Self(for: .v14)
59+
public static let v15 = Self(for: .v15)
60+
public static let v16 = Self(for: .v16)
61+
public static let v17 = Self(for: .v17)
62+
}
63+
64+
extension tvOSViewVersion<SecureFieldType, UITextField> {
65+
public static let v13 = Self(for: .v13)
66+
public static let v14 = Self(for: .v14)
67+
public static let v15 = Self(for: .v15)
68+
public static let v16 = Self(for: .v16)
69+
public static let v17 = Self(for: .v17)
70+
}
71+
#elseif canImport(AppKit)
72+
extension macOSViewVersion<SecureFieldType, NSTextField> {
73+
public static let v10_15 = Self(for: .v10_15)
74+
public static let v11 = Self(for: .v11)
75+
public static let v12 = Self(for: .v12)
76+
public static let v13 = Self(for: .v13)
77+
public static let v14 = Self(for: .v14)
78+
}
79+
#endif

Tests/Tests.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
D575069E2A27F80E00A628E4 /* ProgressViewWithLinearStyleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D575069D2A27F80E00A628E4 /* ProgressViewWithLinearStyleTests.swift */; };
8282
D57506A02A27FC0400A628E4 /* TableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D575069F2A27FC0400A628E4 /* TableTests.swift */; };
8383
D57506A22A281B9C00A628E4 /* SearchFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57506A12A281B9C00A628E4 /* SearchFieldTests.swift */; };
84+
D57E66FA2A6956EB0092F43E /* SecureFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57E66F92A6956EB0092F43E /* SecureFieldTests.swift */; };
8485
D58119C42A211B8A0081F853 /* ListCellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58119C32A211B8A0081F853 /* ListCellTests.swift */; };
8586
D58119C62A227E930081F853 /* ViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58119C52A227E930081F853 /* ViewTests.swift */; };
8687
D58119C82A22AC130081F853 /* ToggleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58119C72A22AC130081F853 /* ToggleTests.swift */; };
@@ -187,6 +188,7 @@
187188
D575069D2A27F80E00A628E4 /* ProgressViewWithLinearStyleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressViewWithLinearStyleTests.swift; sourceTree = "<group>"; };
188189
D575069F2A27FC0400A628E4 /* TableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableTests.swift; sourceTree = "<group>"; };
189190
D57506A12A281B9C00A628E4 /* SearchFieldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchFieldTests.swift; sourceTree = "<group>"; };
191+
D57E66F92A6956EB0092F43E /* SecureFieldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureFieldTests.swift; sourceTree = "<group>"; };
190192
D58119C32A211B8A0081F853 /* ListCellTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListCellTests.swift; sourceTree = "<group>"; };
191193
D58119C52A227E930081F853 /* ViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewTests.swift; sourceTree = "<group>"; };
192194
D58119C72A22AC130081F853 /* ToggleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleTests.swift; sourceTree = "<group>"; };
@@ -384,6 +386,7 @@
384386
D575069D2A27F80E00A628E4 /* ProgressViewWithLinearStyleTests.swift */,
385387
D50FFE8D2A17E2A400C32641 /* ScrollViewTests.swift */,
386388
D57506A12A281B9C00A628E4 /* SearchFieldTests.swift */,
389+
D57E66F92A6956EB0092F43E /* SecureFieldTests.swift */,
387390
D5ADFACB2A4A22AE009494FD /* SheetTests.swift */,
388391
D5ADFAD12A4A41CB009494FD /* SignInWithAppleButtonTests.swift */,
389392
D58119CF2A23A62C0081F853 /* SliderTests.swift */,
@@ -784,6 +787,7 @@
784787
isa = PBXSourcesBuildPhase;
785788
buildActionMask = 2147483647;
786789
files = (
790+
D57E66FA2A6956EB0092F43E /* SecureFieldTests.swift in Sources */,
787791
D50FFE8E2A17E2A400C32641 /* ScrollViewTests.swift in Sources */,
788792
D58547F82A1CDD740068ADF4 /* NavigationStackTests.swift in Sources */,
789793
D57506982A27F32800A628E4 /* DatePickerWithGraphicalStyleTests.swift in Sources */,
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import SwiftUI
2+
import SwiftUIIntrospect
3+
import XCTest
4+
5+
final class SecureFieldTests: XCTestCase {
6+
#if canImport(UIKit)
7+
typealias PlatformSecureField = UITextField
8+
#elseif canImport(AppKit)
9+
typealias PlatformSecureField = NSTextField
10+
#endif
11+
12+
func testSecureField() {
13+
XCTAssertViewIntrospection(of: PlatformSecureField.self) { spies in
14+
let spy0 = spies[0]
15+
let spy1 = spies[1]
16+
let spy2 = spies[2]
17+
18+
VStack {
19+
SecureField("", text: .constant("Secure Field 0"))
20+
#if os(iOS) || os(tvOS)
21+
.introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17), customize: spy0)
22+
#elseif os(macOS)
23+
.introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy0)
24+
#endif
25+
.cornerRadius(8)
26+
27+
SecureField("", text: .constant("Secure Field 1"))
28+
#if os(iOS) || os(tvOS)
29+
.introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17), customize: spy1)
30+
#elseif os(macOS)
31+
.introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy1)
32+
#endif
33+
.cornerRadius(8)
34+
35+
SecureField("", text: .constant("Secure Field 2"))
36+
#if os(iOS) || os(tvOS)
37+
.introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17), customize: spy2)
38+
#elseif os(macOS)
39+
.introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy2)
40+
#endif
41+
}
42+
} extraAssertions: {
43+
#if canImport(UIKit)
44+
XCTAssertEqual($0[safe: 0]?.text, "Secure Field 0")
45+
XCTAssertEqual($0[safe: 1]?.text, "Secure Field 1")
46+
XCTAssertEqual($0[safe: 2]?.text, "Secure Field 2")
47+
#elseif canImport(AppKit)
48+
XCTAssertEqual($0[safe: 0]?.stringValue, "Secure Field 0")
49+
XCTAssertEqual($0[safe: 1]?.stringValue, "Secure Field 1")
50+
XCTAssertEqual($0[safe: 2]?.stringValue, "Secure Field 2")
51+
#endif
52+
}
53+
}
54+
55+
func testSecureFieldsEmbeddedInList() {
56+
XCTAssertViewIntrospection(of: PlatformSecureField.self) { spies in
57+
let spy0 = spies[0]
58+
let spy1 = spies[1]
59+
let spy2 = spies[2]
60+
61+
List {
62+
SecureField("", text: .constant("Secure Field 0"))
63+
#if os(iOS) || os(tvOS)
64+
.introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17), customize: spy0)
65+
#elseif os(macOS)
66+
.introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy0)
67+
#endif
68+
69+
SecureField("", text: .constant("Secure Field 1"))
70+
#if os(iOS) || os(tvOS)
71+
.introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17), customize: spy1)
72+
#elseif os(macOS)
73+
.introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy1)
74+
#endif
75+
76+
SecureField("", text: .constant("Secure Field 2"))
77+
#if os(iOS) || os(tvOS)
78+
.introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17), customize: spy2)
79+
#elseif os(macOS)
80+
.introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy2)
81+
#endif
82+
}
83+
} extraAssertions: {
84+
#if canImport(UIKit)
85+
XCTAssertEqual($0[safe: 0]?.text, "Secure Field 0")
86+
XCTAssertEqual($0[safe: 1]?.text, "Secure Field 1")
87+
XCTAssertEqual($0[safe: 2]?.text, "Secure Field 2")
88+
#elseif canImport(AppKit)
89+
XCTAssertEqual($0[safe: 0]?.stringValue, "Secure Field 0")
90+
XCTAssertEqual($0[safe: 1]?.stringValue, "Secure Field 1")
91+
XCTAssertEqual($0[safe: 2]?.stringValue, "Secure Field 2")
92+
#endif
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)