I am writing automation testing for my iOS app and I am trying to figure out how to detect in the javascript script when a view controller fully loaded and is on screen...
So right now for example the script taps on a button:
target.frontMostApp().mainWindow().buttons()["loginButton"].tap();
Then, once the app logs in (which could take a few seconds or less) I need to press another button.
Right now, I made it work by simply putting a delay:
target.delay(3);
But I want to be able to detect when the next view controller is loaded so that I know I can access the elements on the new screen just loaded.
Any suggestions?
There are some ways to achieve that:
Tune Up Library
https://github.com/alexvollmer/tuneup_js
I would really recommend to check this out. They have some useful wrapper function to write more advanced test. Some methods is written to extend the UIAElement class. They have waitUntilVisible() method.
But there might be possibility that the element itself is nil. Its not the matter of visibility but its just not in the screen yet.
UIATargetInstance.pushTimeout(delay) and UIATargetInstance.popTimeout()
Apple documentation says :
To provide some flexibility in such cases and to give you finer
control over timing, UI Automation provides for a timeout period, a
period during which it will repeatedly attempt to perform the
specified action before failing. If the action completes during the
timeout period, that line of code returns, and your script can
proceed. If the action doesn’t complete during the timeout period, an
exception is thrown. The default timeout period is five seconds, but
your script can change that at any time.
You can also use UIATarget.delay(delay); function, but this delays the execution of the next statement, not nescessarily waiting to find the element. setTimeout(delay) can also be used to globally set the timeout before UIAutomation decides it could not find the element.
There is Apple's guide explaining more understanding towards the framework here. http://developer.apple.com/library/IOS/#documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/UsingtheAutomationInstrument/UsingtheAutomationInstrument.html
In most cases simply identifying an element specific to the next view controller should be sufficient. The description of the element must be something unique to the new UI however.
i.e.
target.frontmostApp().mainWindo().navigationBar()["My Next View"];
The script should delay until the element can be identified or the timeout has been reached (see pushTimeout popTimout).
In some cases it might be necessary to specify that the element is visible.
.withValueForKey(1, "isVisible")
It's also possible to use waitForInvalid to do the reverse (wait for something in the previous UI to go away).
Search for tuneup library here
Refer function waitUntilVisible for the same. you may include other files to for supporting functions in it.
Hope it help.
Related
I am building an app which list a set of files. When the user performs an action to one of the files, the action is process intensive (performs multiple ajax requests, updates an offline sqlite database, performs various checks on the file, etc). The user can trigger the said action on multiple files at a time.
The problem is that when the action is performed on more than one file, it blocks the UI. Digging down into the issue, removing certain part of the action (i.e. if I remove the section that performs a verification of the file size, type, and calculate the meta when missing, etc), it wears down the effect of UI lock, though it is still there.
From what I read so far, it is suggested to extract such logic out of the main process i.e. to have a separate process to handle those. The proposed solutions I've read are
use worker thread
create a child process
create a server
I've been struggling to understand and come up with a working example for each. I came across this module named piscina which says to generate workers (my understanding it is a wrapper to create worker thread?).
On the repo here I've setup an example which simulates the issue I have. So if I trigger multiple instances of the action by pressing the "Test" button at the bottom. And then try to increment the count at the top, I can experience the UI lock/lags. It takes approximately 10-15 clicks on the "Test" button to replicate. I can also hear the CPU fan increasing when performing this.
Are there any projects/examples around which gives a simplified implementation on how to mitigate or work around this problem?
EDIT
After #tromgy suggestions I've performed the following updates/test:
Adjusting the await run to a regular promise did seem to solve the issue.
But triggering multiple instances simultaneously, for example, 20, still causes UI lock. Attempting the same on my actual project causes memory heap errors.
I tried moving the Piscina instance outside, rather than creating a new instance on each event, it solves the memory leap, but not the UI lock/lag/freeze issue.
I've tried converting invoke to an actual event, the UI issue still persist.
According to following documentation, it is stated that if you don't explicitly specify a trigger you get behavior described below:
If unspecified, the default behavior is to trigger first when the
watermark passes the end of the window, and then trigger again every
time there is late arriving data.
Is this behavior true for FixedWindow as well? For example you would assume fixed window should have a default trigger of repeatedly firing after watermark passes end of window, and discard all late data unless late data is explicitly handled. Also where in the source code can I see definition of trigger for, example FixedWindow object?
The best doc to start with is the guide for triggers, and windows (and following the links from there). In particular, it says that, even though the default trigger fires every time late data arrives, in default configuration it still effectively only triggers once, discarding the late data:
if you are using both the default windowing configuration and the
default trigger, the default trigger emits exactly once, and late data
is discarded. This is because the default windowing configuration has
an allowed lateness value of 0. See the Handling Late Data section for
information about modifying this behavior.
Details
Windowing concept in Beam in general encompasses few things, including assigning windows, handling triggers, handling late data and few other things. However these things are assigned and handled separately. It gets confusing quickly from here.
How the elements are assigned to a window is handled by a WindowFn, see here. For example FixedWindows: link. It is basically the only thing that happens there (almost). Assigning a window is a special case of grouping the elements based on the event timestamps (kinda). You can think of the logic being similar to manually assigning custom keys to elements based on the timestamps, and then applying GroupByKey.
Triggering is a related but separate concept. Triggers are (roughly) just predicates to indicate when the runner is allowed to emit the data accumulated in the window so far (source). I think this is the closest thing to the original design doc for triggers: https://s.apache.org/beam-triggers
Lateness is another related part of the configuration which is also somewhat separate (link). Even though a trigger might allow the runner to emit all the late data forever, the pipeline can be set to not allow any late data (which is the default behavior), or only allow late data for some limited time. This leads to the default trigger behavior described above. Yes, this is confusing. Avoid using any complex triggering and lateness if you can, it likely won't work as you expect it to.
So the window classes only handle the grouping logic, i.e. what kind of elements have the same grouping key. These classes don't care about when you will want to emit the accumulated results. This depends on your business logic, e.g. you might want to handle newly arrived elements, or you might want to discard them, it's not part of the window. This means there's no special triggers for FixedWindows or other windows, you can use any trigger with any window (even if logically some specific trigger doesn't make sense in context of some window).
Default trigger is just that, something that is just set by default. You should assign your own trigger if it doesn't suit your needs. And it likely won't, except for some basic use cases.
Update
An example of how to use FixedWindows with triggers.
I have some code that needs to get called frequently, such as check what day it is, if it's the next day then move the day strings in the tableView.
Now I thought that the viewDidLoad would get called all the time and so it would be 'fine' to put it in there. However, I've left the simulator overnight, and I've pressed the home button and clicked again, changed VCs etc. and viewDidLoad hasn't been hit.
What are my options for doing sporadic checks such as, is it a new day? As x happened etc.
In this specific case, you can subscribe to NSCalendarDayChangedNotification to be notified when the date changes and respond accordingly in your view controller. In general, didBecomeActive or viewDidAppear would likely work.
What are my options for doing sporadic checks such as, is it a new day
It depends what the meaning of "is" is! In particular, "is" when? You say "sporadic", but that's just fluff. When do you need to know this? To what stimulus do you want to respond? When the user opens your app? Then put it in applicationDidBecomeActive. Every day at noon? Then run an NSTimer. Really, the problem here is that you don't seem to know, yourself, just when you need to perform these checks.
Whilst in your app, its quite easy to continually check for something. You simply create a background thread. However, what you describe is a thread that persists from outside the app's lifecycle.
Have a read on this documentation provided by Apple itself. You have to have good excuse to put a background thread. The scope of such thread is limited to only certain scenarios such as downloading background stuff, playing sounds etc.
For your scenario, I'd look at applicationDidBecomeActive(_:) found in your Application Delegate. There you can mimic such continual check. Beware however, don't put heavy word load on start up or your app might be killed automatically if it fails to become active in reasonable amount of time.
The Observable module uses change method as a way of toggling when the observers should get updates of any change in state in the Subject. However, it seems redundant to me, as notify_observers(self) it is going to be called intentionally. Is there a situation where having change makes a difference?
It allows for a split in timing, and for multiple changes without side effects.
The state of an object may or may not change during a sub-process of an application. If it changes, then .change can be invoked without any side effects. It is also possible to call it multiple times.
Later, notifications can be sent. As long as they are sent before any dependent actions are taken, then anything that depends on updates due to the original change should be able to make its update correctly
You might do this for example if processing following a change had a high cost (I/O, CPU time, network bandwidth), but only needed to be done before a second section of code, not simply every time a change occurred.
You might also do this if updates are not strictly necessary in all code paths. I.e. sometimes you care about updating due to a change, but other times it is not necessary, and any change can be ignored.
An example might be if you need to re-generate an XML document every time a content object used by the XML creation code has a property change. You would place calls to .change in the important property setters of the content object, hiding them from the external caller. You don't want to generate a new XML document each time you call content.property= (it could be very slow), instead you wait until you are finished making updates and place a single call to content.notify_observers after all possible changes.
When I try to set the width of a multiline EditBox widget, it flickers for a moment, then gets set.
Is there a way to get rid of the flickering? Or, alternatively, is there a workaround?
It might be a problem with the way the UI rendering is optimized. Try changing your UIFaster setting as described here: http://www.wowwiki.com/CVar_UIFaster
I've usually seen this as a result of multiple calls to :SetWidth() occurring in quick succession. There are two ways this can happen — (a) it's genuinely getting called multiple times, or (b) it's been hooked/replaced with another function which is internally causing multiple calls. As a quick test, try running the following command (or equivalent) via the WoW chat window while your edit box is visible:
/script MyEditBox:SetWidth(100)
If the size changes without flicker, you've got scenario A — go over your addon's logic paths and make sure :SetWidth() is only being called when appropriate (and only once). If it does flicker, you're probably looking at screnario B (or, of course, the UI issue Cogwheel mentions). This may be harder to debug, unless you're hooking/replacing SetWidth yourself, but a good first step would be to disable all other addons and see if the problem resolves itself. If not, my first guess would be a library issue (assuming you're using any).