The Wizard's Curse

At Zecter, we have a couple of products (ZumoDrive, and ZumoCast) that have installation wizards.  These wizards are very important to us because this is how most customers first interact with us, so we spend a lot of time tweaking them.  We've implemented the wizard in HTML, and we render it in a web view built into the native client software.  

The Curse

The wizard runs on Windows, Mac, and Linux.  It is internationalized in seven languages.  There are 5 steps in the wizard.  This means that there are up to 21 different possible views of each of the 5 steps.

21 x 5 = 105 possible views

So there are 105 possible views that can be affected by CSS, HTML, or string changes to the layout.  This is not fun to test manually, and we haven't done a great job of making sure our wizard looks great in all supported locales.

Integration Tests Are Not Enough

Our server runs on Rails, which has support for integration testing.  This is great for testing whether or not sign up and login work through the wizard.  It's not great, however, for testing whether or not the wizard looks right in the native client on each platform in each language.  Sure, we can verify that various bits of information and scripts are displayed, but we can't see how they're displayed and if they're aligned properly.  So to do regression testing you have to run through each screen of the wizard on each platform in each language.  If you find a bug, you have to do it again.  And again.  And so on...  

The Solution

The Wizard's Curse from Adam Thorsen on Vimeo.

 

The solution we've come up with is to write a test helper that takes a snapshot in png format of the wizard screens as the integration tests are executing.  In order to do this we use wkhtmltopdf.  We can set up the test environment to render for each platform and be able to browse through the snapshots using the cover flow view in Finder ( we do web dev on macs.)  This way we don't have to boot up the Windows VM and configure it to connect to the development webserver until I can see that all the screens are rendering reasonably well and are platform appropriate.  This drastically reduces the amount of manual testing required.

 

Other Solutions?

I'd be interested in hearing other people's solutions to these kinds of problems.  Please comment.

My Fireworks Workflow

One thing that I've found frustrating as a web developer over the years is the work flow between design, css layout, and programming.

Typically the workflow (from my perspective as a programmer) will go something like this:

1.  Designer creates layout in Photoshop.

2.  CSS/HTML Guy cuts up design. 

3.  Web developer inserts dynamic content, ajax.

 

Sometimes I'm the CSS guy, sometimes I'm not.  I've never been the designer (at least not in professional situations).  The most friction is between the design phase and the css/html phase.  If a slice contains errors, a new one must be requested from the designer.  Turnaround times can vary, but usually there is an interruption to the work flow.  Common causes of errors are slices that are not suitable for use with CSS tricks such as repeating 1px vertical or horizontal gradients, images related to rounded corners that are not formatted correctly due to transparancy issues, etc. Communicating the exact requirements necessary for image slices to the designer can be time consuming as well.

So, in order to solve this problem and speed up development, I've taken some time to learn the rudiments of Adobe Fireworks.  With Fireworks, I can import a psd and retain all of the layer and textual information.  In this way I can make my own slices without the turnaround times required in requesting them from the designer.

 

Binding an NSTableView Column to NSUserDefaults

I did this a year ago, and didn't need to do it again until now. For some reason even though I had the example of my previous project, it still took me several hours to figure out how to do it again. There don't seem to be any straight forward explanations of how to do this (presumably) extremely common task so here's what I did:

  1. Drag an NSTableView onto an NSWindow.
  2. Go to the bindings tab in Inspector for the NSTableView.
  3. Under the "Content" heading, check the "Bind to" box. The following drop down should already be set to "Shared User Defaults Controller."
  4. Enter the key name of the user defaults setting you wish to map the table column to. For example, "people."
  5. Go to the bindings for the column.
  6. Under the value heading, check the 'Bind to' box. Again, the following drop down should already be set to "Shared User Defaults Controller."
  7. Enter the same key name you entered for the NSTableView ("people").
Now to test this out, you can register some defaults during your app's initialization. Here's some example code:

<style type="text/css">
.code { border: 1px solid #ccc; list-style-type: decimal-leading-zero; padding: 5px; margin: 0; }
.code code { display: block; padding: 3px; margin-bottom: 0; }
.code li { background: #ddd; border: 1px solid #ccc; margin: 0 0 2px 2.2em; }
</style>
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
[dictionary setObject:[NSArray arrayWithObjects:@"alice", @"bob", @"jimmy", nil] forKey:@"people"];
[defaults registerDefaults:dictionary];
If you run into any issues with this example, please let me know and I will revise it to make sure it is more clear.