Repository: rwapp/A11yUITests Branch: master Commit: 4d553c0120ea Files: 71 Total size: 231.3 KB Directory structure: gitextract_53ywak4o/ ├── .gitignore ├── .swiftpm/ │ └── xcode/ │ └── package.xcworkspace/ │ └── contents.xcworkspacedata ├── .travis.yml ├── A11yUITests.podspec ├── CHANGELOG.md ├── Example/ │ ├── A11yUITests/ │ │ ├── AppDelegate.swift │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.xib │ │ │ └── Main.storyboard │ │ ├── Images.xcassets/ │ │ │ ├── A11y_logo.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── ViewController.swift │ ├── A11yUITests.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata/ │ │ └── xcschemes/ │ │ └── A11yUITests-Example.xcscheme │ ├── A11yUITests.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ ├── A11yUITests_ExampleUITests/ │ │ ├── A11yUITests_ExampleUITests.swift │ │ ├── Info.plist │ │ └── References/ │ │ └── A11yUITests-ExampleUITests-test-snapshotTest-0.json │ ├── Podfile │ └── Pods/ │ ├── Local Podspecs/ │ │ └── A11yUITests.podspec.json │ ├── Pods.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ └── Target Support Files/ │ ├── A11yUITests/ │ │ ├── A11yUITests-Info.plist │ │ ├── A11yUITests-dummy.m │ │ ├── A11yUITests-prefix.pch │ │ ├── A11yUITests-umbrella.h │ │ ├── A11yUITests.debug.xcconfig │ │ ├── A11yUITests.modulemap │ │ ├── A11yUITests.release.xcconfig │ │ └── A11yUITests.xcconfig │ ├── Pods-A11yUITests_Example/ │ │ ├── Pods-A11yUITests_Example-Info.plist │ │ ├── Pods-A11yUITests_Example-acknowledgements.markdown │ │ ├── Pods-A11yUITests_Example-acknowledgements.plist │ │ ├── Pods-A11yUITests_Example-dummy.m │ │ ├── Pods-A11yUITests_Example-frameworks.sh │ │ ├── Pods-A11yUITests_Example-umbrella.h │ │ ├── Pods-A11yUITests_Example.debug.xcconfig │ │ ├── Pods-A11yUITests_Example.modulemap │ │ └── Pods-A11yUITests_Example.release.xcconfig │ └── Pods-A11yUITests_ExampleUITests/ │ ├── Pods-A11yUITests_ExampleUITests-Info.plist │ ├── Pods-A11yUITests_ExampleUITests-acknowledgements.markdown │ ├── Pods-A11yUITests_ExampleUITests-acknowledgements.plist │ ├── Pods-A11yUITests_ExampleUITests-dummy.m │ ├── Pods-A11yUITests_ExampleUITests-frameworks.sh │ ├── Pods-A11yUITests_ExampleUITests-umbrella.h │ ├── Pods-A11yUITests_ExampleUITests.debug.xcconfig │ ├── Pods-A11yUITests_ExampleUITests.modulemap │ └── Pods-A11yUITests_ExampleUITests.release.xcconfig ├── LICENSE ├── Package.swift ├── README.md └── Sources/ └── A11yUITests/ ├── Elements/ │ ├── A11yElement.swift │ └── XCUIElement.ElementType+Name.swift ├── Extensions/ │ ├── CGFloat+Extensions.swift │ ├── NSObject+Extensions.swift │ ├── String+Extensions.swift │ ├── UIAccessibilityTraits+Extensions.swift │ ├── XCTest+extensions.swift │ └── XCUIElementSnapshot+Extensions.swift ├── Helpers/ │ └── Failure.swift └── Tests/ ├── A11yAssertions.swift ├── A11ySnapshot.swift ├── A11yTests.swift ├── TestRunner.swift ├── Values.swift └── XCTestCase+A11y.swift ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # OS X .DS_Store # Xcode build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata/ *.xccheckout profile *.moved-aside DerivedData *.hmap *.ipa .build/ # Bundler .bundle # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control # # Note: if you ignore the Pods directory, make sure to uncomment # `pod install` in .travis.yml # # Pods/ ================================================ FILE: .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: .travis.yml ================================================ # references: # * https://www.objc.io/issues/6-build-tools/travis-ci/ # * https://github.com/supermarin/xcpretty#usage osx_image: xcode7.3 language: objective-c # cache: cocoapods # podfile: Example/Podfile # before_install: # - gem install cocoapods # Since Travis is not always on latest version # - pod install --project-directory=Example script: - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/A11yUITests.xcworkspace -scheme A11yUITests-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty - pod lib lint ================================================ FILE: A11yUITests.podspec ================================================ Pod::Spec.new do |s| s.name = 'A11yUITests' s.version = '1.1.0' s.summary = 'Accessibility tests for XCUI Testing.' s.description = <<-DESC A library of common accessibility tests for use with XCUI Tests DESC s.homepage = 'https://github.com/rwapp/A11yUITests' s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'Rob Whitaker' => 'rw@rwapp.co.uk' } s.source = { :git => 'https://github.com/rwapp/A11yUITests.git', :tag => s.version.to_s } s.social_media_url = 'https://twitter.com/MobileA11y' s.ios.deployment_target = '11.0' s.swift_version = '5.0' s.source_files = 'Sources/A11yUITests/**/*' s.frameworks = 'XCTest' end ================================================ FILE: CHANGELOG.md ================================================ # Changelog ## 1.1.0 * Added the ability to change default values for tests * Added the ability to specify accessibility label or accessibility identifier reported in failure messages * New rule for elements with a placeholder and no label. * Improved method for fetching traits meaning no swizzling - thank you [Chris Kolbu](https://github.com/nesevis) * Improved error reporting - thank you [Ryan Ferrell](https://github.com/importRyan) * Added a test for common non-descriptive button titles following [SC 2.4.9: Link Purpose (Link Only) (Level AAA)](https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-link-only) * Added a test for uppercase labels * Added tests for element types in labels * Added a test for closely spaced controls * Added a test for overlapping controls * Updated interactive suite * Fixed a crash when performing a snapshot test on a screen with fewer elements that the reference * Fixes an issue where some tests were run more than once ## 1.0.0 * Addition of snapshot testing ## 0.6.1 * Change to floating point assertion accuracy ## 0.6.0 * Adds a test to flag conflicting accessibility traits * Adds ❌ to failure messages and ⚠️ to warning messages for improved prominence ## 0.5.2 * Adds the ability to ignore elements when running `a11yCheckAllOnScreen()` ## 0.5.1 * Fixed a bug that was causing the library to fail to compile for some users ## 0.5.0 * Adds the ability to specify minimum size and maximum label length * Reduces the default minimum size value to 14 * Improved failure messages - issues that are not strict failures but require investigation are now marked as 'Warning' * Now defaults to checking all interactive elements for minimum size of 44px. Can be overridden by setting `allInteractiveElements` to false. ## 0.4.1 * Swift Package Manager support ## 0.4.0 * Added checks for traits * Buttons * Headers * Images * Added a check for disabled interactive elements * Removed references to individual tests from the docs as a soft deprecation * Note: Checking for traits uses a private property on the iOS SDK. Be careful not to include this code in your shipped app as it may be rejected by Apple. ## 0.3.1 * Minor code quality improvements and clarification to the readme ## 0.3.0 * Improvements for label checks * Ability to specify minimum length * Reporting failure strings in failure reasons * Reporting minimum length in failure reasons * Minimum label length checks added to images and interactive elements * Improved documentation ## 0.2.0 * Clarified function names - this is a breaking change from 0.1.0 * Added test for duplicated element labels * Significant speed and reliability improvements * Improved documentation ## 0.1.0 * Initial release ================================================ FILE: Example/A11yUITests/AppDelegate.swift ================================================ // // AppDelegate.swift // A11yUITests // // Created by r.whitaker@mac.com on 12/05/2019. // Copyright (c) 2019 r.whitaker@mac.com. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { return true } } ================================================ FILE: Example/A11yUITests/Base.lproj/LaunchScreen.xib ================================================ ================================================ FILE: Example/A11yUITests/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Example/A11yUITests/Images.xcassets/A11y_logo.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "a11ylogo.pdf" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "preserves-vector-representation" : true } } ================================================ FILE: Example/A11yUITests/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/A11yUITests/Images.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/A11yUITests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait ================================================ FILE: Example/A11yUITests/ViewController.swift ================================================ // // ViewController.swift // A11yUITests // // Created by r.whitaker@mac.com on 12/05/2019. // Copyright (c) 2019 r.whitaker@mac.com. All rights reserved. // import UIKit class ViewController: UIViewController {} ================================================ FILE: Example/A11yUITests.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; }; 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; 8D9CB28FCB9616A84D4981DB /* Pods_A11yUITests_ExampleUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 112E2CDD3165666239250CC1 /* Pods_A11yUITests_ExampleUITests.framework */; }; ADC7797BB2FBA898C717543D /* Pods_A11yUITests_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 368D7F1C18B401E09270BF57 /* Pods_A11yUITests_Example.framework */; }; B5B61DF923995BEE0096085C /* A11yUITests_ExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5B61DF823995BEE0096085C /* A11yUITests_ExampleUITests.swift */; }; B5E5B26829AB5B6B002E4833 /* A11yUITests-ExampleUITests-test-snapshotTest-0.json in Resources */ = {isa = PBXBuildFile; fileRef = B5E5B26729AB5B6B002E4833 /* A11yUITests-ExampleUITests-test-snapshotTest-0.json */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ B5B61DFB23995BEE0096085C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 607FACC81AFB9204008FA782 /* Project object */; proxyType = 1; remoteGlobalIDString = 607FACCF1AFB9204008FA782; remoteInfo = A11yUITests_Example; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 112E2CDD3165666239250CC1 /* Pods_A11yUITests_ExampleUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_A11yUITests_ExampleUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 368D7F1C18B401E09270BF57 /* Pods_A11yUITests_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_A11yUITests_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 36E9AAF0265EA2E9AF0CCAE9 /* A11yUITests.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = A11yUITests.podspec; path = ../A11yUITests.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 58A9A9460C5B7598B1DD3C90 /* Pods-A11yUITests_ExampleUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-A11yUITests_ExampleUITests.release.xcconfig"; path = "Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests.release.xcconfig"; sourceTree = ""; }; 607FACD01AFB9204008FA782 /* A11yUITests_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = A11yUITests_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 838048D31939BAB6566FDFFC /* Pods-A11yUITests_ExampleUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-A11yUITests_ExampleUITests.debug.xcconfig"; path = "Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests.debug.xcconfig"; sourceTree = ""; }; 8C78D33CFE20D29A24ABD246 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 9B2355B8F6DC8DC1A71D81C9 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; AA5911E12232347529BA4905 /* Pods-A11yUITests_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-A11yUITests_Example.release.xcconfig"; path = "Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example.release.xcconfig"; sourceTree = ""; }; B29200CCF9092577797F1B2A /* Pods-A11yUITests_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-A11yUITests_Example.debug.xcconfig"; path = "Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example.debug.xcconfig"; sourceTree = ""; }; B5B61DF623995BEE0096085C /* A11yUITests_ExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = A11yUITests_ExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; B5B61DF823995BEE0096085C /* A11yUITests_ExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = A11yUITests_ExampleUITests.swift; sourceTree = ""; }; B5B61DFA23995BEE0096085C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B5E5B26729AB5B6B002E4833 /* A11yUITests-ExampleUITests-test-snapshotTest-0.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "A11yUITests-ExampleUITests-test-snapshotTest-0.json"; sourceTree = ""; }; B5FD2A77262A16C40008309E /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 607FACCD1AFB9204008FA782 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ADC7797BB2FBA898C717543D /* Pods_A11yUITests_Example.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; B5B61DF323995BEE0096085C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 8D9CB28FCB9616A84D4981DB /* Pods_A11yUITests_ExampleUITests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 607FACC71AFB9204008FA782 = { isa = PBXGroup; children = ( 607FACF51AFB993E008FA782 /* Podspec Metadata */, 607FACD21AFB9204008FA782 /* Example for A11yUITests */, B5B61DF723995BEE0096085C /* A11yUITests_ExampleUITests */, 607FACD11AFB9204008FA782 /* Products */, 683410DC2F0CE618725319C7 /* Pods */, 8655077FADBE48E4847E2E9D /* Frameworks */, ); sourceTree = ""; }; 607FACD11AFB9204008FA782 /* Products */ = { isa = PBXGroup; children = ( 607FACD01AFB9204008FA782 /* A11yUITests_Example.app */, B5B61DF623995BEE0096085C /* A11yUITests_ExampleUITests.xctest */, ); name = Products; sourceTree = ""; }; 607FACD21AFB9204008FA782 /* Example for A11yUITests */ = { isa = PBXGroup; children = ( 607FACD51AFB9204008FA782 /* AppDelegate.swift */, 607FACD71AFB9204008FA782 /* ViewController.swift */, 607FACD91AFB9204008FA782 /* Main.storyboard */, 607FACDC1AFB9204008FA782 /* Images.xcassets */, 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */, 607FACD31AFB9204008FA782 /* Supporting Files */, ); name = "Example for A11yUITests"; path = A11yUITests; sourceTree = ""; }; 607FACD31AFB9204008FA782 /* Supporting Files */ = { isa = PBXGroup; children = ( 607FACD41AFB9204008FA782 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { isa = PBXGroup; children = ( 36E9AAF0265EA2E9AF0CCAE9 /* A11yUITests.podspec */, 8C78D33CFE20D29A24ABD246 /* README.md */, 9B2355B8F6DC8DC1A71D81C9 /* LICENSE */, B5FD2A77262A16C40008309E /* CHANGELOG.md */, ); name = "Podspec Metadata"; sourceTree = ""; }; 683410DC2F0CE618725319C7 /* Pods */ = { isa = PBXGroup; children = ( B29200CCF9092577797F1B2A /* Pods-A11yUITests_Example.debug.xcconfig */, AA5911E12232347529BA4905 /* Pods-A11yUITests_Example.release.xcconfig */, 838048D31939BAB6566FDFFC /* Pods-A11yUITests_ExampleUITests.debug.xcconfig */, 58A9A9460C5B7598B1DD3C90 /* Pods-A11yUITests_ExampleUITests.release.xcconfig */, ); path = Pods; sourceTree = ""; }; 8655077FADBE48E4847E2E9D /* Frameworks */ = { isa = PBXGroup; children = ( 368D7F1C18B401E09270BF57 /* Pods_A11yUITests_Example.framework */, 112E2CDD3165666239250CC1 /* Pods_A11yUITests_ExampleUITests.framework */, ); name = Frameworks; sourceTree = ""; }; B595722927934F16008F4598 /* References */ = { isa = PBXGroup; children = ( B5E5B26729AB5B6B002E4833 /* A11yUITests-ExampleUITests-test-snapshotTest-0.json */, ); path = References; sourceTree = ""; }; B5B61DF723995BEE0096085C /* A11yUITests_ExampleUITests */ = { isa = PBXGroup; children = ( B595722927934F16008F4598 /* References */, B5B61DF823995BEE0096085C /* A11yUITests_ExampleUITests.swift */, B5B61DFA23995BEE0096085C /* Info.plist */, ); path = A11yUITests_ExampleUITests; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 607FACCF1AFB9204008FA782 /* A11yUITests_Example */ = { isa = PBXNativeTarget; buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "A11yUITests_Example" */; buildPhases = ( 65EF7F6D05208D18D84DDC19 /* [CP] Check Pods Manifest.lock */, 607FACCC1AFB9204008FA782 /* Sources */, 607FACCD1AFB9204008FA782 /* Frameworks */, 607FACCE1AFB9204008FA782 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = A11yUITests_Example; productName = A11yUITests; productReference = 607FACD01AFB9204008FA782 /* A11yUITests_Example.app */; productType = "com.apple.product-type.application"; }; B5B61DF523995BEE0096085C /* A11yUITests_ExampleUITests */ = { isa = PBXNativeTarget; buildConfigurationList = B5B61DFD23995BEE0096085C /* Build configuration list for PBXNativeTarget "A11yUITests_ExampleUITests" */; buildPhases = ( 4828A88E78F5BAB6A23781DF /* [CP] Check Pods Manifest.lock */, B5B61DF223995BEE0096085C /* Sources */, B5B61DF323995BEE0096085C /* Frameworks */, B5B61DF423995BEE0096085C /* Resources */, 5184E1E21087C8F7A0DA65CD /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( B5B61DFC23995BEE0096085C /* PBXTargetDependency */, ); name = A11yUITests_ExampleUITests; productName = A11yUITests_ExampleUITests; productReference = B5B61DF623995BEE0096085C /* A11yUITests_ExampleUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 607FACC81AFB9204008FA782 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1120; LastUpgradeCheck = 1120; ORGANIZATIONNAME = CocoaPods; TargetAttributes = { 607FACCF1AFB9204008FA782 = { CreatedOnToolsVersion = 6.3.1; LastSwiftMigration = 0900; }; B5B61DF523995BEE0096085C = { CreatedOnToolsVersion = 11.2.1; DevelopmentTeam = K55J7MA3F2; ProvisioningStyle = Automatic; TestTargetID = 607FACCF1AFB9204008FA782; }; }; }; buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "A11yUITests" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 607FACC71AFB9204008FA782; productRefGroup = 607FACD11AFB9204008FA782 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 607FACCF1AFB9204008FA782 /* A11yUITests_Example */, B5B61DF523995BEE0096085C /* A11yUITests_ExampleUITests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 607FACCE1AFB9204008FA782 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */, 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; B5B61DF423995BEE0096085C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( B5E5B26829AB5B6B002E4833 /* A11yUITests-ExampleUITests-test-snapshotTest-0.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 4828A88E78F5BAB6A23781DF /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-A11yUITests_ExampleUITests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 5184E1E21087C8F7A0DA65CD /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/A11yUITests/A11yUITests.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/A11yUITests.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 65EF7F6D05208D18D84DDC19 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-A11yUITests_Example-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 607FACCC1AFB9204008FA782 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */, 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; B5B61DF223995BEE0096085C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( B5B61DF923995BEE0096085C /* A11yUITests_ExampleUITests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ B5B61DFC23995BEE0096085C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 607FACCF1AFB9204008FA782 /* A11yUITests_Example */; targetProxy = B5B61DFB23995BEE0096085C /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 607FACD91AFB9204008FA782 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 607FACDA1AFB9204008FA782 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( 607FACDF1AFB9204008FA782 /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 607FACED1AFB9204008FA782 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = 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_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_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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 = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 607FACEE1AFB9204008FA782 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = 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_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_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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 = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; }; 607FACF01AFB9204008FA782 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = B29200CCF9092577797F1B2A /* Pods-A11yUITests_Example.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = A11yUITests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; }; name = Debug; }; 607FACF11AFB9204008FA782 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = AA5911E12232347529BA4905 /* Pods-A11yUITests_Example.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = A11yUITests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MODULE_NAME = ExampleApp; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 5.0; }; name = Release; }; B5B61DFE23995BEE0096085C /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 838048D31939BAB6566FDFFC /* Pods-A11yUITests_ExampleUITests.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = K55J7MA3F2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = A11yUITests_ExampleUITests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "uk.co.rwapp.A11yUITests-ExampleUITests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = A11yUITests_Example; }; name = Debug; }; B5B61DFF23995BEE0096085C /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 58A9A9460C5B7598B1DD3C90 /* Pods-A11yUITests_ExampleUITests.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = K55J7MA3F2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = A11yUITests_ExampleUITests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.2; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "uk.co.rwapp.A11yUITests-ExampleUITests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_TARGET_NAME = A11yUITests_Example; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "A11yUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( 607FACED1AFB9204008FA782 /* Debug */, 607FACEE1AFB9204008FA782 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "A11yUITests_Example" */ = { isa = XCConfigurationList; buildConfigurations = ( 607FACF01AFB9204008FA782 /* Debug */, 607FACF11AFB9204008FA782 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; B5B61DFD23995BEE0096085C /* Build configuration list for PBXNativeTarget "A11yUITests_ExampleUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( B5B61DFE23995BEE0096085C /* Debug */, B5B61DFF23995BEE0096085C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 607FACC81AFB9204008FA782 /* Project object */; } ================================================ FILE: Example/A11yUITests.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/A11yUITests.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Example/A11yUITests.xcodeproj/xcshareddata/xcschemes/A11yUITests-Example.xcscheme ================================================ ================================================ FILE: Example/A11yUITests.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/A11yUITests.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Example/A11yUITests_ExampleUITests/A11yUITests_ExampleUITests.swift ================================================ // // A11yUITests_ExampleUITests.swift // A11yUITests_ExampleUITests // // Created by Rob Whitaker on 05/12/2019. // Copyright © 2019 CocoaPods. All rights reserved. // import XCTest import A11yUITests @testable import A11yUITests_Example class A11yUITestsExampleUITests: XCTestCase { override func setUp() { XCUIApplication().launch() } func test_snapshotTest() { a11ySnapshot() } func test_allTests() { // Produces 24 failures // Accessibility Failure - Button should not contain the word 'button' in the accessibility label. Label: "ENDS WITH BUTTON" Button. // Accessibility Warning - Elements have duplicated labels. Label: "Duplicated" Button, Label: "Duplicated" Button. // Accessibility Failure - Image file name is used as the accessibility label. Offending word: _. // Accessibility Failure - Images should not contain image words in the accessibility label. Offending word: image. // Accessibility Failure - Button accessibility labels shouldn't contain punctuation. Label: "Punctuated." Button. // Accessibility Failure - Buttons should begin with a capital letter. Label: " " Button. // Accessibility Failure - Buttons should begin with a capital letter. Label: "lowercase" Button. // Accessibility Warning - Element may not be tall enough. Label: "Label too small" Label. Minimum height: 14. Current height: 13.0. // Accessibility Warning - Element may not be wide enough. Label: "Label too small" Label. Minimum width: 14. Current width: 13.0. // Accessibility Failure - Interactive element not tall enough. Label: "Too Small" Button. Minimum height: 44.0. Current height: 43.0. // Accessibility Failure - Interactive element not wide enough. Label: "Too Small" Button. Minimum width: 44.0. Current width: 43.0. // Accessibility Warning - Label may be too long. Label: "A very long overly descriptive label that isn't required use context instead to infer meaning or add a hint if required" Button. Max length: 40. // Accessibility Warning - Label may not be meaningful. Label: " " Button. Minimum length: 2. // Accessibility Failure - Interactive element not tall enough. [No identifier] Text Field. Minimum height: 44.0. Current height: 34.00. // Accessibility Failure - Image should have Image trait. Label: "A11y_logo" Image. // Accessibility Failure - Screen has no element with a header trait. // Accessibility Failure - Button should have Button or Link trait. Label: "No trait" Button. // Accessibility Warning - Element disabled. Label: "Disabled" Button. // Accessibility Failure - Elements shouldn't have both Button and Link traits. Label: "Conflicting traits" Button. // Accessibility Failure - No label for element with placeholder "Placeholder". [No identifier] Text Field. // Accessibility Warning - Label is uppercased. Label: "ENDS WITH BUTTON" Button. // Accessibility Failure - Button label may not be descriptive. Label: "Click here" Button. Offending word: click here // Accessibility Warning - Controls are closely spaced. Label: "Click here" Button, Label: "Duplicated" Button. // Accessibility Failure - Controls are overlapping. Label: "Conflicting traits" Button, Label: "Overlapping" Button. a11yCheckAllOnScreen() } func test_images() { // produces 4 failures // Accessibility Failure - Image file name is used as the accessibility label. Offending word: _. // Accessibility Failure - Images should not contain image words in the accessibility label. Offending word: image. // Accessibility Warning - Label may not be meaningful. Label: "A11y_logo" Image. Minimum length: 10. // Accessibility Failure - Image should have Image trait. Label: "A11y_logo" Image. let images = XCUIApplication().images.allElementsBoundByIndex a11y(tests: a11yTestSuiteImages, on: images, minMeaningfulLength: 10) } func test_buttons() { // produces 16 failures // Accessibility Failure - Button should not contain the word 'button' in the accessibility label Label: "ENDS WITH BUTTON" Button. // Accessibility Warning - Elements have duplicated labels. Label: "Duplicated" Button, Label: "Duplicated" Button. // Accessibility Failure - Button accessibility labels shouldn't contain punctuation Label: "Punctuated." Button. // Accessibility Failure - Buttons should begin with a capital letter. Label: " " Button. // Accessibility Failure - Buttons should begin with a capital letter. Label: "lowercase" Button. // Accessibility Failure - Interactive element not tall enough. Label: "Too Small" Button. Minimum height: 44.0. Current height: 43.0. // Accessibility Failure - Interactive element not wide enough. Label: "Too Small" Button. Minimum width: 44.0. Current width: 43.0. // Accessibility Warning - Label is too long. Label: "A very long overly descriptive label that isn't required use context instead to infer meaning or add a hint if required" Button. Max length: 40. // Accessibility Warning - Label may not be meaningful. Label: " " Button. Minimum length: 2. // Accessibility Failure - Button should have Button or Link trait. Label: "No trait" Button. // Accessibility Warning - Element disabled. Label: "Disabled" Button. // Accessibility Failure - Elements shouldn't have both Button and Link traits. Label: "Conflicting traits" Button. // Accessibility Warning - Label is uppercased. Label: "ENDS WITH BUTTON" Button. // Accessibility Failure - Button label may not be descriptive. Label: "Click here" Button. Offending word: click here // Accessibility Warning - Controls are closely spaced. Label: "Duplicated" Button, Label: "Click here" Button. // Accessibility Failure - Controls are overlapping. Label: "Conflicting traits" Button, Label: "Overlapping" Button. let buttons = XCUIApplication().buttons.allElementsBoundByIndex a11y(tests: a11yTestSuiteInteractive, on: buttons) } func test_labels() { // produces 2 failures // Accessibility Warning - Element not tall enough. Label: "Label too small" Label. Minimum height: 14. Current height: 13.0. // Accessibility Warning - Element not wide enough. Label: "Label too small" Label. Minimum width: 14. Current width: 13.0. let labels = XCUIApplication().staticTexts.allElementsBoundByIndex a11y(tests: a11yTestSuiteLabels, on: labels) } func test_individualTest_individualButton() { // produces 2 failures // Accessibility Failure - Button should not contain the word 'button' in the accessibility label. Label: "ENDS WITH BUTTON" Button. // Accessibility Warning - Label is uppercased. Label: "ENDS WITH BUTTON" Button. let button = XCUIApplication().buttons["ENDS WITH BUTTON"] a11y(tests: [.buttonLabel], on: [button]) } } ================================================ FILE: Example/A11yUITests_ExampleUITests/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString 1.0 CFBundleVersion 1 ================================================ FILE: Example/A11yUITests_ExampleUITests/References/A11yUITests-ExampleUITests-test-snapshotTest-0.json ================================================ { "generated" : "2023-02-26T09:17:02Z", "filename" : "A11yUITests-ExampleUITests-test-snapshotTest-0.json", "snapshot" : [ { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 79 ], [ 43, 43 ] ], "value" : "", "label" : "Too Small", "type" : "Button" }, { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 130 ], [ 84, 44 ] ], "value" : "", "label" : "Punctuated.", "type" : "Button" }, { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 182 ], [ 116, 44 ] ], "value" : "", "label" : "ENDS WITH BUTTON", "type" : "Button" }, { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 234 ], [ 69, 44 ] ], "value" : "", "label" : "lowercase", "type" : "Button" }, { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 286 ], [ 144, 44 ] ], "value" : "", "label" : " ", "type" : "Button" }, { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 338 ], [ 159, 44 ] ], "value" : "", "label" : "A very long overly descriptive label that isn't required use context instead to infer meaning or add a hint if required", "type" : "Button" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 390 ], [ 13, 13 ] ], "value" : "", "label" : "Label too small", "type" : "Label" }, { "traits" : [ ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 411 ], [ 44, 59.666666666666686 ] ], "value" : "", "label" : "A11y_logo", "type" : "Image" }, { "traits" : [ "Image" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 478.66666666666669 ], [ 44, 59.666666666666686 ] ], "value" : "", "label" : "image of the Mobile A11y logo", "type" : "Image" }, { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 546.33333333333337 ], [ 74, 44 ] ], "value" : "", "label" : "Duplicated", "type" : "Button" }, { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 598.33333333333337 ], [ 74, 44 ] ], "value" : "", "label" : "Duplicated", "type" : "Button" }, { "traits" : [ ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 642.33333333333337 ], [ 51, 44 ] ], "value" : "", "label" : "Click here", "type" : "Button" }, { "traits" : [ "Button", "Not Enabled" ], "placeholder" : "", "enabled" : false, "frame" : [ [ 16, 694.33333333333337 ], [ 60, 44 ] ], "value" : "", "label" : "Disabled", "type" : "Button" }, { "traits" : [ "Button", "Link" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 746.33333333333337 ], [ 114, 58.666666666666629 ] ], "value" : "", "label" : "Conflicting traits", "type" : "Button" }, { "traits" : [ "Button" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 79, 746.33333333333337 ], [ 90, 54.333333333333258 ] ], "value" : "", "label" : "Overlapping", "type" : "Button" }, { "traits" : [ ], "placeholder" : "Placeholder", "enabled" : true, "frame" : [ [ 16, 813 ], [ 361, 34 ] ], "value" : "Placeholder", "label" : "", "type" : "Text Field" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 20, 91.666666666666671 ], [ 35, 18 ] ], "value" : "", "label" : "Too Small", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 143 ], [ 84, 18 ] ], "value" : "", "label" : "Punctuated.", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 195 ], [ 116, 18 ] ], "value" : "", "label" : "Ends with button", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 247 ], [ 69, 18 ] ], "value" : "", "label" : "lowercase", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 299 ], [ 144, 18 ] ], "value" : "", "label" : "No accessibility label", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 351 ], [ 159, 18 ] ], "value" : "", "label" : "Long accessibility label", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 559.33333333333337 ], [ 74, 18 ] ], "value" : "", "label" : "Duplicated", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 611.33333333333337 ], [ 74, 18 ] ], "value" : "", "label" : "Duplicated", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 655.33333333333337 ], [ 51, 18 ] ], "value" : "", "label" : "No trait", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 707.33333333333337 ], [ 60, 18 ] ], "value" : "", "label" : "Disabled", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 16, 766.66666666666663 ], [ 114, 18 ] ], "value" : "", "label" : "Conflicting traits", "type" : "Label" }, { "traits" : [ "Static Text" ], "placeholder" : "", "enabled" : true, "frame" : [ [ 94, 753.33333333333337 ], [ 59.333333333333343, 40.333333333333258 ] ], "value" : "", "label" : "Overlapping", "type" : "Label" } ], "version" : "1.1" } ================================================ FILE: Example/Podfile ================================================ use_frameworks! platform :ios, '11.0' target 'A11yUITests_Example' do target 'A11yUITests_ExampleUITests' do inherit! :search_paths pod 'A11yUITests', :path => '../' end end ================================================ FILE: Example/Pods/Local Podspecs/A11yUITests.podspec.json ================================================ { "name": "A11yUITests", "version": "1.0.0", "summary": "Accessibility tests for XCUI Testing.", "description": "A library of common accessibility tests for use with XCUI Tests", "homepage": "https://github.com/rwapp/A11yUITests", "license": { "type": "MIT", "file": "LICENSE" }, "authors": { "Rob Whitaker": "rw@rwapp.co.uk" }, "source": { "git": "https://github.com/rwapp/A11yUITests.git", "tag": "1.0.0" }, "social_media_url": "https://twitter.com/MobileA11y", "platforms": { "ios": "11.0" }, "swift_versions": "5.0", "source_files": "Sources/A11yUITests/**/*", "frameworks": "XCTest", "swift_version": "5.0" } ================================================ FILE: Example/Pods/Pods.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 17FDB1F0B86F11EFDFA84279CF4AA057 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2565A65844EDD8B489BA9976915D4DA7 /* String+Extensions.swift */; }; 238FB925228BF10462B8B067EF780C8D /* A11yUITests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9CECF5F8FF0D192E15ADA2E7F5E79EA1 /* A11yUITests-dummy.m */; }; 3381D04F7EB08959C620CAF19C1D5504 /* XCUIElementSnapshot+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACA07E49A454084A01A00FAC5E14FC5 /* XCUIElementSnapshot+Extensions.swift */; }; 358E24597528C6CD0FA30ABB4E2A6B14 /* Pods-A11yUITests_ExampleUITests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 194ED318FCC5418CB903C4D1EA0AFB8B /* Pods-A11yUITests_ExampleUITests-dummy.m */; }; 3F27A667C6E9B253F9DE85BF13DEA0F9 /* NSObject+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0F7A495F3E70B94110AB67E40E0C33C /* NSObject+Extensions.swift */; }; 3F52713A686DACEA0488AE02276913E3 /* A11yUITests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D5FE81638FEE2217F5479E5A6AEEC33 /* A11yUITests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4254173723043B6EDBD3007BA60C7857 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EBC8F300895E39EA0DF6D6B2B5E6BCD /* XCTest.framework */; }; 4506F6D361FD18CF8BBE40CDB5A5F967 /* UIAccessibilityTraits+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5661872E3513F051E79EF0B643777E42 /* UIAccessibilityTraits+Extensions.swift */; }; 5C010D72D1D73C139089C53A1337D737 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA8B94E9D3B433157168D1EECCEC11CD /* Foundation.framework */; }; 5ED0F81956203C722779A287F87BDB63 /* Pods-A11yUITests_ExampleUITests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 13357D88C84F61D0461D6480AFA4BECB /* Pods-A11yUITests_ExampleUITests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5EF8B909FEC4CF7506680C929771ED53 /* A11yTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA571919F1C24A1FF9C981ADE6C15CD7 /* A11yTests.swift */; }; 656CFD36E712E8E7AC09BF1154394876 /* XCUIElement.ElementType+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1417692524BF327AB8A9959529D3777 /* XCUIElement.ElementType+Name.swift */; }; 687CF6C490C50856A274D0BEA2EEBBD9 /* XCTestCase+A11y.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9DA61CD1C94B157A741AB9549AC8B94 /* XCTestCase+A11y.swift */; }; 6D2767059B928CAF7CB6956EA2A0FEDF /* A11yAssertions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CCF0A4BB003F06C90AC5440FF731179 /* A11yAssertions.swift */; }; 749040B9DDDE7A34914B1121187A1115 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA8B94E9D3B433157168D1EECCEC11CD /* Foundation.framework */; }; 7868E4AED48565BDE14FBD0C1956C9AE /* Pods-A11yUITests_Example-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C78F5BE202F945BDD5F08D62226B8979 /* Pods-A11yUITests_Example-dummy.m */; }; 7CEF1D4C56FDCA7E64C4210740CEE2DB /* Pods-A11yUITests_Example-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 6418B7E6BB7698182C01F81569F93979 /* Pods-A11yUITests_Example-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8BE342D78F958D3B0C22E3FE1D594B35 /* TestRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED4AB13ABE158CD779DE2538AE4901AA /* TestRunner.swift */; }; 8E3E1CD6FE7730051804AB1E03B18365 /* Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CD316ABE953A851F64274D60AB4CFC4 /* Values.swift */; }; 96E3DD27029B0CCFBB4314CC510EE0E3 /* A11ySnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818899D18C1C55CEB8B08544F21BA24D /* A11ySnapshot.swift */; }; A7E74E087DF362B7D0BFDEC879AAB7E8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA8B94E9D3B433157168D1EECCEC11CD /* Foundation.framework */; }; B574354929AA3BC1003E077A /* XCTest+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B574354829AA3BC1003E077A /* XCTest+extensions.swift */; }; B5E5B26629AA6802002E4833 /* CGFloat+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E5B26529AA6802002E4833 /* CGFloat+Extensions.swift */; }; D477E37CF14AF319305184A16E2B5F55 /* Failure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69AEE66AFD1AFED6E6CCAAAC140E75C0 /* Failure.swift */; }; FCA4D31DBB3A43D7C2B64776E31A08AB /* A11yElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 733D6503FF64B33C74F6C7072D6340FD /* A11yElement.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 53985416026C5AC2DC081EAAFACFBED7 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = 1CD04A6F172AA7EE2B75168D0CBABA8F; remoteInfo = A11yUITests; }; BE98C7D17C5FD4B27B9AF584FAD407A1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = 7C950F990A68123DBF2635DDBEBED3AA; remoteInfo = "Pods-A11yUITests_Example"; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 06BDBEFE7BF7A558A6B24469FA04EC9C /* Pods-A11yUITests_ExampleUITests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-A11yUITests_ExampleUITests"; path = Pods_A11yUITests_ExampleUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 092785D9D413E6A3F91CDF4C8FDB10DF /* Pods-A11yUITests_ExampleUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-A11yUITests_ExampleUITests.debug.xcconfig"; sourceTree = ""; }; 0C86D2B44EC444FE6634E1956FA0D8DC /* A11yUITests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = A11yUITests; path = A11yUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 13357D88C84F61D0461D6480AFA4BECB /* Pods-A11yUITests_ExampleUITests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-A11yUITests_ExampleUITests-umbrella.h"; sourceTree = ""; }; 17860584BFC7619F0247D7B50FC37452 /* Pods-A11yUITests_ExampleUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-A11yUITests_ExampleUITests.release.xcconfig"; sourceTree = ""; }; 194ED318FCC5418CB903C4D1EA0AFB8B /* Pods-A11yUITests_ExampleUITests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-A11yUITests_ExampleUITests-dummy.m"; sourceTree = ""; }; 2565A65844EDD8B489BA9976915D4DA7 /* String+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; 26464675A37C2C0341F3D45AA37F9016 /* Pods-A11yUITests_ExampleUITests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-A11yUITests_ExampleUITests.modulemap"; sourceTree = ""; }; 28C69C0BBE2D53342C4FFDC03ECDE8DC /* A11yUITests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = A11yUITests.modulemap; sourceTree = ""; }; 2BE35B690B2EA963572A82E02421D56A /* A11yUITests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "A11yUITests-Info.plist"; sourceTree = ""; }; 3006D75A5EC288FBDE9985E019D4F35F /* Pods-A11yUITests_ExampleUITests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-A11yUITests_ExampleUITests-Info.plist"; sourceTree = ""; }; 35A1596E3D68A0F3D5CABE98AC87FB42 /* A11yUITests-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "A11yUITests-prefix.pch"; sourceTree = ""; }; 3ACA07E49A454084A01A00FAC5E14FC5 /* XCUIElementSnapshot+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "XCUIElementSnapshot+Extensions.swift"; sourceTree = ""; }; 44439EABAF52646700C93C1E0F120809 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 5661872E3513F051E79EF0B643777E42 /* UIAccessibilityTraits+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "UIAccessibilityTraits+Extensions.swift"; sourceTree = ""; }; 568E339865C8AB97A822908C0ABFD693 /* A11yUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = A11yUITests.release.xcconfig; sourceTree = ""; }; 5A6274C8A56060543AACFF9A29E0FA94 /* Pods-A11yUITests_ExampleUITests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-A11yUITests_ExampleUITests-frameworks.sh"; sourceTree = ""; }; 5BBB5085CDE27F6E27902E357ADD4671 /* Pods-A11yUITests_Example-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-A11yUITests_Example-Info.plist"; sourceTree = ""; }; 5CD316ABE953A851F64274D60AB4CFC4 /* Values.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Values.swift; sourceTree = ""; }; 5EBC8F300895E39EA0DF6D6B2B5E6BCD /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 6418B7E6BB7698182C01F81569F93979 /* Pods-A11yUITests_Example-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-A11yUITests_Example-umbrella.h"; sourceTree = ""; }; 69AEE66AFD1AFED6E6CCAAAC140E75C0 /* Failure.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = Failure.swift; sourceTree = ""; }; 733D6503FF64B33C74F6C7072D6340FD /* A11yElement.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = A11yElement.swift; sourceTree = ""; }; 7D5FE81638FEE2217F5479E5A6AEEC33 /* A11yUITests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "A11yUITests-umbrella.h"; sourceTree = ""; }; 7D93755EE0F70BD6B883E63787B745E9 /* Pods-A11yUITests_Example-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-A11yUITests_Example-acknowledgements.markdown"; sourceTree = ""; }; 818899D18C1C55CEB8B08544F21BA24D /* A11ySnapshot.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = A11ySnapshot.swift; sourceTree = ""; }; 887479CA6E6C3F1C701E12C2D9907331 /* Pods-A11yUITests_Example-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-A11yUITests_Example-acknowledgements.plist"; sourceTree = ""; }; 8CCF0A4BB003F06C90AC5440FF731179 /* A11yAssertions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = A11yAssertions.swift; sourceTree = ""; }; 903CD4027157B6A698757E981449B3F4 /* Pods-A11yUITests_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-A11yUITests_Example.debug.xcconfig"; sourceTree = ""; }; 90C8DC89E518D011FEF8986D6FC21D18 /* Pods-A11yUITests_Example */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-A11yUITests_Example"; path = Pods_A11yUITests_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9CECF5F8FF0D192E15ADA2E7F5E79EA1 /* A11yUITests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "A11yUITests-dummy.m"; sourceTree = ""; }; 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; A03C76D4957732DC2D03CAC031A739A2 /* Pods-A11yUITests_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-A11yUITests_Example.release.xcconfig"; sourceTree = ""; }; A1417692524BF327AB8A9959529D3777 /* XCUIElement.ElementType+Name.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "XCUIElement.ElementType+Name.swift"; sourceTree = ""; }; A3189CD00B02C7674C5C0329F6A04407 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; AA571919F1C24A1FF9C981ADE6C15CD7 /* A11yTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = A11yTests.swift; sourceTree = ""; }; B0F7A495F3E70B94110AB67E40E0C33C /* NSObject+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "NSObject+Extensions.swift"; sourceTree = ""; }; B574354829AA3BC1003E077A /* XCTest+extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTest+extensions.swift"; sourceTree = ""; }; B5E5B26529AA6802002E4833 /* CGFloat+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extensions.swift"; sourceTree = ""; }; B8CB243D68E343282AB2BFB05512AEBC /* Pods-A11yUITests_ExampleUITests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-A11yUITests_ExampleUITests-acknowledgements.markdown"; sourceTree = ""; }; B9DA61CD1C94B157A741AB9549AC8B94 /* XCTestCase+A11y.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = "XCTestCase+A11y.swift"; sourceTree = ""; }; BCA42AF9766943558108BC586923734E /* Pods-A11yUITests_ExampleUITests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-A11yUITests_ExampleUITests-acknowledgements.plist"; sourceTree = ""; }; C78F5BE202F945BDD5F08D62226B8979 /* Pods-A11yUITests_Example-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-A11yUITests_Example-dummy.m"; sourceTree = ""; }; CA8B94E9D3B433157168D1EECCEC11CD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; D10A369997BE151A7B00B0D634CCB88D /* A11yUITests.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; path = A11yUITests.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; ED4AB13ABE158CD779DE2538AE4901AA /* TestRunner.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TestRunner.swift; sourceTree = ""; }; F275FD5731FF6D12054EAFCDB2C2A009 /* A11yUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = A11yUITests.debug.xcconfig; sourceTree = ""; }; F73F27430AC93DB2B512DC2A4B670390 /* Pods-A11yUITests_Example.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-A11yUITests_Example.modulemap"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 7851D5A802A58C6771B7AE487DFBB419 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 749040B9DDDE7A34914B1121187A1115 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; A347EF0802D61C3BC498EFAB4BE649B3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( A7E74E087DF362B7D0BFDEC879AAB7E8 /* Foundation.framework in Frameworks */, 4254173723043B6EDBD3007BA60C7857 /* XCTest.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; F0880C17A1F439F20EC87488CD556657 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5C010D72D1D73C139089C53A1337D737 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 08DE12A47275D036893D86C515A8973C /* Extensions */ = { isa = PBXGroup; children = ( B0F7A495F3E70B94110AB67E40E0C33C /* NSObject+Extensions.swift */, 2565A65844EDD8B489BA9976915D4DA7 /* String+Extensions.swift */, 5661872E3513F051E79EF0B643777E42 /* UIAccessibilityTraits+Extensions.swift */, 3ACA07E49A454084A01A00FAC5E14FC5 /* XCUIElementSnapshot+Extensions.swift */, B574354829AA3BC1003E077A /* XCTest+extensions.swift */, B5E5B26529AA6802002E4833 /* CGFloat+Extensions.swift */, ); name = Extensions; path = Sources/A11yUITests/Extensions; sourceTree = ""; }; 0A2339E11F0D3EA493D41707FA0AAF83 /* Targets Support Files */ = { isa = PBXGroup; children = ( 4FB24E13AF805A5BD01BAAB460CC3587 /* Pods-A11yUITests_Example */, 845BBB2BD49115827CD3B30D56270D41 /* Pods-A11yUITests_ExampleUITests */, ); name = "Targets Support Files"; sourceTree = ""; }; 0D38C9565A31D1BCAA70B94389E389C5 /* Support Files */ = { isa = PBXGroup; children = ( 28C69C0BBE2D53342C4FFDC03ECDE8DC /* A11yUITests.modulemap */, 9CECF5F8FF0D192E15ADA2E7F5E79EA1 /* A11yUITests-dummy.m */, 2BE35B690B2EA963572A82E02421D56A /* A11yUITests-Info.plist */, 35A1596E3D68A0F3D5CABE98AC87FB42 /* A11yUITests-prefix.pch */, 7D5FE81638FEE2217F5479E5A6AEEC33 /* A11yUITests-umbrella.h */, F275FD5731FF6D12054EAFCDB2C2A009 /* A11yUITests.debug.xcconfig */, 568E339865C8AB97A822908C0ABFD693 /* A11yUITests.release.xcconfig */, ); name = "Support Files"; path = "Example/Pods/Target Support Files/A11yUITests"; sourceTree = ""; }; 11BC2FB848D6AFB1A4344EF78CB8D577 /* Products */ = { isa = PBXGroup; children = ( 0C86D2B44EC444FE6634E1956FA0D8DC /* A11yUITests */, 90C8DC89E518D011FEF8986D6FC21D18 /* Pods-A11yUITests_Example */, 06BDBEFE7BF7A558A6B24469FA04EC9C /* Pods-A11yUITests_ExampleUITests */, ); name = Products; sourceTree = ""; }; 14581DCAB6A53EA4F5CF8E5E3EA5F461 /* Development Pods */ = { isa = PBXGroup; children = ( 3C547D309951E50BFA91E8E75AD963CD /* A11yUITests */, ); name = "Development Pods"; sourceTree = ""; }; 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */ = { isa = PBXGroup; children = ( 974814B39C0012DECD183BBB91B32103 /* iOS */, ); name = Frameworks; sourceTree = ""; }; 17E1551BBF5E373B802854988EDBA42A /* Elements */ = { isa = PBXGroup; children = ( 733D6503FF64B33C74F6C7072D6340FD /* A11yElement.swift */, A1417692524BF327AB8A9959529D3777 /* XCUIElement.ElementType+Name.swift */, ); name = Elements; path = Sources/A11yUITests/Elements; sourceTree = ""; }; 3C547D309951E50BFA91E8E75AD963CD /* A11yUITests */ = { isa = PBXGroup; children = ( 17E1551BBF5E373B802854988EDBA42A /* Elements */, 08DE12A47275D036893D86C515A8973C /* Extensions */, 6223CBB65E90A88225BEF718CADE547F /* Helpers */, AD5FE0D0DA966FAAFD255B8E1E8E8F3D /* Pod */, 0D38C9565A31D1BCAA70B94389E389C5 /* Support Files */, D22421805968E8555D6333F4CDC95E31 /* Tests */, ); name = A11yUITests; path = ../..; sourceTree = ""; }; 4FB24E13AF805A5BD01BAAB460CC3587 /* Pods-A11yUITests_Example */ = { isa = PBXGroup; children = ( F73F27430AC93DB2B512DC2A4B670390 /* Pods-A11yUITests_Example.modulemap */, 7D93755EE0F70BD6B883E63787B745E9 /* Pods-A11yUITests_Example-acknowledgements.markdown */, 887479CA6E6C3F1C701E12C2D9907331 /* Pods-A11yUITests_Example-acknowledgements.plist */, C78F5BE202F945BDD5F08D62226B8979 /* Pods-A11yUITests_Example-dummy.m */, 5BBB5085CDE27F6E27902E357ADD4671 /* Pods-A11yUITests_Example-Info.plist */, 6418B7E6BB7698182C01F81569F93979 /* Pods-A11yUITests_Example-umbrella.h */, 903CD4027157B6A698757E981449B3F4 /* Pods-A11yUITests_Example.debug.xcconfig */, A03C76D4957732DC2D03CAC031A739A2 /* Pods-A11yUITests_Example.release.xcconfig */, ); name = "Pods-A11yUITests_Example"; path = "Target Support Files/Pods-A11yUITests_Example"; sourceTree = ""; }; 6223CBB65E90A88225BEF718CADE547F /* Helpers */ = { isa = PBXGroup; children = ( 69AEE66AFD1AFED6E6CCAAAC140E75C0 /* Failure.swift */, ); name = Helpers; path = Sources/A11yUITests/Helpers; sourceTree = ""; }; 845BBB2BD49115827CD3B30D56270D41 /* Pods-A11yUITests_ExampleUITests */ = { isa = PBXGroup; children = ( 26464675A37C2C0341F3D45AA37F9016 /* Pods-A11yUITests_ExampleUITests.modulemap */, B8CB243D68E343282AB2BFB05512AEBC /* Pods-A11yUITests_ExampleUITests-acknowledgements.markdown */, BCA42AF9766943558108BC586923734E /* Pods-A11yUITests_ExampleUITests-acknowledgements.plist */, 194ED318FCC5418CB903C4D1EA0AFB8B /* Pods-A11yUITests_ExampleUITests-dummy.m */, 5A6274C8A56060543AACFF9A29E0FA94 /* Pods-A11yUITests_ExampleUITests-frameworks.sh */, 3006D75A5EC288FBDE9985E019D4F35F /* Pods-A11yUITests_ExampleUITests-Info.plist */, 13357D88C84F61D0461D6480AFA4BECB /* Pods-A11yUITests_ExampleUITests-umbrella.h */, 092785D9D413E6A3F91CDF4C8FDB10DF /* Pods-A11yUITests_ExampleUITests.debug.xcconfig */, 17860584BFC7619F0247D7B50FC37452 /* Pods-A11yUITests_ExampleUITests.release.xcconfig */, ); name = "Pods-A11yUITests_ExampleUITests"; path = "Target Support Files/Pods-A11yUITests_ExampleUITests"; sourceTree = ""; }; 974814B39C0012DECD183BBB91B32103 /* iOS */ = { isa = PBXGroup; children = ( CA8B94E9D3B433157168D1EECCEC11CD /* Foundation.framework */, 5EBC8F300895E39EA0DF6D6B2B5E6BCD /* XCTest.framework */, ); name = iOS; sourceTree = ""; }; AD5FE0D0DA966FAAFD255B8E1E8E8F3D /* Pod */ = { isa = PBXGroup; children = ( D10A369997BE151A7B00B0D634CCB88D /* A11yUITests.podspec */, A3189CD00B02C7674C5C0329F6A04407 /* LICENSE */, 44439EABAF52646700C93C1E0F120809 /* README.md */, ); name = Pod; sourceTree = ""; }; CF1408CF629C7361332E53B88F7BD30C = { isa = PBXGroup; children = ( 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, 14581DCAB6A53EA4F5CF8E5E3EA5F461 /* Development Pods */, 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */, 11BC2FB848D6AFB1A4344EF78CB8D577 /* Products */, 0A2339E11F0D3EA493D41707FA0AAF83 /* Targets Support Files */, ); sourceTree = ""; }; D22421805968E8555D6333F4CDC95E31 /* Tests */ = { isa = PBXGroup; children = ( 8CCF0A4BB003F06C90AC5440FF731179 /* A11yAssertions.swift */, 818899D18C1C55CEB8B08544F21BA24D /* A11ySnapshot.swift */, AA571919F1C24A1FF9C981ADE6C15CD7 /* A11yTests.swift */, ED4AB13ABE158CD779DE2538AE4901AA /* TestRunner.swift */, 5CD316ABE953A851F64274D60AB4CFC4 /* Values.swift */, B9DA61CD1C94B157A741AB9549AC8B94 /* XCTestCase+A11y.swift */, ); name = Tests; path = Sources/A11yUITests/Tests; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 8C90B68806D2B95BC842D1BDECAE52F3 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 7CEF1D4C56FDCA7E64C4210740CEE2DB /* Pods-A11yUITests_Example-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 98BBA971953A7289544B16A9F170EE86 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 5ED0F81956203C722779A287F87BDB63 /* Pods-A11yUITests_ExampleUITests-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 9DCA8AF35B3CCB177BADF6724B530087 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 3F52713A686DACEA0488AE02276913E3 /* A11yUITests-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 1CD04A6F172AA7EE2B75168D0CBABA8F /* A11yUITests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F81AABECA9FE6B92033421F984327B6 /* Build configuration list for PBXNativeTarget "A11yUITests" */; buildPhases = ( 9DCA8AF35B3CCB177BADF6724B530087 /* Headers */, EF4D0D1E675E5EE006145F01D34B79FB /* Sources */, A347EF0802D61C3BC498EFAB4BE649B3 /* Frameworks */, D8B49A0707624F66B2B125D9682308C3 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = A11yUITests; productName = A11yUITests; productReference = 0C86D2B44EC444FE6634E1956FA0D8DC /* A11yUITests */; productType = "com.apple.product-type.framework"; }; 4C69BDC8B5DB6D7A9DE7EFACC6E74D41 /* Pods-A11yUITests_ExampleUITests */ = { isa = PBXNativeTarget; buildConfigurationList = 86E521689B8F2AF76DF22FA6493AC9F2 /* Build configuration list for PBXNativeTarget "Pods-A11yUITests_ExampleUITests" */; buildPhases = ( 98BBA971953A7289544B16A9F170EE86 /* Headers */, 3E0B07CFB3F92673859B6CCE5CA329FC /* Sources */, 7851D5A802A58C6771B7AE487DFBB419 /* Frameworks */, 8A19A4B7E89678C35214451F1906087C /* Resources */, ); buildRules = ( ); dependencies = ( 4BD91002CAE666BF9411E19CADECE30C /* PBXTargetDependency */, 097ABD9AA09B25308C80ED4ACCC80285 /* PBXTargetDependency */, ); name = "Pods-A11yUITests_ExampleUITests"; productName = Pods_A11yUITests_ExampleUITests; productReference = 06BDBEFE7BF7A558A6B24469FA04EC9C /* Pods-A11yUITests_ExampleUITests */; productType = "com.apple.product-type.framework"; }; 7C950F990A68123DBF2635DDBEBED3AA /* Pods-A11yUITests_Example */ = { isa = PBXNativeTarget; buildConfigurationList = 4EF03673BE65FB95051728DAE0BB0524 /* Build configuration list for PBXNativeTarget "Pods-A11yUITests_Example" */; buildPhases = ( 8C90B68806D2B95BC842D1BDECAE52F3 /* Headers */, F1B2AA67106D5FA56B902609B6EC12BF /* Sources */, F0880C17A1F439F20EC87488CD556657 /* Frameworks */, DA05552A30571E20735EA34EDF09AF7A /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Pods-A11yUITests_Example"; productName = Pods_A11yUITests_Example; productReference = 90C8DC89E518D011FEF8986D6FC21D18 /* Pods-A11yUITests_Example */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ BFDFE7DC352907FC980B868725387E98 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1240; LastUpgradeCheck = 1240; }; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( Base, en, ); mainGroup = CF1408CF629C7361332E53B88F7BD30C; productRefGroup = 11BC2FB848D6AFB1A4344EF78CB8D577 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 1CD04A6F172AA7EE2B75168D0CBABA8F /* A11yUITests */, 7C950F990A68123DBF2635DDBEBED3AA /* Pods-A11yUITests_Example */, 4C69BDC8B5DB6D7A9DE7EFACC6E74D41 /* Pods-A11yUITests_ExampleUITests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8A19A4B7E89678C35214451F1906087C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D8B49A0707624F66B2B125D9682308C3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; DA05552A30571E20735EA34EDF09AF7A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 3E0B07CFB3F92673859B6CCE5CA329FC /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 358E24597528C6CD0FA30ABB4E2A6B14 /* Pods-A11yUITests_ExampleUITests-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; EF4D0D1E675E5EE006145F01D34B79FB /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 6D2767059B928CAF7CB6956EA2A0FEDF /* A11yAssertions.swift in Sources */, FCA4D31DBB3A43D7C2B64776E31A08AB /* A11yElement.swift in Sources */, 96E3DD27029B0CCFBB4314CC510EE0E3 /* A11ySnapshot.swift in Sources */, 5EF8B909FEC4CF7506680C929771ED53 /* A11yTests.swift in Sources */, 238FB925228BF10462B8B067EF780C8D /* A11yUITests-dummy.m in Sources */, D477E37CF14AF319305184A16E2B5F55 /* Failure.swift in Sources */, 3F27A667C6E9B253F9DE85BF13DEA0F9 /* NSObject+Extensions.swift in Sources */, 17FDB1F0B86F11EFDFA84279CF4AA057 /* String+Extensions.swift in Sources */, B5E5B26629AA6802002E4833 /* CGFloat+Extensions.swift in Sources */, B574354929AA3BC1003E077A /* XCTest+extensions.swift in Sources */, 8BE342D78F958D3B0C22E3FE1D594B35 /* TestRunner.swift in Sources */, 4506F6D361FD18CF8BBE40CDB5A5F967 /* UIAccessibilityTraits+Extensions.swift in Sources */, 8E3E1CD6FE7730051804AB1E03B18365 /* Values.swift in Sources */, 687CF6C490C50856A274D0BEA2EEBBD9 /* XCTestCase+A11y.swift in Sources */, 656CFD36E712E8E7AC09BF1154394876 /* XCUIElement.ElementType+Name.swift in Sources */, 3381D04F7EB08959C620CAF19C1D5504 /* XCUIElementSnapshot+Extensions.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; F1B2AA67106D5FA56B902609B6EC12BF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 7868E4AED48565BDE14FBD0C1956C9AE /* Pods-A11yUITests_Example-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 097ABD9AA09B25308C80ED4ACCC80285 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "Pods-A11yUITests_Example"; target = 7C950F990A68123DBF2635DDBEBED3AA /* Pods-A11yUITests_Example */; targetProxy = BE98C7D17C5FD4B27B9AF584FAD407A1 /* PBXContainerItemProxy */; }; 4BD91002CAE666BF9411E19CADECE30C /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = A11yUITests; target = 1CD04A6F172AA7EE2B75168D0CBABA8F /* A11yUITests */; targetProxy = 53985416026C5AC2DC081EAAFACFBED7 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 3D820D0F79ADED34149436213068283C /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 903CD4027157B6A698757E981449B3F4 /* Pods-A11yUITests_Example.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = "Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example.modulemap"; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 4291585FD48D3354B5499761EF3EDC11 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 17860584BFC7619F0247D7B50FC37452 /* Pods-A11yUITests_ExampleUITests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = "Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests.modulemap"; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 8B79262DBBED73EB4DB5890C5730D4D7 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = A03C76D4957732DC2D03CAC031A739A2 /* Pods-A11yUITests_Example.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = "Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example.modulemap"; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 903A0004D3E6651EFD5D2E16214D101B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; 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; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "POD_CONFIGURATION_RELEASE=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 = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = NO; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 5.0; SYMROOT = "${SRCROOT}/../build"; }; name = Release; }; 9A62C97535D0F3B4FC082D79F1B2E168 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = F275FD5731FF6D12054EAFCDB2C2A009 /* A11yUITests.debug.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREFIX_HEADER = "Target Support Files/A11yUITests/A11yUITests-prefix.pch"; INFOPLIST_FILE = "Target Support Files/A11yUITests/A11yUITests-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MODULEMAP_FILE = "Target Support Files/A11yUITests/A11yUITests.modulemap"; PRODUCT_MODULE_NAME = A11yUITests; PRODUCT_NAME = A11yUITests; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; AB118C225CB7FC8043642A5839AAC250 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 092785D9D413E6A3F91CDF4C8FDB10DF /* Pods-A11yUITests_ExampleUITests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACH_O_TYPE = staticlib; MODULEMAP_FILE = "Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests.modulemap"; OTHER_LDFLAGS = ""; OTHER_LIBTOOLFLAGS = ""; PODS_ROOT = "$(SRCROOT)"; PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; B4EFE046ACF8F37157F6E322C7FCFC28 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; 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; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "POD_CONFIGURATION_DEBUG=1", "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 = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; STRIP_INSTALLED_PRODUCT = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; SYMROOT = "${SRCROOT}/../build"; }; name = Debug; }; FA2FBB3B31E1CA68192F7B1B5C155C20 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 568E339865C8AB97A822908C0ABFD693 /* A11yUITests.release.xcconfig */; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREFIX_HEADER = "Target Support Files/A11yUITests/A11yUITests-prefix.pch"; INFOPLIST_FILE = "Target Support Files/A11yUITests/A11yUITests-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MODULEMAP_FILE = "Target Support Files/A11yUITests/A11yUITests.modulemap"; PRODUCT_MODULE_NAME = A11yUITests; PRODUCT_NAME = A11yUITests; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 1F81AABECA9FE6B92033421F984327B6 /* Build configuration list for PBXNativeTarget "A11yUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( 9A62C97535D0F3B4FC082D79F1B2E168 /* Debug */, FA2FBB3B31E1CA68192F7B1B5C155C20 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( B4EFE046ACF8F37157F6E322C7FCFC28 /* Debug */, 903A0004D3E6651EFD5D2E16214D101B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4EF03673BE65FB95051728DAE0BB0524 /* Build configuration list for PBXNativeTarget "Pods-A11yUITests_Example" */ = { isa = XCConfigurationList; buildConfigurations = ( 3D820D0F79ADED34149436213068283C /* Debug */, 8B79262DBBED73EB4DB5890C5730D4D7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 86E521689B8F2AF76DF22FA6493AC9F2 /* Build configuration list for PBXNativeTarget "Pods-A11yUITests_ExampleUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( AB118C225CB7FC8043642A5839AAC250 /* Debug */, 4291585FD48D3354B5499761EF3EDC11 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; } ================================================ FILE: Example/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Example/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Example/Pods/Target Support Files/A11yUITests/A11yUITests-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier ${PRODUCT_BUNDLE_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Example/Pods/Target Support Files/A11yUITests/A11yUITests-dummy.m ================================================ #import @interface PodsDummy_A11yUITests : NSObject @end @implementation PodsDummy_A11yUITests @end ================================================ FILE: Example/Pods/Target Support Files/A11yUITests/A11yUITests-prefix.pch ================================================ #ifdef __OBJC__ #import #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif ================================================ FILE: Example/Pods/Target Support Files/A11yUITests/A11yUITests-umbrella.h ================================================ #ifdef __OBJC__ #import #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif FOUNDATION_EXPORT double A11yUITestsVersionNumber; FOUNDATION_EXPORT const unsigned char A11yUITestsVersionString[]; ================================================ FILE: Example/Pods/Target Support Files/A11yUITests/A11yUITests.debug.xcconfig ================================================ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/A11yUITests FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 LIBRARY_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift OTHER_LDFLAGS = $(inherited) -framework "XCTest" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES SWIFT_INCLUDE_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES ================================================ FILE: Example/Pods/Target Support Files/A11yUITests/A11yUITests.modulemap ================================================ framework module A11yUITests { umbrella header "A11yUITests-umbrella.h" export * module * { export * } } ================================================ FILE: Example/Pods/Target Support Files/A11yUITests/A11yUITests.release.xcconfig ================================================ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/A11yUITests FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 LIBRARY_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift OTHER_LDFLAGS = $(inherited) -framework "XCTest" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES SWIFT_INCLUDE_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES ================================================ FILE: Example/Pods/Target Support Files/A11yUITests/A11yUITests.xcconfig ================================================ CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/A11yUITests FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 OTHER_LDFLAGS = $(inherited) -framework "XCTest" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier ${PRODUCT_BUNDLE_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example-acknowledgements.markdown ================================================ # Acknowledgements This application makes use of the following third party libraries: Generated by CocoaPods - https://cocoapods.org ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example-acknowledgements.plist ================================================ PreferenceSpecifiers FooterText This application makes use of the following third party libraries: Title Acknowledgements Type PSGroupSpecifier FooterText Generated by CocoaPods - https://cocoapods.org Title Type PSGroupSpecifier StringsTable Acknowledgements Title Acknowledgements ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example-dummy.m ================================================ #import @interface PodsDummy_Pods_A11yUITests_Example : NSObject @end @implementation PodsDummy_Pods_A11yUITests_Example @end ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example-frameworks.sh ================================================ #!/bin/sh set -e set -u set -o pipefail function on_error { echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" } trap 'on_error $LINENO' ERR if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy # frameworks to, so exit 0 (signalling the script phase was successful). exit 0 fi echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" # Used as a return value for each invocation of `strip_invalid_archs` function. STRIP_BINARY_RETVAL=0 # This protects against multiple targets copying the same framework dependency at the same time. The solution # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") # Copies and strips a vendored framework install_framework() { if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then local source="${BUILT_PRODUCTS_DIR}/$1" elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" elif [ -r "$1" ]; then local source="$1" fi local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" if [ -L "${source}" ]; then echo "Symlinked..." source="$(readlink "${source}")" fi # Use filter instead of exclude so missing patterns don't throw errors. echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" local basename basename="$(basename -s .framework "$1")" binary="${destination}/${basename}.framework/${basename}" if ! [ -r "$binary" ]; then binary="${destination}/${basename}" elif [ -L "${binary}" ]; then echo "Destination binary is symlinked..." dirname="$(dirname "${binary}")" binary="${dirname}/$(readlink "${binary}")" fi # Strip invalid architectures so "fat" simulator / device frameworks work on device if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then strip_invalid_archs "$binary" fi # Resign the code if required by the build settings to avoid unstable apps code_sign_if_enabled "${destination}/$(basename "$1")" # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then local swift_runtime_libs swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) for lib in $swift_runtime_libs; do echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" code_sign_if_enabled "${destination}/${lib}" done fi } # Copies and strips a vendored dSYM install_dsym() { local source="$1" if [ -r "$source" ]; then # Copy the dSYM into a the targets temp dir. echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" local basename basename="$(basename -s .framework.dSYM "$source")" binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" # Strip invalid architectures so "fat" simulator / device frameworks work on device if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then strip_invalid_archs "$binary" fi if [[ $STRIP_BINARY_RETVAL == 1 ]]; then # Move the stripped file into its final destination. echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" else # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" fi fi } # Copies the bcsymbolmap files of a vendored framework install_bcsymbolmap() { local bcsymbolmap_path="$1" local destination="${BUILT_PRODUCTS_DIR}" echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" } # Signs a framework with the provided identity code_sign_if_enabled() { if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then # Use the current code_sign_identity echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then code_sign_cmd="$code_sign_cmd &" fi echo "$code_sign_cmd" eval "$code_sign_cmd" fi } # Strip invalid architectures strip_invalid_archs() { binary="$1" # Get architectures for current target binary binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" # Intersect them with the architectures we are building for intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" # If there are no archs supported by this binary then warn the user if [[ -z "$intersected_archs" ]]; then echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." STRIP_BINARY_RETVAL=0 return fi stripped="" for arch in $binary_archs; do if ! [[ "${ARCHS}" == *"$arch"* ]]; then # Strip non-valid architectures in-place lipo -remove "$arch" -output "$binary" "$binary" stripped="$stripped $arch" fi done if [[ "$stripped" ]]; then echo "Stripped $binary of architectures:$stripped" fi STRIP_BINARY_RETVAL=1 } if [[ "$CONFIGURATION" == "Debug" ]]; then install_framework "${BUILT_PRODUCTS_DIR}/A11yUITests/A11yUITests.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then install_framework "${BUILT_PRODUCTS_DIR}/A11yUITests/A11yUITests.framework" fi if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then wait fi ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example-umbrella.h ================================================ #ifdef __OBJC__ #import #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif FOUNDATION_EXPORT double Pods_A11yUITests_ExampleVersionNumber; FOUNDATION_EXPORT const unsigned char Pods_A11yUITests_ExampleVersionString[]; ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example.debug.xcconfig ================================================ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example.modulemap ================================================ framework module Pods_A11yUITests_Example { umbrella header "Pods-A11yUITests_Example-umbrella.h" export * module * { export * } } ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_Example/Pods-A11yUITests_Example.release.xcconfig ================================================ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier ${PRODUCT_BUNDLE_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-acknowledgements.markdown ================================================ # Acknowledgements This application makes use of the following third party libraries: ## A11yUITests Copyright (c) 2019 r.whitaker@mac.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Generated by CocoaPods - https://cocoapods.org ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-acknowledgements.plist ================================================ PreferenceSpecifiers FooterText This application makes use of the following third party libraries: Title Acknowledgements Type PSGroupSpecifier FooterText Copyright (c) 2019 r.whitaker@mac.com <r.whitaker@mac.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. License MIT Title A11yUITests Type PSGroupSpecifier FooterText Generated by CocoaPods - https://cocoapods.org Title Type PSGroupSpecifier StringsTable Acknowledgements Title Acknowledgements ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-dummy.m ================================================ #import @interface PodsDummy_Pods_A11yUITests_ExampleUITests : NSObject @end @implementation PodsDummy_Pods_A11yUITests_ExampleUITests @end ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-frameworks.sh ================================================ #!/bin/sh set -e set -u set -o pipefail function on_error { echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" } trap 'on_error $LINENO' ERR if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy # frameworks to, so exit 0 (signalling the script phase was successful). exit 0 fi echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" BCSYMBOLMAP_DIR="BCSymbolMaps" # This protects against multiple targets copying the same framework dependency at the same time. The solution # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") # Copies and strips a vendored framework install_framework() { if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then local source="${BUILT_PRODUCTS_DIR}/$1" elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" elif [ -r "$1" ]; then local source="$1" fi local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" if [ -L "${source}" ]; then echo "Symlinked..." source="$(readlink "${source}")" fi if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do echo "Installing $f" install_bcsymbolmap "$f" "$destination" rm "$f" done rmdir "${source}/${BCSYMBOLMAP_DIR}" fi # Use filter instead of exclude so missing patterns don't throw errors. echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" local basename basename="$(basename -s .framework "$1")" binary="${destination}/${basename}.framework/${basename}" if ! [ -r "$binary" ]; then binary="${destination}/${basename}" elif [ -L "${binary}" ]; then echo "Destination binary is symlinked..." dirname="$(dirname "${binary}")" binary="${dirname}/$(readlink "${binary}")" fi # Strip invalid architectures so "fat" simulator / device frameworks work on device if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then strip_invalid_archs "$binary" fi # Resign the code if required by the build settings to avoid unstable apps code_sign_if_enabled "${destination}/$(basename "$1")" # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then local swift_runtime_libs swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) for lib in $swift_runtime_libs; do echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" code_sign_if_enabled "${destination}/${lib}" done fi } # Copies and strips a vendored dSYM install_dsym() { local source="$1" warn_missing_arch=${2:-true} if [ -r "$source" ]; then # Copy the dSYM into the targets temp dir. echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" local basename basename="$(basename -s .dSYM "$source")" binary_name="$(ls "$source/Contents/Resources/DWARF")" binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" # Strip invalid architectures from the dSYM. if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then strip_invalid_archs "$binary" "$warn_missing_arch" fi if [[ $STRIP_BINARY_RETVAL == 0 ]]; then # Move the stripped file into its final destination. echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" else # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. mkdir -p "${DWARF_DSYM_FOLDER_PATH}" touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" fi fi } # Used as a return value for each invocation of `strip_invalid_archs` function. STRIP_BINARY_RETVAL=0 # Strip invalid architectures strip_invalid_archs() { binary="$1" warn_missing_arch=${2:-true} # Get architectures for current target binary binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" # Intersect them with the architectures we are building for intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" # If there are no archs supported by this binary then warn the user if [[ -z "$intersected_archs" ]]; then if [[ "$warn_missing_arch" == "true" ]]; then echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." fi STRIP_BINARY_RETVAL=1 return fi stripped="" for arch in $binary_archs; do if ! [[ "${ARCHS}" == *"$arch"* ]]; then # Strip non-valid architectures in-place lipo -remove "$arch" -output "$binary" "$binary" stripped="$stripped $arch" fi done if [[ "$stripped" ]]; then echo "Stripped $binary of architectures:$stripped" fi STRIP_BINARY_RETVAL=0 } # Copies the bcsymbolmap files of a vendored framework install_bcsymbolmap() { local bcsymbolmap_path="$1" local destination="${BUILT_PRODUCTS_DIR}" echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" } # Signs a framework with the provided identity code_sign_if_enabled() { if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then # Use the current code_sign_identity echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then code_sign_cmd="$code_sign_cmd &" fi echo "$code_sign_cmd" eval "$code_sign_cmd" fi } if [[ "$CONFIGURATION" == "Debug" ]]; then install_framework "${BUILT_PRODUCTS_DIR}/A11yUITests/A11yUITests.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then install_framework "${BUILT_PRODUCTS_DIR}/A11yUITests/A11yUITests.framework" fi if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then wait fi ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests-umbrella.h ================================================ #ifdef __OBJC__ #import #else #ifndef FOUNDATION_EXPORT #if defined(__cplusplus) #define FOUNDATION_EXPORT extern "C" #else #define FOUNDATION_EXPORT extern #endif #endif #endif FOUNDATION_EXPORT double Pods_A11yUITests_ExampleUITestsVersionNumber; FOUNDATION_EXPORT const unsigned char Pods_A11yUITests_ExampleUITestsVersionString[]; ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests.debug.xcconfig ================================================ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/A11yUITests" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/A11yUITests/A11yUITests.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer/Library/Frameworks" '@executable_path/Frameworks' '@loader_path/Frameworks' LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift OTHER_LDFLAGS = $(inherited) -framework "A11yUITests" -framework "XCTest" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests.modulemap ================================================ framework module Pods_A11yUITests_ExampleUITests { umbrella header "Pods-A11yUITests_ExampleUITests-umbrella.h" export * module * { export * } } ================================================ FILE: Example/Pods/Target Support Files/Pods-A11yUITests_ExampleUITests/Pods-A11yUITests_ExampleUITests.release.xcconfig ================================================ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/A11yUITests" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/A11yUITests/A11yUITests.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer/Library/Frameworks" '@executable_path/Frameworks' '@loader_path/Frameworks' LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift OTHER_LDFLAGS = $(inherited) -framework "A11yUITests" -framework "XCTest" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_ROOT = ${SRCROOT}/Pods PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES ================================================ FILE: LICENSE ================================================ Copyright (c) 2019 r.whitaker@mac.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Package.swift ================================================ // swift-tools-version:5.3 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "A11yUITests", platforms: [ .iOS(.v11) ], products: [ .library( name: "A11yUITests", targets: ["A11yUITests"] ), ], targets: [ .target( name: "A11yUITests", dependencies: [], path: "Sources/A11yUITests" ), ], swiftLanguageVersions: [.v5] ) ================================================ FILE: README.md ================================================ # A11yUITests [![Version](https://img.shields.io/cocoapods/v/A11yUITests.svg?style=flat)](https://cocoapods.org/pods/A11yUITests) [![License](https://img.shields.io/cocoapods/l/A11yUITests.svg?style=flat)](https://cocoapods.org/pods/A11yUITests) [![Platform](https://img.shields.io/cocoapods/p/A11yUITests.svg?style=flat)](https://cocoapods.org/pods/A11yUITests) [![Twitter](https://img.shields.io/twitter/follow/MobileA11y?style=flat)](https://twitter.com/mobilea11y) **⚠️ This library is no longer maintained and you probably shouldn't use it. ⚠️** Instead consider using one or more of these tools that, tbh, do a better job. * [AccessibilitySnapshot](https://github.com/cashapp/AccessibilitySnapshot) - An accessibility snapshot testing library that can cover more than this approach is able to. * [Reveal](https://revealapp.com) - An inspector that can provide you a visual representation of your app's accessibility and more. A11yTests is an extension to `XCTestCase` that adds tests for common accessibility issues that can be run as part of an XCUI Test suite. Tests can either be run separately or integrated into existing XCUI Tests. ## Using These Tests Good accessibility is not about ticking boxes and conforming to regulations and guidelines, but about how your app is experienced. You will only ever know if your app is actually accessible by letting real people use it. Consider these tests as hints for where you might be able to do better, and use them to detect regressions. Failures for these tests should be seen as warnings for further investigation, not strict failures. As such i'd recommend always having `continueAfterFailure = true` set. The library has two types of tests - [assertions](#assertion-tests) and [snapshots](#snapshot-tests). Assertion tests check each individual element for potential accessibility failures. Snapshot tests creates a snapshot of your app's accessibility tree and stores this as a reference for future tests. If something changes in the accessibility tree in a future test, the test will fail signifying you should validate the change. No assertions are made against the accessibility tree, only a check for any changes since the last snapshot state. Failures have two categories: Warning and Failure. Failures are fails against WCAG or the HIG. Warnings may be acceptable, but require investigation. add `import A11yUITests` to the top of your test file. ## Assertion tests Assertion tests check each individual element for potential accessibility failures. ### Running Tests Tests can be run individually or in suites. #### Running All Tests on All Elements ```swift func test_allTests() { XCUIApplication().launch() a11yCheckAllOnScreen() } ``` #### Specifying Tests/Elements To specify elements and tests use `a11y(tests: [A11yTests], on elements: [XCUIElement])` passing an array of tests to run and an array of elements to run them on. To run all interactive element tests on all buttons: ```swift func test_buttons() { let buttons = XCUIApplication().buttons.allElementsBoundByIndex a11y(tests: a11yTestSuiteInteractive, on: buttons) } ``` To run a single test on a single element pass arrays with the test and element. To check if a button has a valid accessibility label: ```swift func test_individualTest_individualButton() { let button = XCUIApplication().buttons["My Button"] a11y(tests: [.buttonLabel], on: [button]) } ``` #### Ignoring Elements When running `a11yCheckAllOnScreen()` it is possible to ignore elements using their accessibility identifiers by passing any identifiers you wish to ignore with the `ignoringElementIdentifiers: [String]` argument. ### Test Suites A11yUITests contains 4 pre-built test suites with tests suitable for different elements. `a11yTestSuiteAll` Runs all tests. `a11yTestSuiteImages` Runs tests suitable for images. `a11yTestSuiteInteractive` runs tests suitable for interactive elements. `a11yTestSuiteLabels` runs tests suitable for static text elements. Alternatively you can create an array of `A11yTests` enum values for the tests you want to run. ### Tests #### Minimum Size `minimumSize` or checks an element is at least 14px x 14px. To specify a minimum size set a value to `A11yTestValues.minSize` Severity: Warning Note: 14px is arbitrary. #### Minimum Interactive Size `minimumInteractiveSize` checks tappable elements are a minimum of 44px x 44px. This satisfies [WCAG 2.1 Success Criteria 2.5.5 Target Size Level AAA](https://www.w3.org/TR/WCAG21/#target-size) To specify a custom minimum interactive size set a value to `A11yTestValues.minInteractiveSize`. This is not recommended. Severity: Error Note: Many of Apple's controls fail this requirement. For this reason, when running a suite of tests with `minimumInteractiveSize` only buttons and cells are checked. This may still result in some failures for `UITabBarButton`s for example. For full compliance, you should run `a11yCheckValidSizeFor(interactiveElement: XCUIElement)` on any element that your user might interact with, eg. sliders, steppers, switches, segmented controls. But you will need to make your own subclass as Apple's are not strictly adherent to WCAG. #### Label Presence `labelPresence` checks the element has an accessibility label that is a minimum of 2 characters long. Pass a `minMeaningfulLength` argument to `a11yCheckValidLabelFor(element: XCUIElement, minMeaningfulLength: Int )` to change the minimum length. Or to set a minimum length for all tests set a value to `A11yTestValues.minMeaningfulLength` This counts towards [WCAG 2.1 Guideline 1.1 Text Alternatives](https://www.w3.org/TR/WCAG21/#text-alternatives) but does not guarantee compliance. Severity: Warning Additionally this tests checks for elements that have a placeholder but no label and that the label is not uppercased. Severity: Failure Note: A length of 2 is arbitrary #### Button Label `buttonLabel` checks labels for interactive elements begin with a capital letter and don't contain a period or the word button. Checks the label is a minimum of 2 characters long. Checks the button doesn't contain common non-descriptive titles. This also checks that other interactive elements don't include their type in their label. Pass a `minMeaningfulLength` argument to `a11yCheckValidLabelFor(interactiveElement: XCUIElement, minMeaningfulLength: Int )` to change the minimum length. Or to set a minimum length for all tests set a value to `A11yTestValues.minMeaningfulLength` This follows [Apple's guidance for writing accessibility labels](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/iPhoneAccessibility/Making_Application_Accessible/Making_Application_Accessible.html). This follows [WCAG 2.1 Success Criterion 2.4.9 Link Purpose](https://www.w3.org/WAI/WCAG21/Understanding/link-purpose-link-only) Severity: Error Note: This test is not localised. Note: A length of 2 is arbitrary #### Image Label `imageLabel` checks accessible images don't contain the words image, picture, graphic, or icon, and checks that the label isn't reusing the image filename. Checks the label is a minimum of 2 characters long. Pass a `minMeaningfulLength` argument to `a11yCheckValidLabelFor(image: XCUIElement, minMeaningfulLength: Int )` to change the minimum length. Or to set a minimum length for all tests set a value to `A11yTestValues.minMeaningfulLength` This follows [Apple's guidelines for writing accessibility labels](https://developer.apple.com/videos/play/wwdc2019/254/). Care should be given when deciding whether to make images accessible to avoid creating unnecessary noise. Severity: Error Note: This test is not localised. Note: A length of 2 is arbitrary #### Label Length `labelLength` checks accessibility labels are <= 40 characters. To set a maiximum length for all tests set a value to `A11yTestValues.maxMeaningfulLength` This follows [Apple's guidelines for writing accessibility labels](https://developer.apple.com/videos/play/wwdc2019/254/). Ideally, labels should be as short as possible while retaining meaning. If you feel your element needs more context consider adding an accessibility hint. Severity: Warning Note: A length of 40 is arbitrary #### Header `header` checks the screen has at least one text element with a header trait. Headers are used by VoiceOver users to orientate and quickly navigate content. This follows [WCAG 2.1 Success Criterion 2.4.10](https://www.w3.org/WAI/WCAG21/Understanding/section-headings.html) Severity: Error #### Button Trait `buttonTrait` checks that a button element has the Button or Link trait applied. This follows [Apple's guide for using traits](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/iPhoneAccessibility/Making_Application_Accessible/Making_Application_Accessible.html). Severity: Error #### Image Trait `imageTrait` checks that an image element has the Image trait applied. This follows [Apple's guide for using traits](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/iPhoneAccessibility/Making_Application_Accessible/Making_Application_Accessible.html). Severity: Error #### Conflicting Traits `conflictingTraits` checks elements don't have conflicting traits. Elements can't be both a button and a link, or static text and updates frequently #### Disabled Elements `disabled` checks that elements aren't disabled. Disabled elements can be confusing if it is not clear why the element is disabled. Ideally keep the element enabled and clearly message if your app is not ready to process the action. Severity: Warning #### Duplicated Labels `duplicated` checks all elements provided for duplication of accessibility labels. Duplicated accessibility labels can make your screen confusing to navigate with VoiceOver, and make Voice Control fail. Ideally you should avoid duplication if possible. Severity: Warning #### Control Spacing `controlSpacing` checks that controls have minimum padding between them. This is 8px for iPhone and 12px for iPad. 12px minimum is recommended for iPad by the [HIG]( https://developer.apple.com/design/human-interface-guidelines/inputs/pointing-devices). 8px is set for iPhone and can be changed by setting a value to `A11yTestValues.iPhonePadding`. Note: 8px on iPhone is arbitrary. #### Control Overlap `controlOverlap` checks that controls don't have overlapping frames. Severity: Failure ## Snapshot tests Snapshot creates a JSON representation of your screen's accessibility tree on the first run. On subsequent runs this initial snapshot is taken as a reference. The test fails if there are any differences between the reference snapshot and the current snapshot. No assertions are made that the accessibility tree is correct or valid, you must make these checks yourself and generate a known-good reference snapshot to protect against future regressions. ### Running tests In your UI test call `a11ySnapshot()`. On first run the test will fail because no snapshot has been created for this test. A reference snapshot is generated. Grab the reference snapshot from the URL provided in the failure message or find it attached in the test's XCResult. Add this file to your **UITest** target ensuring the filename matches the `filename` property of the generated json file. Subsequent test runs will be compared against this snapshot, if you wish to generate a new snapshot, remove the reference from your UITest target, run the test, and a new reference will be generated. ### Tests Snapshot testing checks for changes in the following: * Accessibility label * Frame * Enabled status * Control type * Accessibility traits ### Test properties Use `A11yTestValues` to set various default values for all tests. Property | Default | Purpose ---|---|--- `minSize` | 14 | Minimum element size on screen for accessible elements. arbitrary. `minInteractiveSize` | 44 | Minimum size on screen for interactive elements. 44 is specified by [WCAG](https://www.w3.org/TR/WCAG21/#target-size) `minMeaningfulLength` | 2 | Minimum length of an accessible string. arbitrary. `maxMeaningfulLength` | 40 | Maximum length of an accessible string. arbitrary. `allInteractiveElements` | true | When false this skips the 44px size test on interactive elements. This is useful when relying heavily on standard iOS components that do not have valid sizes. Note: Using these elements is still a failure under WCAG, you should customise their appearance so they are large enough. `floatComparisonTolerance` | 0.1 | Float comparison threshold `preferredItemLabel` | label | Failure messages prefer reporting the items label, accessibility Identifier, or both. ## Example To run the example project, clone the repo, and run `pod install` from the Example directory first. `A11yUITests_ExampleUITests.swift` contains example tests that show a fail for each test above. ## Requirements iOS 11 Swift 5 ## Installation ### Swift Package Manager This library support [Swift Package Manager](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app). Ensure the package is added as a dependancy to your UITests target, not your app's target. ### Cocoapods A11yUITests is available through [CocoaPods](https://cocoapods.org). To install add the pod to your target's test target in your podfile. eg ```ruby target 'My_Application' do target 'My_Application_UITests' do pod 'A11yUITests' end end ``` ## Note * This library accesses a private property in the iOS SDK, so care should be taken when adding it to your project to ensure you are not shipping this code. If you submit this code to app review you will likely receive a rejection from Apple. If you do submit this code then you've installed it wrong, go take another look at [Installation](#installation). ## Known Issues If two elements of the same type have the same identifier (eg, two buttons both labeled 'Next') this can cause the tests to crash on some iOS versions. This was an issue on iOS 13 and appears fixed as of iOS 15. Elements that are hidden from accessibility are still assessed by these tests. This is due to how XCUI presents elements to the test runner, I'm not currently aware of a way to detect elements hidden from accessibility. ## Author Rob Whitaker, rw@rwapp.co.uk\ https://mobilea11y.com ## License A11yUITests is available under the MIT license. See the LICENSE file for more info. ================================================ FILE: Sources/A11yUITests/Elements/A11yElement.swift ================================================ // // A11yElement.swift // A11yUITests // // Created by Rob Whitaker on 08/12/2019. // import XCTest struct A11yElement { struct CodableElement: Codable { static let version = 1 let label: String let frame: CGRect let type: String let traits: [String] let enabled: Bool let placeholder: String? let value: String? } typealias A11ySnapshot = XCUIElementSnapshot & NSObject let label: String let frame: CGRect let type: XCUIElement.ElementType let underlyingElement: XCUIElement let traits: UIAccessibilityTraits? let enabled: Bool let placeholder: String? let value: String? let id = UUID() let axIdentifier: String var shouldIgnore: Bool { return type == .window || type == .scrollBar || type == .other || type == .navigationBar || type == .table || type == .scrollView || type == .key || type == .keyboard || type == .tabBar } var isInteractive: Bool { // strictly switches, steppers, sliders, segmented controls, & text fields should be included // but standard iOS implementations aren't large enough. return self.type == .button || self.type == .cell } var isControl: Bool { return type == .button || type == .slider || type == .stepper || type == .segmentedControl || type == .textField || type == .switch || type == .pageIndicator || type == .link || type == .searchField || type == .secureTextField || type == .datePicker || type == .picker || type == .pickerWheel || type == .cell } var description: String { "\(itemLabel) \(self.type.name())" } var itemLabel: String { let noIdentifier = "[No identifier]" var itemLabel: String let label = self.label.count > 0 ? "Label: \"\(self.label)\"" : nil let identifier = self.axIdentifier.count > 0 ? "Identifier: \"\(axIdentifier)\"" : nil switch A11yTestValues.preferredItemLabel { case .label: itemLabel = label ?? identifier ?? noIdentifier case .identifier: itemLabel = identifier ?? label ?? noIdentifier case .both: itemLabel = [label, identifier].compactMap { $0 } .joined(separator: ", ") if itemLabel.count < 1 { itemLabel = noIdentifier } } return itemLabel } var codable: CodableElement? { guard !shouldIgnore else { return nil } return CodableElement(label: label, frame: frame, type: type.name(), traits: traits?.names() ?? UIAccessibilityTraits.none.names(), enabled: enabled, placeholder: placeholder, value: value) } init(_ element: XCUIElement) { label = element.label frame = element.frame type = element.elementType underlyingElement = element enabled = element.isEnabled placeholder = element.placeholderValue value = element.value as? String axIdentifier = element.identifier guard let snapshot = try? element.snapshot() as? A11ySnapshot else { traits = nil return } traits = snapshot.traits } } extension A11yElement: Hashable { func hash(into hasher: inout Hasher) { hasher.combine(id) } } ================================================ FILE: Sources/A11yUITests/Elements/XCUIElement.ElementType+Name.swift ================================================ // // XCUIElement.ElementType+Name.swift // A11yUITests // // Created by Rob Whitaker on 26/03/2021. // import XCTest internal extension XCUIElement.ElementType { func name() -> String { switch self { case .staticText: return "Label" case .button: return "Button" case .textField: return "Text Field" case .cell: return "Cell" case .switch: return "Switch" case .alert: return "Alert" case .pageIndicator: return "Page Indicator" case .activityIndicator: return "Activity Indicator" case .link: return "Link" case .searchField: return "Search Field" case .slider: return "Slider" case .textView: return "Text View" case .secureTextField: return "Secure Text Field" case .datePicker: return "Date Picker" case .stepper: return "Stepper" case .dialog: return "Dialog" case .progressIndicator: return "Progress Indicator" case .segmentedControl: return "Segmented Control" case .picker: return "Picker" case .pickerWheel: return "Picker Wheel" case .image: return "Image" default: return "Other" } } } ================================================ FILE: Sources/A11yUITests/Extensions/CGFloat+Extensions.swift ================================================ // // CGFloat+Extensions.swift // A11yUITests // // Created by Rob Whitaker on 25/02/2023. // import Foundation extension CGFloat { var printable: String { String(format: "%.1f", self) } } ================================================ FILE: Sources/A11yUITests/Extensions/NSObject+Extensions.swift ================================================ // // NSObject+Extensions.swift // A11yUITests // // Created by Rob Whitaker on 28/03/2021. // import Foundation extension NSObject { // This code kindly provided by [Chris Kolbu](https://github.com/nesevis) func optionalValue(for key: String) -> T? { guard self.responds(to: Selector(key)), let value = self.value(forKey: key) else { print("Unable to get property \"\(type(of: self)).\(key)\". This is likely due to a change in Apple's private API. Please raise an issue https://github.com/rwapp/A11yUITests/issues") return nil } guard let castValue = value as? T else { print("Unable to cast property \"\(type(of: self)).\(key)\" from `\(type(of: value))` to `\(T.self)`. This is likely due to a change in Apple's private API. Please raise an issue https://github.com/rwapp/A11yUITests/issues") return nil } return castValue } } ================================================ FILE: Sources/A11yUITests/Extensions/String+Extensions.swift ================================================ // // String+Extensions.swift // A11yUITests // // Created by Rob Whitaker on 28/03/2021. // import XCTest internal extension String { init(_ staticString: StaticString) { self = staticString.withUTF8Buffer { String(decoding: $0, as: UTF8.self) } } func containsCaseInsensitive(_ substring: String) -> Bool { return self.lowercased().contains(substring.lowercased()) } func containsWords(_ words : [String]) -> [String] { var contained = [String]() for word in words { if self.containsCaseInsensitive(word) { contained.append(word) } } return contained } } extension StringProtocol { func prepending(_ aString: T) -> String where T : StringProtocol { "\(aString)\(self)" } } ================================================ FILE: Sources/A11yUITests/Extensions/UIAccessibilityTraits+Extensions.swift ================================================ // // UIAccessibilityTraits+Extensions.swift // A11yUITests // // Created by Rob Whitaker on 27/03/2021. // import UIKit internal extension UIAccessibilityTraits { func nameString() -> String { names().joined(separator: ", ") } func names() -> [String] { if self == .none { return ["None"] } var traits = [String]() if self.contains(.button) { traits.append("Button") } if self.contains(.link) { traits.append("Link") } if self.contains(.header) { traits.append("Header") } if self.contains(.searchField) { traits.append("Search Field") } if self.contains(.image) { traits.append("Image") } if self.contains(.selected) { traits.append("Selected") } if self.contains(.playsSound) { traits.append("Plays Sound") } if self.contains(.keyboardKey) { traits.append("Keyboard Key") } if self.contains(.staticText) { traits.append("Static Text") } if self.contains(.summaryElement) { traits.append("Summary Element") } if self.contains(.notEnabled) { traits.append("Not Enabled") } if self.contains(.updatesFrequently) { traits.append("Updates Frequently") } if self.contains(.startsMediaSession) { traits.append("Starts Media Session") } if self.contains(.adjustable) { traits.append("Adjustable") } if self.contains(.allowsDirectInteraction) { traits.append("Allows Direct Interaction") } if self.contains(.causesPageTurn) { traits.append("Causes Page Turn") } if self.contains(.tabBar) { traits.append("Tab Bar") } return traits } } ================================================ FILE: Sources/A11yUITests/Extensions/XCTest+extensions.swift ================================================ // // XCTest+extensions.swift // A11yUITests // // Created by Rob Whitaker on 25/02/2023. // import XCTest func A11yAssertGreaterThanOrEqual(_ expression1: @autoclosure () -> T, _ expression2: @autoclosure () -> T, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) where T : Comparable { guard !(expression1() >= expression2()) else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yAssertGreaterThan(_ expression1: @autoclosure () -> T, _ expression2: @autoclosure () -> T, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) where T : Comparable { guard expression2() >= expression1() else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yAssertFalse(_ expression: @autoclosure () -> Bool, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) { guard expression() else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yAssert(_ expression: @autoclosure () -> Bool, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) { guard !expression() else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yAssertNil(_ expression: @autoclosure () -> Any?, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) { guard expression() != nil else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yAssertEqual(_ expression1: @autoclosure () -> T, _ expression2: @autoclosure () -> T, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) where T : Equatable { guard expression1() != expression2() else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yAssertEqual(_ expression1: @autoclosure () -> T, _ expression2: @autoclosure () -> T, accuracy: T, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) where T : FloatingPoint { guard ((expression1() - expression2()) - accuracy) > 0 else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yAssertLessThanOrEqual(_ expression1: @autoclosure () -> T, _ expression2: @autoclosure () -> T, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) where T : Comparable { guard expression1() > expression2() else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yAssertNotEqual(_ expression1: @autoclosure () -> T, _ expression2: @autoclosure () -> T, message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) where T : Equatable { guard expression1() == expression2() else { return } fail(severity.message, report(message, elements, reason), file, line) } func A11yFail(message: String, elements: [A11yElement]? = nil, reason: String? = nil, severity: Failure, file: StaticString, line: UInt) { fail(severity.message, report(message, elements, reason), file, line) } private func fail(_ failure: String, _ message: String, _ file: StaticString, _ line: UInt) { _XCTPreformattedFailureHandler(nil, false, String(file), Int(line), failure, message) } private func report(_ message: String, _ elements: [A11yElement]?, _ reason: String? ) -> String { var reasonMessage = "" if let reason = reason { reasonMessage = "\n\(reason)" } let elementMessage = elements?.compactMap { $0 } .map { "\($0.description)" } .joined(separator: ", ") .description .appending(".") .prepending("\n") ?? "" return "\(message)\(elementMessage)\(reasonMessage)" } ================================================ FILE: Sources/A11yUITests/Extensions/XCUIElementSnapshot+Extensions.swift ================================================ // // XCUIElementSnapshot+Extensions.swift // A11yUITests // // Created by Rob Whitaker on 28/03/2021. // import XCTest internal extension XCUIElementSnapshot where Self: NSObject { var traits: UIAccessibilityTraits? { optionalValue(for: "traits") } } ================================================ FILE: Sources/A11yUITests/Helpers/Failure.swift ================================================ // // Failure.swift // A11yUITests // // Created by Rob Whitaker on 12/07/2022. // import Foundation enum Failure: String { case failure, warning var message: String { let prefix = self == .warning ? "⚠️" : "❌" return "\(prefix) Accessibility \(self.rawValue.capitalized)" } } ================================================ FILE: Sources/A11yUITests/Tests/A11yAssertions.swift ================================================ // // A11yAssertions.swift // A11yUITests // // Created by Rob Whitaker on 28/03/2021. // import XCTest final class A11yAssertions { private var hasHeader = false private var duplicatedItems = [String: Set]() private var closeControls = [Int: Set]() private var overlappedControls = [Int: Set]() func setupTests() { hasHeader = false } func validSizeFor(_ element: A11yElement, _ minSize: Int, _ file: StaticString, _ line: UInt) { guard !element.shouldIgnore else { return } let minFloatSize = CGFloat(minSize) let heightDifference = element.frame.size.height - minFloatSize A11yAssertGreaterThanOrEqual(heightDifference, -A11yTestValues.floatComparisonTolerance, message: "Element may not be tall enough.", elements: [element], reason: "Minimum height: \(minSize). Current height: \(element.frame.size.height.printable)", severity: .warning, file: file, line: line) let widthDifference = element.frame.size.width - minFloatSize A11yAssertGreaterThanOrEqual(widthDifference, -A11yTestValues.floatComparisonTolerance, message: "Element may not be wide enough.", elements: [element], reason: "Minimum width: \(minSize). Current width: \(element.frame.size.width.printable)", severity: .warning, file: file, line: line) } func validLabelFor(_ element: A11yElement, _ length: Int, _ file: StaticString, _ line: UInt) { guard !element.shouldIgnore, element.type != .cell else { return } if let placeholder = element.placeholder, placeholder.count > 0, element.label.count == 0 { A11yFail(message: "No label for element with placeholder \"\(placeholder)\".", elements: [element], severity: .failure, file: file, line: line) } else { A11yAssertGreaterThan(element.label.count, length, message: "Label may not be meaningful.", elements: [element], reason: "Minimum length: \(length)", severity: .warning, file: file, line: line) } let notLetters = CharacterSet.uppercaseLetters.inverted let capitalised = element.label.uppercased() if capitalised.trimmingCharacters(in: notLetters).count > 0 { A11yAssertNotEqual(capitalised, element.label, message: "Label is uppercased.", elements: [element], severity: .warning, file: file, line: line) } } func validLabelFor(interactiveElement element: A11yElement, _ length: Int, _ file: StaticString, _ line: UInt) { guard element.isControl else { return } // TODO: Localise this check let nondescriptiveLabels = ["click here", "tap here", "more"] let contained = element.label.containsWords(nondescriptiveLabels) contained.forEach { A11yFail(message: "Button label may not be descriptive.", elements: [element], reason: "Offending word: \($0)", severity: .failure, file: file, line: line) } // TODO: Localise this check A11yAssertFalse(element.label.containsCaseInsensitive("button"), message: "Button should not contain the word 'button' in the accessibility label.", elements: [element], severity: .failure, file: file, line: line) if let first = element.label.first { A11yAssert(first.isUppercase, message: "Buttons should begin with a capital letter.", elements: [element], severity: .failure, file: file, line: line) } A11yAssertNil(element.label.range(of: "."), message: "Button accessibility labels shouldn't contain punctuation.", elements: [element], severity: .failure, file: file, line: line) if element.type == .textView || element.type == .textField || element.type == .searchField || element.type == .secureTextField { A11yAssertFalse(element.label.containsCaseInsensitive("field"), message: "Text fields should not include their type in the label.", elements: [element], severity: .failure, file: file, line: line) } if element.traits?.contains(.link) ?? false || element.type == .link { A11yAssertFalse(element.label.containsCaseInsensitive("link"), message: "Links should not include their type in the label.", elements: [element], severity: .failure, file: file, line: line) } if element.traits?.contains(.adjustable) ?? false || element.type == .slider { A11yAssertFalse(element.label.containsCaseInsensitive("adjustable"), message: "Links should not include their type in the label.", elements: [element], severity: .failure, file: file, line: line) A11yAssertFalse(element.label.containsCaseInsensitive("slider"), message: "Links should not include their type in the label.", elements: [element], severity: .failure, file: file, line: line) } } func validLabelFor(image: A11yElement, _ length: Int, _ file: StaticString, _ line: UInt) { guard image.type == .image else { return } // TODO: Localise this test let avoidWords = ["image", "picture", "graphic", "icon", "photo"] let contained = image.label.containsWords(avoidWords) contained.forEach { A11yFail(message: "Images should not contain image words in the accessibility label.", elements: [image], reason: "Offending word: \($0)", severity: .failure, file: file, line: line) } let possibleFilenames = ["_", "-", "png", "jpg", "jpeg", "pdf", "avci", "heic", "heif", "svg"] let containedFilenames = image.label.containsWords(possibleFilenames) containedFilenames.forEach { A11yFail(message: "Image file name is used as the accessibility label.", elements: [image], reason: "Offending word: \($0)", severity: .failure, file: file, line: line) } } func validTraitFor(image: A11yElement, _ file: StaticString, _ line: UInt) { guard image.type == .image else { return } A11yAssert(image.traits?.contains(.image) ?? false, message: "Image should have Image trait.", elements: [image], severity: .failure, file: file, line: line) } func validTraitFor(button: A11yElement, _ file: StaticString, _ line: UInt) { guard button.type == .button else { return } A11yAssert(button.traits?.contains(.button) ?? false || button.traits?.contains(.link) ?? false, message: "Button should have Button or Link trait.", elements: [button], severity: .failure, file: file, line: line) } func conflictingTraits(_ element: A11yElement, _ file: StaticString, _ line: UInt) { guard let traits = element.traits else { return } A11yAssert(!traits.contains(.button) || !traits.contains(.link), message: "Elements shouldn't have both Button and Link traits.", elements: [element], severity: .failure, file: file, line: line) A11yAssert(!traits.contains(.staticText) || !traits.contains(.updatesFrequently), message: "Elements shouldn't have both Static Text and Updates Frequently traits.", elements: [element], severity: .failure, file: file, line: line) } func labelLength(_ element: A11yElement, _ maxLength: Int, _ file: StaticString, _ line: UInt) { guard element.type != .staticText, element.type != .textView, !element.shouldIgnore else { return } A11yAssertLessThanOrEqual(element.label.count, maxLength, message: "Label may be too long.", elements: [element], reason: "Max length: \(maxLength)", severity: .warning, file: file, line: line) } func validSizeFor(interactiveElement: A11yElement, allElements: Bool, _ file: StaticString, _ line: UInt) { if (!allElements && !interactiveElement.isInteractive) || !interactiveElement.isControl { return } let heightDifference = interactiveElement.frame.size.height - A11yTestValues.minInteractiveSize A11yAssertGreaterThanOrEqual(heightDifference, -A11yTestValues.floatComparisonTolerance, message: "Interactive element not tall enough.", elements: [interactiveElement], reason: "Minimum height: \(A11yTestValues.minInteractiveSize). Current height: \(interactiveElement.frame.size.height.printable)", severity: .failure, file: file, line: line) let widthDifference = interactiveElement.frame.size.width - A11yTestValues.minInteractiveSize A11yAssertGreaterThanOrEqual(widthDifference, -A11yTestValues.floatComparisonTolerance, message: "Interactive element not wide enough.", elements: [interactiveElement], reason: "Minimum width: \(A11yTestValues.minInteractiveSize). Current width: \(interactiveElement.frame.size.width.printable)", severity: .failure, file: file, line: line) } func hasHeader(_ element: A11yElement) { guard !hasHeader, element.traits?.contains(.header) ?? false else { return } hasHeader = true } func checkHeader(_ file: StaticString, _ line: UInt) { A11yAssert(hasHeader, message: "Screen has no element with a header trait.", severity: .failure, file: file, line: line) } func disabled(_ element: A11yElement, _ file: StaticString, _ line: UInt) { guard element.isControl else { return } A11yAssert(element.enabled, message: "Element disabled.", elements: [element], severity: .warning, file: file, line: line) } func duplicatedLabels(_ element1: A11yElement, _ element2: A11yElement) { guard element1.isControl, element2.isControl, element1.id != element2.id, element1.label.count > 0, element2.label.count > 0 else { return } if element1.label == element2.label { var items = duplicatedItems[element1.label] ?? Set() items.insert(element1) items.insert(element2) duplicatedItems[element1.label] = items } } func checkDuplicates(_ file: StaticString, _ line: UInt) { for duplicatePair in duplicatedItems.enumerated() { let element = duplicatePair.element.value A11yFail(message: "Elements have duplicated labels.", elements: Array(element), severity: .warning, file: file, line: line) } } func controlSpacing(_ element1: A11yElement, _ element2: A11yElement, tests: [A11yTests] ) { guard element1.isControl, element2.isControl, element1.id != element2.id else { return } let hash = hashElements(element1, element2) guard overlappedControls[hash] == nil, closeControls[hash] == nil else { return } if element1.frame.intersects(element2.frame) { if tests.contains(.controlOverlap) { overlappedControls[hash] = [element1, element2] } return } let padding = UIDevice.current.userInterfaceIdiom == .pad ? 12 : A11yTestValues.iPhonePadding let expandedFrame1 = CGRect(x: element1.frame.origin.x - CGFloat(padding), y: element1.frame.origin.y - CGFloat(padding), width: element1.frame.size.width + CGFloat(padding * 2), height: element1.frame.size.height + CGFloat(padding * 2)) if tests.contains(.controlSpacing) && expandedFrame1.intersects(element2.frame) { closeControls[hash] = [element1, element2] } } func checkControlSpacing(_ file: StaticString, _ line: UInt) { overlappedControls.values.forEach { A11yFail(message: "Controls are overlapping.", elements: Array($0), severity: .failure, file: file, line: line) } closeControls.values.forEach { A11yFail(message: "Controls are closely spaced.", elements: Array($0), severity: .warning, file: file, line: line) } } private func hashElements(_ element1: A11yElement, _ element2: A11yElement) -> Int { var hasher = Hasher() [element1.id.uuidString, element2.id.uuidString].sorted { $0 > $1 } .forEach { hasher.combine($0) } return hasher.finalize() } } ================================================ FILE: Sources/A11yUITests/Tests/A11ySnapshot.swift ================================================ // // Snapshot.swift // A11yUITests // // Created by Rob Whitaker on 15/01/2022. // import Foundation import XCTest extension XCTestCase { public func a11ySnapshot(testName: StaticString = #function, testsFile: StaticString = #file, line: UInt = #line) { A11ySnapshot.shared.a11ySnapshot(from: self, testName: testName, testsFile: testsFile, line: line) } } final class A11ySnapshot { static let shared = A11ySnapshot() private struct SnapshotWrapper: Codable { private static let wrapperVersion = 1 static let snapshotVersion = "\(SnapshotWrapper.wrapperVersion).\(A11yElement.CodableElement.version)" var filename: String var version: String var generated: Date let snapshot: [A11yElement.CodableElement] init(snapshots: [A11yElement.CodableElement], fileName: String) { filename = fileName snapshot = snapshots version = SnapshotWrapper.snapshotVersion generated = Date() } } private struct Screen { let snapshot: SnapshotWrapper let elements: [A11yElement] init(elements: [A11yElement], fileName: String) { self.elements = elements.filter { $0.codable != nil } self.snapshot = SnapshotWrapper(snapshots: elements.compactMap { $0.codable }, fileName: fileName) } } private let forbiddenCharacters: [Character] = ["(", ")",] private var calledInFunction = 0 private var currentFunction = "" private var currentSuite = "" private var fileName: String { var fileName = "\(currentSuite)-\(currentFunction)-\(calledInFunction)" fileName.removeAll(where: { forbiddenCharacters.contains($0) }) fileName = fileName.replacingOccurrences(of: "_", with: "-") fileName.append(".json") return fileName } private let fileManager = FileManager.default public init() {} public func a11ySnapshot(from test: XCTestCase, testName: StaticString = #function, testsFile: StaticString = #file, line: UInt = #line) { let elements = XCUIApplication() .descendants(matching: .any) .allElementsBoundByAccessibilityElement .map { A11yElement($0) } makeSnapshot(screen: elements, testName: String(testName), testsFile: testsFile, test: test, line: line) } private func makeSnapshot(screen: [A11yElement], testName: String, testsFile: StaticString, test: XCTestCase, line: UInt) { let suite = ((String(testsFile) as NSString).lastPathComponent as NSString).deletingPathExtension if currentFunction == testName && currentSuite == suite { calledInFunction += 1 } else { calledInFunction = 0 currentFunction = testName currentSuite = suite } let screen = Screen(elements: screen, fileName: fileName) let path = Bundle(for: type(of: test)).bundleURL.appendingPathComponent(fileName) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 if let data = try? Data(contentsOf: path), let referenceScreen = try? decoder.decode(SnapshotWrapper.self, from: data) { compareScreens(reference: referenceScreen, screen: screen, test: test, file: testsFile, line: line) } else { if let docPath = createNewSnapshot(screen.snapshot, test: test, file: testsFile, line: line) { A11yFail(message: "No reference snapshot. Generated new snapshot.\nCheck test report or \(docPath)", severity: .warning, file: testsFile, line: line) return } A11yFail(message: "No reference snapshot. Unable to create new reference", severity: .failure, file: testsFile, line: line) } } private func createNewSnapshot(_ snapshot: SnapshotWrapper, test: XCTestCase, file: StaticString, line: UInt) -> URL? { guard let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { A11yFail(message: "Unable get documents directory", severity: .failure, file: file, line: line) return nil } do { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted encoder.dateEncodingStrategy = .iso8601 let jsonData = try encoder.encode(snapshot) do { let documentPath = documentDirectory.appendingPathComponent(fileName) try jsonData.write(to: documentPath) let attachment = XCTAttachment(contentsOfFile: documentPath) test.add(attachment) return documentPath } catch { print("Unable to write snapshot to disk. \(error.localizedDescription)") return nil } } catch { print("Unable to encode snapshot. \(error.localizedDescription)") return nil } } private func compareScreens(reference: SnapshotWrapper, screen: Screen, test: XCTestCase, file: StaticString, line: UInt) { if reference.version < SnapshotWrapper.snapshotVersion { if let docPath = createNewSnapshot(screen.snapshot, test: test, file: file, line: line) { A11yFail(message: "Reference snapshot is outdated. Generated new snapshot. Check for regressions before replacing as reference.\nCheck test report or \(docPath)", severity: .warning, file: file, line: line) return } A11yFail(message: "Reference snapshot is outdated. Unable to create new reference", severity: .failure, file: file, line: line) return } A11yAssertEqual(reference.snapshot.count, screen.snapshot.snapshot.count, message: "Snapshots contain a different number of items. This screen has changed", severity: .failure, file: file, line: line) for i in 0.. i else { return } let snapshotElement = screen.elements[i] let referenceElement = reference.snapshot[i] let snapshotElementLabel = snapshotElement.label A11yAssertEqual(referenceElement.label, snapshotElementLabel, message: "Label does not match reference snapshot", elements: [snapshotElement], reason: "Reference: \(referenceElement.label). Snapshot: \(snapshotElementLabel)", severity: .failure, file: file, line: line) A11yAssertEqual(referenceElement.type, snapshotElement.type.name(), message: "Type does not match reference snapshot", elements: [snapshotElement], reason: "Reference: \(referenceElement.type). Snapshot: \(snapshotElement.type)", severity: .failure, file: file, line: line) A11yAssertEqual(referenceElement.traits, snapshotElement.traits?.names() ?? [], message: "Traits do not match reference snapshot", elements: [snapshotElement], reason: "Reference: \(referenceElement.traits.joined(separator: ", ")). Snapshot: \(snapshotElement.traits?.nameString() ?? "")", severity: .failure, file: file, line: line) A11yAssertEqual(referenceElement.enabled, snapshotElement.enabled, message: "Enabled status does not match reference snapshot", elements: [snapshotElement], reason: "Reference: \(referenceElement.enabled). Snapshot: \(snapshotElement.enabled)", severity: .failure, file: file, line: line) compareFrame(reference: referenceElement.frame, snapshot: snapshotElement, label: snapshotElementLabel, file: file, line: line) } } private func compareFrame(reference: CGRect, snapshot: A11yElement, label: String, file: StaticString, line: UInt) { let refX = reference.origin.x let refY = reference.origin.y let refWidth = reference.size.width let refHeight = reference.size.height let snapX = snapshot.frame.origin.x let snapY = snapshot.frame.origin.y let snapWidth = snapshot.frame.size.width let snapHeight = snapshot.frame.size.height A11yAssertEqual(refX, snapX, accuracy: A11yTestValues.floatComparisonTolerance, message: "Frame does not match reference snapshot", elements: [snapshot], reason: "Reference x: \(refX.printable). Snapshot x: \(snapX.printable)", severity: .failure, file: file, line: line) A11yAssertEqual(refY, snapY, accuracy: A11yTestValues.floatComparisonTolerance, message: "Frame does not match reference snapshot", elements: [snapshot], reason: "Reference y: \(refY.printable). Snapshot y: \(snapY.printable)", severity: .failure, file: file, line: line) A11yAssertEqual(refWidth, snapWidth, accuracy: A11yTestValues.floatComparisonTolerance, message: "Frame does not match reference snapshot", elements: [snapshot], reason: "Reference width: \(refWidth.printable). Snapshot width: \(snapWidth.printable)", severity: .failure, file: file, line: line) A11yAssertEqual(refHeight, snapHeight, accuracy: A11yTestValues.floatComparisonTolerance, message: "Frame does not match reference snapshot", elements: [snapshot], reason: "Reference height: \(refHeight.printable). Snapshot height: \(snapHeight.printable)", severity: .failure, file: file, line: line) } } ================================================ FILE: Sources/A11yUITests/Tests/A11yTests.swift ================================================ // // A11yTests.swift // A11yUITests // // Created by Rob Whitaker on 26/03/2021. // public enum A11yTests: CaseIterable { case minimumSize, minimumInteractiveSize, labelPresence, buttonLabel, imageLabel, labelLength, duplicated, imageTrait, header, buttonTrait, conflictingTraits, disabled, controlSpacing, controlOverlap } ================================================ FILE: Sources/A11yUITests/Tests/TestRunner.swift ================================================ // // TestRunner.swift // A11yUITests // // Created by Rob Whitaker on 19/04/2021. // import Foundation final class TestRunner { let assertions = A11yAssertions() func a11y(_ tests: [A11yTests], _ elements: [A11yElement], _ minLength: Int, _ maxLength: Int, _ minSize: Int, _ allInteractiveElements: Bool, _ file: StaticString, _ line: UInt) { assertions.setupTests() for element in elements.filter( { !$0.shouldIgnore } ) { runTests(tests, elements, element, minLength, maxLength, minSize, allInteractiveElements, file, line) } if tests.contains(.header) { assertions.checkHeader(file, line) } if tests.contains(.duplicated) { assertions.checkDuplicates(file, line) } if tests.contains(.controlSpacing) || tests.contains(.controlOverlap) { assertions.checkControlSpacing(file, line) } } private func runTests(_ tests: [A11yTests], _ elements: [A11yElement], _ element: A11yElement, _ minLength: Int, _ maxLength: Int, _ minSize: Int, _ allInteractiveElements: Bool, _ file: StaticString, _ line: UInt) { var tests = tests if tests.contains(.buttonLabel) || tests.contains(.imageLabel) { tests.append(.labelPresence) } if tests.contains(.minimumSize) { assertions.validSizeFor(element, minSize, file, line) } if tests.contains(.minimumInteractiveSize) { assertions.validSizeFor(interactiveElement: element, allElements: allInteractiveElements, file, line) } if tests.contains(.labelPresence) { assertions.validLabelFor(element, minLength, file, line) } if tests.contains(.buttonLabel) { assertions.validLabelFor(interactiveElement: element, minLength, file, line) } if tests.contains(.imageLabel) { assertions.validLabelFor(image: element, minLength, file, line) } if tests.contains(.labelLength) { assertions.labelLength(element, maxLength, file, line) } if tests.contains(.imageTrait) { assertions.validTraitFor(image: element, file, line) } if tests.contains(.buttonTrait) { assertions.validTraitFor(button: element, file, line) } if tests.contains(.header) { assertions.hasHeader(element) } if tests.contains(.disabled) { assertions.disabled(element, file, line) } if tests.contains(.conflictingTraits) { assertions.conflictingTraits(element, file, line) } for element2 in elements { if tests.contains(.duplicated) { assertions.duplicatedLabels(element, element2) } if tests.contains(.controlSpacing) || tests.contains(.controlOverlap) { assertions.controlSpacing(element, element2, tests: tests) } } } } ================================================ FILE: Sources/A11yUITests/Tests/Values.swift ================================================ // // Values.swift // A11yUITests // // Created by Rob Whitaker on 19/04/2021. // import CoreGraphics public enum A11yTestValues { public enum ReportValue { case label, identifier, both } public static let minSize = 14 public static let minInteractiveSize: CGFloat = 44.0 public static let minMeaningfulLength = 2 public static let maxMeaningfulLength = 40 public static let allInteractiveElements = true public static let floatComparisonTolerance: CGFloat = 0.1 public static let preferredItemLabel: ReportValue = .label public static let iPhonePadding = 8 } ================================================ FILE: Sources/A11yUITests/Tests/XCTestCase+A11y.swift ================================================ // // XCTestCase+A11y.swift // A11yUITestsUITests // // Created by Rob Whitaker on 05/12/2019. // Copyright © 2019 RWAPP. All rights reserved. // import XCTest extension XCTestCase { private var testRunner: TestRunner { TestRunner() } // MARK: - Test Suites public var a11yTestSuiteAll: [A11yTests] { A11yTests.allCases } public var a11yTestSuiteImages: [A11yTests] { [.minimumSize, .labelPresence, .imageLabel, .labelLength, .imageTrait] } public var a11yTestSuiteInteractive: [A11yTests] { // Valid tests for any interactive elements, eg. buttons, cells, switches, text fields etc. // Note: Many standard Apple controls fail these tests. [.minimumInteractiveSize, .labelPresence, .buttonLabel, .labelLength, .duplicated, .buttonTrait, .disabled, .conflictingTraits, .disabled, .controlSpacing, .controlOverlap] } public var a11yTestSuiteLabels: [A11yTests] { // valid for any text elements, eg. labels, text views [.minimumSize, .labelPresence, .conflictingTraits] } // MARK: - Test Groups /// Run all checks on every element on screen public func a11yCheckAllOnScreen(file: StaticString = #file, line: UInt = #line, ignoringElementIdentifiers: [String] = [String]()) { let elements = XCUIApplication() .descendants(matching: .any) .allElementsBoundByAccessibilityElement .filter ({ !ignoringElementIdentifiers.contains($0.identifier) }) a11yAllTestsOn(elements: elements, file: file, line: line) } /// Run all checks on the elements provided /// - Parameters: /// - elements: Array of elements to run checks against /// - minMeaningfulLength: An optional parameter to specify the minimum label length for controls. Default is 2 public func a11yAllTestsOn(elements: [XCUIElement], minMeaningfulLength length: Int = A11yTestValues.minMeaningfulLength, maxMeaningfulLength maxLength: Int = A11yTestValues.maxMeaningfulLength, minSize: Int = A11yTestValues.minSize, allInteractiveElements: Bool = A11yTestValues.allInteractiveElements, file: StaticString = #file, line: UInt = #line) { a11y(tests: a11yTestSuiteAll, on: elements, minMeaningfulLength: length, maxMeaningfulLength: maxLength, allInteractiveElements: allInteractiveElements, file: file, line: line) } /// Run the provided tests on the provided elements /// - Parameters: /// - tests: Array of test suites to run /// - elements: Array of elements to run checks against /// - minMeaningfulLength: An optional parameter to specify the minimum label length for controls. Default is 2 /// - maxMeaningfulLength: An optional parameter to specify the maximum label length for controls. Default is 40 /// - minSize: An optional parameter to specify the minimum size for elements. Default is 14 /// - allInteractiveElements: An optional parameter to run interactive element size check on all interactive elements. Default is true public func a11y(tests: [A11yTests], on elements: [XCUIElement], minMeaningfulLength minLength: Int = A11yTestValues.minMeaningfulLength, maxMeaningfulLength maxLength: Int = A11yTestValues.maxMeaningfulLength, minSize: Int = A11yTestValues.minSize, allInteractiveElements: Bool = A11yTestValues.allInteractiveElements, file: StaticString = #file, line: UInt = #line) { let a11yElements = elements.map { A11yElement($0) } testRunner.a11y(tests, a11yElements, minLength, maxLength, minSize, allInteractiveElements, file, line) } // MARK: - Individual Tests /// Checks element has a minimum size /// - Parameters: /// - element: Element to run check against /// - minSize: An optional parameter to specify the minimum size for the element. Default is 14 public func a11yCheckValidSizeFor(element: XCUIElement, minSize: Int = A11yTestValues.minSize, file: StaticString = #file, line: UInt = #line) { let a11yElement = A11yElement(element) testRunner.assertions.validSizeFor(a11yElement, minSize, file, line) } /// Check the provided element has a label with a minimum length of `length` /// - Parameters: /// - element: Element to run check against /// - minMeaningfulLength: An optional parameter to specify the minimum label length for controls. Default is 2 public func a11yCheckValidLabelFor(element: XCUIElement, minMeaningfulLength length: Int = A11yTestValues.minMeaningfulLength, file: StaticString = #file, line: UInt = #line) { let a11yElement = A11yElement(element) testRunner.assertions.validLabelFor(a11yElement, length, file, line) } /// Check the provided interactive element has a valid label /// - Parameters: /// - interactiveElement: Interactive element to run check against /// - minMeaningfulLength: An optional parameter to specify the minimum label length for controls. Default is 2 public func a11yCheckValidLabelFor(interactiveElement: XCUIElement, minMeaningfulLength length: Int = A11yTestValues.minMeaningfulLength, file: StaticString = #file, line: UInt = #line) { let a11yElement = A11yElement(interactiveElement) testRunner.assertions.validLabelFor(interactiveElement: a11yElement, length, file, line) } /// Check the provided image has a valid label /// - Parameters: /// - image: Image element to run the check against /// - minMeaningfulLength: An optional parameter to specify the minimum label length for controls. Default is 2 public func a11yCheckValidLabelFor(image: XCUIElement, minMeaningfulLength length: Int = A11yTestValues.minMeaningfulLength, file: StaticString = #file, line: UInt = #line) { let a11yElement = A11yElement(image) testRunner.assertions.validLabelFor(image: a11yElement, length, file, line) } /// Check the provided element's label is less than the provided number of characters /// - Parameters: /// - element: Element to run check against /// - maxLength: An optional parameter to specify the maximum label length for controls. Default is 40 public func a11yCheckLabelLength(element: XCUIElement, maxLength: Int = A11yTestValues.maxMeaningfulLength, file: StaticString = #file, line: UInt = #line) { let a11yElement = A11yElement(element) testRunner.assertions.labelLength(a11yElement, maxLength, file, line) } /// Check the provided interactive element has a minimum size of 44px square /// - Parameters: /// - interactiveElement: Interactive element to run check against /// - allElements: An optional parameter to run interactive element size check on all interactive elements. Default is true public func a11yCheckValidSizeFor(interactiveElement: XCUIElement, allElements: Bool = A11yTestValues.allInteractiveElements, file: StaticString = #file, line: UInt = #line) { let a11yElement = A11yElement(interactiveElement) testRunner.assertions.validSizeFor(interactiveElement: a11yElement, allElements: allElements, file, line) } }