views:

559

answers:

4

I'm trying to setup automated unit tests for an iPhone application. I'm using a UIWebView and need to simulate clicks on different links. I've tried doing this with JavaScript, but it doesn't produce the same result as when I manually click on the links. The main problem is with links that have their target property set.

When you manually click on a standard "popup" link (e.g. <a href="http://example.com" target="_blank">), the UIWebView will ignore the click event and won't navigate to anything. If you then try clicking on this very same link automatically via the JavaScript dispatchEvent() method, the UIWebView will completely ignore the target attribute and will open up the link normally in the current page.

I need an my automatic unit testing to produce the exact same results as when you manually click a link.

I believe the only way for this automated unit test to work correctly is to simulate a mouse click at a specific x/y coordinate (i.e. where the link is located). Since the unit testing will only be used internally, private API calls are fine.

It seems like this should be possible since the iPhone app isimulate seems to do something similar.

Is there any way to do this in the framework?

I found a similar question titled Simulate mouse click to window instead of screen, however I'm guessing this method is only valid for OS X, and not for iPhone OS.

+1  A: 

I suppose you could simulate the touches by calling the touchesBegan/touchesEnded methods directly on the UIView (check the UIResponder class).

Martin Cote
I tried using code similar to the example provided here: http://cocoawithlove.com/2008/10/synthesizing-touch-event-on-iphone.html but it doesn't work. On a normal UIView subclass, it will obviously call the touchesBegan/touchesEnded methods since the code example calls it directly. The problem is that when you send it to a UIWebView, it doesn't pass that event on as though the user clicked at that point on whatever HTML element happens to be at that location.
Senseful
A: 

For your specific case, it may be sufficient to test in the simulator and use a MacOS event generator to make the clicks.

The private calls for recording and sending events are part of GraphicServices/GSEvent.h with the standard use at your own risk disclaimers. Every UIEvent is really a UIInternalEvent that has a reference to a __GSEvent, so for recording you can use the _gsEvent property to get the underlying event.

@property (nonatomic,assign) struct __GSEvent *_gsEvent;

I have not used any of this stuff, but it looks like GSSendSystemEvent would be a good place to start.

drawnonward
+1  A: 

The proper way to do this would be to construct your own UIEvent and then post this event to your UIApplication instance via its -sendEvent: method.

However, there doesn't appear to be a public API for constructing a UIEvent, so you might be out of luck.

Dave DeLong
I tried creating a UIEvent as described on http://cocoawithlove.com/2008/10/synthesizing-touch-event-on-iphone.html I even modified the code a bit to make the properties of the artificial UITouch the exact same as they are for a real UITouch. This still doesn't trigger a simple click on the browser, however.
Senseful
+1  A: 

Could you store the locations of the clicks in a data structure that you use in your tests and then simulate standard touch events as described here described here

--- Just spotted that you didn't have much luck with the example on this link. The only other options I can suggest would be to manipulate the html when running from a test to replace any _target links (you know that UIWebView handles these properly when clicking manually, so I think a small bodge is ok for the unit test?).

Nice walkthrough in this answer

davbryn
Thanks for the suggestion. Unfortunately, manually modifying the links doesn't help since I am testing the behavior when a link like this is pressed. If I modify the link, the test isn't testing the correct behavior, and is then useless.
Senseful