Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial corner_stones import

  • Loading branch information...
commit c51110890cea87638a1fd592816ac0a5506d37c9 0 parents
@senny authored
4 .gitignore
@@ -0,0 +1,4 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
1  .rvmrc
@@ -0,0 +1 @@
+rvm --create ruby-1.9.3@corner_stones
4 Gemfile
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in corner_stones.gemspec
+gemspec
82 README.md
@@ -0,0 +1,82 @@
+# Corner Stones
+
+assists you in building PageObjects to make your acceptance tests more object oriented.
+
+## Installation
+
+``` terminal
+$ gem install corner_stones
+```
+
+or in your **Gemfile**
+
+``` ruby
+gem 'corner_stones'
+```
+
+## Examples
+
+a lot of examples can be found in the [integration specs](https://github.com/senny/corner_stones/tree/master/spec/integration).
+Some features of corner_stones are listed below.
+
+### Tabs
+
+```ruby
+tabs = CornerStones::Tabs.new('.tab-navigation')
+tabs.open('Details') # open a tab
+```
+
+```ruby
+tabs = CornerStones::Tabs.new('.tab-navigation').tap do |t|
+ t.extend(CornerStones::Tabs::ActiveTracking)
+end
+
+tabs.open('About') # open a tab and verify that the opened tab is active
+tabs.assert_current_tab_is('Main') # verify that the tab 'Main' is active
+```
+
+### Flash Messages
+
+```ruby
+flash = CornerStones::FlashMessages.new
+flash.assert_flash_is_present(:notice, 'Article saved') # verify that a given flash message is present
+```
+
+### Tables
+
+```ruby
+table = CornerStones::Table.new('.articles')
+table.rows # returns an array of rows. Each row is represented as a Hash {header} => {value}
+table.row('Title' => 'Management') # returns the row-hash for the row with 'Management' in the 'Title' column
+```
+
+```ruby
+table = CornerStones::Table.new('.articles').tap do |t|
+ t.extend(CornerStones::Table::SelectableRows)
+ t.extend(CornerStones::Table::DeletableRows)
+ end
+table.select_row('Created at' => '01.12.2001') # select the row, which has '01.12.2001' in the 'Created at' column
+table.delete_row('ID' => '9') # delete the row, which contains '9' in the 'ID' column
+```
+
+### Forms
+
+```ruby
+form = CornerStones::Form.new('.new-article', :select_fields => ['Author'])
+form.fill_in_with('Title' => 'Some Article', 'Author' => 'C. J.') # fill out the form
+form.submit # submit the form using the 'Save' button
+form.submit(:button => 'Save Article') # submit the form using the 'Save Article' button
+
+form.process(:fill_in => {'Title' => 'Some Article', 'Author' => 'C. J.'},
+ :button => 'Save Article) # fill out + submit
+```
+
+```ruby
+form = CornerStones::Form.new('.update-article').tap do |f|
+ f.extend(CornerStones::Form::WithInlineErrors)
+end
+form.errors # returns an Array of form errors
+form.assert_has_no_errors # verify that the form was submitted correctly
+form.submit # verifies that the form has no errors
+form.submit(:assert_valid => false) # do not veirfy that no errors were present
+```
5 Rakefile
@@ -0,0 +1,5 @@
+require "bundler/gem_tasks"
+
+FileList['tasks/**/*.rake'].each { |task| import task }
+
+task :default => :test
25 corner_stones.gemspec
@@ -0,0 +1,25 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "corner_stones/version"
+
+Gem::Specification.new do |s|
+ s.name = "corner_stones"
+ s.version = CornerStones::VERSION
+ s.authors = ["Yves Senn"]
+ s.email = ["yves.senn@gmail.com"]
+ s.homepage = ""
+ s.summary = %q{capybara building blocks for acceptance tests}
+ s.description = %q{This gem makes it easy to build PageObjects and make your acceptance tests more object oriented. It includes a implementations for common elements like tables, tabs, navigations etc.}
+
+ s.rubyforge_project = "corner_stones"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+
+ # specify any dependencies here; for example:
+ # s.add_development_dependency "rspec"
+ s.add_runtime_dependency "capybara"
+
+end
8 lib/corner_stones.rb
@@ -0,0 +1,8 @@
+require "capybara"
+require "capybara/dsl"
+
+require "corner_stones/version"
+
+module CornerStones
+
+end
5 lib/corner_stones/all.rb
@@ -0,0 +1,5 @@
+require 'corner_stones'
+require 'corner_stones/tabs'
+require 'corner_stones/table'
+require 'corner_stones/form'
+require 'corner_stones/flash_messages'
35 lib/corner_stones/flash_messages.rb
@@ -0,0 +1,35 @@
+module CornerStones
+ class FlashMessages
+
+ class FlashMessageMissingError < StandardError; end
+
+ include Capybara::DSL
+
+ def initialize(options = {})
+ @options = options
+ end
+
+ def message(type, text)
+ messages[type].detect {|message| message[:text] == text}
+ end
+
+ def messages
+ message_types.inject(Hash.new {|hash, key| hash[key] = []}) do |present_messages, type|
+ all(".#{type} p").map do |message|
+ present_messages[type] << {:text => message.text}
+ end
+ present_messages
+ end
+ end
+
+ def message_types
+ @options.fetch(:message_types) { [:notice, :error, :alert] }
+ end
+
+ def assert_flash_is_present(type, message)
+ unless message(type, message)
+ raise FlashMessageMissingError, "the flash message: '#{message}' with type: #{type} was not found"
+ end
+ end
+ end
+end
57 lib/corner_stones/form.rb
@@ -0,0 +1,57 @@
+require 'corner_stones/form/with_inline_errors'
+
+module CornerStones
+ class Form
+
+ include Capybara::DSL
+
+ def initialize(scope, options = {})
+ @scope = scope
+ @options = options
+ end
+
+ def process(params)
+ fill_in_with(params[:fill_in])
+ submit(params)
+ end
+
+ def submit(submit_options = {})
+ submit_text = submit_options.fetch(:button) { 'Save' }
+ within @scope do
+ click_button(submit_text)
+ end
+ end
+
+ def fill_in_with(attributes)
+ within @scope do
+ attributes.each do |name, value|
+ if select_fields.include?(name)
+ select(value, :from => name)
+ elsif autocomplete_fields.include?(name)
+ autocomplete(value, :in => name)
+ else
+ fill_in(name, :with => value)
+ end
+ end
+ end
+ end
+
+ def autocomplete(value, options)
+ autocomplete_id = find_field(options[:in])[:id]
+ fill_in(options[:in], :with => value)
+ page.execute_script %Q{ $('##{autocomplete_id}').trigger("focus") }
+ page.execute_script %Q{ $('##{autocomplete_id}').trigger("keydown") }
+ sleep 1
+ page.execute_script %Q{ $('.ui-menu-item a:contains("#{value}")').trigger("mouseenter").trigger("click"); }
+ end
+
+ def select_fields
+ @options.fetch(:select_fields) { [] }
+ end
+
+ def autocomplete_fields
+ @options.fetch(:autocomplete_fields) { [] }
+ end
+ end
+
+end
33 lib/corner_stones/form/with_inline_errors.rb
@@ -0,0 +1,33 @@
+module CornerStones
+ class Form
+ module WithInlineErrors
+
+ class FormHasErrorsError < StandardError; end
+
+ def submit(options = {})
+ assert_valid = options.fetch(:assert_valid) { true }
+ super
+ assert_has_no_errors if assert_valid
+ end
+
+ def errors
+ all('.error').map do |container|
+ label = container.all('label').first
+ input = container.all('input, textarea, select').first
+ error = container.all('.help-inline').first
+
+ { 'Field' => label && label.text,
+ 'Value' => input && input.value,
+ 'Error' => error && error.text }
+ end
+ end
+
+ def assert_has_no_errors
+ unless errors == []
+ raise FormHasErrorsError
+ end
+ end
+
+ end
+ end
+end
47 lib/corner_stones/table.rb
@@ -0,0 +1,47 @@
+require 'corner_stones/table/selectable_rows'
+require 'corner_stones/table/deletable_rows'
+
+module CornerStones
+
+ class Table
+ include Capybara::DSL
+
+ def initialize(scope, options = {})
+ @scope = scope
+ @data_selector = options.fetch(:data_selector) { 'td' }
+ @options = options
+ end
+
+ def row(options)
+ rows.detect { |row|
+ identity = row.select { |key, value| options.has_key?(key) }
+ identity == options
+ }
+ end
+
+ def rows
+ within @scope do
+ all('tbody tr').map do |row|
+ attributes_for_row(row)
+ end
+ end
+ end
+
+ def headers
+ @options[:headers] || detect_table_headers
+ end
+
+ def detect_table_headers
+ all('thead th').map(&:text)
+ end
+
+ def attributes_for_row(row)
+ data = row.all(@data_selector)
+
+ real_data = data[0...headers.size].map(&:text)
+
+ Hash[headers.zip(real_data)]
+ end
+ end
+
+end
15 lib/corner_stones/table/deletable_rows.rb
@@ -0,0 +1,15 @@
+module CornerStones
+ class Table
+ module DeletableRows
+
+ def delete_row(options)
+ row(options)['Delete-Link'].click
+ end
+
+ def attributes_for_row(row)
+ super.merge('Delete-Link' => row.find('.delete-action a'))
+ end
+
+ end
+ end
+end
15 lib/corner_stones/table/selectable_rows.rb
@@ -0,0 +1,15 @@
+module CornerStones
+ class Table
+ module SelectableRows
+
+ def select_row(options)
+ visit row(options)['Selected-Link']
+ end
+
+ def attributes_for_row(row)
+ super.merge('Selected-Link' => row['data-selected-url'])
+ end
+
+ end
+ end
+end
19 lib/corner_stones/tabs.rb
@@ -0,0 +1,19 @@
+require 'corner_stones/tabs/active_tracking'
+
+module CornerStones
+ class Tabs
+
+ include Capybara::DSL
+
+ def initialize(element_scope)
+ @element_scope = element_scope
+ end
+
+ def open(tab)
+ within(@element_scope) do
+ click_link(tab)
+ end
+ end
+
+ end
+end
24 lib/corner_stones/tabs/active_tracking.rb
@@ -0,0 +1,24 @@
+module CornerStones
+ class Tabs
+ module ActiveTracking
+
+ class ActiveTabMismatchError < StandardError; end
+
+ def open(tab)
+ super
+ assert_current_tab_is(tab)
+ end
+
+ def assert_current_tab_is(tab)
+ current_tab = nil
+ wait_until do
+ current_tab = find(@element_scope).find('.active').text
+ current_tab == tab
+ end
+ rescue Capybara::TimeoutError
+ raise ActiveTabMismatchError, "the active tab is '#{current_tab}' instead of '#{tab}'"
+ end
+
+ end
+ end
+end
3  lib/corner_stones/version.rb
@@ -0,0 +1,3 @@
+module CornerStones
+ VERSION = "0.0.1"
+end
67 spec/integration/corner_stones/flash_messages_spec.rb
@@ -0,0 +1,67 @@
+require 'integration/spec_helper'
+
+require 'corner_stones/flash_messages'
+
+describe CornerStones::FlashMessages do
+ given_the_html <<-HTML
+ <div class="alert">
+ <p>Article was not saved. Please correct the errors.</p>
+ </div>
+ <div class="notice">
+ <p>Article saved.</p>
+ </div>
+ <div class="notice">
+ <p>Successfully logged in</p>
+ </div>
+ HTML
+
+ subject { CornerStones::FlashMessages.new}
+
+ it 'assebles present messages into a hash' do
+ subject.messages.must_equal(:alert => [{:text => 'Article was not saved. Please correct the errors.'}],
+ :notice => [{:text => 'Article saved.'}, {:text => 'Successfully logged in'}])
+ end
+
+ it 'you can select a message by type and content' do
+ subject.message(:notice, 'Article saved.').must_equal({:text => 'Article saved.'})
+ end
+
+ it 'nil is returned when no message was found' do
+ subject.message(:alert, 'Article saved.').must_equal(nil)
+ end
+
+ describe '#assert_flash_is_present' do
+ it 'passes when the flash is present' do
+ subject.assert_flash_is_present(:alert, 'Article was not saved. Please correct the errors.')
+ end
+
+ it 'fails when the flash is missing' do
+ lambda do
+ subject.assert_flash_is_present(:notice, 'I am not displayed')
+ end.must_raise(CornerStones::FlashMessages::FlashMessageMissingError)
+ end
+ end
+
+ describe 'custom message types' do
+ given_the_html <<-HTML
+ <div class="alert-error">
+ <p>Article was not saved. Please correct the errors.</p>
+ </div>
+ <div class="alert-info">
+ <p>Article saved.</p>
+ </div>
+ <div class="alert-info">
+ <p>Successfully logged in</p>
+ </div>
+ HTML
+
+ subject { CornerStones::FlashMessages.new(:message_types => [:'alert-info', :'alert-error', :'alert-warning'])}
+
+ it 'uses the :message_type option to determine the available messages' do
+ subject.messages.must_equal(:'alert-error' => [{:text => 'Article was not saved. Please correct the errors.'}],
+ :'alert-info' => [{:text => 'Article saved.'}, {:text => 'Successfully logged in'}])
+ end
+
+ end
+end
+
154 spec/integration/corner_stones/form_spec.rb
@@ -0,0 +1,154 @@
+require 'integration/spec_helper'
+
+require 'corner_stones/form'
+require 'corner_stones/form/with_inline_errors'
+
+describe CornerStones::Form do
+
+ given_the_html <<-HTML
+ <form action="/articles" method="post" class="article-form">
+ <label for="title">Title</label>
+ <input type="text" name="title" id="title">
+
+ <label for="author">Author</label>
+ <select name="author" id="author">
+ <option value="1">Robert C. Martin</option>
+ <option value="2">Eric Evans</option>
+ <option value="3">Kent Beck</option>
+ </select>
+
+ <label for="body">Body</label>
+ <textarea name="body" id="body">
+ </textarea>
+
+ <input type="submit" name="button" value="Save">
+ <input type="submit" name="button" value="Save Article">
+
+ </form>
+ HTML
+
+ subject { CornerStones::Form.new('.article-form', :select_fields => ['Author']) }
+
+ it 'allows you to fill in the form' do
+ subject.fill_in_with('Title' => 'Domain Driven Design',
+ 'Author' => 'Eric Evans',
+ 'Body' => '...')
+
+ find('#title').value.must_equal 'Domain Driven Design'
+ find('#author').value.must_equal '2'
+ find('#body').value.must_equal '...'
+ end
+
+ it 'allows you to submit the form' do
+ subject.submit
+
+ current_path.must_equal '/articles'
+ page.driver.request.post?.must_equal true
+ end
+
+ it 'you can supply the submit-button text with the :button option' do
+ subject.submit(:button => 'Save Article')
+
+ page.driver.request.params['button'].must_equal 'Save Article'
+ end
+
+ it 'allows you to process (fill_in_with + submit) the form' do
+ subject.process(:fill_in => {
+ 'Title' => 'Domain Driven Design',
+ 'Author' => 'Eric Evans',
+ 'Body' => 'Some Content...'})
+
+ current_path.must_equal '/articles'
+ page.driver.request.post?.must_equal true
+
+ page.driver.request.params.must_equal({"title" => "Domain Driven Design", "author" => "2", "body" => "Some Content...", 'button' => 'Save'})
+ end
+
+ it 'allows you to process (fill_in_with + submit) the form using an alternate button' do
+ subject.process(:fill_in => {'Title' => 'Domain Driven Design',
+ 'Author' => 'Eric Evans',
+ 'Body' => 'Some Content...'},
+ :button => 'Save Article')
+
+ page.driver.request.params['button'].must_equal('Save Article')
+ end
+
+ describe 'mixins' do
+ describe 'form errors' do
+
+ before do
+ subject.extend(CornerStones::Form::WithInlineErrors)
+ end
+
+ describe 'with errors' do
+ given_the_html <<-HTML
+ <form action="/articles" method="post" class="form-with-errors article-form">
+ <div>
+ <label for="title">Title</label>
+ <input type="text" name="title" id="title">
+ </div>
+
+ <div class="error">
+ <label for="author">Author</label>
+ <select name="author" id="author">
+ <option value="1">Robert C. Martin</option>
+ <option value="2">Eric Evans</option>
+ <option value="3">Kent Beck</option>
+ </select>
+ <span class="help-inline">The author is not active</span>
+ </div>
+
+ <div class="error">
+ <label for="body">Body</label>
+ <textarea name="body" id="body">...</textarea>
+ <span class="help-inline">invalid body</span>
+ </div>
+
+ <input type="submit" value="Save">
+
+ </form>
+ HTML
+
+ it 'assembles the errors into a hash' do
+ subject.errors.must_equal([{"Field" => "Author", "Value" => "1", "Error" => "The author is not active"},
+ {"Field" => "Body", "Value" => "...", "Error" => "invalid body"}])
+ end
+
+ it '#assert_has_no_errors fails' do
+ lambda do
+ subject.assert_has_no_errors
+ end.must_raise(CornerStones::Form::WithInlineErrors::FormHasErrorsError)
+ end
+
+ it 'does not allow you to submit the form by default' do
+ lambda do
+ subject.submit
+ end.must_raise(CornerStones::Form::WithInlineErrors::FormHasErrorsError)
+ end
+
+ it 'bypass the auto-error-validation when passing :assert_valid => false' do
+ subject.submit(:assert_valid => false)
+ end
+ end
+
+ describe 'without errors' do
+ given_the_html <<-HTML
+ <form action="/articles" method="post" class="form-without-errors article-form">
+ <label for="title">Title</label>
+ <input type="text" name="title" id="title">
+
+ <input type="submit" value="Save">
+ <form>
+ HTML
+ end
+
+ it '#assert_has_no_errors passes' do
+ subject.assert_has_no_errors
+ end
+
+ it 'allows you to submit the form' do
+ subject.submit
+ end
+ end
+ end
+end
189 spec/integration/corner_stones/table_spec.rb
@@ -0,0 +1,189 @@
+require 'integration/spec_helper'
+
+require 'corner_stones/table'
+require 'corner_stones/table/deletable_rows'
+require 'corner_stones/table/selectable_rows'
+
+describe CornerStones::Table do
+
+ given_the_html <<-HTML
+ <table class="articles">
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>Title</th>
+ <th>Author</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>Clean Code</td>
+ <td>Robert C. Martin</td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>Domain Driven Design</td>
+ <td>Eric Evans</td>
+ </tr>
+ </tbody>
+ </table
+ HTML
+
+ subject { CornerStones::Table.new('.articles') }
+
+ describe 'headers' do
+ it 'get detected automatically from the "th" tags' do
+ subject.headers.must_equal ['ID', 'Title', 'Author']
+ end
+
+ it 'can be supplied with the :headers option' do
+ table_with_custom_headers = CornerStones::Table.new('.articles', :headers => ['A-ID', 'strTitle', 'strAuthor'])
+ table_with_custom_headers.headers.must_equal ['A-ID', 'strTitle', 'strAuthor']
+ end
+ end
+
+ describe "data" do
+ it 'is read into an array of hashes ({header} => {data})' do
+ subject.rows.must_equal [{'ID' => '1',
+ 'Title' => 'Clean Code',
+ 'Author' => 'Robert C. Martin'},
+ {'ID' => '2',
+ 'Title' => 'Domain Driven Design',
+ 'Author' => 'Eric Evans'}]
+ end
+
+ it 'a row can be accessed with a single key' do
+ subject.row('Title' => 'Domain Driven Design').must_equal({ 'ID' => '2',
+ 'Title' => 'Domain Driven Design',
+ 'Author' => 'Eric Evans' })
+ end
+
+ it 'a row can be accessed with multiple keys' do
+ subject.row('ID' => '1',
+ 'Author' => 'Robert C. Martin').must_equal({'ID' => '1',
+ 'Title' => 'Clean Code',
+ 'Author' => 'Robert C. Martin'})
+ end
+
+ it 'nil is returned when no matching row was found' do
+ subject.row('ID' => '3').must_equal(nil)
+ end
+ end
+
+ describe 'custom tables' do
+ describe 'inline headers' do
+ given_the_html <<-HTML
+ <table class="articles">
+ <tbody>
+ <tr>
+ <th>Clean Code</th>
+ <td>Robert C. Martin</td>
+ </tr>
+ <tr>
+ <th>Domain Driven Design</th>
+ <td>Eric Evans</td>
+ </tr>
+ </tbody>
+ </table>
+ HTML
+
+ subject { CornerStones::Table.new('.articles', :headers => ['Book', 'Author'], :data_selector => 'th,td') }
+
+ it 'the option :data_selector can be used to widen the data to other elements' do
+ subject.rows.must_equal [{ 'Book' => 'Clean Code',
+ 'Author' => 'Robert C. Martin'},
+ { 'Book' => 'Domain Driven Design',
+ 'Author' => 'Eric Evans'}]
+ end
+
+ end
+ end
+
+ describe 'mixins' do
+ describe 'deletable rows' do
+ given_the_html <<-HTML
+ <table class="articles">
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>Title</th>
+ <th>Author</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>Clean Code</td>
+ <td>Robert C. Martin</td>
+ <td class="delete-action"><a href="/delete/clean_code">X</a></td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>Domain Driven Design</td>
+ <td>Eric Evans</td>
+ <td class="delete-action"><a href="/delete/domain_driven_design">X</a></td>
+ </tr>
+ </tbody>
+ </table>
+ HTML
+
+ before do
+ subject.extend(CornerStones::Table::DeletableRows)
+ end
+
+ it 'it includes the "Delete-Link" object in the data' do
+ subject.rows.each do |row|
+ row['Delete-Link'].must_be_kind_of(Capybara::Node::Element)
+ end
+ end
+
+ it 'allows you to trigger a deletion with a row selector' do
+ subject.delete_row('Title' => 'Domain Driven Design')
+ current_path.must_equal '/delete/domain_driven_design'
+ end
+ end
+
+ describe 'selectable rows' do
+ given_the_html <<-HTML
+ <table class="articles">
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th>Title</th>
+ <th>Author</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-selected-url="/articles/clean_code">
+ <td>1</td>
+ <td>Clean Code</td>
+ <td>Robert C. Martin</td>
+ </tr>
+ <tr data-selected-url="/articles/domain_driven_design">
+ <td>2</td>
+ <td>Domain Driven Design</td>
+ <td>Eric Evans</td>
+ </tr>
+ </tbody>
+ </table>
+ HTML
+
+ before do
+ subject.extend(CornerStones::Table::SelectableRows)
+ end
+
+ it 'it includes the "Selected-Link" object in the data' do
+ subject.rows.map do |row|
+ row['Selected-Link']
+ end.must_equal ['/articles/clean_code', '/articles/domain_driven_design']
+ end
+
+ it 'allows you to select a row' do
+ subject.select_row('ID' => '1')
+ current_path.must_equal '/articles/clean_code'
+ end
+ end
+
+ end
+end
49 spec/integration/corner_stones/tabs_spec.rb
@@ -0,0 +1,49 @@
+require 'integration/spec_helper'
+
+require 'corner_stones/tabs'
+require 'corner_stones/tabs/active_tracking'
+
+describe CornerStones::Tabs do
+
+ given_the_html <<-HTML
+ <ul class="main-tabs-nav">
+ <li class="active"><a href='/main'>Main</a></li>
+ <li><a href='/details'>Details</a></li>
+ <li><a href='/more_stuff'>More Stuff</a></li>
+ </ul>
+ HTML
+
+ subject { CornerStones::Tabs.new('.main-tabs-nav') }
+
+ it 'opens a given tab' do
+ subject.open('Details')
+ current_path.must_equal '/details'
+ end
+
+ describe 'mixins' do
+ describe 'active tab tracking' do
+ before do
+ subject.extend(CornerStones::Tabs::ActiveTracking)
+ end
+
+ it 'asserts the current tab after opening a new tab' do
+ lambda do
+ subject.open('More Stuff')
+ end.must_raise CornerStones::Tabs::ActiveTracking::ActiveTabMismatchError
+ end
+
+ describe '#assert_current_tab_is' do
+ it 'passes when the given tab is active' do
+ subject.assert_current_tab_is('Main')
+ end
+
+ it 'fails when the given tab is not active' do
+ lambda do
+ subject.assert_current_tab_is('More Stuff')
+ end.must_raise CornerStones::Tabs::ActiveTracking::ActiveTabMismatchError
+ end
+ end
+ end
+ end
+
+end
12 spec/integration/spec_helper.rb
@@ -0,0 +1,12 @@
+require 'minitest/spec'
+require 'minitest/autorun'
+
+require 'capybara'
+require 'capybara/dsl'
+
+Capybara.default_wait_time = 0
+
+require 'integration/support/response_macros'
+
+include ResponseMacros
+include Capybara::DSL
12 spec/integration/support/response_macros.rb
@@ -0,0 +1,12 @@
+module ResponseMacros
+
+ def given_the_html(html)
+ before do
+ Capybara.app = lambda do |env|
+ [200, {}, html]
+ end
+ visit '/'
+ end
+ end
+
+end
6 tasks/test.rake
@@ -0,0 +1,6 @@
+require 'rake/testtask'
+
+Rake::TestTask.new do |t|
+ t.pattern = 'spec/**/*_spec.rb'
+ t.libs.push 'spec'
+end
7 travis.yml
@@ -0,0 +1,7 @@
+language: ruby
+rvm:
+ - 1.9.2
+ - 1.9.3
+notifications:
+ email:
+ - yves.senn@gmail.com
Please sign in to comment.
Something went wrong with that request. Please try again.