Git Product home page Git Product logo

gtxilib's Introduction

Carthage compatible

What is GTXiLib?

GTXiLib, Google Toolbox for Accessibility for the iOS platform or simply GTX-eye is a framework for iOS accessibility testing. GTXiLib has XCTest integration and can be used with any XCTest-based frameworks such as EarlGrey. GTXiLib enhances the value of your tests by installing "accessibility checks" on them; your existing test cases can double as accessibility tests with no other code change on your part. GTXiLib is able to accomplish this by hooking into the test tear-down process and invoking the registered accessibility checks (such as check for presence of accessibility label) on all elements on the screen.

Getting Started

To install GTXiLib on all the tests of a specific test class add the following snippet of code to it.

In Objective-C. Note that GTX is installed in the class + (void)setUp, not the instance - (void)setUp.

// Include the GTXiLib umbrella header.

// Note that that is +setUp not -setUp
+ (void)setUp {
  [super setUp];

  // ... your other setup code (if any) comes here.

  // Create an array of checks to be installed.
  NSArray *checksToBeInstalled = @[
      [GTXChecksCollection checkForAXLabelPresent]
  ];

  // Install GTX on all tests in *this* test class.
  [GTXiLib installOnTestSuite:[GTXTestSuite suiteWithAllTestsInClass:self]
                       checks:checksToBeInstalled
          elementExcludeLists:@[]];
}

In Swift. Note that GTX is installed in the class class func setUp, not the instance func setUp().

override class func setUp() {
  super.setUp()

  let checksToBeInstalled = GTXChecksCollection.allGTXChecks()!
    GTXiLib.install(on: GTXTestSuite(allTestsIn: self)!, checks: checksToBeInstalled, elementExcludeLists: [])
}

Once installed, GTX will run all registered accessibility checks before test case tearDown and fail the test if any accessibility checks fail. With the above snippet of code your tests will now begin to catch issues where you have added UI elements to your app but forgot to set accessibility labels on them.

In the above snippet we have only installed checkForAXLabelPresent, but you can also install multiple checks from GTXChecksCollection or include your own custom checks as well:

// Inside +setUp ...
// Create a new check (for example that ensures that all AX label is not an image name)
id<GTXChecking> myNewCheck =
    [GTXCheckBlock GTXCheckWithName:@"AXlabel is not image name"
                              block:^BOOL(id element, GTXErrorRefType errorPtr) {
    // Ensure accessibilityLabel does not end with .png
    return ![[element accessibilityLabel] hasSuffix:@".png"];
  }];

// Create an array of checks to be installed.
NSArray *checksToBeInstalled = @[
    [GTXChecksCollection checkForAXLabelPresent],
    [GTXChecksCollection checkForAXTraitDontConflict],
    myNewCheck,
];

// Install GTX on all tests in *this* test class.
[GTXiLib installOnTestSuite:[GTXTestSuite suiteWithAllTestsInClass:self]
                     checks:checksToBeInstalled
        elementExcludeLists:@[]];

Note that GTX is being added to +setUp method, not the instance method -setUp since GTX must only be installed once (for a given test run).

To add GTXiLib to your project use cocoapods.

Podfile

If installing via CocoaPods, you need to add GTXiLib as a dependency in your Podfile. GTXiLib only runs in test processes, so do not add it to your main app's spec. Additionally, CocoaPods no longer requires use_frameworks!. use_frameworks! will cause your build to fail with error ld: framework not found. Your Podfile should look like:

target 'myapp' do
  # Configuration for app myapp

  # Note the lack of use_frameworks!

  target 'myappTests' do
    inherit! :search_paths
    # Pods for testing
    pod 'GTXiLib'
  end

end

CocoaPods and Swift

GTXiLib supports Swift projects. The installation instructions are almost the same as for Objective-C projects. Your Podfile should look like

use_modular_headers!
target "NameOfYourProject" do
  pod "GTXiLib"
end

