I'm testing login page - specifically "Autologin" checkbox, so that user being logged-in once, will be automatically logged-in upon reopening the app (by default user should login from scratch).
How can I simulate this behaviour? Is restarting an app is the only way? Can I reset an app somehow to initial screen (as if being restarted), but so that userdata/cookies should be kept?
My initial solution was to close the app by Espresso.pressBackUnconditionally() (it is similar to Espresso.pressBack() but will not throw an exception when Espresso navigates outside the application or process under test) and to launch activity again: activityRule.launchActivity(null).
However, at the end we came up with more sophisticated solution of relaunching activity within instrumentation:
with(activityRule) {
finishActivity()
launchActivity(null)
}
Activity test rule is deprecated.
You can do this using the following code in Kotlin
activityScenarioRule.scenario.close()
ActivityScenario.launch(YourActivity::class.java, null)
Related
Some background
I am currently writing a UI Test for a settings pane, and click on buttons to enable certain permissions such as push notifications and location services.
However, if the alert for the permission has been displayed before (regardless of the user allowing or denying access to the permission), the alert will not display again, and will just take the user to the settings app. Unfortunately, these settings do not reset, meaning the first time I run the UI tests, alerts will show; and on all subsequent UI test runs, the buttons will take me to the settings app unless I reset the device before the tests begin.
My issue
Thus, my test needs to know if the app went into the background, and attempt to foreground it to continue the testing:
if app.state == background {
foregroundApp()
}
// continue with other tests
Is there any way to determine if the app is in the background?
What I tried
I researched methods to determine the state of the application (running/background/etc) from a UI test, and was not able to find much. I tried to check whether certain elements exist:
if (app.navigationBars.element.exists) ...
but this gives me runtime errors[1] if the user is taken to the settings page because the app under test is in the background, and the test cannot lookup the navigationBars (or other elements).
I tried using some of the methods from Facebook's private headers for XCUIApplication() and XCUIElement().
XCUIApplication().state always returns 3 no matter what state the app is currently in, and any attempts to call XCUIApplication().resolve() to foreground the app give me the same errors as before[1]
I tried to rewrite the logic to foreground the app before resuming the tests, but methods such as XCUIApplication().launch() kill the app before restarting, which I cannot do. Only siri service seems to work for me, but I cannot access the siri service through the corporate proxy, and modifying proxy permissions is not possible.
Is there any other way to check the app state?
Errors
[1] This error is printed every time I try to do something involving state. I do not call snapshotView anywhere, and thus the suggestion to use afterScreenUpdates is useless.
Failure to get snapshot within 15.0s
Cannot snapshot view (<UIKeyboardImpl: 0x7febcc75d000; frame = (0 0;
414 226); layer = <CALayer: 0x608000625720>>) with
afterScreenUpdates:NO, because the view is not in a window. Use
afterScreenUpdates:YES.`
tl;dr
I need to check whether the app I am UI testing has entered the background (i.e. user pressed the home button). Checking for existence of particular elements such as navigation bars doesn't work, neither do most methods from Facebook's private headers for XCUIApplication/XCUIElement. Foregrounding the app also causes issues, and relaunching the app is not an option; neither is siri service.
You can do this in Swift 4, using XCUIApplication.state, which will give you information about the state of the app - whether it's in the foreground or background etc. however, it's not possible to find this information in Swift 3 and below. Essentially, UI testing in Swift 3 doesn't support leaving the app.
i've met a problem when integrating my game with Facebook Unity SDK, the latest version, on IOS7, IPhone-4s.
Each time the game requests a Facebook login operation, game will become inactive and turns into background, and a Facebook login page appears, then IOS will killed my game, even the memory used by that game is only 90M or so. After login completed, IOS re-launched game, at which time Facebook SDK couldn't find the previous game process who performed the login operation and thus the login result could not be passed into new game instance.
So, there are two questions:
1) Is there any way to make game process alive in background? I have no idea why 90M memory usage is large enough that IOS want to kill my process.
2) Is there any way let the new game process get login result performed by the previous game process?
3) Is there any way to open embedded webView login dialog of Facebook in unity when performs a login operation instead of jumping out my game?
thanks you.
------------ UPDATE ----------
Solution found for the 3rd question:
1) Locating Facebook/Editor/iOS/FbUnityInterface.mm
2) Find method -(void)login:(const char *)scope { ... }
3) change
openWithBehavior:FBSessionLoginBehaviorWithFallbackToWebView
to
openWithBehavior:FBSessionLoginBehaviorForcingWebView
4) now, each time you request login, an embed web-view dialog will be popped out instead of jumping out of current game to Facebook login dialog.
1) First of all make sure that you haven't checked 'PlayerSettings | Other Settings | Configuration | Exit on suspend' option, which kills your app when you leave it.
90MB on iPhone4S could be quite a lot, the device itself has only 512 MB RAM memory, where system takes a lot. If you have many apps open, then your app, then facebook app which nowadays is not lightweight as well, then the biggest active process (your game) could be killed.
2) Yes there is. Facebook Unity3d plugin has a method for checking the logged status, which should return true after succesfull login (even if the app was killed).
if( FB.IsLoggedIn )
{
// your code here
}
3) There is no easy way to do that with current version of Unity3D Facebook plugin.
Try making a debug build in Xcode and see what it says when the application is killed in the background. It should give a stacktrace to see what happens. That 90MB shouldn't be a problem for an iPhone4S so out of memory crash could be ruled out.
I am using Display.screenshot() to get a screen shot for the current displayed screen.
My application has all available persmissions set to allow,
it works well in all device application, but it doesn't work on Facebook and Twitter app -
on those apps i got an exception:
Error: net.rim.device.api.system.ControlledAccessException: Unauthorized attempt to attach to this application
what should I do to overcome this?
You seem to be calling Application.getApplication() somewhere in the code.
Your ApplicationMenuItem code generally runs within the UI application whose menu it is launched from. So when you click your ApplicationMenuItem within facebook app, it executes within the event dispatcher thread of facebook app.
However, since your code is not a part of the facebook app, it can't access its Application Object using the Application.getApplication() method.
If you are not calling this method yourself, maybe Display.screenshot() calls it internally. To solve this, you need to run the code in your app's event dispatcher thread. This can be done by using the special method addMenuItem(long, ApplicationMenuItem, ApplicationDescriptor) while registering the menu item and passing it your app descriptor.
As the title says, my project will never bring up the FB login screen until I have called
[facebook logout];
This makes sense when I've already logged in, but it happens on startup as well (i.e. the user is not yet logged in).
Hmmm...I've just tried resetting contents and settings in the simulator, and that seems to have fixed the problem. For my own peace of mind, why when I close the simulator and rerun the project does it not revert to either a state where the app is 'new' and hasn't been run before, or to a resume state - whereby the logged in user info would be available immediately?
On my device I have just tested this:
Fresh install
Open app, login via FB Connect
Close app, remove from running in background apps
Reopen app
Try to login, no response until I first click logout
So is it somehow retaining the fact that it has logged in before? If so, is there a "loggedInAlready" variable or something similar that I can check against?
Added this to didFinishLaunchingWithOptions
if([facebook isSessionValid])//if already able to log in
{
[self loginToFacebook];//attempt to login automatically on startup
}
Seems to have solved the problem. I guess that because I had:
if([facebook isSessionValid]){
[facebook login];
}
in the login button press, that when it resumed it was still in a valid session and so the button press wouldn't do anything until the logout button ended the session.
Now it automatically checks if the session is valid on startup, and if so it logs straight in for me.
:-) All's well that ends well.
How programmatically restart an iPhone app in iOS?
I find this way http://writeitstudios.com/david/?p=54
But may be something simple.
The only way I know to do this is not ideal, but it works.
First, your app has to opt out of background execution (multitasking) The app has to quit when exited, not run as a background task. This is done with the plist key UIApplicationExitsOnSuspend.
Second, your app needs to register a custom URL scheme that can be used to launch the app.
Third, you need a web page hosted somewhere that when loaded will redirect to your app's custom URL scheme.
Forth, the user needs an active Internet connection.
To exit and restart, call UIApplication openURL on your hosted redirecting web page. Your app will exit and safari will launch and load your page. The page will redirect Safari to your custom URL scheme, prompting Safari to internally call openURL, causing iOS to launch your app.
my post that you linked to is referring to a Cocoa Application, not the iOS. On the iOS, you can quit an application (but Apple doesn't like this) by using exit(0); but I don't recommend that. You cannot restart iPhone apps though.
Unless you're developing for jailbroken devices, Apple won't even allow you to programatically terminate your app. So restarting the device is out of the question.
Your AppDelegate instance has a method
(void)applicationDidBecomeActive:(UIApplication *)application
{
}
In here, you can put logic to figure out if the app should restart, or continue doing whatever it was doing. For example you can have a BOOL variable appMustRestart that is false at first but gets triggered as true whenever something happens in your app that you'd like the next time to be a fresh relaunch.
if (appMustRestart)
{
[self resetVars]; // call a method that resets all your vars to initial settings
// INSERT CODE HERE TO TRANSFER FOCUS TO INITIAL VIEWCONTROLLER
}