BDD applied to JavaScript RIAs

The big picture (click to enlarge). Drawn with



Is there any difference in the implementation of Behavior Driven Development in the case of a Rich Client Application (or Rich Internet Application) ?

BDD's primary goal is communication. In that regard, there are no differences. However I see the differences in the outside-in implementation techniques.

There is no need to test the application through the GUI to make sure the specifications (customer acceptance criteria) are met.

With JavaScript we can easily test anything in the GUI with the help of the Passive View Pattern and some fine-grained integration tests against the DOM. This means that I can ensure the GUI connects with the application using unit tests + fine-grained integration tests. I can cover all the paths with automated tests, most of them unit test.

In a traditional website I can't "mock" a panel (or any other view) to check that some text has been added to it as a result of a "click" event triggered by a button. In fact, we can't use truly event oriented programming. Because the UI is just a picture,  rather than a set of objects with methods, behavior. With JavaScript this is a big advantage because we can use test doubles for those views in the unit tests, and then write contract tests to make sure those views manage the DOM properly. As a result, what in traditional web development have to be integration tests, now are unit tests.

We are back to those days where libraries to handle GUIs were so powerful and nice for both, developers and users. This time with 10+ years experience in agile testing and all kind of testing tools.

Thanks to this fact, we can design a Ports and Adapters Architecture for our application so that the GUI is just another port, at the same level than the acceptance tests. I can express the scenarios using plain JavaScript (or CoffeeScript) accessing the application through the "tests adapter",  ignoring any GUI detail.
If I use Cucumber (I am using SpecFlow right now),  my step definitions do not hit the UI. They just load the page and access the Business API (test API).

  2. [Given(@"^I start a new task$")]
  3. public void GivenIStartANewTask(int minutes)
  4. {
  5. var browser = ScenarioContext.Current[browserKey] as IWebDriver;
  6. var navigation = browser.Navigate();
  7. navigation.GoToUrl(appUrl);
  8. var jsExecutor = browser as IJavaScriptExecutor;
  10. // invoking my JavaScript Business API here
  11. var invoked = (string)js.ExecuteScript(
  12. "return app.startNewTask();");
  14. // making sure the Business API got the call
  15. invoked.Should().Be("newTaskCreated");
  16. }

The "Should" comes from FluentAssertions. The browser is Webdriver (Selenium).
If I don't user Cucumber, another option is to directly write the scenario with CoffeeScript.

  1. describe "LiveTeamApp: the team productivity application", ->
  2. beforeEach ->
  3. loadApp(appAddress, initTests)
  5. describe "the tasks management system", ->
  6. it "counts the time consumed by every task", ->
  7. app.startNewTask()
  8. waits two.seconds
  9. app.finishCurrentTask()
  10. app.lastFinishedTask.elapsedSeconds.should.equal(2)

This is Jasmine plus  Chai's syntactic sugar (should).
This scenario is actual code from my application, which has been developed entirely following this process (please check it out with your team, I believe you will like it 😉

Notice how I am writing a programmatic interface (the test adapter) to talk to the application with the language of the domain.  

For asynchronous cases, I am writing a small fluent API called Flas, which uses Gherkin to encapsulate blocks containing jQuery ajax requests. The Given-When-Then blocks scope asynchronous calls so that every block is executed once the calls have finished.

For more complex scenarios where I need several instances of the application at the same time (to design and test how users interact with each other), I am using CasperJS. This the case of LiveTeamApp's chat service, where users can chat with each other and also chat with the whole team. The acceptance criteria has been written with CasperJs to open several browsers and use the programmatic API from all of them to interact. Again, no need to hit the GUI in those acceptance tests.

My friend Ivan Stepaniuk and I presented this work and ideas first in Agile Testing Days 2012. Since them I am improving my technique, to write better and better acceptance tests.

The workshop

If you want to learn more and practice the technique, I encourage you to attend to my workshop. In the workshop you practice the whole BDD cycle, from the specifications workshop to the views implementation. See more information about the workshop in this post.

The book

I am starting to write a book on this. If you want to help me out with it please let me know. I expect it to be published in late 2013 or 2014. There is a great book on TDD with JavaScript written by Christian Johansen. It covers thoroughly all you need to get started with JavaScript and TDD as well as advanced topics. I'll try to write my book as a complement to Christian's. My TDD style is a bit different from Christian's but my motivation to write the book is not because of that, but to show readers the whole BDD cycle in a rich client application.
I won't repeat the great lessons you can read in  The Cucumber Book which is a must-read. Even if you are not using Cucumber, Matt's and Aslak's book is fantastic to learn BDD.
The other books I would expect my readers to read before, are the ones by Gojko Adzic on Briding the Communication Gap and Specification by Example 🙂


Enjoyed reading this post?
Subscribe to the RSS feed and have all new posts delivered straight to you.
  • Marcin Gryszko

    I’d add to the diagram that the server side is also a port (or many ports) and requires adapters (as for widgets/UI components, where you have your humble view). You test interactions between the interactor and server side adapters using unit tests and have small focused integration tests of those adapters.

  • carlosble

    You are right Marcin, in fact I use test doubles for those artifacts that act as server proxies in my unit tests. Then I design the server side test-first and eventually the end to end tests cover the whole integration.
    I like to have smart clients and dumb servers.

  • Pingback: Weekly Roundup: Jonathan Kohl at Agile Vancouver()