Objective-C Support

Link to Objective-C Support copied to clipboard

axeDevToolsUIKit.xcframework

Follow the Setup axeDevToolsUIKit.xcframework. Stop at 'Manual Testing' and follow the steps below instead.

Manual Testing

Note: The below snippets are for iOS 13 and higher. Prior to iOS 13, include the below snippets in the AppDelegate's applicationDidBecomeActive and applicationWillResignActive

Add the below code to SceneDelegate.m:

#import <axeDevToolsUIKit/axeDevToolsUIKit-Swift.h>

Add an AxeDevTools object to your SceneDelegate.m:

@implementation SceneDelegate
AxeDevTools* axeDevTools;

In sceneDidBecomeActive configure your cloud OR local connection: Replace 'USERNAME' and 'PASSWORD' with your credentials. Server should be left as an empty String.

// Configure axe DevTools Cloud credentials
NSError* error;
axeDevTools = [AxeDevTools loginWithUsername:@"USERNAME"
                                 andPassword:@"PASSWORD"
                                    toServer:@""
                                       error:&error];

[axeDevTools showA11yFABWithCustomFAB:[[A11yFAB alloc] init]];
// Configure local connection:
// Important: Adjust Info.plist settings for local networking.
NSError* error;
axeDevTools = [AxeDevTools setLocalConnectionAndReturnError:&error];
[axeDevTools showA11yFABWithCustomFAB:[[A11yFAB alloc] init]];

In sceneWillResignActive stop testing and remove the floating action button.

[axeDevTools hideA11yFAB];

From here, you can now run your application to access the floating action button. The button can be moved around the screen to not obstruct development. When you're ready for a scan, tap the button and a scan of the current screen will be sent to axe DevTools Mobile Dashboard where you can view the results.

Unit Testing

First you will need to initiate the axe DevTools object. We recommend utilizing the setUp method within your test file. If you prefer, you can also use username and password here instead (code snippet available in Manual Testing).

AxeDevTools* axeDevTools;

- (void)setUp {
    NSError* error;
    axeDevTools = [AxeDevTools loginWithAPIKey:@"API_KEY"
                                      toServer:@""
                                         error:&error];
}

Then, you can begin testing your app for accessibility issues!

Testing Views on Storyboards

To test the initial view of a storyboard:

NSError* error;
AxeResult* result = [axeDevTools runOnStoryboardName:@"Main"
                                    viewControllerId:@"" 
                                              bundle:nil
                                               error:&error];
XCTAssertEqual(result.failures.count, 0); // This allows you to assert if there are accessibility failures

Note that you can change which view controller within the storyboard is tested by passing in the view controller's id. If an empty string is passed, the framework will scan the initial view controller of the storyboard.

Testing View Controllers

If your view controllers are created programmatically, pass in an instance of your view controller to the run method:

NSError* error;
AxeResult* result = [axeDevTools runOnViewController:UIViewController()
                                               error:&error];
XCTAssertEqual(result.failures.count, 0); // This allows you to assert if there are accessibility failures

Testing Views

If you would prefer to only test individual views for accessibility issues, pass in an instance of your view to the run method:

NSError* error;
AxeResult* result = [axeDevTools runOnView: UIView() error: &error];
XCTAssertEqual(result.failures.count, 0); // This allows you to assert if there are accessibility failures

Send Scans to Dashboard

Utilize postResult if you would like to send the scan to the Dashboard:

[axeDevTools postResult:result withTags:@[@"Build 10.6.1"] withScanName:@"" error:&error];

If you do not want to tag your scan, you can pass in an empty array to the withTags parameter. If you would like to give the scan a custom scan name, you can pass it into the withScanName parameter.

UI Testing

First you will need to initiate the axe DevTools object. We recommend utilizing the setUp method within your test file. If you prefer, you can also use username and password here instead (code snippet available in Manual Testing).

AxeDevTools* axeDevTools;

- (void)setUp {
    NSError* error;
    axeDevTools = [AxeDevTools loginWithAPIKey:@"API_KEY"
                                      toServer:@""
                                         error:&error];
}

Because the Floating Action Button is still required for UI Testing, first follow the steps in Interactive Testing; but instead of using the A11yFAB, use the AutomatedTestFAB. The automated Floating Action Button is invisible so that it will not interfere with any screenshot testing you have but is still programmatically tappable to capture a scan.

Update the showA11yFAB call to the following:

[axeDevTools showA11yFABWithCustomFAB:[[AutomatedTestFAB alloc] init]];

When you're ready to capture a scan, use the floating action button's accessibility identifier "com.deque.axeDevTools.accessibilityFab" to programmatically tap it and send a scan to the dashboard:

XCUIElement* fab = app.buttons[@"com.deque.axeDevTools.accessibilityFab"];
[fab tap];

Wait for the FAB to return to know it has finished uploading. The FAB's label will now hold a key you can use to retrieve the scan from the server.

XCTAssert([fab waitForExistenceWithTimeout:5]);
AxeDevToolsResultKey* key = [[AxeDevToolsResultKey alloc] initWithFabTitle:fab.label];

With this key, you can now get additional information from the scan such as passes and failures.

NSError* error;
AxeResult* result = [axeDevTools getResult:key error:&error];
XCTAssertEqual(result.failures.count, 0);

You can also update the scan's name or add tags.

NSError* error;
[axeDevTools updateScanName:key to:@"New Scan Name" error:&error];
[axeDevTools tagResult:key withTags:@[@"Sample Tag"] error:&error];

