Load controller from storyboard using Cucumberish with UI Testing - swift

I am trying to implement UI testing with BDD using Cucumberish framework.
I understand quite well the Feature files parsing system and I managed to tests some UI elements of the main screen.
However I would like to load any controller from storyboard before using UI testing on the corresponding screen.
Here is my initialization code:
#objc class CucumberishSwiftInit: NSObject {
#objc class func CucumberishSwiftInit()
{
var application : XCUIApplication!
//A closure that will be executed just before executing any of your features
beforeStart { () -> Void in
application = XCUIApplication()
}
//A Given step definition
Given("the app is running") { (args, userInfo) -> Void in
application.launch()
let bundle = Bundle.main
// I double checked the storyboard name and I can access it in my Unit Tests target
// application crashes here
let storyboard = UIStoryboard(name: "Main", bundle: bundle)
// never executed
Swift.print("storyboard \(storyboard)")
}
let bundle = Bundle(for: CucumberishSwiftInit.self)
Cucumberish.executeFeatures(inDirectory: "Features", from: bundle, includeTags: nil, excludeTags: ["skip"])
}
}
Some feature file:
#run #welcome
Feature: Some feature
Some feature desc
Scenario: Can load screen
Given the app is running
...
The application crashed on the UIStoryboard init statement, caught "NSInvalidArgumentException", "Could not find a storyboard named 'Main' in bundle NSBundle (loaded). I have no clue why as it is working using with my unit tests.

The error you're getting is due to the fact that the .storyboard file you are trying to load is not part of the bundle of the application you are running.
The reason that's happening is that when you run a UI test your code is not running in the same process as your application, and it can only interact with it through the XCUIApplication proxy. (The mechanics might be slightly different, but that's gist, unfortunately there's little documentation that I can link.)
UI testing is a different style of testing than what you can do with XCTest. Programmatically loading an instance of a screen from a .storyboard is not possible.
In other words, you can't use any code from your app in your UI tests, but rather have to interact with it like a real user would, and write assertions for what's on the screen.

Related

Xcode Swift app does not start after changing folder structure

I'm new to swift and trying to create a basic app with Firebase. But when i tried to build and run the app on simulator, i get the following error:
Application launch for 'com.example.SnapchatClone' did not return a valid pid nor a launch error.
Domain: NSPOSIXErrorDomain
Code: 3
Failure Reason: No such process
User Info: {
DVTErrorCreationDateKey = "2022-12-19 18:25:55 +0000";
IDERunOperationFailingWorker = IDELaunchiPhoneSimulatorLauncher;
}
I'm not sure about the reason but I have relocated some files, like AppDelegate.swift and SceneDelegate.swift to Delegates folder, and View Controller files to ViewControllers folder.
I have tried to changed the DelegateClassName to '$(PRODUCT_MODULE_NAME).Delegate.SceneDelegate', clean and build again, restart the mac, adding a UIWindow definition to AppDelegate class. Nothing changes.
Can someone explain the error message and offer a solution?

How to debug an app activated from dock menu

I'm trying to understand how to debug a dock open document event.
I'd like to understand the environment so that normal document restoration can be disabled on startup when the app is stated to open some document, especially when the doc itself is a candidate for restoration.
But, since the app is seemingly started, "no debug", breaks in several app delegate methods are never called; i.e.,
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool
func applicationDockMenu(sender: NSApplication) -> NSMenu?
As each document open event will instantiate a document window, normally I'd like to avoid that but having so is useful, so I'd like the ability to debug it while in this sort of start up, so long as I'm attached to the debugger.
If you want to debug the app launch process while the app is not connected to a debugger, you may need to just rely on unified logging. For example, I often use this pattern, with a private OSLog for each source file, which I can then observe these log statements in the Console:
// ViewController.swift
import Cocoa
import os.log
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "ViewController")
class ViewController: NSViewController {
var string = "..."
override func viewDidLoad() {
super.viewDidLoad()
os_log(.debug, log: log, "viewDidLoad: string = %{public}#", string)
}
...
}
Then, if the Console is configured to show debugging statements (e.g. “Action” » “Include Debug Messages”), I can filter for these (e.g. type subsystem: in the search bar, followed by your subsystem, the bundle identifier in this case). Then, completely independent of Xcode, I can watch these log statements from the Console app (and filter for my subsystem and/or category) as my app runs, not attached to the debugger:
This technique works for both macOS and iOS apps.
For more information, see the Unified Logging and Activity Tracing video.
Obviously, once your debug build is running, but having been launched independently of the debugger, you can manually attach Xcode’s debugger to it via the “Debug” » “Attach to process” menu option.
But attaching a debugger to an app that is already running is not practical when you’re trying to debug the startup sequence when an app launches. But the aforementioned unified logging is often sufficient for confirming what methods were called when, through the judicious use of os_log statements.

