Skip to content
Merged
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
48 changes: 48 additions & 0 deletions Features.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
64A6131A2CD56A5F00FC2BF2 /* APICallsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A613192CD56A5F00FC2BF2 /* APICallsView.swift */; };
64DA2B6B2C741B820025D34B /* TextFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DA2B6A2C741B820025D34B /* TextFieldView.swift */; };
64F102DB2C98913D00EE2E47 /* ApplePayButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F102DA2C98913D00EE2E47 /* ApplePayButtonView.swift */; };
A1B2C3012F70000100AA0001 /* BaseUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3112F70000100AA0001 /* BaseUITestCase.swift */; };
A1B2C3012F70000100AA0002 /* HomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3112F70000100AA0002 /* HomeScreen.swift */; };
A1B2C3012F70000100AA0003 /* AlertScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3112F70000100AA0003 /* AlertScreen.swift */; };
A1B2C3012F70000100AA0004 /* TextFieldScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3112F70000100AA0004 /* TextFieldScreen.swift */; };
A1B2C3012F70000100AA0005 /* APICallsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3112F70000100AA0005 /* APICallsScreen.swift */; };
A1B2C3012F70000100AA0006 /* AlertScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3112F70000100AA0006 /* AlertScreenTests.swift */; };
A1B2C3012F70000100AA0007 /* TextFieldScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3112F70000100AA0007 /* TextFieldScreenTests.swift */; };
A1B2C3012F70000100AA0008 /* APICallsScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3112F70000100AA0008 /* APICallsScreenTests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -80,6 +88,14 @@
64A613192CD56A5F00FC2BF2 /* APICallsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APICallsView.swift; sourceTree = "<group>"; };
64DA2B6A2C741B820025D34B /* TextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldView.swift; sourceTree = "<group>"; };
64F102DA2C98913D00EE2E47 /* ApplePayButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplePayButtonView.swift; sourceTree = "<group>"; };
A1B2C3112F70000100AA0001 /* BaseUITestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUITestCase.swift; sourceTree = "<group>"; };
A1B2C3112F70000100AA0002 /* HomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreen.swift; sourceTree = "<group>"; };
A1B2C3112F70000100AA0003 /* AlertScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertScreen.swift; sourceTree = "<group>"; };
A1B2C3112F70000100AA0004 /* TextFieldScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldScreen.swift; sourceTree = "<group>"; };
A1B2C3112F70000100AA0005 /* APICallsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APICallsScreen.swift; sourceTree = "<group>"; };
A1B2C3112F70000100AA0006 /* AlertScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertScreenTests.swift; sourceTree = "<group>"; };
A1B2C3112F70000100AA0007 /* TextFieldScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldScreenTests.swift; sourceTree = "<group>"; };
A1B2C3112F70000100AA0008 /* APICallsScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APICallsScreenTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -176,12 +192,36 @@
children = (
532E1C392F2B0F800074BEC8 /* Info.plist */,
647416CB2D0A1F7300D0E1A8 /* TestHelpers.swift */,
A1B2C3212F70000100AA0001 /* Screens */,
A1B2C3212F70000100AA0002 /* Tests */,
17E30DC92C03922500E60561 /* FeaturesUITests.swift */,
17E30DCB2C03922500E60561 /* FeaturesUITestsLaunchTests.swift */,
);
path = FeaturesUITests;
sourceTree = "<group>";
};
A1B2C3212F70000100AA0001 /* Screens */ = {
isa = PBXGroup;
children = (
A1B2C3112F70000100AA0002 /* HomeScreen.swift */,
A1B2C3112F70000100AA0003 /* AlertScreen.swift */,
A1B2C3112F70000100AA0004 /* TextFieldScreen.swift */,
A1B2C3112F70000100AA0005 /* APICallsScreen.swift */,
);
path = Screens;
sourceTree = "<group>";
};
A1B2C3212F70000100AA0002 /* Tests */ = {
isa = PBXGroup;
children = (
A1B2C3112F70000100AA0001 /* BaseUITestCase.swift */,
A1B2C3112F70000100AA0006 /* AlertScreenTests.swift */,
A1B2C3112F70000100AA0007 /* TextFieldScreenTests.swift */,
A1B2C3112F70000100AA0008 /* APICallsScreenTests.swift */,
);
path = Tests;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -348,6 +388,14 @@
buildActionMask = 2147483647;
files = (
175423962C03E52B00310374 /* WebView.swift in Sources */,
A1B2C3012F70000100AA0001 /* BaseUITestCase.swift in Sources */,
A1B2C3012F70000100AA0002 /* HomeScreen.swift in Sources */,
A1B2C3012F70000100AA0003 /* AlertScreen.swift in Sources */,
A1B2C3012F70000100AA0004 /* TextFieldScreen.swift in Sources */,
A1B2C3012F70000100AA0005 /* APICallsScreen.swift in Sources */,
A1B2C3012F70000100AA0006 /* AlertScreenTests.swift in Sources */,
A1B2C3012F70000100AA0007 /* TextFieldScreenTests.swift in Sources */,
A1B2C3012F70000100AA0008 /* APICallsScreenTests.swift in Sources */,
17E30DCC2C03922500E60561 /* FeaturesUITestsLaunchTests.swift in Sources */,
17E30DCA2C03922500E60561 /* FeaturesUITests.swift in Sources */,
647416CC2D0A1F7900D0E1A8 /* TestHelpers.swift in Sources */,
Expand Down
Binary file not shown.
4 changes: 4 additions & 0 deletions Features/APICallsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ struct APICallsView: View {
VStack(spacing: 20) {
Text("Request Status")
.font(.headline)
.accessibilityIdentifier("api.statusHeader")

Text("Success: \(successCount) / 25")
.accessibilityIdentifier("api.successLabel")
Text("Failures: \(failureCount) / 25")
.accessibilityIdentifier("api.failureLabel")

Button(action: {
sendRequests()
Expand All @@ -31,6 +34,7 @@ struct APICallsView: View {
.foregroundColor(.white)
.cornerRadius(10)
}
.accessibilityIdentifier("api.sendRequestsButton")
.disabled(isRequesting)
}
.padding()
Expand Down
1 change: 1 addition & 0 deletions Features/AlertView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ struct AlertView: View {
Button("Generate Alert") {
showingAlert = true
}
.accessibilityIdentifier("alerts.generateButton")
.padding()
.background(Color(red: 0, green: 0, blue: 0.5))
.foregroundStyle(.white)
Expand Down
11 changes: 10 additions & 1 deletion Features/TextFieldView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import SwiftUI

struct TextFieldView: View {
@State private var inputText = ""
@State private var submittedText = ""
@State private var showBanner = false
@Environment(\.presentationMode) var presentationMode

Expand All @@ -11,19 +12,27 @@ struct TextFieldView: View {
TextField("Enter your text here", text: $inputText)
.textFieldStyle(.roundedBorder)
.padding()
.accessibilityIdentifier("text.inputField")

Button("Submit") {
// Handle the submitted text here
submittedText = inputText
print("Submitted text: \(inputText)")
}
.accessibilityIdentifier("text.submitButton")
.padding()
.background(Color(red: 0, green: 0, blue: 0.5))
.foregroundStyle(.white)
.clipShape(Capsule())

if !submittedText.isEmpty {
Text("Submitted: \(submittedText)")
.accessibilityIdentifier("text.submittedValueLabel")
}

Button("Back") {
presentationMode.wrappedValue.dismiss()
}
.accessibilityIdentifier("text.backButton")
.padding()
.background(Color(red: 0.5, green: 0, blue: 0))
.foregroundStyle(.white)
Expand Down
57 changes: 3 additions & 54 deletions FeaturesUITests/FeaturesUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,59 +8,8 @@
import XCTest

final class FeaturesUITests: XCTestCase {
var app: XCUIApplication!

override func setUpWithError() throws {
try super.setUpWithError()
continueAfterFailure = false

app = XCUIApplication()
app.launch()
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

func testGenerateAlert() throws {
let app = XCUIApplication()
app.collectionViews.staticTexts["Alerts"].tap()
app.buttons["Generate Alert"].tap()
app.buttons["OK"].tap()
}

func testTypeText() throws {
let app = XCUIApplication()
app.collectionViews/*@START_MENU_TOKEN@*/.staticTexts["Text"]/*[[".cells",".buttons[\"Text\"].staticTexts[\"Text\"]",".staticTexts[\"Text\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.tap()
app.textFields["Enter your text here"].tap()
app.typeText("Using standard typeText")
app.buttons["Submit"].tap()
}


func testSetText() throws {
let app = XCUIApplication()
app.collectionViews/*@START_MENU_TOKEN@*/.staticTexts["Text"]/*[[".cells",".buttons[\"Text\"].staticTexts[\"Text\"]",".staticTexts[\"Text\"]"],[[[-1,2],[-1,1],[-1,0,1]],[[-1,2],[-1,1]]],[0]]@END_MENU_TOKEN@*/.tap()
//sleep(1)
app.textFields["Enter your text here"].setText("Using setText", doubleTap: false)
app.buttons["Submit"].tap()
}



func testAPICalls() throws {
let app = XCUIApplication()
app.collectionViews.staticTexts["Network Capture"].tap()
app.buttons["Send 25 GET Requests"].tap()

let successLabel = app.staticTexts["Success: 25 / 25"]

// Wait for up to 30 seconds until the success label appears
let exists = NSPredicate(format: "exists == true")
expectation(for: exists, evaluatedWith: successLabel, handler: nil)
waitForExpectations(timeout: 30, handler: nil)

// Verify the success label or other elements if necessary
XCTAssertTrue(successLabel.exists, "The success label did not appear within the timeout period.")
func testLegacySuiteMigrated() {
// Tests are now organized in FeaturesUITests/Screens and FeaturesUITests/Tests.
XCTAssertTrue(true)
}
}
46 changes: 46 additions & 0 deletions FeaturesUITests/Screens/APICallsScreen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import XCTest

final class APICallsScreen {
static let shared = APICallsScreen()

private let app = XCUIApplication()

private init() {}

var sendRequestsButton: XCUIElement { app.buttons["api.sendRequestsButton"] }
var successLabel: XCUIElement { app.staticTexts["api.successLabel"] }
var failureLabel: XCUIElement { app.staticTexts["api.failureLabel"] }

func startRequests() async {
sendRequestsButton.tap()
}

func waitUntilRequestsComplete(timeout: TimeInterval) -> Bool {
let predicate = NSPredicate(format: "isEnabled == true")
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: sendRequestsButton)
return XCTWaiter.wait(for: [expectation], timeout: timeout) == .completed
}

func parsedRequestCounts() -> (success: Int, failure: Int)? {
guard
let successText = successLabel.label.split(separator: ":").dropFirst().first,
let failureText = failureLabel.label.split(separator: ":").dropFirst().first
else {
return nil
}

let successValue = successText.trimmingCharacters(in: .whitespaces).split(separator: " ").first
let failureValue = failureText.trimmingCharacters(in: .whitespaces).split(separator: " ").first

guard
let successString = successValue,
let failureString = failureValue,
let success = Int(successString),
let failure = Int(failureString)
else {
return nil
}

return (success, failure)
}
}
21 changes: 21 additions & 0 deletions FeaturesUITests/Screens/AlertScreen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import XCTest

final class AlertScreen {
static let shared = AlertScreen()

private let app = XCUIApplication()

private init() {}

var generateAlertButton: XCUIElement { app.buttons["alerts.generateButton"] }
var alert: XCUIElement { app.alerts["Alert Title"] }
var alertOKButton: XCUIElement { app.alerts["Alert Title"].buttons["OK"] }

func generateAlert() async {
generateAlertButton.tap()
}

func dismissAlertWithOK() async {
alertOKButton.tap()
}
}
29 changes: 29 additions & 0 deletions FeaturesUITests/Screens/HomeScreen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import XCTest

final class HomeScreen {
static let shared = HomeScreen()

private let app = XCUIApplication()

private init() {}

func featureItem(_ identifier: String) -> XCUIElement {
app.descendants(matching: .any).matching(identifier: identifier).firstMatch
}

var alertsItem: XCUIElement { featureItem("Alerts") }
var textItem: XCUIElement { featureItem("Text") }
var networkCaptureItem: XCUIElement { featureItem("Network Capture") }

func openAlerts() async {
alertsItem.tap()
}

func openText() async {
textItem.tap()
}

func openNetworkCapture() async {
networkCaptureItem.tap()
}
}
21 changes: 21 additions & 0 deletions FeaturesUITests/Screens/TextFieldScreen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import XCTest

final class TextFieldScreen {
static let shared = TextFieldScreen()

private let app = XCUIApplication()

private init() {}

var inputField: XCUIElement { app.textFields["text.inputField"] }
var submitButton: XCUIElement { app.buttons["text.submitButton"] }
var submittedValueLabel: XCUIElement { app.staticTexts["text.submittedValueLabel"] }

func enterText(_ text: String) async {
inputField.setText(text, doubleTap: false)
}

func submit() async {
submitButton.tap()
}
}
27 changes: 27 additions & 0 deletions FeaturesUITests/Tests/APICallsScreenTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import XCTest

final class APICallsScreenTests: BaseUITestCase {
private let homeScreen = HomeScreen.shared
private let apiCallsScreen = APICallsScreen.shared

func testRequestsCompleteWithExpectedTotal() async throws {
XCTAssertTrue(waitForExists(homeScreen.networkCaptureItem, message: "Network Capture feature is not visible on home screen."))
await homeScreen.openNetworkCapture()

XCTAssertTrue(waitForExists(apiCallsScreen.sendRequestsButton, message: "Send requests button is missing."))
await apiCallsScreen.startRequests()

let completed = apiCallsScreen.waitUntilRequestsComplete(timeout: 40)
XCTAssertTrue(completed, "Requests did not complete within timeout.")

XCTAssertTrue(waitForExists(apiCallsScreen.successLabel, message: "Success label is missing."))
XCTAssertTrue(waitForExists(apiCallsScreen.failureLabel, message: "Failure label is missing."))

guard let counts = apiCallsScreen.parsedRequestCounts() else {
XCTFail("Unable to parse success/failure counts from labels.")
return
}

XCTAssertEqual(counts.success + counts.failure, 25, "Total completed requests should always be 25.")
}
}
20 changes: 20 additions & 0 deletions FeaturesUITests/Tests/AlertScreenTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import XCTest

final class AlertScreenTests: BaseUITestCase {
private let homeScreen = HomeScreen.shared
private let alertScreen = AlertScreen.shared

func testGenerateAndDismissAlert() async throws {
XCTAssertTrue(waitForExists(homeScreen.alertsItem, message: "Alerts feature is not visible on home screen."))
await homeScreen.openAlerts()

XCTAssertTrue(waitForExists(alertScreen.generateAlertButton, message: "Generate Alert button was not found."))
await alertScreen.generateAlert()

XCTAssertTrue(waitForExists(alertScreen.alert, timeout: 3, message: "Alert did not appear."))
XCTAssertTrue(waitForExists(alertScreen.alertOKButton, message: "OK button is missing from alert."))

await alertScreen.dismissAlertWithOK()
XCTAssertFalse(alertScreen.alert.exists, "Alert should be dismissed after tapping OK.")
}
}
18 changes: 18 additions & 0 deletions FeaturesUITests/Tests/BaseUITestCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import XCTest

class BaseUITestCase: XCTestCase {
let app = XCUIApplication()

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

@discardableResult
func waitForExists(_ element: XCUIElement, timeout: TimeInterval = 5, message: String) -> Bool {
let exists = element.waitForExistence(timeout: timeout)
XCTAssertTrue(exists, message)
return exists
}
}
Loading