XCTWaiter Expectation not firing - swift

I'm using XCTWaiter to wait for certain conditions in a UI automation setup. This is my custom waitFor method:
// UITools.swift
public class func waitFor(_ element:Any, timeout:UInt, clause:String) -> Bool
{
let predicate = NSPredicate(format: clause)
let expectation = testcase.expectation(for: predicate, evaluatedWith: element)
print("Waiting for \(element) to become \"\(clause)\" within \(timeout) seconds ...")
let result = XCTWaiter.wait(for: [expectation], timeout: TimeInterval(timeout))
switch result
{
case .completed:
return true
case .invertedFulfillment:
print("waitFor result is in inverted fulfillment.")
return true
case .timedOut:
print("waitFor result is timed out.")
case .incorrectOrder:
print("waitFor result is in incorrect order.")
case .interrupted:
print("waitFor result is interrupted.")
}
return false
}
This method works fine in cases where I wait for XCUIElements but I have a case where I want to wait for a network request to finish so I use a flag that is set to true once the network request is finished. Here's a simplified example:
class Hub : NSObject
{
var isTestRailCasesRetrived = false
func retrieveTestRailCaseData()
{
isTestRailCasesRetrived = false
testrailClient.getTestCases()
{
(response:TestRailModel) in
// Do processing here ...
print("Found \(totalCases) TestRail cases for suite with ID \(suite.id).")
self.isTestRailCasesRetrived = true
}
UITools.waitFor(self, timeout: 30, clause: "isTestRailCasesRetrived == true")
}
}
However, the XCTWaiter never reaches a complete and just times out after the timeout. It seems that isTestRailCasesRetrived is never evaluated in this situation. Does somebody know why?

