Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ A sample application built solely to showcase axe DevTools Mobile implementation

------

## Two ways to test

This sample demonstrates both ways to run accessibility scans with axe DevTools Mobile. Each lives in its own folder under `axe-devtools-ios-sample-appUITests/` so you can find the pattern you need at a glance.

| Approach | What it does | Where to look | Credentials |
| --- | --- | --- | --- |
| **Targeted scanning** | You choose exactly which screens to scan with `axe.run(onElement:)`, then report via an HTML report and/or upload to the dashboard. | [`TargetedScan/TargetedScanUITests.swift`](axe-devtools-ios-sample-appUITests/TargetedScan/TargetedScanUITests.swift) | `Login.swift` |
| **AutoScan** | Zero-code: your test just drives the app (no imports, no scan calls). The framework automatically captures, de-duplicates, and scans each unique screen, then writes one HTML report. | [`AutoScan/AutoScanUITests.swift`](axe-devtools-ios-sample-appUITests/AutoScan/AutoScanUITests.swift) | [`axe_config.json`](axe-devtools-ios-sample-appUITests/axe_config.json) |

Both approaches produce a self-contained **HTML report** locally. With targeted scanning you call `generateHtmlReportAndSummary()` yourself; with AutoScan it happens automatically when the test bundle finishes — controlled entirely by `axe_config.json`. AutoScan ships **disabled** (`"axeAutoScanMode": false`); set it to `true` and add your credentials in that file to try it.

------

## Get Started:

> Prerequisites:
Expand All @@ -18,9 +31,9 @@ A sample application built solely to showcase axe DevTools Mobile implementation