with an optional version specifier for "GTXiLib". Note the use_modular_headers! line and the lack of use_frameworks!. As of CocoaPods 1.5.0, use_frameworks! is no longer required for Swift projects. use_frameworks! makes Abseil, which is a dependency of GTXiLib, fail to import properly. Thus, you cannot use use_frameworks!, which means you must use use_modular_headers!. You may also specify :modular_headers => true on a per-pod basis. Then, add import GTXiLib to your Swift files, and you can use GTXiLib APIs.

If your project does not contain Swift files, use_modular_headers! is optional.

Incremental Accessibility

GTXiLib APIs support a practical solution for improving accessibility of large projects which may not have included accessibility from the get-go -- incremental accessibility. Adding GTXiLib to a project that is already halfway through development may lead to several test failures and fixing them at once can be time consuming and tedious. To solve this problem incrementally:

  • Use the above snippet to add GTXiLib to all test cases but fix errors in a small subset of them.
    • Exclude elements that you don't control using GTXiLib's excludeList APIs.
  • Then use GTXTestSuite's suiteWithClass:andTests: method to create a test suite with only the tests cases that have been fixed and add GTXiLib only to that suite.

Once the code is checked into your repo GTXiLib will catch any new failures in those tests. From this point:

  • Every new test being added must be added to the suite.
  • Based on team priorities keep moving existing tests into the suite until all methods are in the suite.

If at any point all the tests of a test class are in the suite use suiteWithAllTestsInClass: method instead of listing all the methods, this also ensures that new methods added to the class are automatically under accessibility checking.

If GTXiLib is installed on every test in your project, use suiteWithAllTestsFromAllClassesInheritedFromClass: to automatically add accessibility checking to any test case added.

Authoring your own checks

GTXiLib has APIs that allow for creation of your own accessibility checks (in fact it does not have to be related to accessibility, for example i18n layout checks or even memory usage checks). To create new checks use GTXiLib's checkWithName:block: API and provide a unique name and block that evaluates the check and returns YES/NO for success/failure. Add the newly created check to the array of checks being passed on to GTXiLib via the install API call.

Dealing with GTXiLib Failures

When GTXiLib fails it has most likely found an accessibility bug and you must fix it. But due to various team priorities it may not be possible to do so right away in which case you have the following options at your disposal:

  • Temporarily exclude the test case by using suiteWithAllTestsInClass:exceptTests:.
  • Temporarily exclude the offending element using element excludeList APIs.

But if you believe GTXiLib has caught a bug that is not an accessibility issue please let us know by filing a bug or better fix it for everyone.

Integrating GTXiLib into custom test frameworks

If you are test framework author you can use GTXToolKit class to integrate accessibility checking into your test framework. GTXiLib's own XCTest integration is also built using the APIs provided by GTXToolKit. Using GTXToolKit for performing accessibility checks on a given element involves:

  1. Creating a GTXToolKit object.
  2. Associating a set of checks with it.
  3. Use it on the element to be checked.
GTXToolKit *toolkit = [[GTXToolKit alloc] init];

// Register one or more built in checks:
[toolkit registerCheck:[GTXChecksCollection checkForAXLabelPresent]];
[toolkit registerCheck:[GTXChecksCollection checkForAXLabelNotPunctuated]];

// and/or add a couple of your own:
id<GTXChecking> fooCustomCheck =
    [GTXCheckBlock GTXCheckWithName:@"AXlabel is not image name"
                              block:^BOOL(id element, GTXErrorRefType errorPtr) {
    // Check logic comes here...
    return YES;
 }];
[toolkit registerCheck:fooCustomCheck];

// Use the toolkit on an element.
NSError *error;
BOOL success = [toolkit checkElement:someElement error:&error];
if (!success) {
  NSLog(@"Element FAILED accessibility checks! Error: %@",
        [error localizedDescription]);
} else {
  NSLog(@"Element PASSED accessibility checks!");
}

GTXToolKit objects can also be applied on a tree of elements by just providing the root element.

// Use the toolkit on a tree of elements by providing a root element.
NSError *error;
BOOL success = [toolkit checkAllElementsFromRootElements:@[rootElement]
                                                   error:&error];