Full Example

#import <axeDevToolsUIKit/axeDevToolsUIKit-Swift.h>
#import <XCTest/XCTest.h>

@interface ObjcUITests : XCTestCase
@end

@implementation ObjcUITests
AxeDevTools* axeDevTools;

- (void)setUp {
    self.continueAfterFailure = NO;

    NSError* error;
    axeDevTools = [AxeDevTools loginWithAPIKey:@"API_KEY"
                                      toServer:@""
                                         error:&error];
}

- (void)testMainScreen {
    XCUIApplication *app = [[XCUIApplication alloc] init];
    [app launch];

    NSError* error;
    XCUIElement* fab = app.buttons[@"com.deque.axeDevTools.accessibilityFab"];
    [fab tap];
    XCTAssert([fab waitForExistenceWithTimeout:5]);
    AxeDevToolsResultKey* key = [[AxeDevToolsResultKey alloc] initWithFabTitle:fab.label];

    // Update scan name in Dashboard
    [axeDevTools updateScanName:key to:@"New Scan Name" error:&error];

    // Update tags in Dashboard for scan
    [axeDevTools tagResult:key withTags:@[@"Sample Tag"] error:&error];

    // Fetch result
    AxeResult* result = [axeDevTools getResult:key error:&error];
    XCTAssertEqual(result.failures.count, 0);
}

@end

axeDevToolsXCUI.xcframework

Follow the Setup axeDevToolsXCUI.xcframework. All the features available on this page are fully supported in Objective-C. Import the header in any file you plan to use the XCUI framework in:

#import <axeDevToolsXCUI/axeDevToolsXCUI-Swift.h>

Utilize the setUp method in your UITests to initialize an AxeDevTools object to interact with available features. Generate an API key at axe.deque.com. If preferred, you can instead authenticate with username and password.

@interface ObjcUITests : XCTestCase
@end

@implementation ObjcUITests
AxeDevTools* axeDevTools;

- (void)setUp {
    NSError* error;
    axeDevTools = [AxeDevTools loginWithAPIKey:@"API_KEY"
                                      toServer:@""
                                         error:&error];
}

Run a Scan

To run a scan on a screen in your application or on any XCUIElement in your application, create a new test case within your UITests and call the run method within your AxeDevTools object:

- (void)testAccessibilityOfFirstScreen {
    XCUIApplication *app = [[XCUIApplication alloc] init];
    [app launch];

    NSError* error;
    AxeResult* result = [axeDevTools runOnElement:app error:&error];
    XCTAssertEqual(result.failures.count, 0); // This allows you to assert if there are accessibility failures
}

Send Scan to the Dashboard

Once you have the scan, you can send it to the Dashboard by calling the postResult method from the AxeDevTools object:

NSError* error;
[axeDevTools postResult:result withTags:@[@"Build 10.6.1"] withScanName:@"" error:&error];

If you do not want to tag your scan, you can pass in an empty array to the withTags parameter. If you would like to give the scan a custom scan name, you can pass it into the withScanName parameter.

Full Example

#import <axeDevToolsXCUI/axeDevToolsXCUI-Swift.h>
#import <XCTest/XCTest.h>

@interface ObjcUITests : XCTestCase
@end

@implementation ObjcUITests
AxeDevTools* axeDevTools;

- (void)setUp {
    NSError* error;
    axeDevTools = [AxeDevTools loginWithAPIKey:@"API_KEY"
                                      toServer:@""
                                         error:&error];
}

- (void)testAccessibilityOfFirstScreen {
    XCUIApplication *app = [[XCUIApplication alloc] init];
    [app launch];

    NSError* error;
    AxeResult* result = [axeDevTools runOnElement:app error:&error];
    XCTAssertEqual(result.failures.count, 0);
    [axeDevTools postResult:result
                   withTags:@[@"Build 10.6.1"]
               withScanName:@""
                      error:&error];
}

@end

Features in Both Frameworks

Ignoring Views

Once you're logged in, use the AxeDevTools object to ignore rules for specific views. You can ignore all views of a specific class, or ignore a view with a specific Accessibility Identifier:

NSDictionary* ignoreRules = @{ @"UILabel": @[@"InScrollView"], // ignore InScrollView for all UILabels
                               @"LoginScreen.Button": @[@"TouchTargetSize"] // ignore TouchTargetSize for the view with this accessibility id
};
[[axeDevTools configuration] ignoreWithRulesFor: ignoreRules];

Ignoring Rules

Once you're logged in, use the AxeDevTools object to ignore any rules for an entire scan:

[[axeDevTools configuration] ignoreWithRules:@[@"A11yElementFocusBox"] :true];

You can also re-add rules to the configuration by changing the bool from true to false:

[[axeDevTools configuration] ignoreWithRules:@[@"A11yElementFocusBox"] :false];

Save Scans Locally

Save results locally to utilize the Desktop app, or utilize the axe DevTools reporting tool to build an executive report off a set of scans within your CI/CD pipeline.

A scan will be saved as a .json file. Saving scans locally is only supported within automated testing. If the path and file name are not specified, the results will be named "(APPID)-(CURRENT_SCREEN_TITLE).json" and will be saved in a folder called "AxeDevToolsResults" within your User folder.

Once logged in, use the AxeDevTools object to save your scan as a JSON file. To use the default path and file name, send empty strings to the parameters:

NSError* error;
[axeDevTools saveResult:result toPath:@"" withName:@"" error:&error];