diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 125e0da1..21b63f03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,9 +19,9 @@ jobs: strategy: matrix: run-config: - - { xcode_version: '15.4', simulator: 'name=iPad Air (5th generation),OS=17.5', run_extra_validations: 'false' } + - { xcode_version: '15.4', simulator: 'name=iPad (10th generation),OS=17.5', run_extra_validations: 'false' } - { xcode_version: '15.4', simulator: 'name=iPhone 15,OS=17.5', run_extra_validations: 'false' } - - { xcode_version: '16.1', simulator: 'name=iPad Air (5th generation),OS=18.1', run_extra_validations: 'false' } + - { xcode_version: '16.1', simulator: 'name=iPad (10th generation),OS=18.1', run_extra_validations: 'false' } - { xcode_version: '16.1', simulator: 'name=iPhone 16,OS=18.1', run_extra_validations: 'true' } steps: - name: Checkout Project diff --git a/Scripts/ci.sh b/Scripts/ci.sh index 17387f10..57f75f64 100755 --- a/Scripts/ci.sh +++ b/Scripts/ci.sh @@ -15,7 +15,7 @@ fi rm -rf ${PWD}/build # Run KIF Tests -env NSUnbufferedIO=YES xcodebuild test -project KIF.xcodeproj -scheme KIF -derivedDataPath=${PWD}/build/KIF -destination "platform=iOS Simulator,${SIMULATOR}" | xcpretty -c +env NSUnbufferedIO=YES xcodebuild test -project KIF.xcodeproj -scheme KIF -derivedDataPath=${PWD}/build/KIF -destination "platform=iOS Simulator,${SIMULATOR}" CODE_SIGNING_ALLOWED=NO | xcbeautify if [ $RUN_EXTRA_VALIDATIONS != "true" ]; then exit 0 @@ -25,14 +25,14 @@ fi swift build -Xcc "-isysroot" -Xcc "$(xcrun --sdk iphonesimulator --show-sdk-path)" -Xcc "-target" -Xcc "x86_64-apple-ios$(xcrun --sdk iphonesimulator --show-sdk-version)-simulator" # Consume KIF via Swift Package Manager in an Xcode project -env NSUnbufferedIO=YES xcodebuild test -project "Documentation/Examples/SPMIntegration/SPMIntegration.xcodeproj" -scheme "SPMIntegration" -derivedDataPath=${PWD}/build/SPMIntegration -destination "platform=iOS Simulator,${SIMULATOR}" | xcpretty -c +env NSUnbufferedIO=YES xcodebuild test -project "Documentation/Examples/SPMIntegration/SPMIntegration.xcodeproj" -scheme "SPMIntegration" -derivedDataPath=${PWD}/build/SPMIntegration -destination "platform=iOS Simulator,${SIMULATOR}" CODE_SIGNING_ALLOWED=NO | xcbeautify # Test the "Testable" example project -env NSUnbufferedIO=YES xcodebuild test -project "Documentation/Examples/Testable/Testable.xcodeproj" -scheme Testable -derivedDataPath=${PWD}/build/Testable -destination "platform=iOS Simulator,${SIMULATOR}" | xcpretty -c +env NSUnbufferedIO=YES xcodebuild test -project "Documentation/Examples/Testable/Testable.xcodeproj" -scheme Testable -derivedDataPath=${PWD}/build/Testable -destination "platform=iOS Simulator,${SIMULATOR}" CODE_SIGNING_ALLOWED=NO | xcbeautify # Test the "TestableSwift" example project -env NSUnbufferedIO=YES xcodebuild test -project "Documentation/Examples/TestableSwift/TestableSwift.xcodeproj" -scheme "TestableSwift" -derivedDataPath=${PWD}/build/TestableSwift -destination "platform=iOS Simulator,${SIMULATOR}" | xcpretty -c +env NSUnbufferedIO=YES xcodebuild test -project "Documentation/Examples/TestableSwift/TestableSwift.xcodeproj" -scheme "TestableSwift" -derivedDataPath=${PWD}/build/TestableSwift -destination "platform=iOS Simulator,${SIMULATOR}" CODE_SIGNING_ALLOWED=NO | xcbeautify # Test the "Calculator" example project -env NSUnbufferedIO=YES xcodebuild test -project "Documentation/Examples/Calculator/Calculator.xcodeproj" -scheme "Calculator" -derivedDataPath=${PWD}/build/Calculator -destination "platform=iOS Simulator,${SIMULATOR}" | xcpretty -c +env NSUnbufferedIO=YES xcodebuild test -project "Documentation/Examples/Calculator/Calculator.xcodeproj" -scheme "Calculator" -derivedDataPath=${PWD}/build/Calculator -destination "platform=iOS Simulator,${SIMULATOR}" CODE_SIGNING_ALLOWED=NO | xcbeautify diff --git a/Sources/KIF/Additions/UIView-KIFAdditions.m b/Sources/KIF/Additions/UIView-KIFAdditions.m index 986490d7..4155b5a8 100644 --- a/Sources/KIF/Additions/UIView-KIFAdditions.m +++ b/Sources/KIF/Additions/UIView-KIFAdditions.m @@ -375,31 +375,67 @@ - (UIAccessibilityElement *)accessibilityElementMatchingBlock:(BOOL(^)(UIAccessi continue; } - @autoreleasepool { - CGRect visibleRect = [collectionView layoutAttributesForItemAtIndexPath:indexPath].frame; - [collectionView scrollRectToVisible:visibleRect animated:NO]; - [collectionView layoutIfNeeded]; - UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; - if (cell == nil) { - [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:NO]; + if (@available(iOS 18, *)) { + @autoreleasepool { + CGRect visibleRect = [collectionView layoutAttributesForItemAtIndexPath:indexPath].frame; + [collectionView scrollRectToVisible:visibleRect animated:NO]; [collectionView layoutIfNeeded]; - cell = [collectionView cellForItemAtIndexPath:indexPath]; + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + for (NSUInteger attempts = 0; attempts < 10 && !cell && collectionView.window; attempts++) { + CFRunLoopRunInMode(UIApplicationCurrentRunMode, 0.01, false); + cell = [collectionView cellForItemAtIndexPath:indexPath]; + } + if (cell == nil) { + [collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:NO]; + [collectionView layoutIfNeeded]; + cell = [collectionView cellForItemAtIndexPath:indexPath]; + } + // Skip this cell if it can't be found + if (!cell) { + continue; + } + UIAccessibilityElement *element = [cell accessibilityElementMatchingBlock:matchBlock notHidden:NO disableScroll:NO]; + + // Skip this cell if it isn't the one we're looking for + if (!element) { + continue; + } } - // Skip this cell if it can't be found - if (!cell) { - continue; - } - UIAccessibilityElement *element = [cell accessibilityElementMatchingBlock:matchBlock notHidden:NO disableScroll:NO]; - - // Skip this cell if it isn't the one we're looking for - if (!element) { - continue; + + // Note: using KIFRunLoopRunInModeRelativeToAnimationSpeed here may cause tests to stall + CFRunLoopRunInMode(UIApplicationCurrentRunMode, CELL_SCROLL_DELAY_STABILIZATION, false); + return [self accessibilityElementMatchingBlock:matchBlock disableScroll:NO]; + } else { + @autoreleasepool { + // Get the cell directly from the dataSource because UICollectionView will only vend visible cells + UICollectionViewCell *cell = [collectionView.dataSource collectionView:collectionView cellForItemAtIndexPath:indexPath]; + + // The cell contents might change just prior to being displayed, so we simulate the cell appearing onscreen + if ([collectionView.delegate respondsToSelector:@selector(collectionView:willDisplayCell:forItemAtIndexPath:)]) { + [collectionView.delegate collectionView:collectionView willDisplayCell:cell forItemAtIndexPath:indexPath]; + } + + UIAccessibilityElement *element = [cell accessibilityElementMatchingBlock:matchBlock notHidden:NO disableScroll:NO]; + + // Remove the cell from the collection view so that it doesn't stick around + [cell removeFromSuperview]; + + // Skip this cell if it isn't the one we're looking for + // Sometimes we get cells with no size here which can cause an endless loop, so we ignore those + if (!element || CGSizeEqualToSize(cell.frame.size, CGSizeZero)) { + continue; + } } + + // Scroll to the cell and wait for the animation to complete + CGRect frame = [collectionView.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath].frame; + [collectionView scrollRectToVisible:frame animated:YES]; + // Note: using KIFRunLoopRunInModeRelativeToAnimationSpeed here may cause tests to stall + CFRunLoopRunInMode(UIApplicationCurrentRunMode, 0.5, false); + + // Now try finding the element again + return [self accessibilityElementMatchingBlock:matchBlock]; } - - // Note: using KIFRunLoopRunInModeRelativeToAnimationSpeed here may cause tests to stall - CFRunLoopRunInMode(UIApplicationCurrentRunMode, CELL_SCROLL_DELAY_STABILIZATION, false); - return [self accessibilityElementMatchingBlock:matchBlock disableScroll:NO]; } }