Skip to content

Commit 9071107

Browse files
committed
Migrate tests using Swift Testing
1 parent aa28507 commit 9071107

File tree

11 files changed

+3713
-3852
lines changed

11 files changed

+3713
-3852
lines changed

Package.resolved

Lines changed: 0 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ let package = Package(
1919
dependencies: [
2020
// Dependencies declare other packages that this package depends on.
2121
.package(url: "https://github.com/ra1028/swiftui-hooks", exact: "0.0.8"),
22-
.package(url: "https://github.com/Quick/Quick", from: "6.1.0"),
23-
.package(url: "https://github.com/Quick/Nimble", from: "11.2.1")
2422
],
2523
targets: [
2624
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
@@ -34,8 +32,6 @@ let package = Package(
3432
name: "FormHookTests",
3533
dependencies: [
3634
"FormHook",
37-
"Quick",
38-
"Nimble",
3935
.product(name: "Hooks", package: "swiftui-hooks")
4036
]),
4137
]

Sources/FormHook/FormTypes.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ public struct FormError<FieldName>: Equatable where FieldName: Hashable {
170170
}
171171

172172
/// Returns the array of strings associated with the given field name, if any exist.
173-
public subscript(_ name: FieldName) -> [String]? {
174-
messages[name]
173+
public subscript(_ name: FieldName) -> [String] {
174+
messages[name] ?? []
175175
}
176176

177177
/// Sets the given array of strings as the message for the given field name and updates its validity accordingly.
@@ -202,7 +202,11 @@ public struct FormError<FieldName>: Equatable where FieldName: Hashable {
202202
let errorFields = errorFields.union(other.errorFields)
203203
var newMessages = messages
204204
for (key, newValue) in other.messages {
205-
newMessages[key] = newValue
205+
if let existingValue = newMessages[key] {
206+
newMessages[key] = existingValue + newValue
207+
} else {
208+
newMessages[key] = newValue
209+
}
206210
}
207211
return Self(errorFields: errorFields, messages: newMessages)
208212
}
@@ -300,7 +304,7 @@ public struct FormState<FieldName>: Equatable where FieldName: Hashable {
300304
FieldState(
301305
isDirty: dirtyFields.contains(name),
302306
isInvalid: errors.errorFields.contains(name),
303-
error: errors[name] ?? []
307+
error: errors[name]
304308
)
305309
}
306310
}

Tests/FormHookTests/ContextualFormTests.swift

Lines changed: 95 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88
import Foundation
99
import SwiftUI
10-
import Quick
11-
import Nimble
10+
import Testing
1211
@preconcurrency @testable import FormHook
1312

1413
enum TestContextFieldName: Hashable {
@@ -17,98 +16,105 @@ enum TestContextFieldName: Hashable {
1716
case password
1817
}
1918

20-
final class ContextualFormTests: QuickSpec {
21-
override func spec() {
22-
contextualFormTypeSpecs()
19+
@Suite("ContextualForm")
20+
struct ContextualFormTests {
21+
22+
@Suite("Type definitions")
23+
struct TypeDefinitionTests {
24+
25+
@Test("has the correct structure")
26+
func hasCorrectStructure() {
27+
// Just test that the type exists and can be referenced
28+
let _: ContextualForm<Text, TestContextFieldName>.Type = ContextualForm<Text, TestContextFieldName>.self
29+
// Test passes by compilation
30+
}
31+
32+
@Test("supports different content types")
33+
func supportsDifferentContentTypes() {
34+
// Test generic type constraints work
35+
let _: ContextualForm<VStack<Text>, TestContextFieldName>.Type = ContextualForm<VStack<Text>, TestContextFieldName>.self
36+
let _: ContextualForm<AnyView, TestContextFieldName>.Type = ContextualForm<AnyView, TestContextFieldName>.self
37+
// Test passes by compilation
38+
}
39+
40+
@Test("enforces Hashable constraint on FieldName")
41+
func enforcesHashableConstraint() {
42+
// This test ensures that the FieldName generic is properly constrained
43+
// If TestContextFieldName didn't conform to Hashable, this wouldn't compile
44+
let _: ContextualForm<Text, TestContextFieldName>.Type = ContextualForm<Text, TestContextFieldName>.self
45+
// Test passes by compilation
46+
}
2347
}
2448

25-
func contextualFormTypeSpecs() {
26-
describe("ContextualForm") {
27-
context("type definitions") {
28-
it("has the correct structure") {
29-
// Just test that the type exists and can be referenced
30-
let _: ContextualForm<Text, TestContextFieldName>.Type = ContextualForm<Text, TestContextFieldName>.self
31-
expect(true) == true
32-
}
33-
34-
it("supports different content types") {
35-
// Test generic type constraints work
36-
let _: ContextualForm<VStack<Text>, TestContextFieldName>.Type = ContextualForm<VStack<Text>, TestContextFieldName>.self
37-
let _: ContextualForm<AnyView, TestContextFieldName>.Type = ContextualForm<AnyView, TestContextFieldName>.self
38-
expect(true) == true
39-
}
40-
41-
it("enforces Hashable constraint on FieldName") {
42-
// This test ensures that the FieldName generic is properly constrained
43-
// If TestContextFieldName didn't conform to Hashable, this wouldn't compile
44-
let _: ContextualForm<Text, TestContextFieldName>.Type = ContextualForm<Text, TestContextFieldName>.self
45-
expect(true) == true
46-
}
47-
}
49+
@Suite("Integration with form types")
50+
struct FormTypeIntegrationTests {
4851

49-
context("integration with form types") {
50-
it("works with FormControl type") {
51-
// Test that FormControl and ContextualForm use compatible types
52-
var formState = FormState<TestContextFieldName>()
53-
let options = FormOption<TestContextFieldName>(
54-
mode: .onSubmit,
55-
reValidateMode: .onChange,
56-
resolver: nil,
57-
context: nil,
58-
shouldUnregister: true,
59-
shouldFocusError: true,
60-
delayErrorInNanoseconds: 0,
61-
onFocusField: { _ in }
62-
)
63-
let formControl = FormControl(options: options, formState: .init(
64-
get: { formState },
65-
set: { formState = $0 }
66-
))
67-
68-
// Test that FormControl can work with the same field type
69-
_ = formControl.register(name: TestContextFieldName.username, options: .init(
70-
rules: NoopValidator<String>(),
71-
defaultValue: "test"
72-
))
73-
74-
expect(formControl.instantFormState.formValues[.username] as? String) == "test"
75-
}
76-
77-
it("supports resolver functions") {
78-
func testResolver(
79-
values: FormValue<TestContextFieldName>,
80-
context: Any?,
81-
fieldNames: [TestContextFieldName]
82-
) async -> Result<FormValue<TestContextFieldName>, FormError<TestContextFieldName>> {
83-
return .success(values)
84-
}
85-
86-
// Test that resolver type is compatible
87-
let _: Resolver<TestContextFieldName> = testResolver
88-
expect(true) == true
89-
}
90-
}
52+
@Test("works with FormControl type")
53+
func worksWithFormControlType() {
54+
// Test that FormControl and ContextualForm use compatible types
55+
var formState = FormState<TestContextFieldName>()
56+
let options = FormOption<TestContextFieldName>(
57+
mode: .onSubmit,
58+
reValidateMode: .onChange,
59+
resolver: nil,
60+
context: nil,
61+
shouldUnregister: true,
62+
shouldFocusError: true,
63+
delayErrorInNanoseconds: 0,
64+
onFocusField: { _ in }
65+
)
66+
let formControl = FormControl(options: options, formState: .init(
67+
get: { formState },
68+
set: { formState = $0 }
69+
))
9170

92-
context("error handling types") {
93-
it("works with FormError") {
94-
let error = FormError<TestContextFieldName>(
95-
errorFields: [.username],
96-
messages: [.username: ["Test error"]]
97-
)
98-
99-
expect(error.errorFields.contains(.username)) == true
100-
expect(error[.username]) == ["Test error"]
101-
}
102-
103-
it("supports FormValue operations") {
104-
var formValue: FormValue<TestContextFieldName> = [:]
105-
formValue[.username] = "test"
106-
formValue[.email] = "test@example.com"
107-
108-
expect(formValue[.username] as? String) == "test"
109-
expect(formValue[.email] as? String) == "test@example.com"
110-
}
71+
// Test that FormControl can work with the same field type
72+
_ = formControl.register(name: TestContextFieldName.username, options: .init(
73+
rules: NoopValidator<String>(),
74+
defaultValue: "test"
75+
))
76+
77+
#expect(formControl.instantFormState.formValues[.username] as? String == "test")
78+
}
79+
80+
@Test("supports resolver functions")
81+
func supportsResolverFunctions() {
82+
func testResolver(
83+
values: FormValue<TestContextFieldName>,
84+
context: Any?,
85+
fieldNames: [TestContextFieldName]
86+
) async -> Result<FormValue<TestContextFieldName>, FormError<TestContextFieldName>> {
87+
return .success(values)
11188
}
89+
90+
// Test that resolver type is compatible
91+
let _: Resolver<TestContextFieldName> = testResolver
92+
// Test passes by compilation
93+
}
94+
}
95+
96+
@Suite("Error handling types")
97+
struct ErrorHandlingTests {
98+
99+
@Test("works with FormError")
100+
func worksWithFormError() {
101+
let error = FormError<TestContextFieldName>(
102+
errorFields: [.username],
103+
messages: [.username: ["Test error"]]
104+
)
105+
106+
#expect(error.errorFields.contains(.username))
107+
#expect(error[.username] == ["Test error"])
108+
}
109+
110+
@Test("supports FormValue operations")
111+
func supportsFormValueOperations() {
112+
var formValue: FormValue<TestContextFieldName> = [:]
113+
formValue[.username] = "test"
114+
formValue[.email] = "test@example.com"
115+
116+
#expect(formValue[.username] as? String == "test")
117+
#expect(formValue[.email] as? String == "test@example.com")
112118
}
113119
}
114120
}

0 commit comments

Comments
 (0)