diff --git a/.github/workflows/verify-ios.yml b/.github/workflows/verify-ios.yml index ddf5882fc0..247c3b8a65 100644 --- a/.github/workflows/verify-ios.yml +++ b/.github/workflows/verify-ios.yml @@ -54,3 +54,26 @@ jobs: - name: Verify formatting run: yarn lint-clang + unit-tests: + name: ๐Ÿ“– Unit tests + runs-on: macOS-14 + defaults: + run: + working-directory: ./ios/KeyboardControllerNative + steps: + - uses: actions/checkout@v4 + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: "15.3" + + - name: Install xcpretty + run: gem install xcpretty + + - name: Run unit tests + run: "set -o pipefail && xcodebuild \ + test \ + -scheme KeyboardControllerNative \ + -only-testing KeyboardControllerNativeTests \ + -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \ + CODE_SIGNING_ALLOWED=NO | xcpretty" diff --git a/FabricExample/ios/Podfile.lock b/FabricExample/ios/Podfile.lock index 63c6cb17f5..41b17f956c 100644 --- a/FabricExample/ios/Podfile.lock +++ b/FabricExample/ios/Podfile.lock @@ -1597,7 +1597,7 @@ SPEC CHECKSUMS: React-jsitracing: 4fed160d939e93a39049481f47744af246a7ac2c React-logger: 3eb80a977f0d9669468ef641a5e1fabbc50a09ec React-Mapbuffer: 84ea43c6c6232049135b1550b8c60b2faac19fab - react-native-keyboard-controller: 7d37211044d15aa8178b04df9a85263f52a07203 + react-native-keyboard-controller: 779693f3474f963ee1d9df1d965368ba82c88abf react-native-safe-area-context: 1e374c51edf537be56313b893b6e96b0e254ddfe React-nativeconfig: b4d4e9901d4cabb57be63053fd2aa6086eb3c85f React-NativeModulesApple: cd26e56d56350e123da0c1e3e4c76cb58a05e1ee diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 17c929a55d..2fc4f90e56 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1405,7 +1405,7 @@ SPEC CHECKSUMS: React-jsinspector: 85583ef014ce53d731a98c66a0e24496f7a83066 React-logger: 3eb80a977f0d9669468ef641a5e1fabbc50a09ec React-Mapbuffer: 84ea43c6c6232049135b1550b8c60b2faac19fab - react-native-keyboard-controller: 27a2f1da4a1fedf9f01bf49e2dcabba700daa284 + react-native-keyboard-controller: e0f1b0b71a76e05c99fc6bfdd8b8ec05bead4105 react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b react-native-text-input-mask: 22ca8eeef84d42a896f79428f7d175a5eb8b1c4e React-nativeconfig: b4d4e9901d4cabb57be63053fd2aa6086eb3c85f diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative.xcodeproj/project.pbxproj b/ios/KeyboardControllerNative/KeyboardControllerNative.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..d1bca20ebd --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNative.xcodeproj/project.pbxproj @@ -0,0 +1,633 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 0873ED562BB6B7380004F3A4 /* KeyboardControllerNativeApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED552BB6B7380004F3A4 /* KeyboardControllerNativeApp.swift */; }; + 0873ED582BB6B7380004F3A4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED572BB6B7380004F3A4 /* ContentView.swift */; }; + 0873ED5A2BB6B7390004F3A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0873ED592BB6B7390004F3A4 /* Assets.xcassets */; }; + 0873ED5D2BB6B7390004F3A4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0873ED5C2BB6B7390004F3A4 /* Preview Assets.xcassets */; }; + 0873ED672BB6B7390004F3A4 /* KeyboardControllerNativeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED662BB6B7390004F3A4 /* KeyboardControllerNativeTests.swift */; }; + 0873ED712BB6B7390004F3A4 /* KeyboardControllerNativeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED702BB6B7390004F3A4 /* KeyboardControllerNativeUITests.swift */; }; + 0873ED732BB6B7390004F3A4 /* KeyboardControllerNativeUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED722BB6B7390004F3A4 /* KeyboardControllerNativeUITestsLaunchTests.swift */; }; + 0873ED822BB6B94B0004F3A4 /* FocusedInputHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED7F2BB6B94B0004F3A4 /* FocusedInputHolder.swift */; }; + 0873ED832BB6B94B0004F3A4 /* FocusedInputHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED7F2BB6B94B0004F3A4 /* FocusedInputHolder.swift */; }; + 0873ED842BB6B94B0004F3A4 /* FocusedInputHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED7F2BB6B94B0004F3A4 /* FocusedInputHolder.swift */; }; + 0873ED852BB6B94B0004F3A4 /* TextInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED802BB6B94B0004F3A4 /* TextInput.swift */; }; + 0873ED862BB6B94B0004F3A4 /* TextInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED802BB6B94B0004F3A4 /* TextInput.swift */; }; + 0873ED872BB6B94B0004F3A4 /* TextInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED802BB6B94B0004F3A4 /* TextInput.swift */; }; + 0873ED882BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED812BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift */; }; + 0873ED892BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED812BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift */; }; + 0873ED8A2BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED812BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift */; }; + 0873ED8C2BB6B95A0004F3A4 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED8B2BB6B95A0004F3A4 /* Extensions.swift */; }; + 0873ED8D2BB6B95A0004F3A4 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED8B2BB6B95A0004F3A4 /* Extensions.swift */; }; + 0873ED8E2BB6B95A0004F3A4 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED8B2BB6B95A0004F3A4 /* Extensions.swift */; }; + 0873ED902BB6B9960004F3A4 /* Extension+UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED8F2BB6B9960004F3A4 /* Extension+UIView.swift */; }; + 0873ED912BB6B9960004F3A4 /* Extension+UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED8F2BB6B9960004F3A4 /* Extension+UIView.swift */; }; + 0873ED922BB6B9960004F3A4 /* Extension+UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0873ED8F2BB6B9960004F3A4 /* Extension+UIView.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0873ED632BB6B7390004F3A4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0873ED4A2BB6B7380004F3A4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0873ED512BB6B7380004F3A4; + remoteInfo = KeyboardControllerNative; + }; + 0873ED6D2BB6B7390004F3A4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0873ED4A2BB6B7380004F3A4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0873ED512BB6B7380004F3A4; + remoteInfo = KeyboardControllerNative; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0873ED522BB6B7380004F3A4 /* KeyboardControllerNative.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KeyboardControllerNative.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0873ED552BB6B7380004F3A4 /* KeyboardControllerNativeApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardControllerNativeApp.swift; sourceTree = ""; }; + 0873ED572BB6B7380004F3A4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 0873ED592BB6B7390004F3A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 0873ED5C2BB6B7390004F3A4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 0873ED622BB6B7390004F3A4 /* KeyboardControllerNativeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeyboardControllerNativeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 0873ED662BB6B7390004F3A4 /* KeyboardControllerNativeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardControllerNativeTests.swift; sourceTree = ""; }; + 0873ED6C2BB6B7390004F3A4 /* KeyboardControllerNativeUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeyboardControllerNativeUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 0873ED702BB6B7390004F3A4 /* KeyboardControllerNativeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardControllerNativeUITests.swift; sourceTree = ""; }; + 0873ED722BB6B7390004F3A4 /* KeyboardControllerNativeUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardControllerNativeUITestsLaunchTests.swift; sourceTree = ""; }; + 0873ED7F2BB6B94B0004F3A4 /* FocusedInputHolder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FocusedInputHolder.swift; path = ../../traversal/FocusedInputHolder.swift; sourceTree = ""; }; + 0873ED802BB6B94B0004F3A4 /* TextInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TextInput.swift; path = ../../traversal/TextInput.swift; sourceTree = ""; }; + 0873ED812BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewHierarchyNavigator.swift; path = ../../traversal/ViewHierarchyNavigator.swift; sourceTree = ""; }; + 0873ED8B2BB6B95A0004F3A4 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = ../../Extensions.swift; sourceTree = ""; }; + 0873ED8F2BB6B9960004F3A4 /* Extension+UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Extension+UIView.swift"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0873ED4F2BB6B7380004F3A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0873ED5F2BB6B7390004F3A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0873ED692BB6B7390004F3A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0873ED492BB6B7380004F3A4 = { + isa = PBXGroup; + children = ( + 0873ED542BB6B7380004F3A4 /* KeyboardControllerNative */, + 0873ED652BB6B7390004F3A4 /* KeyboardControllerNativeTests */, + 0873ED6F2BB6B7390004F3A4 /* KeyboardControllerNativeUITests */, + 0873ED532BB6B7380004F3A4 /* Products */, + ); + sourceTree = ""; + }; + 0873ED532BB6B7380004F3A4 /* Products */ = { + isa = PBXGroup; + children = ( + 0873ED522BB6B7380004F3A4 /* KeyboardControllerNative.app */, + 0873ED622BB6B7390004F3A4 /* KeyboardControllerNativeTests.xctest */, + 0873ED6C2BB6B7390004F3A4 /* KeyboardControllerNativeUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 0873ED542BB6B7380004F3A4 /* KeyboardControllerNative */ = { + isa = PBXGroup; + children = ( + 0873ED8F2BB6B9960004F3A4 /* Extension+UIView.swift */, + 0873ED8B2BB6B95A0004F3A4 /* Extensions.swift */, + 0873ED7F2BB6B94B0004F3A4 /* FocusedInputHolder.swift */, + 0873ED802BB6B94B0004F3A4 /* TextInput.swift */, + 0873ED812BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift */, + 0873ED552BB6B7380004F3A4 /* KeyboardControllerNativeApp.swift */, + 0873ED572BB6B7380004F3A4 /* ContentView.swift */, + 0873ED592BB6B7390004F3A4 /* Assets.xcassets */, + 0873ED5B2BB6B7390004F3A4 /* Preview Content */, + ); + path = KeyboardControllerNative; + sourceTree = ""; + }; + 0873ED5B2BB6B7390004F3A4 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 0873ED5C2BB6B7390004F3A4 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 0873ED652BB6B7390004F3A4 /* KeyboardControllerNativeTests */ = { + isa = PBXGroup; + children = ( + 0873ED662BB6B7390004F3A4 /* KeyboardControllerNativeTests.swift */, + ); + path = KeyboardControllerNativeTests; + sourceTree = ""; + }; + 0873ED6F2BB6B7390004F3A4 /* KeyboardControllerNativeUITests */ = { + isa = PBXGroup; + children = ( + 0873ED702BB6B7390004F3A4 /* KeyboardControllerNativeUITests.swift */, + 0873ED722BB6B7390004F3A4 /* KeyboardControllerNativeUITestsLaunchTests.swift */, + ); + path = KeyboardControllerNativeUITests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0873ED512BB6B7380004F3A4 /* KeyboardControllerNative */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0873ED762BB6B7390004F3A4 /* Build configuration list for PBXNativeTarget "KeyboardControllerNative" */; + buildPhases = ( + 0873ED4E2BB6B7380004F3A4 /* Sources */, + 0873ED4F2BB6B7380004F3A4 /* Frameworks */, + 0873ED502BB6B7380004F3A4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = KeyboardControllerNative; + productName = KeyboardControllerNative; + productReference = 0873ED522BB6B7380004F3A4 /* KeyboardControllerNative.app */; + productType = "com.apple.product-type.application"; + }; + 0873ED612BB6B7390004F3A4 /* KeyboardControllerNativeTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0873ED792BB6B7390004F3A4 /* Build configuration list for PBXNativeTarget "KeyboardControllerNativeTests" */; + buildPhases = ( + 0873ED5E2BB6B7390004F3A4 /* Sources */, + 0873ED5F2BB6B7390004F3A4 /* Frameworks */, + 0873ED602BB6B7390004F3A4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0873ED642BB6B7390004F3A4 /* PBXTargetDependency */, + ); + name = KeyboardControllerNativeTests; + productName = KeyboardControllerNativeTests; + productReference = 0873ED622BB6B7390004F3A4 /* KeyboardControllerNativeTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 0873ED6B2BB6B7390004F3A4 /* KeyboardControllerNativeUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0873ED7C2BB6B7390004F3A4 /* Build configuration list for PBXNativeTarget "KeyboardControllerNativeUITests" */; + buildPhases = ( + 0873ED682BB6B7390004F3A4 /* Sources */, + 0873ED692BB6B7390004F3A4 /* Frameworks */, + 0873ED6A2BB6B7390004F3A4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0873ED6E2BB6B7390004F3A4 /* PBXTargetDependency */, + ); + name = KeyboardControllerNativeUITests; + productName = KeyboardControllerNativeUITests; + productReference = 0873ED6C2BB6B7390004F3A4 /* KeyboardControllerNativeUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0873ED4A2BB6B7380004F3A4 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1530; + LastUpgradeCheck = 1530; + TargetAttributes = { + 0873ED512BB6B7380004F3A4 = { + CreatedOnToolsVersion = 15.3; + }; + 0873ED612BB6B7390004F3A4 = { + CreatedOnToolsVersion = 15.3; + TestTargetID = 0873ED512BB6B7380004F3A4; + }; + 0873ED6B2BB6B7390004F3A4 = { + CreatedOnToolsVersion = 15.3; + TestTargetID = 0873ED512BB6B7380004F3A4; + }; + }; + }; + buildConfigurationList = 0873ED4D2BB6B7380004F3A4 /* Build configuration list for PBXProject "KeyboardControllerNative" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0873ED492BB6B7380004F3A4; + productRefGroup = 0873ED532BB6B7380004F3A4 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0873ED512BB6B7380004F3A4 /* KeyboardControllerNative */, + 0873ED612BB6B7390004F3A4 /* KeyboardControllerNativeTests */, + 0873ED6B2BB6B7390004F3A4 /* KeyboardControllerNativeUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0873ED502BB6B7380004F3A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0873ED5D2BB6B7390004F3A4 /* Preview Assets.xcassets in Resources */, + 0873ED5A2BB6B7390004F3A4 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0873ED602BB6B7390004F3A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0873ED6A2BB6B7390004F3A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0873ED4E2BB6B7380004F3A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0873ED902BB6B9960004F3A4 /* Extension+UIView.swift in Sources */, + 0873ED582BB6B7380004F3A4 /* ContentView.swift in Sources */, + 0873ED8C2BB6B95A0004F3A4 /* Extensions.swift in Sources */, + 0873ED562BB6B7380004F3A4 /* KeyboardControllerNativeApp.swift in Sources */, + 0873ED882BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift in Sources */, + 0873ED822BB6B94B0004F3A4 /* FocusedInputHolder.swift in Sources */, + 0873ED852BB6B94B0004F3A4 /* TextInput.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0873ED5E2BB6B7390004F3A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0873ED8D2BB6B95A0004F3A4 /* Extensions.swift in Sources */, + 0873ED892BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift in Sources */, + 0873ED912BB6B9960004F3A4 /* Extension+UIView.swift in Sources */, + 0873ED832BB6B94B0004F3A4 /* FocusedInputHolder.swift in Sources */, + 0873ED672BB6B7390004F3A4 /* KeyboardControllerNativeTests.swift in Sources */, + 0873ED862BB6B94B0004F3A4 /* TextInput.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0873ED682BB6B7390004F3A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0873ED922BB6B9960004F3A4 /* Extension+UIView.swift in Sources */, + 0873ED732BB6B7390004F3A4 /* KeyboardControllerNativeUITestsLaunchTests.swift in Sources */, + 0873ED8E2BB6B95A0004F3A4 /* Extensions.swift in Sources */, + 0873ED712BB6B7390004F3A4 /* KeyboardControllerNativeUITests.swift in Sources */, + 0873ED8A2BB6B94B0004F3A4 /* ViewHierarchyNavigator.swift in Sources */, + 0873ED842BB6B94B0004F3A4 /* FocusedInputHolder.swift in Sources */, + 0873ED872BB6B94B0004F3A4 /* TextInput.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0873ED642BB6B7390004F3A4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0873ED512BB6B7380004F3A4 /* KeyboardControllerNative */; + targetProxy = 0873ED632BB6B7390004F3A4 /* PBXContainerItemProxy */; + }; + 0873ED6E2BB6B7390004F3A4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0873ED512BB6B7380004F3A4 /* KeyboardControllerNative */; + targetProxy = 0873ED6D2BB6B7390004F3A4 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0873ED742BB6B7390004F3A4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.4; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 0873ED752BB6B7390004F3A4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.4; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0873ED772BB6B7390004F3A4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"KeyboardControllerNative/Preview Content\""; + DEVELOPMENT_TEAM = 6QJHD36PJF; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.keyboardcontroller.KeyboardControllerNative; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0873ED782BB6B7390004F3A4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"KeyboardControllerNative/Preview Content\""; + DEVELOPMENT_TEAM = 6QJHD36PJF; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.keyboardcontroller.KeyboardControllerNative; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 0873ED7A2BB6B7390004F3A4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 6QJHD36PJF; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.keyboardcontroller.KeyboardControllerNativeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeyboardControllerNative.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/KeyboardControllerNative"; + }; + name = Debug; + }; + 0873ED7B2BB6B7390004F3A4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 6QJHD36PJF; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.keyboardcontroller.KeyboardControllerNativeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeyboardControllerNative.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/KeyboardControllerNative"; + }; + name = Release; + }; + 0873ED7D2BB6B7390004F3A4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 6QJHD36PJF; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.keyboardcontroller.KeyboardControllerNativeUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = KeyboardControllerNative; + }; + name = Debug; + }; + 0873ED7E2BB6B7390004F3A4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 6QJHD36PJF; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.keyboardcontroller.KeyboardControllerNativeUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = KeyboardControllerNative; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0873ED4D2BB6B7380004F3A4 /* Build configuration list for PBXProject "KeyboardControllerNative" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0873ED742BB6B7390004F3A4 /* Debug */, + 0873ED752BB6B7390004F3A4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0873ED762BB6B7390004F3A4 /* Build configuration list for PBXNativeTarget "KeyboardControllerNative" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0873ED772BB6B7390004F3A4 /* Debug */, + 0873ED782BB6B7390004F3A4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0873ED792BB6B7390004F3A4 /* Build configuration list for PBXNativeTarget "KeyboardControllerNativeTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0873ED7A2BB6B7390004F3A4 /* Debug */, + 0873ED7B2BB6B7390004F3A4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0873ED7C2BB6B7390004F3A4 /* Build configuration list for PBXNativeTarget "KeyboardControllerNativeUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0873ED7D2BB6B7390004F3A4 /* Debug */, + 0873ED7E2BB6B7390004F3A4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0873ED4A2BB6B7380004F3A4 /* Project object */; +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/AccentColor.colorset/Contents.json b/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000000..0afb3cf0ee --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors": [ + { + "idiom": "universal" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..b121e3bce8 --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images": [ + { + "idiom": "universal", + "platform": "ios", + "size": "1024x1024" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/Contents.json b/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..74d6a722cf --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNative/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative/ContentView.swift b/ios/KeyboardControllerNative/KeyboardControllerNative/ContentView.swift new file mode 100644 index 0000000000..2b01558afc --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNative/ContentView.swift @@ -0,0 +1,24 @@ +// +// ContentView.swift +// KeyboardControllerNative +// +// Created by Kiryl Ziusko on 29/03/2024. +// + +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundStyle(.tint) + Text("Hello, world!") + } + .padding() + } +} + +#Preview { + ContentView() +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative/Extension+UIView.swift b/ios/KeyboardControllerNative/KeyboardControllerNative/Extension+UIView.swift new file mode 100644 index 0000000000..ee010d42a2 --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNative/Extension+UIView.swift @@ -0,0 +1,15 @@ +// +// Extension+UIView.swift +// Tests +// +// Created by Kiryl Ziusko on 21/02/2024. +// + +import Foundation +import UIKit + +public extension UIView { + var reactTag: NSNumber { + return tag as NSNumber + } +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative/KeyboardControllerNativeApp.swift b/ios/KeyboardControllerNative/KeyboardControllerNative/KeyboardControllerNativeApp.swift new file mode 100644 index 0000000000..8d96ff7237 --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNative/KeyboardControllerNativeApp.swift @@ -0,0 +1,17 @@ +// +// KeyboardControllerNativeApp.swift +// KeyboardControllerNative +// +// Created by Kiryl Ziusko on 29/03/2024. +// + +import SwiftUI + +@main +struct KeyboardControllerNativeApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNative/Preview Content/Preview Assets.xcassets/Contents.json b/ios/KeyboardControllerNative/KeyboardControllerNative/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000000..74d6a722cf --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNative/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info": { + "author": "xcode", + "version": 1 + } +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNativeTests/KeyboardControllerNativeTests.swift b/ios/KeyboardControllerNative/KeyboardControllerNativeTests/KeyboardControllerNativeTests.swift new file mode 100644 index 0000000000..23b7aa8e64 --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNativeTests/KeyboardControllerNativeTests.swift @@ -0,0 +1,175 @@ +// +// KeyboardControllerNativeTests.swift +// KeyboardControllerNativeTests +// +// Created by Kiryl Ziusko on 29/03/2024. +// + +@testable import KeyboardControllerNative +import XCTest + +extension XCTestCase { + func waitForFocusChange( + to textField: TestableInput, + timeout: TimeInterval = 10.0, + file: StaticString = #file, + line: UInt = #line + ) { + let expectation = XCTestExpectation(description: "Wait for focus change to \(textField.tag)") + + XCTAssertFalse( + textField.becomeFirstResponderCalled, + "Expected focus shouldn't be initially set for tag \(textField.tag)" + ) + + DispatchQueue.main.async { + XCTAssertTrue( + textField.becomeFirstResponderCalled, + "Expected focus to be set to text field with tag \(textField.tag)", + file: file, + line: line + ) + expectation.fulfill() + } + + wait(for: [expectation], timeout: timeout) + } +} + +protocol TestableInput: UIView, TextInput { + var becomeFirstResponderCalled: Bool { get set } + func becomeFirstResponder() -> Bool +} + +class TestableTextField: UITextField, TestableInput { + var becomeFirstResponderCalled = false + + override func becomeFirstResponder() -> Bool { + becomeFirstResponderCalled = true + return super.becomeFirstResponder() + } +} + +class TestableTextView: UITextView, TestableInput { + var becomeFirstResponderCalled = false + + override func becomeFirstResponder() -> Bool { + becomeFirstResponderCalled = true + return super.becomeFirstResponder() + } +} + +final class KeyboardControllerNativeTests: XCTestCase { + var rootView: UIView! + var textFields: [TestableInput]! + + override func setUpWithError() throws { + super.setUp() + + rootView = UIView() + textFields = (1 ... 13).map { tag in + let textField = (tag % 2 == 0 ? TestableTextField() : TestableTextView()) as TestableInput + textField.tag = tag + let isEditable = tag != 3 && tag != 4 // Assuming ids 3 and 4 are not editable, similar to our Android test + (textField as? UITextField)?.isEnabled = isEditable + (textField as? UITextView)?.isEditable = isEditable + + return textField + } + + let subView = UIView() + for (index, textField) in textFields.enumerated() { + if index == 4 { + rootView.addSubview(subView) + } + if index >= 4, index <= 6 { + subView.addSubview(textField) + } else { + rootView.addSubview(textField) + } + } + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testSetFocusToNextShouldSetFocusToNextField() throws { + let textInput1 = textFields[0] + FocusedInputHolder.shared.set(textInput1) + + ViewHierarchyNavigator.setFocusTo(direction: "next") + + waitForFocusChange(to: textFields[1]) + } + + func testSetFocusToPrevShouldSetFocusToPreviousField() throws { + let textInput2 = textFields[1] + FocusedInputHolder.shared.set(textInput2) + + ViewHierarchyNavigator.setFocusTo(direction: "prev") + + waitForFocusChange(to: textFields[0]) + } + + func testSetFocusToNextShouldSkipNonEditableFields() throws { + let textInput2 = textFields[1] + FocusedInputHolder.shared.set(textInput2) + + ViewHierarchyNavigator.setFocusTo(direction: "next") + + waitForFocusChange(to: textFields[4]) + } + + func testSetFocusToPrevShouldSkipNonEditableFields() throws { + let textInput5 = textFields[4] + FocusedInputHolder.shared.set(textInput5) + + ViewHierarchyNavigator.setFocusTo(direction: "prev") + + waitForFocusChange(to: textFields[1]) + } + + func testSetFocusToNextWithinGroup() throws { + let textInput5 = textFields[4] + FocusedInputHolder.shared.set(textInput5) + + ViewHierarchyNavigator.setFocusTo(direction: "next") + + waitForFocusChange(to: textFields[5]) + } + + func testSetFocusToPrevWithinGroup() throws { + let textInput6 = textFields[5] + FocusedInputHolder.shared.set(textInput6) + + ViewHierarchyNavigator.setFocusTo(direction: "prev") + + waitForFocusChange(to: textFields[4]) + } + + func testSetFocusToNextExitsGroup() throws { + let textInput7 = textFields[6] + FocusedInputHolder.shared.set(textInput7) + + ViewHierarchyNavigator.setFocusTo(direction: "next") + + waitForFocusChange(to: textFields[7]) + } + + func testSetFocusToPrevEntersGroupAtLastElement() throws { + let textInput8 = textFields[7] + FocusedInputHolder.shared.set(textInput8) + + ViewHierarchyNavigator.setFocusTo(direction: "prev") + + waitForFocusChange(to: textFields[6]) + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNativeUITests/KeyboardControllerNativeUITests.swift b/ios/KeyboardControllerNative/KeyboardControllerNativeUITests/KeyboardControllerNativeUITests.swift new file mode 100644 index 0000000000..8886b4fbb6 --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNativeUITests/KeyboardControllerNativeUITests.swift @@ -0,0 +1,41 @@ +// +// KeyboardControllerNativeUITests.swift +// KeyboardControllerNativeUITests +// +// Created by Kiryl Ziusko on 29/03/2024. +// + +import XCTest + +final class KeyboardControllerNativeUITests: XCTestCase { + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + // In UI tests itโ€™s important to set the initial state - such as interface orientation, + // which required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // UI tests must launch the application that they test. + let app = XCUIApplication() + app.launch() + + // Use XCTAssert and related functions to verify your tests produce the correct results. + } + + func testLaunchPerformance() throws { + if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { + // This measures how long it takes to launch your application. + measure(metrics: [XCTApplicationLaunchMetric()]) { + XCUIApplication().launch() + } + } + } +} diff --git a/ios/KeyboardControllerNative/KeyboardControllerNativeUITests/KeyboardControllerNativeUITestsLaunchTests.swift b/ios/KeyboardControllerNative/KeyboardControllerNativeUITests/KeyboardControllerNativeUITestsLaunchTests.swift new file mode 100644 index 0000000000..425457650c --- /dev/null +++ b/ios/KeyboardControllerNative/KeyboardControllerNativeUITests/KeyboardControllerNativeUITestsLaunchTests.swift @@ -0,0 +1,32 @@ +// +// KeyboardControllerNativeUITestsLaunchTests.swift +// KeyboardControllerNativeUITests +// +// Created by Kiryl Ziusko on 29/03/2024. +// + +import XCTest + +// swiftlint:disable:next type_name +final class KeyboardControllerNativeUITestsLaunchTests: XCTestCase { + override class var runsForEachTargetApplicationUIConfiguration: Bool { + true + } + + override func setUpWithError() throws { + continueAfterFailure = false + } + + func testLaunch() throws { + let app = XCUIApplication() + app.launch() + + // Insert steps here to perform after app launch but before taking a screenshot, + // such as logging into a test account or navigating somewhere in the app + + let attachment = XCTAttachment(screenshot: app.screenshot()) + attachment.name = "Launch Screen" + attachment.lifetime = .keepAlways + add(attachment) + } +} diff --git a/package.json b/package.json index d2dc637967..d041bf5a9f 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "!android/gradlew", "!android/gradlew.bat", "!ios/build", + "!ios/KeyboardControllerNative", "!**/__tests__", "!**/__fixtures__", "!**/__mocks__" diff --git a/react-native-keyboard-controller.podspec b/react-native-keyboard-controller.podspec index 7c0f85bed4..8729a0b458 100644 --- a/react-native-keyboard-controller.podspec +++ b/react-native-keyboard-controller.podspec @@ -18,6 +18,7 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/kirillzyusko/react-native-keyboard-controller.git", :tag => "#{s.version}" } s.source_files = "ios/**/*.{h,m,mm,swift}" + s.exclude_files = "ios/KeyboardControllerNative/**/*" s.public_header_files = "ios/**/*.h" # This guard prevent to install the dependencies when we run `pod install` in the old architecture.