@thelacanians/vue-native-cli 0.4.15 → 0.6.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 (116) hide show
  1. package/dist/cli.js +329 -15
  2. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +118 -0
  3. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +178 -1
  4. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeneratedModuleRegistry.kt +28 -0
  5. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +3 -0
  6. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ComponentFactoryTest.kt +674 -0
  7. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ErrorOverlayViewTest.kt +183 -0
  8. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/EventThrottleTest.kt +203 -0
  9. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/HotReloadManagerTest.kt +162 -0
  10. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/JSPolyfillsTest.kt +153 -0
  11. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeBridgeTest.kt +6 -3
  12. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeModuleTest.kt +475 -0
  13. package/native/android/gradle.properties +1 -0
  14. package/native/android/gradlew +1 -1
  15. package/native/ios/VueNativeCore/Package.swift +1 -1
  16. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/EventThrottle.swift +1 -0
  17. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +143 -5
  18. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +43 -0
  19. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +116 -4
  20. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +100 -0
  21. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeneratedModuleRegistry.swift +28 -0
  22. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +3 -0
  23. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/CertificatePinningTests.swift +190 -0
  24. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/ComponentFactoryTests.swift +585 -0
  25. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/EventThrottleTests.swift +161 -0
  26. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/HotReloadManagerTests.swift +88 -0
  27. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSPolyfillsTests.swift +319 -0
  28. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/NativeModuleTests.swift +400 -0
  29. package/native/macos/VueNativeMacOS/Package.swift +34 -0
  30. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/ErrorOverlayView.swift +112 -0
  31. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/EventThrottle.swift +58 -0
  32. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/HotReloadManager.swift +153 -0
  33. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSPolyfills.swift +696 -0
  34. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSRuntime.swift +347 -0
  35. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/NativeBridge.swift +877 -0
  36. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/VueNativeWindowController.swift +125 -0
  37. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/ComponentRegistry.swift +209 -0
  38. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActionSheetFactory.swift +155 -0
  39. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActivityIndicatorFactory.swift +85 -0
  40. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VAlertDialogFactory.swift +132 -0
  41. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VButtonFactory.swift +83 -0
  42. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VCheckboxFactory.swift +108 -0
  43. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VDropdownFactory.swift +155 -0
  44. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VImageFactory.swift +270 -0
  45. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VInputFactory.swift +257 -0
  46. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VKeyboardAvoidingFactory.swift +22 -0
  47. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VListFactory.swift +324 -0
  48. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VModalFactory.swift +231 -0
  49. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VOutlineViewFactory.swift +276 -0
  50. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPickerFactory.swift +134 -0
  51. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPressableFactory.swift +120 -0
  52. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VProgressBarFactory.swift +71 -0
  53. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRadioFactory.swift +193 -0
  54. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRefreshControlFactory.swift +25 -0
  55. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSafeAreaFactory.swift +46 -0
  56. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VScrollViewFactory.swift +190 -0
  57. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSectionListFactory.swift +374 -0
  58. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSegmentedControlFactory.swift +125 -0
  59. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSliderFactory.swift +131 -0
  60. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSplitViewFactory.swift +215 -0
  61. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VStatusBarFactory.swift +25 -0
  62. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSwitchFactory.swift +92 -0
  63. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VTextFactory.swift +336 -0
  64. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VToolbarFactory.swift +212 -0
  65. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VVideoFactory.swift +245 -0
  66. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VViewFactory.swift +314 -0
  67. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VWebViewFactory.swift +162 -0
  68. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/NativeComponentFactory.swift +54 -0
  69. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/ClickableView.swift +100 -0
  70. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/Extensions.swift +23 -0
  71. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/GestureWrapper.swift +183 -0
  72. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/NSColor+Hex.swift +78 -0
  73. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/FlippedView.swift +19 -0
  74. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/LayoutNode.swift +493 -0
  75. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AnimationModule.swift +354 -0
  76. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AppStateModule.swift +62 -0
  77. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/BiometryModule.swift +60 -0
  78. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/CameraModule.swift +167 -0
  79. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ClipboardModule.swift +34 -0
  80. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DeviceInfoModule.swift +49 -0
  81. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DragDropModule.swift +50 -0
  82. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/FileDialogModule.swift +86 -0
  83. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/HapticsModule.swift +42 -0
  84. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/KeyboardModule.swift +28 -0
  85. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/LinkingModule.swift +49 -0
  86. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/MenuModule.swift +95 -0
  87. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NativeModuleRegistry.swift +63 -0
  88. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NotificationsModule.swift +112 -0
  89. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/PermissionsModule.swift +149 -0
  90. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ShareModule.swift +37 -0
  91. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/WindowModule.swift +71 -0
  92. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Resources/vue-native-placeholder.js +2 -0
  93. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Styling/StyleEngine.swift +885 -0
  94. package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/ComponentFactoryTests.swift +80 -0
  95. package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/VueNativeMacOSTests.swift +149 -0
  96. package/native/shared/VueNativeShared/AGENTS.md +129 -0
  97. package/native/shared/VueNativeShared/Package.swift +14 -0
  98. package/native/shared/VueNativeShared/Sources/VueNativeShared/CertificatePinning.swift +134 -0
  99. package/native/shared/VueNativeShared/Sources/VueNativeShared/EventThrottle.swift +78 -0
  100. package/native/shared/VueNativeShared/Sources/VueNativeShared/HotReloadManager.swift +162 -0
  101. package/native/shared/VueNativeShared/Sources/VueNativeShared/JSRuntime.swift +412 -0
  102. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AsyncStorageModule.swift +68 -0
  103. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AudioModule.swift +359 -0
  104. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/DatabaseModule.swift +259 -0
  105. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/FileSystemModule.swift +233 -0
  106. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/GeolocationModule.swift +156 -0
  107. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/NetworkModule.swift +59 -0
  108. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/PerformanceModule.swift +113 -0
  109. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/SecureStorageModule.swift +119 -0
  110. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/WebSocketModule.swift +212 -0
  111. package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeEventDispatcher.swift +6 -0
  112. package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModule.swift +26 -0
  113. package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModuleRegistry.swift +37 -0
  114. package/native/shared/VueNativeShared/Sources/VueNativeShared/SharedJSPolyfills.swift +673 -0
  115. package/native/shared/VueNativeShared/Tests/VueNativeSharedTests/VueNativeSharedTests.swift +44 -0
  116. package/package.json +8 -2
