How to run code in an iOS app from a UI test in Xcode 7? - xcode7

Is there a way to run code in the app from a UI test in Xcode 7? This is possible with application tests (since the tests run in the app), but there doesn't appear to be a simple way with UI tests.
Has anyone figured out a workaround?

The most straight forward way to run code in the app you are executing your app from UI tests is to supply launchArguments via XCUIApplication.
ui test code
import XCTest
class UITestUITests: XCTestCase {
override func setUp() {
super.setUp()
let app = XCUIApplication()
app.launchArguments += ["-anargument", "false","-anotherargument","true"]
app.launch()
}
}
app code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
print("All arguments: \(NSProcessInfo.processInfo().arguments)\n\n")
print("anargument: \(NSUserDefaults.standardUserDefaults().boolForKey("anargument"))")
print("anotherargument: \(NSUserDefaults.standardUserDefaults().boolForKey("anotherargument"))")
return true
}
app output when launched from ui test:
All arguments: ["/...../AnApp.app/UITest", "-anargument", "false", "-anotherargument", "true"]
anargument: false
anotherargument: true

UI Testing runs in a separate process from your app. There is currently, as of Xcode 7.1.1, no way to interact directly with the production app's code from the framework.
Every interaction must route through accessibility. This means that you could wire up a button that executed code in your app, then have the tests call that button. This is obviously not scalable and I would recommend against it.
Maybe there is another way to achieve your goals? What exactly are you trying to accomplish?

I'm thinking of passing an environment variable to the app when testing which launches an embedded HTTP server. Then I can communicate with the app through the server. Crazy, right? And yet, I can't believe nobody has done this yet.
My biggest concern with this approach is that the embedded server will be in the production app. I'm not sure if that is a problem, or if there's a simple way to only include it when running UI tests.

Related

How to pass/parse server data to objects in WatchKit table rows?

My tutorial is a WhatsApp/SnapChat app. Naturally the avatar image, country flag, user name, gender symbol and conversation data all come from the server and host app.
These kinds of apps do not use Parse like APIs or other 3rd party dependencies because they use REST/JSON with their own servers.
How do I get this same data and UI elements onto the watch table row? Do we have to re-write the same HTTP GET methods in our watch extension as well as re-copy UI elements into watchOS cassettes folder? Can we not just call the same methods that already exist in the iOS host app? I'm not sure how the Connectivity Framework would be used.
Could you please give an example of GET and POST methods to assign an avatar or username to the watch table row view object? For example for a Node.js server.
Since your iOS host app has already downloaded and deserialized the data, it doesn't make any sense for the watch to duplicate that code or effort and GET the same data.
As for providing an example, you should show what you tried in code, and explain the specific problem you're having.
Documentation
You should use the Watch Connectivity framework to share data between your iOS and watchOS apps.
You'll find a good introduction in the watchOS 2 Transition Guide. See Communicating with Your Companion iOS App for details.
Apple also provides Lister sample code which demonstrates how to use WCSession to transfer both application context and files between iOS and watchOS.
Since the host app is written in Obj-C should WatchConnectivity / WCSessionDelegate be imported into every file header file that contains data that needs to be sent to the watch extension?
WCSession is a singleton that you configure at launch time, early in the life of both your iOS app and watch extension. See the transition guide's Activating the Session Object for more information.
If you don't understand how or where your apps should handle watch connectivity, there are plenty of tutorials and sample projects which you can easily find via Google.
So based on what you said I just need to use the Connectivity Framework. sendMessageToWatch and didReceiveMessage methods.
The exact methods you use depend on what you want to transfer -- application context, user info, files, or messages -- and whether it takes place in the foreground or background. See the transition guide's Choosing the Right Communication Option for more information.
If you check some chat app projects that are already on GitHub you will see how to use Connectivity Framework precisely. Obj-C and Swift.
Here's one that specifically shows you how to pass messages back and forth.
https://github.com/carbamide/MessagingTest
This is not my code. As you can see code is almost the same.
ViewController.swift
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
if (WCSession.isSupported()) {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
}
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
print(applicationContext)
let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
let alert = UIAlertController(title: "Application Context Received", message: applicationContext.description, preferredStyle: .Alert)
alert.addAction(okButton)
self.presentViewController(alert, animated: true, completion: nil)
}
watchOS InterfaceController.swift
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
print(applicationContext)
let okButton = WKAlertAction(title: "OK", style: WKAlertActionStyle.Default, handler: { () -> Void in })
self.presentAlertControllerWithTitle("Application Context Received", message: applicationContext.description, preferredStyle: .Alert, actions: [okButton])
}