Found a workaround. This method works successfully in this particular case where above code didn't. It blocks XCUITest code execution until this wait loop is finished ...
/// Ass-simple brute force wait method for when nothing else works.
///
public class func waitUntil(timeout:Int = 30, evalblock:#escaping (() -> Bool))
{
var count = 0
repeat
{
if count >= timeout || evalblock() == true
{
break
}
else
{
Darwin.sleep(1)
}
count += 1
}
while true
}

NSPredicate works with Objective-C runtime and a properties or functions evaluated by it, must be marked with #objc attribute.
Solution:
class Hub : NSObject
{
#objc var isTestRailCasesRetrived = false
func retrieveTestRailCaseData()
{
isTestRailCasesRetrived = false
testrailClient.getTestCases()
{
(response:TestRailModel) in
// Do processing here ...
print("Found \(totalCases) TestRail cases for suite with ID \(suite.id).")
self.isTestRailCasesRetrived = true
}
UITools.waitFor(self, timeout: 30, clause: "isTestRailCasesRetrived == true")
}
}

Related

How to implement the logic without state variables

There are two observables: the first named activator emits booleans. The second named signaler emits void events. There's a function f() which must be called under the next conditions:
If the last event from activator is true, and event from signaler comes, call f(). Otherwise (the last activator's event is false, or activator has not yet emitted anything), "remember" that signaler sent the event. As soon as activator emits true, call f() and clear "remembered" flag.
Example:
let activator = PublishRelay<Bool>()
let signaler = PublishRelay<Void>()
signaler.accept(()) // activator not emitted yet, just remember that signal came
activator.accept(true) // go to active state. signal is waiting. call f()
signaler.accept(()) // already activated. call f()
activator.accept(false)// go to inactive state
activator.accept(true) // go to active state.
signaler.accept(()) // call f()
activator.accept(false)// go to inactive state
signaler.accept(()) // inactive state, remember that signal came
signaler.accept(()) // still inactive state, remember that signal came
activator.accept(true) // go to active state. there is signal waiting. call f().
signaler.accept(()) // active state. call f().
I can achieve the desired behaviour using two state variables _isActive and _waiting:
var _isActive = false
var _waiting = false
activator.bind { isActive in
self._isActive = isActive
if isActive && self._waiting {
f()
self._waiting = false
}
}.disposed(by: _bag)
signaler.bind {
if self._isActive {
f()
} else {
self._waiting = true
}
}.disposed(by: _bag)
The question is: can I implement it without state variables, only by means of reactive operators?
You need a state machine, but you can contain the state so you aren't leaving the monad... Something like this:
func example(activator: Observable<Bool>, signaler: Observable<Void>) -> Observable<Void> {
enum Action {
case signal
case active(Bool)
}
return Observable.merge(signaler.map(to: Action.signal), activator.map(Action.active))
.scan((isWaiting: false, isActive: false, fire: Void?.none)) { state, action in
switch action {
case .signal:
if state.isActive {
return (state.isWaiting, state.isActive, ())
}
else {
return (true, state.isActive, .none)
}
case .active(let active):
if active && state.isWaiting {
return (false, active, ())
}
else {
return (state.isWaiting, active, .none)
}
}
}
.compactMap { $0.fire }
}
Note how the logic inside the scan closure is the same as the external logic you already have. With the above, you can now do something like this:
let activator = PublishRelay<Bool>()
let signaler = PublishRelay<Void>()
example(
activator: activator.asObservable(),
signaler: signaler.asObservable()
)
.bind(onNext: f)
Lastly, as a bonus. Here's a unit test proving it works:
class RxSandboxTests: XCTestCase {
func test() {
let scheduler = TestScheduler(initialClock: 0)
let activator = scheduler.createColdObservable([.next(20, true), .next(40, false), .next(50, true), .next(70, false), .next(100, true)])
let signaler = scheduler.createColdObservable([.next(10, ()), .next(30, ()), .next(60, ()), .next(80, ()), .next(90, ()), .next(110, ())])
let result = scheduler.start {
example(activator: activator.asObservable(), signaler: signaler.asObservable())
}
XCTAssertEqual(result.events.map { $0.time }, [220, 230, 260, 300, 310])
}
}

Can't find a way to implement a wait function in my Swift code

I can't find a way to implement a wait function, I'm using swiftforwindows and no examples online have been able to solve it so far. It's Swift 4.2
The class is basically an array that when a function is called each index on the array gets a constant value deducted. the tick function is what is being called. I'm new to Swift.
class resProj {
var list = [1,1,1,1]
var projReq = [100,200,300,50]
var completed = false
func tick(){
for count in 0..<projReq.count{
if projReq[count] <= list[count]{
projReq[count] = 0
}
else if projReq[count] > list[count]{
projReq[count] -= list[count]
}
}
print(projReq)
}
init(
mathsP mathsIn: Int,
scienceP sciecnceIn: Int,
enginerP enginerIn: Int,
businessP businessIn: Int) {
self.list [0] = mathsIn
self.list [1] = sciecnceIn
self.list [2] = enginerIn
self.list [3] = businessIn
}
}
var spaceElev = resProj(
mathsP: 10,
scienceP: 20,
enginerP: 30,
businessP: 5)
var x = false
while x == false{
//wait function here pls//
print("tick", terminator:"?")
let y = readLine()
if y == "y"{
spaceElev.tick()
}
else{
print("gotta put y")
}
var templist = spaceElev.projReq
var templistcount = 0
templistcount = templist.count
for loop in 0..<templistcount{
if templist[loop] == 0{
templistcount -= 1
}
}
if templistcount == 0 {
x = true
print("project completed")
}
}
}
Where it says //wait function here pls// I would like to make the program wait for 1 second.
There are a lot of way to do this but most common way is create a completion function. For example:
func doSth(_ someParameter: String, _ completion: ()->()) {
print(someParameter)
// After your code is finish call completion
completion()
}
And when you call (there is two way to call):
doSth("Done") {
print("You can be sure that this block will work after your func finish")
}
or you can simply create another func and send it as a parameter.
You can also use DispatchQueue:
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
// put your func here...
}
You can simple use the UNIX-Functin func sleep(_: UInt32) -> UInt32.
In your case use sleep(1) to wait one second.
You could use Grand Central Dispatch or perform.
GCD solution:
let delayInSeconds = 1
DispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) {
print("tick", terminator:"?")
}
If you want to learn more about Grand Central Dispatch (GCD) I suggest you read through this:
Grand Central Dispatch - Wikipedia
Grand Central Dispatch Tutorial - Ray Wenderlich
Perform solution:
Create a function like this:
#objc func delayedFunc() {
//write the code here that you want to execute with a one second delay
}
Then call this where you want the delayed function to execute:
let delayInSeconds = 1
perform(#selector(delayedFunc), with: nil, afterDelay: delayInSeconds)
You can use the RunLoop class:
func wait(for interval: TimeInterval) {
RunLoop.current.run(until: Date() + interval)
}

Is there a way to make a signal similar to combineLatest without needing all the signals to initially fire?

I have an array of signals
var signals = [Signal<ActionResult?, NoError>]()
where
enum ActionResult
case failed
case pending
case completed
}
I want to create a combined signal that returns true if one or more of the signals fires a .pending
let doesAnyOfTheActionsLoad = Signal.combineLatest(signals).map { values in
values.reduce(false, { (result, nextResult) -> Bool in
if result == true { return true }
if case .pending? = nextResult {
return true
}
return false
})
}
My only problem is that the combineLatest will only fire if all signals have fired at least once, and i need my signal to fire regardless if all signals have fired. Is there a way to do this in ReactiveSwift?
Try this:
let doesAnyOfTheActionsLoad = Signal.merge(signals).map { $0 == .pending}
If you want the signal to stay true after one .pending, then you need to store the current state with something like the scan operator:
let doesAnyOfTheActionsLoad = Signal.merge(signals).scan(false) { state, next in
if case .pending? = next {
return true
}
else {
return state
}
}
scan is like the "live" reactive version of reduce; it sends along the current result each time a new value comes in and is accumulated.
The other solutions are technically correct but I thought this might fit your use case better.
// Only ever produces either a single `true` or a single `false`.
let doesAnyOfTheActionsLoad =
SignalProducer<Bool, NoError>
.init(signals)
.flatten(.merge) // Merge the signals together into a single signal.
.skipNil() // Discard `nil` values.
.map { $0 == .pending } // Convert every value to a bool representing whether that value is `.pending`.
.filter { $0 } // Filter out `false`.
.concat(value: false) // If all signals complete without going to `.pending`, send a `false`.
.take(first: 1) // Only take one value (so we avoid the concatted value in the case that something loads).

