Skip to content

Commit

Permalink
Add Support for type, hasKeyboardFocus, printAllElements, setLanguage
Browse files Browse the repository at this point in the history
  • Loading branch information
0xWDG committed Aug 9, 2024
1 parent 03389bd commit d1233f8
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 31 deletions.
9 changes: 4 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ import PackageDescription
let package = Package(
name: "XCUITestHelper",
platforms: [
.iOS(.v14),
.macOS(.v11)
.iOS(.v16),
.macOS(.v13),
.watchOS(.v9),
.tvOS(.v16)
],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "XCUITestHelper",
targets: ["XCUITestHelper"])
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "XCUITestHelper"),
.testTarget(
Expand Down
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# XCUITestHelper

XCUITestHelper is a package what contains extensions for XCUITest.
XCUITestHelper helps you writing UI tests within SwiftUI. It provides a set of useful extensions on [XCUIApplication](Sources/XCUITestHelper/XCUIApplication.swift), [XCUIElement](Sources/XCUITestHelper/XCUIElement.swift) and [XCUIElementQuery](Sources/XCUITestHelper/XCUIElementQuery.swift) to make your tests more readable and easier to maintain.

[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2F0xWDG%2FXCUITestHelper%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/0xWDG/XCUITestHelper)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2F0xWDG%2FXCUITestHelper%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/0xWDG/XCUITestHelper)
Expand Down Expand Up @@ -29,9 +29,10 @@ targets: [

1. In Xcode, open your project and navigate to **File****Swift Packages****Add Package Dependency...**
2. Paste the repository URL (`https://github.com/0xWDG/XCUITestHelper`) and click **Next**.
3. Click **Finish**.
3. Make sure you add it to the **UITest target**!
4. Click **Finish**.

## Usage
## Usage / Examples

```swift
import XCTest
Expand All @@ -45,21 +46,31 @@ final class MyAppUITests: XCTestCase {
func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launchArguments += ["-AppleLanguages", "(en-US)"]
app.launchArguments += ["-AppleLocale", "\"en-US\""]

// * Set the app language to English.
app.setLanguage(to: .english)
// Do this before launching the app.
app.launch()

// Wait for 1 second to continue
// * `Wait` for 1 second to continue
app.wait(for: 1)

// Go back to previous screen (navigation)
// * Tap a `random` cell in a collection view.
// Random works with any kind of element, not just buttons.
app.collectionViews.buttons.random.tap()

// * Go back to previous screen (NavigationView)
app.navigateBack()

// Tap on the last button
// * Tap on the last button
app.buttons.lastMatch.tap()

// Tap on the second button
// * Tap on the second button
app.buttons[1].tap()

// * Type something, and then clear it.
let textfield = app.searchFields.firstMatch
app.type(in: textfield, text: "a", action: .clear)
}
}
```
Expand Down
24 changes: 7 additions & 17 deletions Sources/XCUITestHelper/XCUIApplication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,20 @@

#if canImport(XCTest)
import XCTest
import Foundation

extension XCUIApplication {
/// Navigate back
public func navigateBack() {
self.navigationBars.buttons.element(boundBy: 0).tap()
}

/// Wait for a duration
///
/// - Parameter duration: Duration to wait
public func wait(for duration: TimeInterval) {
let testCase = XCTestCase()
let waitExpectation = testCase.expectation(
description: "Waiting"
)

let when = DispatchTime.now() + duration
DispatchQueue.main.asyncAfter(deadline: when) {
waitExpectation.fulfill()
}

testCase.waitForExpectations(
timeout: duration + 0.5
)
/// Set language of test to
///
/// - Parameter to: language
public func setLanguage(to language: Locale.LanguageCode) {
self.launchArguments += ["-AppleLanguages", "(\(language.identifier))"]
self.launchArguments += ["-AppleLocale", "\"\(language.identifier)\""]
}
}

Expand Down
84 changes: 84 additions & 0 deletions Sources/XCUITestHelper/XCUIElement.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//
// XCUIElement.swift
// XCUITestHelper
//
// Created by Wesley de Groot on 2024-08-08.
// https://wesleydegroot.nl
//
// https://github.com/0xWDG/XCUITestHelper
// MIT License
//

#if canImport(XCTest)
import XCTest

/// Actions that can be performed on an XCUIElement.
public enum XCUIElementAction {
/// Send (last button)
case send

/// Clear (last button on input field)
case clear

/// Do nothing
case none
}

extension XCUIElement {
/// Does the element has keyboard focus?
///
/// - Returns: boolean to indicate if the element has the current keyboard focus
public var hasKeyboardFocus: Bool {
return (self.value(forKey: "hasKeyboardFocus") as? Bool) ?? false
}

/// Type some text and submit
///
/// - Parameter text: Text to type.
/// - Parameter press: Should press "Continue", "Send", "Search", ...
public func type(in textField: XCUIElement, text: String, action: XCUIElementAction = .send) {
if textField.elementType == .textField ||
textField.elementType == .secureTextField ||
textField.elementType == .searchField {

// Focus keyboard
textField.tap()

// Type text
textField.typeText(text)

switch action {
case .send:
// Send (last button)
self.keyboards.buttons.lastMatch.tap()
case .clear:
// Clear (last button on input field)
textField.buttons.lastMatch.tap()
case .none:
// Do nothing
break
}
} else {
fatalError("This element is a \(textField.elementType), expected a *Field.")
}
}

/// Print all elements
func printAllElements() {
print(self.debugDescription)
}

/// Wait for a duration
///
/// - Parameter duration: Duration to wait
public func wait(for duration: TimeInterval) {
let testCase = XCTestCase()
let waitExpectation = testCase.expectation(description: "Waiting")
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
waitExpectation.fulfill()
}
testCase.waitForExpectations(timeout: duration + 0.5)
}
}

#endif
11 changes: 11 additions & 0 deletions Sources/XCUITestHelper/XCUIElementQuery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,31 @@

#if canImport(XCTest)
import XCTest
import Foundation

extension XCUIElementQuery {
/// The last element that matches the query.
public var lastMatch: XCUIElement {
return element(boundBy: count - 1)
}

/// An radom element that matches the query.
public var random: XCUIElement {
return element(boundBy: Int.random(in: 0 ..< count))
}

/// Returns an element that will use the index provided
///
/// - Parameters:
/// - index: The index of element to access.
public subscript(_ index: Int) -> XCUIElement {
return element(boundBy: index)
}

/// Print all elements
func printAllElements() {
print(self.debugDescription)
}
}

#endif

0 comments on commit d1233f8

Please sign in to comment.