Could not load NIB in bundle - Bundle not yet loaded

Just hit a problem where I need to work with a external framework and bundle.
While the frame is imported and its functions can be called just fine, one of it's methods tries to load a nib from the accompanying bundle, which ends in a NSInternalInconsistencyException for the reason
"Could not load NIB in bundle".
I noticed that while the bundle is in the Copy Bundle Resources and can be found by calling Bundle.allBundles, the error message says the bundle is "not yet loaded". Is there something I was supposed to do so the bundle could be loaded beforehand?
Update: I did not provide the related code earlier because the error happened as a colateral effect of a framework call, so I don't know exactly how the nib is "loaded".
The code itself is this:
if let request = AUTRequest.init(transactionType: .debitGeneric) {
AUTCTFClient.executeTransaction(with: request, from: self) { (_response) in
if let response = _response {
print(response)
}
}
}
self is the current viewcontroller and the error happens after the executeTransaction call but before the response block execution.
Is this somehow related to the Bundle not being loaded or is the framework at fault himself?
If you are using code do load the nib, you need to make sure you are loading it from the correct bundle:
let bundle = Bundle(for: ClassName.self)
let view = bundle.loadNibNamed("nib_name", owner: nil, options: nil)![0]
If you are using storyboard, please make sure to select to correct Module (the framework). You can select module in the Identity Inspector (in interface builder press cmd+alt+3).
After trying to find solutions for a while, the most obvious answer is that the framework in question was compiled with missing files, that the "AUTCTFClient.executeTransaction" tries to call in its execution. This point is "confirmed" by older versions of the framework showing some kind of progress view on execution. (but sadly they were not usable in our case)
If you somehow got this problem, it'll probably be best to ask the owners(or search) for an updated or stable version of their framework.

Fails a simple test case using KIF

I try to use KIF in swift project. I run test case on iPhone simulator. Probably I did not set up correctly KIF because use it first time. I used this manual
Test fails in this simple code
func testSelectingOrganizerRole() {
tester().tapView(withAccessibilityLabel: "ORGANIZE")
}
with reason:
A button with Accessibility label "ORGANIZE" exists on initial ViewConroller of storyboard.
Why don't you switch to the UI tests framework available since Xcode 7? A quick intro:
UI testing gives you the ability to find and interact with the UI of your app in order to validate the properties and state of the UI elements.
UI testing includes UI recording, which gives you the ability to generate code that exercises your app's UI the same way you do, and which you can expand upon to implement UI tests. This is a great way to quickly get started writing UI tests.
Using this framework, your simple test would look like this:
let app = XCUIApplication()
app.launch()
app["ORGANIZE"].tap()

How can i use UIAutomation in XCODE 8 , Swift 3

import XCTest
class UnitTestClass: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
}
I have multiple UIViewController classes in my app. Now, i want to test each class by UIAutomation in Xcode 8 ,swift 3. After Searching a lot, i didn't get any useful tutorial or tool in Xcode or swift's latest version. My App's First screen is Login screen. Can anyone help me to find-out the useful solution
I believe UIAutomation was deprecated in Xcode 8. But you can set up UI tests in Xcode 8 by simply doing the following:
Add an iOS UI Testing Bundle target to your project.
Create a test method under the new test file created as part of that target.
Click inside the curly braces within the method.
Click the "record" icon shown below the source editor to start recording your UI actions in the simulator.
Watch this WWDC Video to learn more about UI testing in Xcode.