Return a boolean from a closure

I have been searching in Swift documentation and googling but can't find how to return a value from a block like this:
func checkIfplayerFellDown() -> Bool {
self.enumerateChildNodesWithName("brick", usingBlock: {
(node: SKNode!, stop: UnsafeMutablePointer <ObjCBool>) -> Bool in
if (node.position.y < self.player.position.y) { return false }
})
return true
}
The problem is because I do not understand blocks. I usually use them like this:
world.enumerateChildNodesWithName("name") {node, stop in
if (node.position.y < self.size.height*0.5) {
node.removeFromParent()
}
}
How can I return a boolean from any of this closures? I know I should probably use a syntax out somewhere and I tried some things but none of them worked because I have no idea how the blocks even work.
Any explanation or an example of how this should be done is appreciated.
Use a local variable (outside the block but inside the method) to pass the result out of the block, and also set stop to true when you want to stop the iteration:
func playerFellDown() -> Bool {
var result = true
self.enumerateChildNodesWithName("brick") { (child, stopOut) in
if child.position.y < self.player.position.y {
result = false
stopOut.memory = true
}
}
return result
}

Swift 2 - Use case for using break on if statement?

Swift 2's guide mentions that you can end program execution of an if statement. I personally have never used break with if-statement.
A break statement ends program execution of a loop, an if statement,
or a switch statement...When a break statement is followed by the
name of a statement label, it ends program execution of the loop, if
statement, or switch statement named by that label.
In what situation would one be using break in an if-statement? This language feature seems useless.
TEST:
if (true) {
break TEST
}
For example if you want to describe a number (with Strings) with reference to sets of numbers (even/rational/negative numbers) your code could look something like this:
if condition1 {
// code
if condition2 {
// code
if condition3 {
// code
if condition4 {
//code
}
}
}
}
You can achieve the same logic but without the nested ifs by refactoring it (using guard):
OuterIf: if condition1 {
// code
guard condition2 else { break OuterIf }
// code
guard condition3 else { break OuterIf }
// code
guard condition4 else { break OuterIf }
// code
}
// reads even better when breaking out of "do"
scope: do {
guard condition1 else { break scope }
// code
guard condition2 else { break scope }
// code
guard condition3 else { break scope }
// code
guard condition4 else { break scope }
// code
}
You might think that this can also be achieved with switch and fallthrough but this doesn't work with "normal" cases because it checks all conditions and if one condition is met all following conditions aren't even evaluated.
So the fallthough has to be called conditionally.
This does work but I isn't very readable not to mention its "beauty":
let x = 4
switch x {
case _ where condition1:
// code
if condition2 { fallthrough }
case _ where false:
// code
if condition3 { fallthrough }
case _ where false:
// code
if condition4 { fallthrough }
case _ where false:
// code
break
default: break
}
Using break with an if statement seems a bit contrived, and I can't think of a place where style would demand it. It does, however, save an extra level of indentation when skipping the latter portion of an if statement in an if-else clause, which can be useful for deeply nested loops.
In other languages, a popular (and/or controversial) idiom is to use labels for handling errors in deeply nested functions. For example, one might want to break out of a loop on error, like this:
func testBreak3() {
// doesn't compile!!!
let a = false, b = true, x = 10, y = 20, err = true
if !a {
if b && x > 0 {
if y < 100 {
if err {
break handleError
}
// some statements
} else {
// other stuff
}
}
}
return // avoid error handling
handleError:
print("error")
// handle the error
}
But in Swift (I'm using 2.0 as a reference), labels are different than with other languages; the above example doesn't compile for two reasons: The label isn't declared yet when it's used, and the label must be directly associated with a do, while, if, or case statement. Furthermore, break within an if or do statements requires that statement to be labeled. We can fix this as follows, although the changes make the solution less attractive due to additional tracking via the errorFlagged variable, making refactoring more attractive:
func testBreak() {
let a = false, b = true, x = 10, y = 20, err = true
var errorFlagged = false
nestedIf: if !a {
if b && x > 0 {
if y < 100 {
if err {
errorFlagged = true
break nestedIf
}
// some statements
} else {
// other stuff
}
}
}
// skip handling if no error flagged.
if errorFlagged {
print("error")
// handle error
}
}
I know this is old topic, but just now I used break and it was needed.
So my example
I have array of objects.
When user taps on a cell, i.parameter becomes True for the object in that cell.
I need to know when all the objects in the array have i.parameter = True , that's the condition to stop the game.
func forTimer(){
for i in array {
if i.parameter == false {
break
}
}
}
timer = Timer.scheduledTimer(timeInterval: 0.001, target: self, selector: #selector(forTimer), userInfo: nil, repeats: true)
Even if one i.parameter = false, I do not need to check the rest of the array.
This function is called every millisecond, so I will not have to check the whole array every millisecond.