if (!success) {
  NSLog(@"One or more elements FAILED accessibility checks! Error: %@",
        error);
} else {
  NSLog(@"All elements PASSED accessibility checks!");
}

When using checkAllElementsFromRootElements:, you may want to ignore some elements from checks for various reasons, you can do that using GTXToolKit's ignore APIs.

- (void)ignoreElementsOfClassNamed:(NSString *)className;
- (void)ignoreElementsOfClassNamed:(NSString *)className
                     forCheckNamed:(NSString *)skipCheckName;

Also, note that checkAllElementsFromRootElements: requires an array of root elements, not a single element. The following snippet shows how to run the checks on all elements on the screen:

// Run the checks on all elements on the screen.
[toolkit checkAllElementsFromRootElements:@[[UIApplication sharedApplication].keyWindow]
                                    error:&error];

For full latest reference please refer GTXToolKit.h file.

Analytics

To prioritize and improve GTXiLib, the framework collects usage data and uploads it to Google Analytics. More specifically, the framework collects the MD5 hash of the test app's Bundle ID and pass/fail status of GTXiLib checks. This information allows us to measure the volume of usage. For more detailed information about our analytics collection, please peruse the GTXAnalytics.m file which contains the implementation details. If they wish, users can choose to opt out by disabling the Analytics by adding the following code snippet in test’s +(void) setUp method:

// Disable GTXiLib analytics.
[GTXAnalytics setEnabled:NO];

Discuss

Please join us on the ios-accessibility Google group to discuss all things accessibility and also to keep a tab on all updates to GTXiLib.

Contributors

Please make sure you’ve followed the guidelines in CONTRIBUTING.md before making any contributions.

Note: This is not an official Google product.

gtxilib's People

Contributors

coopercorona avatar freginold avatar j-sid avatar mattmoncur avatar niksawtschuk avatar stephanemoore avatar vigoroustelevision avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gtxilib's Issues

Support configurations of global check constants

As mentioned in #6, it would be a good idea to be able to override global check constants, like tappable area and contrast ratio.

For example, kGTXMinContrastRatioForAccessibleText is set to 3.0. In Apple's guidelines, it is recommended to maintain a minimum contrast ratio of 4.5:1. In the WCAG rules for contrast, a ratio of 4.5:1 must be maintained for all text except for sufficiently large text or logos.

If it was possible to override these constants to fit your need, the library would be more flexible. It also calls into question how large text should be handled, as different ratios may be required.

Different WCAG levels also require different ratios, so this may be yet-another level of configuration we could support.

Add support for Carthage

It should be fairly simple to support both Pods and Carthage installations.

(I plan on putting a PR up for this soon.)

Provide an XCFramework for GTXiLib

Could you please provide an XCFramework for GTXiLib with each new release of GTXiLib? We don't use CocoaPods and it's cumbersome to create an XCFramework on our own machines because of GTXiLib's dependencies on Protobuf.

Not getting accessibility errors in unit test

Hi I have tried using this framework in swift project.
I have setup the test case like this

  override static func setUp() {
    super.setUp()
    // Put setup code here. This method is called before the invocation of each test method in the class.
   
    var gTXChecking : [GTXChecking] = []
    guard let checkForAXLabelPresent = GTXChecksCollection.checkForAXLabelPresent() else {
        fatalError("Fatal Error")
    }
    guard let checkForAXLabelNotPunctuated = GTXChecksCollection.checkForAXLabelNotPunctuated() else {
        fatalError("Fatal Error")
    }
    gTXChecking.append(checkForAXLabelPresent)
    let newCheck = GTXCheckBlock.gtxCheck(withName: "label don't have accessibility") { (element, error) -> Bool in
        
        if (element as AnyObject).accessibilityLabel == nil {
            return false
        }
        return true
    }
    gTXChecking.append(checkForAXLabelNotPunctuated)
    
    gTXChecking.append(newCheck)

   GTXiLib.install(on: GTXTestSuite(allTestsIn: self), checks: gTXChecking, elementBlacklists: [])
}

