222 lines
6.5 KiB
Markdown
222 lines
6.5 KiB
Markdown
---
|
|
title: Flowerbox -- a multi-environment, multi-runner, super-easy JavaScript testing framework framework.
|
|
layout: default
|
|
---
|
|
# Flowerbox
|
|
## A multi-environment, multi-runner, super-easy JavaScript testing framework framework.
|
|
---
|
|
## Super-fast unit testing getting started super guide!
|
|
### (you need Firefox at the very least)
|
|
|
|
{% highlight sh %}
|
|
gem install flowerbox
|
|
flowerbox plant jasmine
|
|
flowerbox spec/javascripts
|
|
{% endhighlight %}
|
|
|
|
## ...and what about integration testing?
|
|
### (whoa nelly, pure JS Cucumber?)
|
|
|
|
{% highlight sh %}
|
|
flowerbox plant cucumber
|
|
flowerbox js-features
|
|
{% endhighlight %}
|
|
|
|
## Hey, I'm already using `jasmine-gem` or `jasmine-headless-webkit`
|
|
### (you're smart!)
|
|
|
|
{% highlight sh %}
|
|
flowerbox transplant spec/javascripts
|
|
flowerbox spec/javascripts
|
|
{% endhighlight %}
|
|
|
|
## I use Sprockets and need to configure asset paths and templates and stuff!
|
|
### (...may the force be with you...)
|
|
|
|
{% highlight ruby %}
|
|
# in spec/javascripts/spec_helper.rb
|
|
|
|
require 'haml-sprockets'
|
|
|
|
Flowerbox.configure do |c|
|
|
c.asset_paths << "app/assets/javascripts"
|
|
c.asset_paths << "vendor/assets/javascripts"
|
|
|
|
c.additional_files << "applications.js.coffee"
|
|
|
|
# ... other stuff ...
|
|
end
|
|
{% endhighlight %}
|
|
|
|
## Firefox is so 2008. Can I run my tests on Chrome?
|
|
### (we like Selenium here!)
|
|
|
|
{% highlight ruby %}
|
|
Flowerbox.configure do |c|
|
|
c.run_with :chrome
|
|
end
|
|
{% endhighlight %}
|
|
|
|
## Chrome is so 2010. Can I run my tests on node.js?
|
|
### (evented hipness! jsdom will give you a fake DOM to work with.)
|
|
|
|
{% highlight ruby %}
|
|
# make sure node and npm are in your path
|
|
# jsdom and ws get installed in your project under node_modules
|
|
|
|
Flowerbox.configure do |c|
|
|
c.run_with :node
|
|
end
|
|
{% endhighlight %}
|
|
|
|
{% highlight coffeescript %}
|
|
# make sure you bind your global things to this
|
|
|
|
class @MyCoolClass extends @MyBaseClass
|
|
cool: -> "yeah man"
|
|
{% endhighlight %}
|
|
|
|
## Where'd headless support go?!
|
|
|
|
No, I knew you'd ask. Read the long bit of text below. _tl;dr_: Selenium with Chrome is
|
|
pretty much the same setup, just as fast, and gives you stack traces and other debugging assistance.
|
|
|
|
---
|
|
|
|
# Plant some Jasmine
|
|
|
|
---
|
|
|
|
# Plant a Cucumber or two
|
|
|
|
## Make a feature like in big boy Cucumber
|
|
### (that's 'cause it *is* big boy Cucumber, just in JS form)
|
|
|
|
{% highlight gherkin %}
|
|
# js-features/features/my_cool_thing.feature
|
|
|
|
Feature: My Cool Thing
|
|
Scenario: Show a cool thing
|
|
Given I have a cool thing
|
|
And I have a cool thing viewer
|
|
When I render the viewer
|
|
Then I should see the cool thing in the viewer
|
|
|
|
@wip # <= tags work, too!
|
|
Scenario: Maybe do something else
|
|
Given something
|
|
When yadda
|
|
Then BAM
|
|
{% endhighlight %}
|
|
|
|
## Write some steps
|
|
### (Flowerbox gives you a donut-full of syntactic sugar that wraps around Cucumber.js. Be sure to drink lots of water!)
|
|
|
|
{% highlight coffeescript %}
|
|
# js-features/steps/given/i_have_a_cool_thing.js.coffee
|
|
|
|
Flowerbox.Given /^I have a cool thing$/, ->
|
|
@data =
|
|
one: 'two'
|
|
three: 'four'
|
|
|
|
@coolThing = new CoolThing(@data)
|
|
{% endhighlight %}
|
|
|
|
{% highlight coffeescript %}
|
|
# js-features/steps/given/i_have_a_cool_thing_viewer.js.coffee
|
|
|
|
Flowerbox.Given /^I have a cool thing viewer$/, ->
|
|
@coolThingViewer = new CoolThingViewer(@coolThing)
|
|
{% endhighlight %}
|
|
|
|
{% highlight coffeescript %}
|
|
# js-features/steps/when/i_render_the_viewer.js.coffee
|
|
|
|
Flowerbox.When /^I render the viewer$/, ->
|
|
@coolThingViewer.render()
|
|
{% endhighlight %}
|
|
|
|
{% highlight coffeescript %}
|
|
# js-features/steps/then/i_should_see_the_cool_thing.js.coffee
|
|
|
|
Flowerbox.Then /^I should see the cool thing in the viewer$/, ->
|
|
@expect(
|
|
@coolThingViewer.$('input[name="one"]').val()
|
|
).toEqual(@data.one)
|
|
|
|
@expect(
|
|
@coolThingViewer.$('input[name="three"]').val()
|
|
).toEqual(@data.three)
|
|
{% endhighlight %}
|
|
|
|
## Get some hooks up in here!
|
|
### (and other fun environment stuff)
|
|
|
|
{% highlight coffeescript %}
|
|
# js-features/support/env.js.coffee
|
|
#
|
|
#= require ../steps
|
|
|
|
Flowerbox.World ->
|
|
@Before (callback) ->
|
|
@something = 'is available everywhere'
|
|
callback()
|
|
|
|
@After (callback) ->
|
|
Put = 'some stuff back'
|
|
callback()
|
|
{% endhighlight %}
|
|
---
|
|
|
|
# Flowerbox! Yea...wha?
|
|
|
|
So I (John) have been in this JavaScript testing game for a while, and, after about
|
|
three years of doing JS testing for Web apps, decided to finally take all the knowledge I had
|
|
and make something that was dead-simple to use.
|
|
|
|
## You already did once...
|
|
|
|
`jasmine-headless-webkit` was my first attempt, but it's a C++/Qt mess. Downloading all of
|
|
Qt is a total pain. Also, Qt4's JavaScript engine, JavaScriptCore, doesn't have stack trace
|
|
support, so it got pretty useless for me for bigger, messy projects (looking at you, Backbone).
|
|
Qt5 has V8, but whatever, I just decided to ditch the whole
|
|
compiling software thing and replace it with running tests in Selenium and/or node.js.
|
|
|
|
## Selenium faster than headless? But CI servers--
|
|
|
|
Sure, spinning up that instance of Firefox or Chrome is slower than starting up a small
|
|
QtWebKit widget, but there's a lot less that can go wrong when using a full-blown
|
|
browser. This also means your CI server config stays leaner. You may already have Qt installed
|
|
for capybara-webkit, but one less thing depending on Qt just makes your life (and mine) easier.
|
|
|
|
Also, when running Flowerbox with Guard, your browser stays open between test runs, so you only
|
|
pay the startup penalty once.
|
|
|
|
And, if you write everything correctly, you can just run your tests on node.js and not even have
|
|
to worry about a browser.
|
|
|
|
## But you said fake browsers are teh bad--
|
|
|
|
I changed my mind. As long as I'm not testing for browser-only things, like CSS interaction
|
|
or position elements, running tests on node.js with a browser-like DOM provided by jsdom
|
|
really is good enough. I use full-blown Ruby Cucumber if I need to test more complex browser
|
|
things.
|
|
|
|
## Cucumber.js? Full-stack testing is the only way!
|
|
|
|
Yeah, and it's slow. I'll carve out what I can in Cucumber.js while I work on Ruby Cucumber
|
|
features. Makes the process of getting those complex integration tests written a lot faster.
|
|
|
|
Also, I've changed my views on unit testing as a process. Unit testing for me is now about
|
|
two things:
|
|
|
|
* Code design through a liberal use of stubs and mocks.
|
|
* Really quickly running through blg blobs of inputs/outputs (parsers and such).
|
|
|
|
Treating unit testing this way taught me how to better organize and design my code, and I
|
|
only use it for really testing code when I need to test those big blobs of things.
|
|
This is my opinion, YMMV, Flowerbox lets you do what you want. Never use Cucumber.js support
|
|
if you don't want to. Write your integration bits in Jasmine. I don't mind.
|
|
|