03 December, 2013

From Zillow: iOS coding using Objective-C duck-typing

Working at Zillow, I've had the opportunity to explore iOS and Objective-C. Please check out my first blog post there which describes a technique that enables subclassing NSOutputStream with reduced code by taking advantage Objective-C dynamic method (selector) resolution to give the effect of duck-typing.

20 February, 2011

Automated Test for Facebook Canvas Apps – Front-end automation with Selenium

There are a number of challenges encountered in establishing test automation for Facebook applications. Among them is the fact that web browsers consider Facebook canvas applications to live in a separate security sandbox from the top-level page. This blog post describes how to use the Selenium 2.0 beta WebDriver technology to automate integrated test scenarios where the application under test is embedded in the Facebook page. The same technique applies to other situations in which the test must interact with elements in an IFrame whose src is a different domain from the top-level page.

Get the right driver

Selenium 2.0 is in beta, and until Beta 2 was released (Feb 2011), the technique described here could only be used for Firefox. With Beta 2, one body of code works with both IE8 and Firefox 3.6 (at least). It's reasonable to hope that as Selenium 2 progresses to its final release, the same tests will be able to run with more browsers. The beta 2 release includes a driver for Chrome, but that driver is not able to execute the tests.

Selenium 2 merges WebDriver into the Selenium project. The tests here rely on the WebDriver API.

Identify the IFrame

In order to interact with the elements of your application, the test will need to get the IFrame name (or index). As of 25 Feb, 2011, the IFrame has a constant name:

 final def canvasName = "iframe_canvas"
The test could alternatively search through all IFrames in the window to locate the relevant item.

Create a driver instance

Selenium lets the test create a driver directly, i.e. new org.openqa.selenium.firefox.FirefoxDriver(). Writing the tests to use RemoteWebDriver allows the test framework to execute the test across platforms:
def seleniumDrivers = [
[browserName: "internet explorer", serverName: "windowshost:4444"],
[browserName: "firefox", serverName: "osxhost:4444"]
].collect {
def browserName = it.browserName
def driverCaps = new DesiredCapabilities()
driverCaps.javascriptEnabled = true
driverCaps.browserName = browserName
return new RemoteWebDriver(new URL("http://$it.serverName/wd/hub" as String), driverCaps)
}
The driver is required to enable JavaScript because it will allow the tests to probe Flash elements in the IFrame.

Write tests

It's not immediately apparent how to best encapsulate the aspects of the test setup where the driver is used to move through the initial flow required to start the application. For the moment, it's just one of the tests upon which the later tests depend.

Log in to Facebook

Nothing tricky about this:
def login(WebDriver selenium) {
//Defines a trivial subclass of WebDriverWait
def waitUntil = new GroovyWebDriverWait(new SystemClock(), selenium, 10, 50)
selenium.get("http://www.facebook.com")
// It seems to be a good idea to check that the field contains all typed characters before going to next test step
waitUntil.keysAccepted(selenium.findElement(By.name("email")), params.userEmail)
waitUntil.keysAccepted(selenium.findElement(By.name("pass")), params.userPassword)
// Click the Login button
selenium.findElement(By.xpath("//label/input")).click()
// Proceed only after Facebook displays the user's page
waitUntil.condition { selenium.findElement(By.id("navAccountLink")) }
}

Load the app

The test could drive the FB interface to locate the application in the UI and launch it from there, but if the objective is to test the workings of the app in the IFrame, send the browser directly to the application.
selenium.get(appURL)
// This is where the driver starts to interact with the application
selenium.switchTo().frame(canvasName)

Wait for rendering

The app probably has dynamically rendered elements. In particular if it uses SWFObject to initialize a Flash player the test should probe for the creation of the corresponding DOM element.

waitUntil.condition { selenium.findElement(By.id(swfElementId)) }

Interact with Flash

If the test is concerned with a Flash application, it will need to make JavaScript calls into function exposed via the Flash ExternalInterface. A convenient way to make a number of useful test functions available is to include FlexPilot. It's (currently) necessary to build a SWF using the bootstrap classes provided with FlexPilot.

Assuming the SWF has successfully loaded FlexPilot, the test can proceed to check that the SWF loading is complete.