@@ -0,0 +1,161 @@
1
+ #if canImport(UIKit)
2
+ import XCTest
3
+ import UIKit
4
+ @testable import VueNativeCore
5
+
6
+ @MainActor
7
+ final class EventThrottleTests: XCTestCase {
8
+
9
+ // MARK: - Initialization
10
+
11
+ func testInitializationWithDefaultInterval() {
12
+ let throttle = EventThrottle { _ in }
13
+ XCTAssertEqual(throttle.interval, 0.016, accuracy: 0.001, "Default interval should be ~16ms")
14
+ }
15
+
16
+ func testInitializationWithCustomInterval() {
17
+ let throttle = EventThrottle(interval: 0.1) { _ in }
18
+ XCTAssertEqual(throttle.interval, 0.1, accuracy: 0.001, "Custom interval should be 0.1s")
19
+ }
20
+
21
+ // MARK: - First Event Fires Immediately
22
+
23
+ func testFirstEventFiresImmediately() {
24
+ var firedPayload: Any?
25
+ var fireCount = 0
26
+
27
+ let throttle = EventThrottle(interval: 1.0) { payload in
28
+ firedPayload = payload
29
+ fireCount += 1
30
+ }
31
+
32
+ throttle.fire("hello")
33
+
34
+ XCTAssertEqual(fireCount, 1, "First event should fire immediately")
35
+ XCTAssertEqual(firedPayload as? String, "hello", "Payload should be passed through")
36
+ }
37
+
38
+ // MARK: - Events Within Throttle Window Are Suppressed
39
+
40
+ func testEventsWithinWindowAreSuppressed() {
41
+ var fireCount = 0
42
+
43
+ let throttle = EventThrottle(interval: 10.0) { _ in
44
+ fireCount += 1
45
+ }
46
+
47
+ // First fire — immediate
48
+ throttle.fire("first")
49
+ XCTAssertEqual(fireCount, 1, "First event should fire immediately")
50
+
51
+ // Rapid fires within the throttle window — should NOT fire immediately
52
+ throttle.fire("second")
53
+ throttle.fire("third")
54
+
55
+ // Only the first call fires synchronously; the rest schedule trailing calls
56
+ XCTAssertEqual(fireCount, 1, "Subsequent events within the throttle window should be suppressed synchronously")
57
+ }
58
+
59
+ // MARK: - Events After Window Expires Fire
60
+
61
+ func testEventsAfterWindowExpireFire() {
62
+ let expectation = self.expectation(description: "Throttled event fires after window")
63
+ var fireCount = 0
64
+
65
+ let throttle = EventThrottle(interval: 0.05) { _ in
66
+ fireCount += 1
67
+ if fireCount == 2 {
68
+ expectation.fulfill()
69
+ }
70
+ }
71
+
72
+ // First fire — immediate
73
+ throttle.fire("first")
74
+ XCTAssertEqual(fireCount, 1, "First event should fire immediately")
75
+
76
+ // Wait for the throttle window to expire, then fire again
77
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
78
+ throttle.fire("second")
79
+ }
80
+
81
+ waitForExpectations(timeout: 1.0)
82
+ XCTAssertEqual(fireCount, 2, "Event after window expiry should fire")
83
+ }
84
+
85
+ // MARK: - Trailing Call Delivers Latest Payload
86
+
87
+ func testTrailingCallDeliversLatestPayload() {
88
+ let expectation = self.expectation(description: "Trailing call fires")
89
+ var payloads: [String] = []
90
+
91
+ let throttle = EventThrottle(interval: 0.05) { payload in
92
+ if let str = payload as? String {
93
+ payloads.append(str)
94
+ }
95
+ if payloads.count == 2 {
96
+ expectation.fulfill()
97
+ }
98
+ }
99
+
100
+ // First fire — immediate
101
+ throttle.fire("first")
102
+
103
+ // Rapid fires — only the latest should be delivered as trailing
104
+ throttle.fire("second")
105
+ throttle.fire("third")
106
+ throttle.fire("fourth")
107
+
108
+ waitForExpectations(timeout: 1.0)
109
+
110
+ XCTAssertEqual(payloads.first, "first", "First payload should be 'first'")
111
+ XCTAssertEqual(payloads.last, "fourth", "Trailing call should deliver the latest payload")
112
+ }
113
+
114
+ // MARK: - Multiple Throttle Instances Are Independent
115
+
116
+ func testMultipleThrottleInstancesAreIndependent() {
117
+ var countA = 0
118
+ var countB = 0
119
+
120
+ let throttleA = EventThrottle(interval: 10.0) { _ in countA += 1 }
121
+ let throttleB = EventThrottle(interval: 10.0) { _ in countB += 1 }
122
+
123
+ throttleA.fire(nil)
124
+ throttleB.fire(nil)
125
+
126
+ XCTAssertEqual(countA, 1, "Throttle A should fire independently")
127
+ XCTAssertEqual(countB, 1, "Throttle B should fire independently")
128
+ }
129
+
130
+ // MARK: - Nil Payload Is Supported
131
+
132
+ func testNilPayloadIsSupported() {
133
+ var fired = false
134
+
135
+ let throttle = EventThrottle(interval: 0.016) { payload in
136
+ XCTAssertNil(payload, "Nil payload should be passed through")
137
+ fired = true
138
+ }
139
+
140
+ throttle.fire(nil)
141
+ XCTAssertTrue(fired, "Handler should fire with nil payload")
142
+ }
143
+
144
+ // MARK: - Dictionary Payload Is Supported
145
+
146
+ func testDictionaryPayloadIsSupported() {
147
+ var receivedPayload: [String: Any]?
148
+
149
+ let throttle = EventThrottle(interval: 0.016) { payload in
150
+ receivedPayload = payload as? [String: Any]
151
+ }
152
+
153
+ let payload: [String: Any] = ["x": 10.0, "y": 20.0]
154
+ throttle.fire(payload)
155
+
156
+ XCTAssertNotNil(receivedPayload, "Dictionary payload should be received")
157
+ XCTAssertEqual(receivedPayload?["x"] as? Double, 10.0, "x should be 10.0")
158
+ XCTAssertEqual(receivedPayload?["y"] as? Double, 20.0, "y should be 20.0")
159
+ }
160
+ }
161
+ #endif
@@ -0,0 +1,88 @@
1
+ #if canImport(UIKit)
2
+ import XCTest
3
+ import UIKit
4
+ @testable import VueNativeCore
5
+
6
+ @MainActor
7
+ final class HotReloadManagerTests: XCTestCase {
8
+
9
+ // MARK: - Properties
10
+
11
+ private var manager: HotReloadManager!
12
+
13
+ // MARK: - Setup / Teardown
14
+
15
+ override func setUp() {
16
+ super.setUp()
17
+ manager = HotReloadManager.shared
18
+ }
19
+
20
+ override func tearDown() {
21
+ manager.disconnect()
22
+ manager = nil
23
+ super.tearDown()
24
+ }
25
+
26
+ // MARK: - Singleton Tests
27
+
28
+ func testSharedInstanceIsSingleton() {
29
+ let instance1 = HotReloadManager.shared
30
+ let instance2 = HotReloadManager.shared
31
+ XCTAssertTrue(instance1 === instance2, "HotReloadManager.shared should always return the same instance")
32
+ }
33
+
34
+ // MARK: - Initialization Tests
35
+
36
+ func testInitializationWithURL() {
37
+ let url = URL(string: "ws://localhost:8174")!
38
+ // connect should not crash
39
+ manager.connect(to: url)
40
+ // Just verify it doesn't crash — we can't easily test the WebSocket connection
41
+ }
42
+
43
+ // MARK: - Disconnect Tests
44
+
45
+ func testDisconnectDoesNotCrash() {
46
+ // Disconnect without connecting first — should be safe
47
+ manager.disconnect()
48
+ }
49
+
50
+ func testDisconnectAfterConnectDoesNotCrash() {
51
+ let url = URL(string: "ws://localhost:9999")!
52
+ manager.connect(to: url)
53
+ manager.disconnect()
54
+ // Should not crash
55
+ }
56
+
57
+ // MARK: - Multiple Connect Calls
58
+
59
+ func testMultipleConnectCallsDoNotCrash() {
60
+ let url1 = URL(string: "ws://localhost:8174")!
61
+ let url2 = URL(string: "ws://localhost:8175")!
62
+
63
+ manager.connect(to: url1)
64
+ manager.connect(to: url2)
65
+ manager.disconnect()
66
+ }
67
+
68
+ // MARK: - URLSessionWebSocketDelegate Conformance
69
+
70
+ func testConformsToURLSessionWebSocketDelegate() {
71
+ // Verify HotReloadManager conforms to the delegate protocol
72
+ XCTAssertTrue(manager is URLSessionWebSocketDelegate,
73
+ "HotReloadManager should conform to URLSessionWebSocketDelegate")
74
+ }
75
+
76
+ // MARK: - Connect/Disconnect Cycle
77
+
78
+ func testConnectDisconnectCycleDoesNotCrash() {
79
+ let url = URL(string: "ws://localhost:8174")!
80
+
81
+ for _ in 0..<5 {
82
+ manager.connect(to: url)
83
+ manager.disconnect()
84
+ }
85
+ // Multiple cycles should not crash
86
+ }
87
+ }
88
+ #endif
@@ -0,0 +1,319 @@
1
+ #if canImport(UIKit)
2
+ import XCTest
3
+ import JavaScriptCore
4
+ import UIKit
5
+ @testable import VueNativeCore
6
+
7
+ @MainActor
8
+ final class JSPolyfillsTests: XCTestCase {
9
+
10
+ // MARK: - Properties
11
+
12
+ private var runtime: JSRuntime!
13
+
14
+ // MARK: - Setup / Teardown
15
+
16
+ override func setUp() {
17
+ super.setUp()
18
+ runtime = JSRuntime.shared
19
+ let initExpectation = expectation(description: "JSRuntime initialized")
20
+ runtime.initialize {
21
+ initExpectation.fulfill()
22
+ }
23
+ waitForExpectations(timeout: 5.0)
24
+ }
25
+
26
+ override func tearDown() {
27
+ runtime = nil
28
+ super.tearDown()
29
+ }
30
+
31
+ // MARK: - Helper
32
+
33
+ /// Evaluate a script synchronously and return the result.
34
+ private func evalSync(_ script: String) -> JSValue? {
35
+ let exp = expectation(description: "eval")
36
+ var result: JSValue?
37
+ runtime.evaluateScript(script) { value in
38
+ result = value
39
+ exp.fulfill()
40
+ }
41
+ waitForExpectations(timeout: 5.0)
42
+ return result
43
+ }
44
+
45
+ // MARK: - console Tests
46
+
47
+ func testConsoleLogDoesNotCrash() {
48
+ // console.log should not throw or crash
49
+ let result = evalSync("console.log('test message'); true")
50
+ XCTAssertNotNil(result, "console.log should not crash")
51
+ XCTAssertTrue(result?.toBool() == true, "Script should evaluate to true")
52
+ }
53
+
54
+ func testConsoleWarnDoesNotCrash() {
55
+ let result = evalSync("console.warn('warning message'); true")
56
+ XCTAssertNotNil(result, "console.warn should not crash")
57
+ XCTAssertTrue(result?.toBool() == true, "Script should evaluate to true")
58
+ }
59
+
60
+ func testConsoleErrorDoesNotCrash() {
61
+ let result = evalSync("console.error('error message'); true")
62
+ XCTAssertNotNil(result, "console.error should not crash")
63
+ XCTAssertTrue(result?.toBool() == true, "Script should evaluate to true")
64
+ }
65
+
66
+ func testConsoleDebugDoesNotCrash() {
67
+ let result = evalSync("console.debug('debug message'); true")
68
+ XCTAssertNotNil(result, "console.debug should not crash")
69
+ }
70
+
71
+ func testConsoleInfoDoesNotCrash() {
72
+ let result = evalSync("console.info('info message'); true")
73
+ XCTAssertNotNil(result, "console.info should not crash")
74
+ }
75
+
76
+ // MARK: - performance.now() Tests
77
+
78
+ func testPerformanceNowReturnsNumber() {
79
+ let result = evalSync("typeof performance.now()")
80
+ XCTAssertEqual(result?.toString(), "number", "performance.now() should return a number")
81
+ }
82
+
83
+ func testPerformanceNowReturnsPositiveValue() {
84
+ let result = evalSync("performance.now() > 0")
85
+ XCTAssertTrue(result?.toBool() == true, "performance.now() should return a positive number")
86
+ }
87
+
88
+ func testPerformanceNowIncreases() {
89
+ let result = evalSync("""
90
+ var a = performance.now();
91
+ var i = 0; while(i < 10000) { i++; }
92
+ var b = performance.now();
93
+ b >= a;
94
+ """)
95
+ XCTAssertTrue(result?.toBool() == true, "performance.now() should be non-decreasing")
96
+ }
97
+
98
+ // MARK: - queueMicrotask Tests
99
+
100
+ func testQueueMicrotaskExists() {
101
+ let result = evalSync("typeof queueMicrotask")
102
+ XCTAssertEqual(result?.toString(), "function", "queueMicrotask should be a function")
103
+ }
104
+
105
+ func testQueueMicrotaskCallbackRuns() {
106
+ let result = evalSync("""
107
+ var microtaskRan = false;
108
+ queueMicrotask(function() { microtaskRan = true; });
109
+ // Microtask should execute after the current task via Promise.resolve().then()
110
+ microtaskRan;
111
+ """)
112
+ // Note: the microtask may not have fired yet since it's Promise-based.
113
+ // But after the evaluateScript drain, it should have run.
114
+ XCTAssertNotNil(result, "queueMicrotask should not crash")
115
+ }
116
+
117
+ // MARK: - setTimeout Tests
118
+
119
+ func testSetTimeoutExists() {
120
+ let result = evalSync("typeof setTimeout")
121
+ XCTAssertEqual(result?.toString(), "function", "setTimeout should be a function")
122
+ }
123
+
124
+ func testSetTimeoutReturnsTimerId() {
125
+ let result = evalSync("var id = setTimeout(function(){}, 1000); typeof id !== 'undefined'")
126
+ XCTAssertTrue(result?.toBool() == true, "setTimeout should return a timer ID")
127
+ }
128
+
129
+ func testSetTimeoutFiresCallback() {
130
+ let exp = expectation(description: "setTimeout fires")
131
+
132
+ runtime.evaluateScript("""
133
+ globalThis.__testTimeoutFired = false;
134
+ setTimeout(function() {
135
+ globalThis.__testTimeoutFired = true;
136
+ }, 50);
137
+ """)
138
+
139
+ // Check after a delay — use evaluateScript directly to avoid
140
+ // nested waitForExpectations (XCTest API violation).
141
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
142
+ self?.runtime.evaluateScript("globalThis.__testTimeoutFired") { value in
143
+ XCTAssertTrue(value?.toBool() == true, "setTimeout callback should have fired")
144
+ exp.fulfill()
145
+ }
146
+ }
147
+
148
+ waitForExpectations(timeout: 2.0)
149
+ }
150
+
151
+ // MARK: - clearTimeout Tests
152
+
153
+ func testClearTimeoutExists() {
154
+ let result = evalSync("typeof clearTimeout")
155
+ XCTAssertEqual(result?.toString(), "function", "clearTimeout should be a function")
156
+ }
157
+
158
+ func testClearTimeoutCancelsPendingCallback() {
159
+ // Verify clearTimeout is callable and does not crash.
160
+ // We cannot reliably test cancellation timing in the simulator
161
+ // because JSC timer scheduling depends on the native run loop.
162
+ let result = evalSync("""
163
+ var __clearTestFired = false;
164
+ var tid = setTimeout(function() { __clearTestFired = true; }, 100000);
165
+ clearTimeout(tid);
166
+ typeof tid !== 'undefined';
167
+ """)
168
+ XCTAssertTrue(result?.toBool() == true, "clearTimeout should accept a timer ID")
169
+ }
170
+
171
+ // MARK: - setInterval Tests
172
+
173
+ func testSetIntervalExists() {
174
+ let result = evalSync("typeof setInterval")
175
+ XCTAssertEqual(result?.toString(), "function", "setInterval should be a function")
176
+ }
177
+
178
+ func testSetIntervalReturnsTimerId() {
179
+ let result = evalSync("""
180
+ var iid = setInterval(function(){}, 1000);
181
+ clearInterval(iid);
182
+ typeof iid !== 'undefined';
183
+ """)
184
+ XCTAssertTrue(result?.toBool() == true, "setInterval should return a timer ID")
185
+ }
186
+
187
+ // MARK: - clearInterval Tests
188
+
189
+ func testClearIntervalExists() {
190
+ let result = evalSync("typeof clearInterval")
191
+ XCTAssertEqual(result?.toString(), "function", "clearInterval should be a function")
192
+ }
193
+
194
+ // MARK: - globalThis Tests
195
+
196
+ func testGlobalThisExists() {
197
+ let result = evalSync("typeof globalThis !== 'undefined'")
198
+ XCTAssertTrue(result?.toBool() == true, "globalThis should be defined")
199
+ }
200
+
201
+ func testGlobalThisIsGlobalObject() {
202
+ let result = evalSync("globalThis === this")
203
+ // In JSC, `this` at the top level is the global object
204
+ XCTAssertNotNil(result, "globalThis should reference the global object")
205
+ }
206
+
207
+ // MARK: - requestAnimationFrame Tests
208
+
209
+ func testRequestAnimationFrameExists() {
210
+ let result = evalSync("typeof requestAnimationFrame")
211
+ XCTAssertEqual(result?.toString(), "function", "requestAnimationFrame should be a function")
212
+ }
213
+
214
+ func testCancelAnimationFrameExists() {
215
+ let result = evalSync("typeof cancelAnimationFrame")
216
+ XCTAssertEqual(result?.toString(), "function", "cancelAnimationFrame should be a function")
217
+ }
218
+
219
+ // MARK: - fetch Tests
220
+
221
+ func testFetchExists() {
222
+ let result = evalSync("typeof fetch")
223
+ XCTAssertEqual(result?.toString(), "function", "fetch should be a function")
224
+ }
225
+
226
+ // MARK: - atob / btoa Tests
227
+
228
+ func testBtoaEncodes() {
229
+ let result = evalSync("btoa('hello')")
230
+ XCTAssertEqual(result?.toString(), "aGVsbG8=", "btoa('hello') should return 'aGVsbG8='")
231
+ }
232
+
233
+ func testAtobDecodes() {
234
+ let result = evalSync("atob('aGVsbG8=')")
235
+ XCTAssertEqual(result?.toString(), "hello", "atob('aGVsbG8=') should return 'hello'")
236
+ }
237
+
238
+ func testBtoaAtobRoundTrip() {
239
+ let result = evalSync("atob(btoa('Vue Native!'))")
240
+ XCTAssertEqual(result?.toString(), "Vue Native!", "btoa/atob round-trip should preserve the string")
241
+ }
242
+
243
+ // MARK: - TextEncoder / TextDecoder Tests
244
+
245
+ func testTextEncoderExists() {
246
+ let result = evalSync("typeof TextEncoder")
247
+ XCTAssertEqual(result?.toString(), "function", "TextEncoder should be defined")
248
+ }
249
+
250
+ func testTextDecoderExists() {
251
+ let result = evalSync("typeof TextDecoder")
252
+ XCTAssertEqual(result?.toString(), "function", "TextDecoder should be defined")
253
+ }
254
+
255
+ func testTextEncoderDecoderRoundTrip() {
256
+ let result = evalSync("""
257
+ var enc = new TextEncoder();
258
+ var dec = new TextDecoder();
259
+ var encoded = enc.encode('hello');
260
+ dec.decode(encoded);
261
+ """)
262
+ XCTAssertEqual(result?.toString(), "hello", "TextEncoder/TextDecoder round-trip should work")
263
+ }
264
+
265
+ // MARK: - URL Tests
266
+
267
+ func testURLConstructorExists() {
268
+ let result = evalSync("typeof URL")
269
+ XCTAssertEqual(result?.toString(), "function", "URL constructor should be defined")
270
+ }
271
+
272
+ func testURLParsingBasic() {
273
+ let result = evalSync("new URL('https://example.com:8080/path?q=1#hash').hostname")
274
+ XCTAssertEqual(result?.toString(), "example.com", "URL should parse hostname")
275
+ }
276
+
277
+ func testURLSearchParamsExists() {
278
+ let result = evalSync("typeof URLSearchParams")
279
+ XCTAssertEqual(result?.toString(), "function", "URLSearchParams should be defined")
280
+ }
281
+
282
+ // MARK: - crypto.getRandomValues Tests
283
+
284
+ func testCryptoGetRandomValuesExists() {
285
+ let result = evalSync("typeof crypto.getRandomValues")
286
+ XCTAssertEqual(result?.toString(), "function", "crypto.getRandomValues should be defined")
287
+ }
288
+
289
+ func testCryptoGetRandomValuesProducesBytes() {
290
+ let result = evalSync("""
291
+ var arr = new Uint8Array(4);
292
+ crypto.getRandomValues(arr);
293
+ arr.length;
294
+ """)
295
+ XCTAssertEqual(result?.toInt32(), 4, "getRandomValues should fill a 4-byte array")
296
+ }
297
+
298
+ // MARK: - Bridge Stubs Tests
299
+
300
+ func testBridgeStubsExist() {
301
+ let result = evalSync("""
302
+ typeof __VN_handleGlobalEvent === 'function' &&
303
+ typeof __VN_handleEvent === 'function' &&
304
+ typeof __VN_resolveCallback === 'function';
305
+ """)
306
+ XCTAssertTrue(result?.toBool() == true, "Bridge stubs should be defined as functions")
307
+ }
308
+
309
+ func testBridgeStubsDoNotCrash() {
310
+ let result = evalSync("""
311
+ __VN_handleGlobalEvent();
312
+ __VN_handleEvent();
313
+ __VN_resolveCallback();
314
+ true;
315
+ """)
316
+ XCTAssertTrue(result?.toBool() == true, "Bridge stubs should be callable without crashing")
317
+ }
318
+ }
319
+ #endif