All code available here: https://github.com/ngauthier/cucumber-webapp-demo
The following stack is used:
- Cucumber
- Capybara
- Selenium
- WEBrick
First, we make our awesome javascript powered webapp:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='jquery-1.4.3.min.js'></script>
<script type='text/javascript'>
$(function() {
$('#special-link').click(function(event) {
$('#results').html("This is totally awesome");
event.preventDefault();
});
});
</script>
</head>
<body>
<h1>My Webapp</h1>
<p>
<a href='#' id='special-link'>Click on this link to make cool stuff happen</a>
</p>
<div id="results"></div>
</body>
</html>
All we're doing here is showing some text when we click a link. But we're using jquery's events to do it.
Now here is our feature file:
Feature: My Awesome Link
Scenario: Clicking the awesome link shows awesome text
Given I am on the home page
Then I should see "My Webapp"
And I should see "Click on this link to make cool stuff happen"
And I should not see "This is totally awesome"
When I click "Click on this link to make cool stuff happen"
Then I should see "This is totally awesome"
And here are our simple step definitions:
Given /^I am on the home page$/ do
visit 'index.html'
end
Then /^I should see "([^"]*)"$/ do |content|
within('body') do
assert page.has_content?(content)
end
end
Then /^I should not see "([^"]*)"$/ do |content|
within('body') do
refute page.has_content?(content)
end
end
When /^I click "([^"]*)"$/ do |link_text|
click_link_or_button(link_text)
end
And here is the cucumber environment file where all the magic happens. See comments for description:
require 'rubygems'
require 'cucumber'
require 'capybara/cucumber'
require 'webrick'
# setup capybara on selenium
Capybara.default_driver = :selenium
# This maps to webrick below
Capybara.app_host = 'http://127.0.0.1:3000'
Capybara.default_selector = :css
# Extend Cucumber's World with minitest assertions
World(MiniTest::Assertions)
# Launch a webrick server in a thread
AfterConfiguration do
server_thread = Thread.new do
project_root = File.join(File.dirname(__FILE__), '..', '..')
WEBrick::HTTPServer.new(
:Port => 3000,
# TODO use the real application directory
# Using the prototype directory for now
:DocumentRoot => File.join(project_root, 'public'),
:Logger => WEBrick::Log.new(File.join(project_root, 'cucumber.log')),
:AccessLog => StringIO.new # to nowhere
).start
end
# Kill the server when cucumber is done
at_exit do
server_thread.exit
end
end
The idea here is to boot webrick in a thread to serve the public directory, then connect selenium up to it. Very simple and light.
All code available here: https://github.com/ngauthier/cucumber-webapp-demo