waitUntil.condition {
// The parameter to executeScript is really a script - if there's no return, there's nothing to check.
selenium.executeScript("return document.getElementById('$swfElementId').
  fp_assertDisplayObject('$mainComponentName')")
}

That should give the general shape of the solution. Hopefully it'll be useful to some folks. Perhaps inspiration will strike once more and additional posts will elaborate on details. Please add a comment if you can suggest an improvement or idea for a following post.

27 September, 2010

Using the Bigdoor API - first glance

The API provided by BigDoor is quite robust, and the documentation is fairly complete, though it is lacking a diagram of the objects that the client needs to manipulate. Since there are at least 27 object types defined in the documentation, some perspective on the relationships among them would be beneficial. Here's a diagram showing relationships among the 10 objects that seem necessary to a minimal implementation.

It seems that one could get started with the Currency and Transaction objects. When looking at the BigDoor API, it's helpful for me to translate some naming conventions. The key is to first remove 'Object' from the name, as every type in the system is termed an 'object'. At the next level there are types called Named XXX. If I read this as XXX Descriptor, it works better for the cases I'm working with. Alternatively, XXX Protytype, in the sense of a JavaScript prototype, might convey the relationship between these object templates and the instances that are created from them.

I'm going to start with just one Currency and one Transaction. I created my currency on the Define Currencies page of the BigDoor Economy UI by using the 'Pre-fill suggested currencies' facility. That created 'Bucks', 'Coins' and 'Experience'. I'm not sure about the Currency Type attribute. I'm starting by using the 'Experience' currency with its default Currency Type of Redeemable Hybrid Currency. I imagine the Dollar Exchange Rate setting of '-1.00' indicates that it cannot be converted to USD. Yes, I did RTFM and it lists 4 Currency Types while the UI provides 9 options and the description of exchange rate doesn't address the possibility of negative values. (In the real world, exchange rates are positive real numbers.) The response to my note to the BigDoor Sherpa revealed that the different types don't drive any behavior and the -1.00 was meant to designate currencies that don't 'convert', though conversion seems a bit nebulous just now. I didn't get a good answer as to why zero wouldn't be a clear indication that the currency is not convertible. It seems that there's some single reference currency against which each currency must be pegged. This makes me feel like Belize or Argentina prior to its financial crisis of 2001 though my currency was assigned the same ID as the Serbian Dinar.

I used the Define Transactions page to create a new object titled "Grant experience points" which references the 'Experience' currency with the Default Amount set to '5.00'.

Now to see if I can use the API to initiate the transaction for a user. It's useful to note at this stage that the End User object is created as a side-effect of the first transaction in which a previously unknown user id is specified.

16 November, 2009

Gonzo Camp II: Writing Ruby

Thanks to Mark Briggs, the Gonzo Camp II event was well-run and very informative. The event brought together a variety of experts, practitioners and students of journalism. Mark's guidance and inspiration created a fertile environment for the development of a variety of entrepreneurial ideas for journalism.

This camp was less productive in terms of running code demonstrated than the inaugural event, probably because a large fraction of the coders who signed up didn't attend. The poor internet connectivity was also an impediment – the prototype that I developed could have had more functions if I'd been able to test faster and download more code to integrate. Still, it was surprising that I was on the only team (out of 5) to demonstrate a working prototype.

The prototype I built for our team implemented a low-cost paywall targeting community news outlets. It implemented a basic HTTP gateway. I built it by extending Mongrel and adding an entry to my local hosts file to simulate a DNS entry. The result was a paywall erected for lodinews.com that allowed viewing of the paper's home page without registration, required confirmation to view any local news article, and allowed unfettered access to AP articles.

It was disappointing that I didn't get to see how others would approach building a prototype within 3-4 hours. On the other hand, it was very interesting to learn about the ideas that were developed with the influence of students and young journalists.

Thanks to Mark's organization and the event sponsors, there were plentiful tasty refreshments, nutritious lunch and a bountiful after-party. Gonzo Camp was definitely a valuable experience.

14 September, 2009

Bahn.de is awesome!

I've appreciated the clean bahn.de website and its complete and accurate railway itinerary creation ever since I first used it in 2003. The site continues to impress with additions of comparative travel charts like this one: Bahn.de comparative energy consumption graph

It's pretty cool to see how much less impact travel by rail will be compared to a car or airline.

While I'm sure more rigorous users have some complaints, the bahn.de service seems much more helpful in getting around Europe than anything else. I must also observe there are no such comprehensive travel solutions for planning a trip in the US. Then again, the only comparable options for transportation in the US are bus and airline – train travel is only possible in certain areas.

In Europe, reservations are only available from the national carriers, so only certain itineraries can be reserved from the Bahn.de website. On the other hand, since I'm traveling with a Eurail pass, it would be necessary for me to make the reservations in person anyway. (It would be nice if the Eurail pass could develop a website for pass holders to make reservations, but I'm sure that's more easily said than done.)

01 September, 2009

Eclipse update sites for XText incubation

I've been fumbling around a bit trying to get XText 0.7.2 working in my Eclipse 3.5 installations, so I thought it might be helpful to write down what I've found.

There are 3 update sites that were needed in order to complete the update today.

  1. MWE SDK from EMFT→ http://download.eclipse.org/modeling/emft/updates/releases/
  2. The Xtext plugin from TMF→ http://download.eclipse.org/modeling/tmf/updates/
  3. The Xtext ANTLR Support plugin (0.7.2) from Itemis→ http://download.itemis.com/updates/
The last is optional, though there are warnings that the capability is limited without ANTLR. It is omitted due to the requirement for EPL in Eclipse projects; ANTLR's current license prevents it from being offered from the Eclipse.org update sites. These all appear in the list of Eclipse update sites on ekkes-corner.

The Itemis update site provides a convenient collection of all the related modeling plugins. I turns out that my difficulty resulted from the fact that I didn't realize p2 (Eclipse Provisioning Platform) wasn't loading the current contents of the update site, so I started to search for update sites that had the 0.7.2 release of the plugins. What I learned is that I can get the current contents of the update sites by opening the Install/Update Preferences and invoking 'Test Connection' on each. Perhaps there's a better way...

Hopefully not too many others will encounter the difficulty I had finding the right versions, particularly for MWE.

01 August, 2009

Groovy Eclipse Plugin alpha zero-day review

In a multi-language project, Eclipse is a crucial tool for a number of reasons that might be apparent to readers of other posts here. One of the languages that is important in this particular project is Groovy. Until the end of July 2009, the Groovy Eclipse plugin was a rather cursory integration that was generally effective in getting Groovy projects to build together with other Eclipse projects, but didn't provide a full set of IDE capability for Groovy.

Great news arrived as July ended: the alpha for V2 of the Groovy eclipse plugin was published for Eclipse 3.5. (The website is currently only referring to Eclipse 3.4.2 support, but there's also a Groovy Eclipse update site for Eclipse 3.5.) After a few hours of exploration, a few bugs and areas needing polish are apparent, but these are so far no more of an impediment than the issues encountered with the old dev-release plugin for Groovy 1.6 (the previous Groovy 1.5 plugin was a bit more useable than 1.6, but not so much as to prevent migration to the newer version).

The basic functions at this stage of the V2 development will be very relevant to this project: the integration of Java with core Groovy is exactly the level of capability at the foundation of the plug-in. Grails developers may not find as much relevance until the plug-in gets more features. Pure Groovy developers might have a more robust IDE than Eclipse. But the support for multiple languages – C, Java & Groovy in this case – makes Eclipse a uniquely comprehensive and extensible solution.

This new plugin offers many more IDE features than previously available, though they remain more basic that the features in Eclipse Java (JDT) environment.

  • The outline view is much improved.
  • Performance is snappy – no observable delays while editing.
  • Compile errors handled properly – previously, java-level errors like missing implementation of abstract method would only appear after a save. Tests would launch and run against the old code, causing consternation if one didn't watch the Problems view.

The biggest downside of installing this plugin so far is the appearance of warnings when using Java generic types in Groovy. While adding the type specifiers to Map and Collection might not be a bad thing, there seem to be a few problems – with the result one may end up specifying <Object> where a more specific type would be accurate and correct in Java. A few editor glitches appear sporadically, though they're not yet pervasive enough to warrant a bug report.

This is an important milestone for Eclipse & Groovy. The team at SpringSource, particularly Andy Clement and Andrew Eisenberg, have done a great job with this alpha release of a promising V2 product!

 

Copyright 2009-2010 John Bito. Creative Commons License
This work is licensed under a Creative Commons Attribution-NoDerivs 3.0 Unported License.