On Web Application State

I've been thinking a bit lately on the tractability of the single-page/client-side/javascript application (or whatever you want to call it) testing problem. When trying to figure out nice ways to set up test suites and catch regressions in Squarespace, I've been kind of at a loss for complete solution. Our first attempts were, in my opinion, illustrative but misguided. Granted, it was just an experiment and not difficult to cook up, but we took the approach of attempting to verify things like animations completing successfully and pixel-perfection after simulating a series of clicks, drags and inputs. This did work for very simple cases, but fell apart when we tried to generalize. 

However, it was not misguided because it did not produce the correct results. It was misguided because it was testing the wrong thing. At Squarespace, we place a focus on achieving absolute perfection in the beauty of our presentation. We seek to leave a lasting impression and consistently sleek widgets is a big part of that. In the pursuit of such goals it's very easy to lose track of the key elements of the experience that make the application really usable.

If you view your application as an object with multiple layers, where the base layer is just the basic interactions modeled with the final HTML structure you intend to keep, you realize most applications remain surprisingly usable with just basic styling for layout and little 'pizzaz'. Clearly, these are the elements you cannot allow to regress.

In a complex applicaton, making sure that these elements are on-screen when they need to be and the user's state in your application is always consistent is _key_. Those transitions are often the highest-level state in your application. In an ideal world, your state-management code would be as ignorant of the interface as possible. So much so that you could simply instantiate and 'use' your application from code like the following:

Having your application be just a plain old object that may delegate to sub-components (that can be replaced with mocks/dummy instances for testing) may not always be practical, but it makes things a heck of a lot simpler. Because web apps are just big state-machines, In theory, if you had some object that encapsulated the current state of your application (Much like Ember's router), it would be incredibly useful to verify that whenever you call app.navigateTo('library') whatever internal state representation was updated correctly. That seems obvious, but it's never occurred to me so clearly when actually testing this behavior would involve calling the methods, then string matching on 'window.location'.

I'm aware that decoupling view from state and testing from the bottom up are nothing new, but it's very easy to forget that we can apply the same principles applied in 'regular' development to the occasionally wild world of the front-end.

Decouple your state, test your state, then move on to the pretty stuff.