This project uses Swift Package Manager to pull in the frameworks from [axe-devtools-ios](https://github.com/dequelabs/axe-devtools-ios/).

1. Add your Deque API Key and your axe Developer Hub Project Id to `Login.swift`.
1. Add your Deque API Key and your axe Developer Hub Project Id to `Login.swift` (for the targeted-scanning tests) and to `axe-devtools-ios-sample-appUITests/axe_config.json` (for the AutoScan tests).

2. Once you have a device or simulator ready to go, open `SampleUITests.swift`, and tap on the diamond to run this suite. The simulator will launch, and the tests will run.
2. Once you have a device or simulator ready to go, open either `TargetedScan/TargetedScanUITests.swift` or `AutoScan/AutoScanUITests.swift`, and tap on the diamond to run the suite. The simulator will launch, and the tests will run.

<img src="doc_img/UITests.png" alt="Shows the click area for running the UI test."/>

Expand All @@ -30,8 +43,8 @@ _Note: This project requires a device on iOS 16.0 or later. Additionally, Virtua

To run a test with this project, or to setup your own project, follow our online guide to get started with [XCUITesting on SauceLabs.](https://docs.deque.com/devtools-mobile/ios-example-sauce-labs-xcui)

Assuming you have already downloaded the sample project to your computer:
1. Add your Deque API Key and your axe Developer Hub Project Id to `Login.swift`.
These steps run the **targeted-scanning** tests. Assuming you have already downloaded the sample project to your computer:
1. Add your Deque API Key and your axe Developer Hub Project Id to `Login.swift`. (To exercise the AutoScan path instead, also enable it in `axe-devtools-ios-sample-appUITests/axe_config.json` as described above.)
2. Open a Terminal window, enter `cd `, then drag and drop the `axe-devtools-ios-sample-app` from Finder into the Terminal window. Hit return/enter.

To run on **Real Devices**, type `sh prepareForSauceRealDevice.sh` in the same window. Hit return/enter.
Expand Down
2 changes: 1 addition & 1 deletion RegressionUITests/RegressionUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class RegressionUITests: XCTestCase {
var lastResult: AxeResult?

override func setUp() {
axe = try? AxeDevTools.startSession(apiKey: Login.APIKey, projectId: Login.projectId)
axe = try? AxeDevTools.startScanSession(apiKey: Login.APIKey, projectId: Login.projectId)

app.launch()
sleep(2) // allow app to fully load, Github actions needed a moment.
Expand Down
49 changes: 43 additions & 6 deletions axe-devtools-ios-sample-app.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
objects = {

/* Begin PBXBuildFile section */
30CF7AC9E4AF9F05A27959C6 /* TargetedScanUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5930CB6C34FD68A1DF754BBE /* TargetedScanUITests.swift */; };
3399D4BF2D58349249B12104 /* axe_config.json in Resources */ = {isa = PBXBuildFile; fileRef = E91A725F8F38EF78E0303331 /* axe_config.json */; };
6A3B4C992A5D8EC20078BB09 /* RegressionUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A3B4C982A5D8EC20078BB09 /* RegressionUITests.swift */; };
6A3B4CA12A5D8F6B0078BB09 /* Login.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AEDD8512886FD4D0017DCF1 /* Login.swift */; };
6AEDD8522886FD4D0017DCF1 /* Login.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AEDD8512886FD4D0017DCF1 /* Login.swift */; };
6AEDD8542886FD500017DCF1 /* Login.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AEDD8512886FD4D0017DCF1 /* Login.swift */; };
6AF13275282E848C00A64994 /* SampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF13274282E848C00A64994 /* SampleUITests.swift */; };
805E4C1E5E82317B9E2A3B89 /* SampleAppNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B17D6D36DF84C738F14736B7 /* SampleAppNavigation.swift */; };
845EEC6DCB3471149282DB01 /* AutoScanUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23D938F193549E1C9DE7418 /* AutoScanUITests.swift */; };
9E38FE2F2E31209F000DAC24 /* NamedTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E38FE2E2E312097000DAC24 /* NamedTextField.swift */; };
9E38FE312E3121D0000DAC24 /* ContactUsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E38FE302E3121C8000DAC24 /* ContactUsTableViewCell.swift */; };
9E38FE332E312271000DAC24 /* Route.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E38FE322E31226E000DAC24 /* Route.swift */; };
Expand Down Expand Up @@ -125,15 +128,18 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
5930CB6C34FD68A1DF754BBE /* TargetedScanUITests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetedScanUITests.swift; sourceTree = "<group>"; };
6A3B4C962A5D8EC20078BB09 /* RegressionUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RegressionUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6A3B4C982A5D8EC20078BB09 /* RegressionUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegressionUITests.swift; sourceTree = "<group>"; };
6AEDD8512886FD4D0017DCF1 /* Login.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Login.swift; sourceTree = "<group>"; };
6AF13274282E848C00A64994 /* SampleUITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SampleUITests.swift; sourceTree = "<group>"; };
9E38FE2E2E312097000DAC24 /* NamedTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NamedTextField.swift; sourceTree = "<group>"; };
9E38FE302E3121C8000DAC24 /* ContactUsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactUsTableViewCell.swift; sourceTree = "<group>"; };
9E38FE322E31226E000DAC24 /* Route.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Route.swift; sourceTree = "<group>"; };
9E38FE362E3169FA000DAC24 /* UIFont+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Extensions.swift"; sourceTree = "<group>"; };
9E76EC592E3004BC0023917A /* ContactUsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactUsTableViewController.swift; sourceTree = "<group>"; };
B17D6D36DF84C738F14736B7 /* SampleAppNavigation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SampleAppNavigation.swift; sourceTree = "<group>"; };
C23D938F193549E1C9DE7418 /* AutoScanUITests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AutoScanUITests.swift; sourceTree = "<group>"; };
E91A725F8F38EF78E0303331 /* axe_config.json */ = {isa = PBXFileReference; includeInIndex = 1; path = axe_config.json; sourceTree = "<group>"; };
F3799A7227E4D0C5009CFC2E /* ItemCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCollectionView.swift; sourceTree = "<group>"; };
F3799A7427E4D0DC009CFC2E /* ItemCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCollectionViewCell.swift; sourceTree = "<group>"; };
F3799A7627E4D7ED009CFC2E /* ItemCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCellViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -239,6 +245,15 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
21B84018A6A78D27990475E2 /* AutoScan */ = {
isa = PBXGroup;
children = (
C23D938F193549E1C9DE7418 /* AutoScanUITests.swift */,
);
name = AutoScan;
path = AutoScan;
sourceTree = "<group>";
};
6A3B4C972A5D8EC20078BB09 /* RegressionUITests */ = {
isa = PBXGroup;
children = (
Expand All @@ -247,6 +262,15 @@
path = RegressionUITests;
sourceTree = "<group>";
};
86674B529DE75ED599ED20CF /* TargetedScan */ = {
isa = PBXGroup;
children = (
5930CB6C34FD68A1DF754BBE /* TargetedScanUITests.swift */,
);
name = TargetedScan;
path = TargetedScan;
sourceTree = "<group>";
};
9E38FE2D2E312081000DAC24 /* Views */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -282,6 +306,15 @@
path = ContactUs;
sourceTree = "<group>";
};
B19CEFD283E99B98B85E565F /* Shared */ = {
isa = PBXGroup;
children = (
B17D6D36DF84C738F14736B7 /* SampleAppNavigation.swift */,
);
name = Shared;
path = Shared;
sourceTree = "<group>";
};
F3133A4628086B0A00389A4C /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -528,7 +561,10 @@
F3F31DAE27DFD32500D87988 /* axe-devtools-ios-sample-appUITests */ = {
isa = PBXGroup;
children = (
6AF13274282E848C00A64994 /* SampleUITests.swift */,
86674B529DE75ED599ED20CF /* TargetedScan */,
21B84018A6A78D27990475E2 /* AutoScan */,
B19CEFD283E99B98B85E565F /* Shared */,
E91A725F8F38EF78E0303331 /* axe_config.json */,
);
path = "axe-devtools-ios-sample-appUITests";
sourceTree = "<group>";
Expand Down Expand Up @@ -608,8 +644,6 @@
dependencies = (
);
name = "axe-devtools-ios-sample-app";
packageProductDependencies = (
);
productName = "axe-devtools-ios-sample-app";
productReference = F3F31D8B27DFD32500D87988 /* axe-devtools-ios-sample-app.app */;
productType = "com.apple.product-type.application";
Expand Down Expand Up @@ -707,6 +741,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3399D4BF2D58349249B12104 /* axe_config.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -806,7 +841,9 @@
buildActionMask = 2147483647;
files = (
6AEDD8542886FD500017DCF1 /* Login.swift in Sources */,
6AF13275282E848C00A64994 /* SampleUITests.swift in Sources */,
30CF7AC9E4AF9F05A27959C6 /* TargetedScanUITests.swift in Sources */,
845EEC6DCB3471149282DB01 /* AutoScanUITests.swift in Sources */,
805E4C1E5E82317B9E2A3B89 /* SampleAppNavigation.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the incorrect version of the framework and MUST be updated before merging

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions axe-devtools-ios-sample-app/Login.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
//

import Foundation

/// Credentials for the **targeted scanning** examples (TargetedScanUITests).
///
/// - API key: https://axe.deque.com/settings
/// - Project ID: https://axe.deque.com/axe-watcher/projects
///
/// Note: the **AutoScan** example reads its credentials from
/// `axe-devtools-ios-sample-appUITests/axe_config.json` instead, not from here.
struct Login {
static let APIKey=""
static let projectId=""
Expand Down
53 changes: 53 additions & 0 deletions axe-devtools-ios-sample-appUITests/AutoScan/AutoScanUITests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// AutoScanUITests.swift
// axe-devtools-ios-sample-appUITests
//
// AUTOSCAN — the zero-code path.
//
// Notice what's NOT here: no `import axeDevToolsXCUI`, no session setup, no
// scan calls, no report calls. That's the whole point of AutoScan.
//
// As long as the axeDevToolsXCUI framework is linked to this test target and
// `axe_config.json` has `"axeAutoScanMode": true`, the framework automatically:
// 1. Starts AutoScan when the test bundle begins.
// 2. Captures and de-duplicates each unique screen as you tap and swipe.
// 3. Scans everything and writes an HTML report when the test bundle finishes.
//
// AutoScan ships DISABLED in this sample. To try it, open axe_config.json,
// set `"axeAutoScanMode": true`, and fill in your axeMobileApiKey/axeProjectId.
// Then just drive the app the way a user would — no other code required.
//
// Full guide: https://docs.deque.com/devtools-mobile/
//

import XCTest

final class AutoScanUITests: XCTestCase {
private let app = XCUIApplication()

override func setUpWithError() throws {
continueAfterFailure = false
app.launch()
}

/// A plain user journey across the app, recorded with Xcode's UI test recorder
/// and then tidied up. There is no accessibility code here — AutoScan captures
/// and scans each screen automatically as these gestures run.
func testUserJourney() throws {
// Home — scroll through the featured content.
app.collectionViews.containing(.other, identifier: "Vertical scroll bar, 4 pages").firstMatch.swipeUp()
app.otherElements.matching(identifier: "Horizontal scroll bar, 1 page").element(boundBy: 0).swipeUp()

// Catalog — browse the categories.
app.images["Category"].firstMatch.tap()
app.scrollViews.firstMatch.swipeUp()

// Cart — add an item.
app.images["Bag"].firstMatch.tap()
app.buttons.matching(identifier: "+").element(boundBy: 1).tap()

// Profile — open and scroll to the help section.
app.images["Menu"].firstMatch.tap()
app.cells.containing(.image, identifier: "Info Square").firstMatch.swipeUp()
}
}
122 changes: 0 additions & 122 deletions axe-devtools-ios-sample-appUITests/SampleUITests.swift

This file was deleted.

Loading
Loading