Skip to content

Commit 049612b

Browse files
authored
Add PlatformHostingControllerHelper to add NSHostingController test support (#321)
1 parent accc5df commit 049612b

File tree

11 files changed

+104
-105
lines changed

11 files changed

+104
-105
lines changed

Example/HostingExample/ViewController.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class ViewController: NSViewController {
6666

6767
struct ContentView: View {
6868
var body: some View {
69-
Color.red.frame(width: 10, height: 10)
69+
Color.red
70+
.frame(width: 200, height: 200)
7071
}
7172
}

Package.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,7 @@ if swiftCryptoCondition {
541541

542542
let compatibilityTestCondition = envEnable("OPENSWIFTUI_COMPATIBILITY_TEST")
543543
if compatibilityTestCondition {
544-
var swiftSettings: [SwiftSetting] = (openSwiftUICompatibilityTestTarget.swiftSettings ?? [])
545-
swiftSettings.append(.define("OPENSWIFTUI_COMPATIBILITY_TEST"))
546-
openSwiftUICompatibilityTestTarget.swiftSettings = swiftSettings
544+
sharedSwiftSettings.append(.define("OPENSWIFTUI_COMPATIBILITY_TEST"))
547545
} else {
548546
openSwiftUICompatibilityTestTarget.dependencies.append("OpenSwiftUI")
549547
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//
2+
// Export.swift
3+
// OpenSwiftUITestsSupport
4+
5+
#if OPENSWIFTUI_COMPATIBILITY_TEST
6+
@_exported import SwiftUI
7+
let compatibilityTestEnabled = true
8+
#else
9+
@_exported import OpenSwiftUI
10+
let compatibilityTestEnabled = false
11+
#endif
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// PlatformAlias.swift
3+
// OpenSwiftUITestsSupport
4+
5+
package import OpenSwiftUI
6+
#if os(iOS)
7+
package import UIKit
8+
package typealias PlatformViewController = UIViewController
9+
package typealias PlatformView = UIView
10+
package typealias PlatformViewControllerRepresentable = UIViewControllerRepresentable
11+
package typealias PlatformViewRepresentable = UIViewRepresentable
12+
package typealias PlatformHostingController = UIHostingController
13+
#elseif os(macOS)
14+
package import AppKit
15+
package typealias PlatformViewController = NSViewController
16+
package typealias PlatformView = NSView
17+
// package typealias PlatformViewControllerRepresentable = NSViewControllerRepresentable
18+
// package typealias PlatformViewRepresentable = NSViewRepresentable
19+
package typealias PlatformHostingController = NSHostingController
20+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// PlatformHostingControllerHelper.swift
3+
// OpenSwiftUITestsSupport
4+
5+
#if canImport(Darwin)
6+
#if os(iOS)
7+
import UIKit
8+
#elseif os(macOS)
9+
import AppKit
10+
#endif
11+
12+
extension PlatformHostingController {
13+
package func triggerLayout() {
14+
#if os(iOS)
15+
let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
16+
window.rootViewController = self
17+
window.makeKeyAndVisible()
18+
view.layoutSubviews()
19+
#else
20+
let window = NSWindow(
21+
contentRect: CGRect(x: 0, y: 0, width: 100, height: 100),
22+
styleMask: [.titled, .closable, .resizable],
23+
backing: .buffered,
24+
defer: false
25+
)
26+
window.contentViewController = self
27+
window.makeKeyAndOrderFront(nil)
28+
view.layout()
29+
#endif
30+
}
31+
}
32+
33+
// FIXME: A workaround to bypass the Issue #87
34+
package func workaroundIssue87(_ vc: PlatformViewController) {
35+
if compatibilityTestEnabled {
36+
return
37+
} else {
38+
// TODO: Use swift-test exist test feature to detect the crash instead or sliently workaroun it
39+
CrashWorkaround.shared.objects.append(vc)
40+
}
41+
}
42+
43+
private final class CrashWorkaround {
44+
private init() {}
45+
static let shared = CrashWorkaround()
46+
var objects: [Any?] = []
47+
}
48+
#endif

Tests/OpenSwiftUICompatibilityTests/Export.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Export.swift
33
// OpenSwiftUICompatibilityTests
44

5-
65
#if OPENSWIFTUI_COMPATIBILITY_TEST
76
@_exported import SwiftUI
87
let compatibilityTestEnabled = true

Tests/OpenSwiftUICompatibilityTests/SwiftUI/Integration/UIKit/UIHostingControllerTests.swift renamed to Tests/OpenSwiftUICompatibilityTests/SwiftUI/Integration/PlatformHostingControllerTests.swift

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
//
2-
// UIHostingControllerTests.swift
2+
// PlatformHostingControllerTests.swift
33
// OpenSwiftUICompatibilityTests
44

5-
#if os(iOS)
5+
#if canImport(Darwin)
66
import Testing
7-
import UIKit
7+
import OpenSwiftUITestsSupport
88

99
@MainActor
10-
struct UIHostingControllerTests {
10+
struct PlatformHostingControllerTests {
1111
@Test(
1212
.bug(
1313
"https://github.com/OpenSwiftUIProject/OpenGraph/issues/",
@@ -16,18 +16,12 @@ struct UIHostingControllerTests {
1616
)
1717
)
1818
func testBasicAnyView() throws {
19-
guard #unavailable(iOS 18) else {
20-
withKnownIssue {
21-
Issue.record("Known crash issue on iOS 18")
22-
}
23-
return
24-
}
2519
struct ContentView: View {
2620
var body: some View {
2721
AnyView(EmptyView())
2822
}
2923
}
30-
let vc = UIHostingController(rootView: ContentView())
24+
let vc = PlatformHostingController(rootView: ContentView())
3125
vc.triggerLayout()
3226
workaroundIssue87(vc)
3327
}
@@ -40,19 +34,13 @@ struct UIHostingControllerTests {
4034
)
4135
)
4236
func testBasicAnyViewWithProperty() throws {
43-
guard #unavailable(iOS 18) else {
44-
withKnownIssue {
45-
Issue.record("Known crash issue on iOS 18")
46-
}
47-
return
48-
}
4937
struct ContentView: View {
5038
var name = ""
5139
var body: some View {
5240
AnyView(EmptyView())
5341
}
5442
}
55-
let vc = UIHostingController(rootView: ContentView())
43+
let vc = PlatformHostingController(rootView: ContentView())
5644
vc.triggerLayout()
5745
workaroundIssue87(vc)
5846
}

Tests/OpenSwiftUICompatibilityTests/SwiftUI/Integration/UIKit/UIHostingController+Helper.swift

Lines changed: 0 additions & 33 deletions
This file was deleted.

Tests/OpenSwiftUICompatibilityTests/SwiftUI/View/Debug/ChangedBodyPropertyTests.swift

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
#if canImport(Darwin) && !OPENSWIFTUI_SWIFT_LOG
66
import Testing
77
import OSLog
8-
9-
#if os(iOS)
10-
import UIKit
11-
#endif
8+
import OpenSwiftUITestsSupport
129

1310
@MainActor
1411
struct ChangedBodyPropertyTests {
@@ -35,24 +32,16 @@ struct ChangedBodyPropertyTests {
3532
#endif
3633
@Test
3734
func zeroPropertyView() throws {
38-
guard #unavailable(iOS 18) else {
39-
withKnownIssue {
40-
Issue.record("Known crash issue on iOS 18")
41-
}
42-
return
43-
}
4435
struct ContentView: View {
4536
var body: some View {
4637
let _ = Self._logChanges()
4738
AnyView(EmptyView())
4839
}
4940
}
50-
#if os(iOS)
51-
let vc = UIHostingController(rootView: ContentView())
41+
let vc = PlatformHostingController(rootView: ContentView())
5242
vc.triggerLayout()
5343
workaroundIssue87(vc)
5444
try verifyLog(expected: "ChangedBodyPropertyTests.ContentView: @self changed.")
55-
#endif
5645
}
5746

5847
#if OPENSWIFTUI_COMPATIBILITY_TEST
@@ -62,25 +51,17 @@ struct ChangedBodyPropertyTests {
6251
#endif
6352
@Test
6453
func propertyView() throws {
65-
guard #unavailable(iOS 18) else {
66-
withKnownIssue {
67-
Issue.record("Known crash issue on iOS 18")
68-
}
69-
return
70-
}
7154
struct ContentView: View {
7255
var name = ""
7356
var body: some View {
7457
let _ = Self._logChanges()
7558
AnyView(EmptyView())
7659
}
7760
}
78-
#if os(iOS)
79-
let vc = UIHostingController(rootView: ContentView())
61+
let vc = PlatformHostingController(rootView: ContentView())
8062
vc.triggerLayout()
8163
workaroundIssue87(vc)
8264
try verifyLog(expected: "ChangedBodyPropertyTests.ContentView: @self changed.")
83-
#endif
8465
}
8566

8667
#if OPENSWIFTUI_COMPATIBILITY_TEST
@@ -90,25 +71,17 @@ struct ChangedBodyPropertyTests {
9071
#endif
9172
@Test
9273
func statePropertyView() throws {
93-
guard #unavailable(iOS 18) else {
94-
withKnownIssue {
95-
Issue.record("Known crash issue on iOS 18")
96-
}
97-
return
98-
}
9974
struct ContentView: View {
10075
@State var name = ""
10176
var body: some View {
10277
let _ = Self._logChanges()
10378
AnyView(EmptyView())
10479
}
10580
}
106-
#if os(iOS)
107-
let vc = UIHostingController(rootView: ContentView())
81+
let vc = PlatformHostingController(rootView: ContentView())
10882
vc.triggerLayout()
10983
workaroundIssue87(vc)
11084
try verifyLog(expected: "ChangedBodyPropertyTests.ContentView: @self, @identity, _name changed.")
111-
#endif
11285
}
11386
}
11487
#endif

Tests/OpenSwiftUICompatibilityTests/SwiftUICore/Data/State/StateTests.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// OpenSwiftUICompatibilityTests
44

55
import Testing
6+
import OpenSwiftUITestsSupport
67

78
#if canImport(Darwin)
89
struct StateTests {
@@ -23,16 +24,11 @@ struct StateTests {
2324
}
2425
}
2526
}
26-
27-
#if os(iOS)
2827
await confirmation { @MainActor confirmation in
29-
let vc = UIHostingController(rootView: ContentView(confirmation: confirmation))
28+
let vc = PlatformHostingController(rootView: ContentView(confirmation: confirmation))
3029
vc.triggerLayout()
3130
workaroundIssue87(vc)
3231
}
33-
#endif
3432
}
35-
36-
// TODO: Add disappear support and test case
3733
}
3834
#endif

Tests/OpenSwiftUICompatibilityTests/SwiftUICore/Modifier/ViewModifier/AppearanceActionModifierTests.swift

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
import Testing
77

88
import Foundation
9-
#if os(iOS)
10-
import UIKit
11-
#endif
9+
import OpenSwiftUITestsSupport
1210

1311
@MainActor
1412
struct AppearanceActionModifierTests {
@@ -24,14 +22,11 @@ struct AppearanceActionModifierTests {
2422
}
2523
}
2624
}
27-
28-
#if os(iOS)
2925
await confirmation { @MainActor confirmation in
30-
let vc = UIHostingController(rootView: ContentView(confirmation: confirmation))
26+
let vc = PlatformHostingController(rootView: ContentView(confirmation: confirmation))
3127
vc.triggerLayout()
3228
workaroundIssue87(vc)
3329
}
34-
#endif
3530
}
3631

3732
@Test
@@ -48,7 +43,7 @@ struct AppearanceActionModifierTests {
4843
Color.red
4944
.onAppear {
5045
Helper.result += "A"
51-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
46+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
5247
toggle.toggle()
5348
}
5449
}
@@ -58,13 +53,16 @@ struct AppearanceActionModifierTests {
5853
.id(toggle)
5954
}
6055
}
61-
#if os(iOS)
62-
let vc = UIHostingController(rootView: ContentView())
56+
let vc = PlatformHostingController(rootView: ContentView())
6357
vc.triggerLayout()
6458
workaroundIssue87(vc)
65-
try await Task.sleep(nanoseconds: 1 * 1_000_000_000)
59+
#expect(Helper.result.hasPrefix("A"))
60+
var timeout = 5
61+
while !Helper.result.hasPrefix("AAD") && timeout > 0{
62+
try await Task.sleep(for: .seconds(1))
63+
timeout -= 1
64+
}
6665
#expect(Helper.result.hasPrefix("AAD"))
67-
#endif
6866
}
6967
}
7068
#endif

0 commit comments

Comments
 (0)