How to get UIAutomation to wait for 2 view changes consistently? - ios-ui-automation

Xcode 6 beta 6
One workflow in my iOS app has a UINavigationController-controlled VC presenting a modal VC; "Save" in the modal VC dismisses it and pushes a new VC onto the navigation stack:
so from
UINC --> VC_1 -modal-> VC_2
to
UINC --> VC_1 --> VC_3
Ideally, I want something like this in my JS:
app.navigationBar().buttons()["Save"].tap();
_waitForView(app.navigationBar().withName("VC_3 title"));
...
// assertions re: VC_3 contents
where _waitForView() throws or otherwise fails the test if the desired view does not appear within the timeout.
On a few occasions, it has waited until VC_3 appeared and carried on correctly. More often than not, however, the first VC_3-specific assertion fails on VC_1 contents -- so my _waitForView() didn't throw/fail!
I've tried various combinations of isValid(), checkIsValid(), pushTimeout()/poptimeout(), and waiting first for VC_1 then VC_3 in _waitForView().
Have others gotten something like this to work consistently?
TIA

Not ideal, but this seems to work:
UIATarget.localTarget().delay(2);
_waitForView(app.navigationBar().withName("VC_3 title"));
I hope not to need the hard-coded 2-second delay long-term, but it'll hopefully be "good enough" while Xcode 6, et al, stabilize...

Related

Why is my AUv3 randomly disappearing with "viewServiceDidTerminateWithError"?

