From 28ceff8ad6ead923b002e929489755b3961f9733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Rutkowski?= Date: Tue, 3 Sep 2024 19:01:23 +0200 Subject: [PATCH] XCUIElementQuery.assertMatchedElements --- README.md | 6 ++-- Sources/XCAppTest/XCAppTest.docc/XCAppTest.md | 8 +++-- .../XCUIElementQuery+Assertions.swift | 35 +++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 83f06ea..eb6d8f5 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ Utilities for easier interaction with XCUITest methods. - `self[2]` - `first(where: { $0.label == "a" })` - `bannerNotifications` + - Asserting elements: + - `assertMatchedElements(perform: { element in /*...*/ })` - `CGVector` extensions: - Normalized offsets: @@ -86,7 +88,7 @@ Utilities for easier interaction with XCUITest methods. - `run("Activity name") { ... }` All of the above assertion functions have optional message as last parameter that can be used to configure what is displayed if assertion fails. For example: `element.assertExists("My element should be visible")`. -Additionally you can configure assertion timeout globally by modifying `XCAppTestTimeout.default` or per call via `timeout` parameter. For example: `XCAppTestTimeout.default = 3`, `element.assertExists(timeout: 3)`. +Additionally you can configure assertion timeout globally by modifying `XCAppTestConfig.defaultTimeout` or per call via `timeout` parameter. For example: `XCAppTestConfig.defaultTimeout = 3`, `element.assertExists(timeout: 3)`. For details see [documentation](https://swiftpackageindex.com/Tunous/XCAppTest/main/documentation/xcapptest). ## Example @@ -120,7 +122,7 @@ func testOpenClosePremiumScreen() throws { 1. Add the following to the dependencies array in your `Package.swift` file: ```swift -.package(url: "https://github.com/Tunous/XCAppTest.git", .upToNextMajor(from: "0.4.0")), +.package(url: "https://github.com/Tunous/XCAppTest.git", .upToNextMajor(from: "0.14.0")), ``` 2. Add `XCAppTest` as a dependency for your **tests** target: diff --git a/Sources/XCAppTest/XCAppTest.docc/XCAppTest.md b/Sources/XCAppTest/XCAppTest.docc/XCAppTest.md index d5b475c..2223825 100644 --- a/Sources/XCAppTest/XCAppTest.docc/XCAppTest.md +++ b/Sources/XCAppTest/XCAppTest.docc/XCAppTest.md @@ -102,7 +102,7 @@ element.assertExists(timeout: 3) - ``XCAppTest/XCTest/XCUIElement/stringValue`` -### Accessing elements and other apps +### Accessing elements - ``XCAppTest/XCTest/XCUIElementQuery/lastMatch`` - ``XCAppTest/XCTest/XCUIElementQuery/subscript(_:)`` @@ -110,6 +110,9 @@ element.assertExists(timeout: 3) - ``XCAppTest/XCTest/XCUIElementQuery/bannerNotifications`` - ``XCAppTest/XCTest/XCUIElement/bannerNotifications`` - ``XCAppTest/XCTest/XCUIElement/ElementType/bannerNotification`` + +### Accessing other apps + - ``XCAppTest/XCTest/XCUIApplication/safari`` - ``XCAppTest/XCTest/XCUIApplication/springboard`` - ``XCAppTest/XCTest/XCUIApplication/messages`` @@ -121,10 +124,11 @@ element.assertExists(timeout: 3) - ``XCAppTest/XCTest/XCUIApplication/assertIsNotInForeground(timeout:_:file:line:)`` - ``XCAppTest/XCTest/XCUIApplication/assertIsInForeground(_:timeout:_:file:line:)`` -### Checking number of elements +### Asserting multiple elements - ``XCAppTest/XCTest/XCUIElementQuery/assertHasCount(_:timeout:_:file:line:)-6w6h2`` - ``XCAppTest/XCTest/XCUIElementQuery/assertHasCount(_:timeout:_:file:line:)-1745l`` +- ``XCAppTest/XCTest/XCUIElementQuery/assertMatchedElements(perform:)`` ### Configuration diff --git a/Sources/XCAppTest/XCUIElementQuery+Assertions.swift b/Sources/XCAppTest/XCUIElementQuery+Assertions.swift index f1a81cb..af1b07b 100644 --- a/Sources/XCAppTest/XCUIElementQuery+Assertions.swift +++ b/Sources/XCAppTest/XCUIElementQuery+Assertions.swift @@ -107,4 +107,39 @@ extension XCUIElementQuery { line: line ) } + + /// Evaluates the query and verifies matched elements in order. + /// + /// Inside of the assertion closure you should use provided argument to access child elements. It is expected that + /// you will call that argument exactly as many times as there are matched child elements. If that count doesn't match + /// the assertion will fail. + /// + /// # Example + /// + /// The following code will match all static texts currently visible in the app and verify that there are exactly 2 of them. + /// The first matched static text will be asserted to have label "One" and the second static text will be asserted to have label "Two". + /// If there is a different number of static texts, or one of the static text has incorrect label an assertion will fail. + /// + /// ```swift + /// XCUIApplication().staticTexts.assertMatchedElements { element in + /// element().assertHasLabel("One") + /// element().assertHasLabel("Two") + /// } + /// ``` + /// + /// - Parameter perform: Closure providing access to matched elements in order. + /// Each time argument received by this closure is invoked a new element will be returned. + /// - Returns: Unmodified UI element query. + @discardableResult + public func assertMatchedElements(perform: (_ element: () -> XCUIElement) -> Void) -> Self { + XCTContext.runActivity(named: "Assert matched elements of \(self)") { _ in + var currentIndex = 0 + perform({ + defer { currentIndex += 1 } + return self[currentIndex] + }) + assertHasCount(currentIndex) + } + return self + } }