Wait for App to idle after Interruption

I have a ViewController that will request access to location services on init via
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
{
[_locationManager requestWhenInUseAuthorization];
}
This triggers the "Allow app to access your location while you use the app?"-alert.
I use [self addUIInterruptionMonitorWithDescription:handler:] to react to this. I am encountering the following problem: after dismissing the request-dialog, the ui-test does not continue. The alert is dismissed, but Xcode waits for the app to become idle, but it looks like the app is idle:
t = 67.35s Wait for app to idle
The test fails, because the app is stuck here. If i tap into the simulator, Xcode logs.
t = 72.27s Synthesize event
and continues the test.
Is there a reason, why Xcode tries to wait for the app? A workaround seems to be to tell Xcode that the UI changed or an event happened. Is there a way to trigger this?
After presenting the alert you must interact with the interface. This is a known bug with Xcode 7.2. Simply tapping the app works just fine, but is required.
addUIInterruptionMonitorWithDescription("Location Dialog") { (alert) -> Bool in
alert.buttons["Allow"].tap()
return true
}
app.buttons["Find Games Nearby?"].tap()
app.tap() // need to interact with the app for the handler to fire
XCTAssert(app.staticTexts["Authorized"].exists)
See my blog post for more information.

Windows Phone 8.1 Voice Commands App Activation

I want to integrate some voice commands in my windows phone 8.1 app.
The first thing I want to do is to open my app by a voice command and navigate to a certain page.
According to MSDN article Quickstart: Voice commands (XAML) I can use the override of protected virtual void OnActivated(IActivatedEventArgs args) method in App.xaml.cs to meet my requirements. But it does'nt work the way I though it would!
I have the method with the following structure:
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.VoiceCommand)
{
var commandArgs = args as VoiceCommandActivatedEventArgs;
if (commandArgs != null)
{
// ... some logic here
}
}
}
The problem is when I'm activating my app by saying "Open 'name of my app' [optional words]" the app opens but the Activated event never fires! The app opens and OnLaunched event fires. So I can't even enter the OnActivated method.
Does anyone know the problem? Why can't I enter OnActivated method using voice commands?
P.S. I tried it with a simulator as well as with a real device.
you can see this article,
http://t.co/Q5hRxRPvwR
is in spanish, but you will understand.
After you install the app and run it, the xml should be installed, like said in documentation.
After ask to cortana "What can I say?" it will show all you can said, and the apps that supports cortana. Choose you app and you will see what you can say for your app, like
If you say what your app can listen, your app will be activated.

Windows Phone Custom URI

in my windows phone 8 application i am using custom uri association to launch another application through my phone.
i.e
await Windows.System.Launcher.LaunchUriAsync(new Uri("sixtag:"));
but my app is not able to get certified for store because of this. the testing team tells that you app terminates unexpectedly while executing this.
now, i don't know how to deal with this.
is there any way to throw exception if the app which i am launching is not installed on phone ?
or i should try something else so my task gets accomplished and app gets certified for store as well.
You do not need to wrap your launch in try/catch or check for success as described in the other answers. As soon as you call LaunchUriAsync, the platform takes over and will automatically handle the possibility of no app being installed by asking the user if she wishes to search in the store.
A couple of things to double-check:
1) Ensure that you can successfully back into your app following the navigation to sixtag.
2) Ensure that your call to LaunchUriAsync is the direct result of a user action (eg. tapping a button)
try
{
await Windows.System.Launcher.LaunchUriAsync(new Uri("sixtag:"));
}
catch
{
MessageBox.Show("please install Sixtag from the app store","AppMissing", MessageBoxButton.OK);
}
you can perhaps display another button and on clicking directly navigate to the app store. See if this solves your problem. Do vote it up if it does :)
You are needed to handle that as shown here . Also Read out Remarks given there.

Using App.Current.Terminate() method in Windows phone 8

As windows phone 8 provides us with this method for programmatically terminate an app, will there be any issue while app submission if we use this in app for terminating a page while there is no backentry in the navigation history?
There won't be any issue in certification when using this call, but make sure you have saved all data in your app when calling this, because this call effectively kills your app immediately - ApplicationClosing even handler won't be raised after it!
Why would you call Application.Terminate when navigating back with an empty back stack? Just let the app close itself. Seems a bit pointless to me to overuse Application.Terminate().
I can't say much about the new Terminate method, but I do have an app (NOTE: Not a game) that does the following at certain points
private void Kill()
{
new Microsoft.Xna.Framework.Game().Exit();
}
This app passed certification without any problems. This was an app for both WP7 and WP8 so I did not have the ability to use Terminate().