I’ve encountered a strange problem during iOS AUv3 Instrument development which I’m having trouble finding information on. I’ve spent a couple weeks now attempting to debug this, and I was wondering if anyone else has encountered it. It feels more like an "OS killed the app" than a crash, so I use the term crash loosely. Here are the symptoms:
It doesn't seem to ever happen on initial instantiation; it's when a project is reloaded. But, you can comment out setFullState and it'll still occur.
The “crash” is inconsistent. Like a lot of slippery bugs, it’ll start happening consistently and then it’ll stop happening completely.
When it does happen, it initially appears to load fine: the view loads and looks correct, and it produces audio. But, after a couple seconds, the plugin view disappears and it stops producing audio. I see this in the console log:
viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}
You don’t have to generate any MIDI events to crash it. It would crash even after I commented out the processing block.
If anyone has any ideas, including how to get some useful debugging info out of this situation, let me know!
I tried to look at crash logs, but there are no crash logs generated
didReceiveMemoryWarning is not tripped. In fact, I did an experiment where I allocated 100 megs and memset’d it on startup, and it didn’t crash it.
I tried attaching a debugger, but it goes from “no debug session” to “waiting to attach” after it crashes-- at no point does it actually attach. It will attach if I then reload the plugin, but then it won’t crash. The Zombies and Leaks tools didn't reveal anything, nor did the memory sanitizers.
Using a Storyboard instead of a XIB didn't change the behavior (not sure why it would, but it was one of the last few differences between this and Apple's example).
I created a very tiny example project which exhibits the problem (unfortunately, I cannot post any code which shows the problem because I cannot find where exactly the problem code is-- maybe it's even a project setting?). It has a minimal GUI, no setFullState, and generates white noise:
https://drive.google.com/open?id=1dw3xTHn3qY411eXLaIb_9_S5PAtrr5Nk
Expected: It doesn't crash or disappear randomly
Actual results: After reloading a project file which uses this AUv3, the plugin will disappear after a few seconds. It initially produces audio normally and the GUI looks OK, but then vanishes.

Qt5 "Attempt to set a screen on a child window" many runtime warning messages

In our Qt5-based application, many messages like this are displayed in the console:
0x1beccb0 void QWindowPrivate::setTopLevelScreen(QScreen*, bool) ( QScreen(0xd25b80) ): Attempt to set a screen on a child window.
It does not prevent the application from running, but I would like to fix them, since it tends to indicate that there is probably something wrong that we are doing. The code is quite large (cannot be included in the post, it is there: http://gforge.inria.fr/frs/?group_id=1465). I cannot ask you to take a look at it (too big), but maybe you will have an idea with the following additional information:
The messages appear only under Linux, and not under Windows
Our application is a 3D modeler, that has several QGLWidgets for
displaying 3D content. If I remove the QGLWidgets, then the messages
disappear.
In the debugger, if I put a breakpoint on
QWindowPrivate::setTopLevelScreen(), it is called by:
kernel/qwindow.cpp:368
368 q->connect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*)));
Update1:
I put a breakpoint on QMessageLogger::warning (qDebug() is a macro that uses this function), now I can better see the stack that looks like:
#0 0x00007fffefa50600 in QMessageLogger::warning() const#plt () from /usr/lib/x86_64-linux-gnu/libQt5Gui.so.5
#1 0x00007fffefa851cb in QWindowPrivate::setTopLevelScreen (this=0xd330e0, newScreen=0x7201a0, recreate=<optimized out>)
at kernel/qwindow.cpp:371
#2 0x00007fffefa7f2f5 in QGuiApplicationPrivate::processWindowSystemEvent (e=e#entry=0x760600)
at kernel/qguiapplication.cpp:1608
#3 0x00007fffefa631f8 in QWindowSystemInterface::sendWindowSystemEvents (flags=...)
at kernel/qwindowsysteminterface.cpp:625
#4 0x00007fffeb7d4100 in userEventSourceDispatch (source=<optimized out>)
at eventdispatchers/qeventdispatcher_glib.cpp:70
(More stack frames follow...)
In QGuiApplicationPrivate::processWindowSystemEvent, it is handling a QWindowSystemInterfacePrivate::ThemeChange event:
1608 case QWindowSystemInterfacePrivate::ThemeChange:
1609 QGuiApplicationPrivate::processThemeChanged(
1610 static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
1611 break;
Update2:
Nearly there !! It is when I call setMinimumWidth() / setMinimumHeight() on a QGLWidget. Now I'd like to know why...
Update3:
More information: the messages are only displayed when I have two screens connected to my computer.
Finally, I understood what happens:
The warning messages occur whenever setMinimumWidth() / setMinimumHeight() are called on a QGLWidget under Linux with a dual screen display.
This is probably a bug in Qt. It will probably be not fixed, since it is recommended in the documentation to use the new QOpenGLWidget instead, that appeared in Qt 5.4 (note: "OpenGL" instead of "GL"), which I did and the warning messages disappeared.
Edit: I saw a message from someone that had problems with text not rendering properly with the new QOpenGLWidget which I answer here: When using the new QOpenGLWidget, one needs to take care that it no longer has an independent OpenGL context, it shares the OpenGL context with Qt (therefore, OpenGL states modified in the rendering function needs to be restored after exiting the rendering function, for instance blending mode).

UI Automation Error: UI TESTING FAILURE-APP failed to quiesce within 30.0s

Since xCode updated i'm having trouble running any ui test case. It gives me this error when its expected to do a simple tapping action for example:
XCUIApplication *app = [[XCUIApplication alloc] init];
XCUIElement *passwordSecureTextField = app.secureTextFields[#"Password"];
[passwordSecureTextField tap];
Anyone have any ideas why am i getting this error? I've searched on google and here but haven't found any solutions.
Thank you.
Make sure you don't have any animations on screen during UI Automation tests. We had a text alert flashing on the login screen for debug/test builds of our app, and it would cause the "failed to quiesce" error until it was removed.
There are some other posts about this error that mention issues with UIRefreshControl, so I would suspect animating that or UIActivityIndicatorView would cause the same problem.
It might help to turn on the "All Exceptions" breakpoint. I used it and I recall getting the same error. It will break at the line with the problematic code and should show you the stack trace of the error with more info.
I had a similar error - as well as the simulator running very slowly. In my case it was fixed very simply by the method given in the accepted answer here: Xcode simulator extremely slow.
To save you a click: The issue was that I had accidentally pressed Cmd + T at some point, enabling "Slow animations".
I had to turn off the "Personal Hotspot" in order to get a working test environment (Because the blue bar in the top apparently disturbed XCTestRunner)
But as some tests need internet connection I can't do testing when being in the wild:-(
Anthony F's answer says it all. Likely something is still animating. The system seems to wait for the app UI to "settle" (go idle) and when that happens, it performs the tap action. However, when the UI constantly runs animations, it will never settle.
Xcode Console Output
Enable the console output in Xcode to see what happens when running the test.
Below is an example of the log, when it works well. The system waits for the app to go idle and when that has happened, it goes to find the button in the hierarchy.
t = 16.95s Tap "#go" Button
t = 16.95s Wait for app to idle
t = 17.00s Find the "#go" Button
t = 17.00s Snapshot accessibility hierarchy for XXX
t = 17.09s Find: Descendants matching type Button
t = 17.09s Find: Elements matching predicate '"#go" IN identifiers'
t = 17.10s Wait for app to idle
t = 17.15s Synthesize event
t = 17.41s Wait for app to idle
Below is an example when it fails. The system waits for the app to settle so that it can look for the button in the hierarchy. Since, it does not settle, it waits "forever" finally running into the timeout.
t = 18.88s Set device orientation to Unknown
t = 18.93s Tap "#go" Button
t = 18.93s Wait for app to idle
t = 79.00s Assertion Failure: UI Testing Failure - App failed to quiesce within 60s
In my case the "failed to quiesce" was caused, because at time t=18.90s, demo data was generated which caused repeated updates of a UIProgressView. From then on the app UI never settled ("quiesced").
("quiesce" as a word is not in my active vocabulary, which certainly has delayed my recognition of what was going on. The console output pushed me into the right direction. I'd bet "idle" rings more bells than "quiesce" for many developers.)

Storyboard/Modules

I have made like an "Asteroid" copy, that works pretty well! I made it with different modules (enemies, controls and background). Now I have also made like a starting screen, where the player can choose to play the game, view highscores etc.
The problem is that I have no clue how to implement this into a storyboard.. I might have misunderstood the use of modules.
I am starting in a Scene1, which is the intro+buttons to start the game. Next, I want to move to scene2(when player presses start button), and that seems to be no problem, and scene 1 gets purged. But when I die, I want to move to scene1 again. Problem is that some listeners dont get removed, and the game crashes shortly after scene switch.
I guess the main problem is that in my scene2, I have put in require("background"), enemies and controls in my enterscene, which I dont know how to remove when it should be purged.
Ive entered all of the modules and put them in the same group that gets purged on exitscene, but not everything gets removed.
How do you think I would fix this the easiest way? I am very new to Corona and still in a early learning stage.
Display objects, like display.newImageRect()'s and display.newText() that are created in the createScene() function and added to the "group" display group will be automatically removed when the scene is purged.
Any timers, transitions, or audio.plays that have onComplete handlers, as well as network requests and any event handler that attaches to the Runtime must be removed by hand. If you're various object you are creating are doing any of these things, their remove functions should undo these actions so that removing them will clean them up.
I find it best if I'm adding runtime handlers, timers, etc. to do it in enterScene() and make sure I undo them in exitScene(). Then if its something that is done in createScene() it should be cleaned up in destoryScene().
modules are kind deprecated to start.
Second, putting stuff in other files and calling them with "require" is supposed to be used to call libraries, not code that will run. "require" is not a dofile, or a eval, it will run once, and only once (when the first "require" of the file is made).
If you still want to put things in other files, like loading your background, you need to do a "background.lua" file that has a "background.load()" function and a "background.unload()" function, and call them in appropriate places.

How do I pause my app until a crash report has been submitted?

Background
I'm using UKCrashReporter in my app.
I've installed my own Uncaught
Exception Handler.
I'm setting up the
managedObjectContext of the object
activeItemController in
applicationDidFinishLaunching (1)
The Problem
If the managedObjectContext method throws an exception, the crash reporter dialog box only flashes up before the app crashes and so the user never gets to report the crash.
I want my app to continue only after the crash has been reported, not whilst the window is showing.
What I've tried
If UKCrashReporterCheckForCrash()
were an objective C method, I assume
I could call
performSelectorOnMainThread:waitUntilDone:YES
but it's not.
I've looked at some other Stack
Overflow questions about using
Conditional Locks to pause apps,
but I can't understand how I'd use it
for a C function.
How would I go about doing this in a nice way? Do people have any advice
for me? Any responses would be much
appreciated.
The Code
// In app delegate
-(void)applicationWillFinishLaunching:(NSNotification *)aNotification {
UKCrashReporterCheckForCrash(); // A C function which then creates a window if
// it detects a crash has happened.
}
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[activeItemController setMoContextDisk:[self managedObjectContext]];
[activeItemController setMoContextMemory:[self managedObjectContextMemory]];
}
Update 1
I've been asked for more details on what I'm trying to do, so here goes.
The bug that triggered this thinking was an exception when merging managedObjectModels. My app got caught in a loop printing "Uncaught exception" to the console every few milliseconds.
And when I installed the uncaught exception handler before this exception happened, I'd get the described behaviour - my app would fire up, display the crash report dialog briefly, then continue to load and crash again.
Summary - I want to be able to handle errors that happen on startup.
(1) I'm not using bindings to do this, as I thought bindings would make testing the class more problematic.
I think your problem is with thinking of it as "pausing" your app. Think of it more as a different initial UI state. Your attempts to block the run loop will prevent any interactive window from ... well, being interactive. :-)
Your best bet is to show your main UI (and connect data sources, etc) only if the "am I prompting the user to submit a crash report" method says "no, go ahead and start normally". Otherwise, show your window and, when the user sends or declines to send the report, close the window and ask your app controller to continue the normal startup.
I looked at UKCrashReporterCheckForCrash() and it doesn't appear to create a window of any kind. It merely submits the crash. Could you describe what you're doing with more detail?