When I am running test cases it is not throwing any error(even if I have not set accessibility labels and text to UILable or UIButton.)

GTXiLib does not catch errors on XCUITests

Hey all, I want to make accessibility testing on UI tests by using GTXiLib. I download with this framework via cocoapods with the code block below:
target 'AccesibilityTests' do use_frameworks! pod 'GTXiLib', :git => 'https://github.com/google/GTXiLib.git', :tag => "2.1.0" end

And I successfully install GTXiLib.

I create a UI test swift file like provided below: (By the way all the elements are defined and declared in the tester classes, does this matter? Should we define all the elements in the test suite class to GTXiLib work?)

import GTXiLib
import XCTest

class AccessibilityTestSuite: UITestSuite {
private var tester1: Tester1!
private var tester2: Tester2!

override func setUp() {
    super.setUp()
    
   //launch app
   //make set up 
    
    let checksToBeInstalled: [GTXChecking] = GTXChecksCollection.allGTXChecks()
    let tmp = GTXTestSuite.init(allTestsIn: AccessibilityTestSuite.self)
    GTXiLib.install(on: tmp ?? GTXTestSuite(), checks: checksToBeInstalled, elementBlacklists: [])
}

override func tearDown() {
    tester1 = nil
    super.tearDown()
}

func testCase() {
   //testing process
}

}

However this test is always passing. I know that there are elements on my suite that should not pass accessibility testing. What could be wrong with this issue? Thank you in advance!

@niksawtschuk , thank you!

How to find reported element when there is no accessibility Id in GTXiLib report?

Hi all,
I have a question. I have successfully called GTXiLib on my UI tests and get a report of accessibility checks. However, I receive error report like:

Screen Shot 2019-09-15 at 12 52 24

I can not understand which UI buttons does this report try to point on. How can I learn which button is failing by reading this report? I mean should not this report include accessibility Id on the report to know the button that fails? Thank you @niksawtschuk @j-sid !

Must be part of view hierarchy to use this method, see API docs for more info, GTXiLib contrastRatioOfUILabel check!

Hey all, I have a question.

I used to receive errors of GTXiLib checks, however I start to receive error that says : failed: caught "NSInternalInconsistencyException", "Label <UILabel: 0x7f9f39166ea0; frame = (40 0; 53.6667 50); text = 'Design'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6000007991d0>> must be part of view hierarchy to use this method, see API docs for more info."

What could be has changed? Thank you so much! @niksawtschuk

Tappable area check not using Apple's recommendation

I noticed that the minimum tappable area check was failing for elements it should be passing for, according to Apple's recommendation, which is 44pt x 44 pt.

It looks like the current default is 48pt x 48pt, which is a Material design standard. Since this is an iOS library, it makes most sense to follow Apple's rules by default.

Perhaps it would be a good idea to allow configuring rules like this one for the default checks.

Example App

There should be an example application in this repo showcasing a working example of different types of checks in a simple manner.

Ideally, this would use EarlGrey to show a very basic UI test.

No Longer Compiles With 5.0.0 - 'string' file not found

We are trying to update to 5.0.0 in our project that is currently running 4.4 and can no longer build any files that try to import GTXiLib.

/GTXiLib/accessibility_label_not_punctuated_check.h:20:10: 'string' file not found
GTXiLib/xml_utils.h:22:10: While building module 'tinyxml' imported from 
GTXiLib/xml_utils.h:22:
/<module-includes>:1:9: In file included from <module-includes>:1:
tinyxml/tinyxml-umbrella.h:13:9: In file included from 
tinyxml/tinyxml-umbrella.h:13:
tinyxml/tinyxml2.h:36:13: 'cctype' file not found
Test/TestUITests/TestUITests.swift:9:8: Could not build Objective-C module 'GTXiLib'

image

I have attached a sample project where I just created a new project and imported GTXiLib via cocoapods as described in the README and am getting the error above.
Test.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.