pagemodels 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.txt +58 -0
- data/Rakefile +7 -0
- data/examples/rails_and_cucumber/.gitignore +4 -0
- data/examples/rails_and_cucumber/Gemfile +11 -0
- data/examples/rails_and_cucumber/README.txt +23 -0
- data/examples/rails_and_cucumber/Rakefile +7 -0
- data/examples/rails_and_cucumber/app/controllers/application_controller.rb +3 -0
- data/examples/rails_and_cucumber/app/controllers/financial_reports_controller.rb +7 -0
- data/examples/rails_and_cucumber/app/models/transaction.rb +25 -0
- data/examples/rails_and_cucumber/app/views/financial_reports/show.html.erb +20 -0
- data/examples/rails_and_cucumber/app/views/layouts/application.html.erb +14 -0
- data/examples/rails_and_cucumber/config/application.rb +18 -0
- data/examples/rails_and_cucumber/config/boot.rb +6 -0
- data/examples/rails_and_cucumber/config/cucumber.yml +8 -0
- data/examples/rails_and_cucumber/config/environment.rb +5 -0
- data/examples/rails_and_cucumber/config/environments/development.rb +23 -0
- data/examples/rails_and_cucumber/config/environments/test.rb +30 -0
- data/examples/rails_and_cucumber/config/initializers/secret_token.rb +7 -0
- data/examples/rails_and_cucumber/config/initializers/session_store.rb +8 -0
- data/examples/rails_and_cucumber/config/routes.rb +3 -0
- data/examples/rails_and_cucumber/features/financial_reporting.feature +29 -0
- data/examples/rails_and_cucumber/features/pagemodels/financial_report_page.rb +29 -0
- data/examples/rails_and_cucumber/features/step_definitions/financial_reporting_steps.rb +14 -0
- data/examples/rails_and_cucumber/features/support/env.rb +13 -0
- data/examples/rails_and_cucumber/lib/tasks/cucumber.rake +57 -0
- data/examples/rails_and_cucumber/script/cucumber +10 -0
- data/examples/rails_and_cucumber/script/rails +6 -0
- data/examples/rspec_and_capybara/Gemfile +6 -0
- data/examples/rspec_and_capybara/README.txt +19 -0
- data/examples/rspec_and_capybara/Rakefile +4 -0
- data/examples/rspec_and_capybara/spec/google_search_spec.rb +15 -0
- data/examples/rspec_and_capybara/spec/pagemodels/google_results_page.rb +24 -0
- data/examples/rspec_and_capybara/spec/pagemodels/google_search_page.rb +15 -0
- data/examples/rspec_and_capybara/spec/spec_helper.rb +11 -0
- data/lib/page_models/base.rb +28 -0
- data/lib/page_models/configuration.rb +30 -0
- data/lib/page_models/core.rb +13 -0
- data/lib/page_models/errors.rb +10 -0
- data/lib/page_models/integration/capybara.rb +0 -0
- data/lib/page_models/integration/cucumber.rb +16 -0
- data/lib/page_models/integration/rails.rb +1 -0
- data/lib/page_models/integration/rspec.rb +19 -0
- data/lib/page_models/version.rb +3 -0
- data/lib/pagemodels.rb +1 -0
- data/pagemodels.gemspec +23 -0
- data/spec/page_models/base_spec.rb +58 -0
- data/spec/page_models/configuration_spec.rb +37 -0
- data/spec/spec_helper.rb +1 -0
- metadata +118 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.txt
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
Page Models move complex and copy-pasted code out of your acceptance tests and into easily managed Ruby classes with (optional) integration for Rails, Cucumber, and RSpec.
|
2
|
+
|
3
|
+
|
4
|
+
~~~~~~~~
|
5
|
+
# env.rb
|
6
|
+
require 'pagemodels'
|
7
|
+
|
8
|
+
PageModels.configure do |config|
|
9
|
+
config.driver = :capybara
|
10
|
+
config.integrate :rspec
|
11
|
+
config.integrate :cucumber
|
12
|
+
config.integrate :rails
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
17
|
+
# my_cucumber_test.feature
|
18
|
+
Given I open the GitHub project page for the user "rickgrundy" and the repo "page-models"
|
19
|
+
When I look at the commit history
|
20
|
+
Then I should see at least 3 commits
|
21
|
+
|
22
|
+
|
23
|
+
~~~~~~~~~~~~~~~~~~~~~~
|
24
|
+
# my_cucumber_steps.rb
|
25
|
+
When /I look at the commit history/ do
|
26
|
+
page_model.navigate_to_commits
|
27
|
+
end
|
28
|
+
|
29
|
+
Then /I should see at least (\d+) commits/ do |count|
|
30
|
+
page_model.verify_commit_count(count)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
~~~~~~~~~~~~~~~~~~~~~~
|
35
|
+
# GitHubProjectPage.rb
|
36
|
+
class GitHubProjectPage < PageModels::Base
|
37
|
+
def initialize(user, repo)
|
38
|
+
@user, @repo = user, repo
|
39
|
+
end
|
40
|
+
|
41
|
+
def url
|
42
|
+
"https://www.github.com/#{@user}/#{@repo}/"
|
43
|
+
end
|
44
|
+
|
45
|
+
def verify!
|
46
|
+
should have_content "#{@user} / #{@repo}"
|
47
|
+
should have_content "Source"
|
48
|
+
should have_content "Commits"
|
49
|
+
end
|
50
|
+
|
51
|
+
def navigate_to_commits
|
52
|
+
click_link "Commits"
|
53
|
+
end
|
54
|
+
|
55
|
+
def verify_commit_count(count)
|
56
|
+
all(".commit").should have_at_least(count).things
|
57
|
+
end
|
58
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
This example demonstrates how to use page models to test a Rails app with Cucumber and RSpec, using Capybara/Rack-Test as a driver.
|
2
|
+
|
3
|
+
This example demonstrates how to use page models with RSpec to write acceptance tests for any website (in this case Google.com), using Capybara/Selenium/Firefox as a driver.
|
4
|
+
|
5
|
+
~~~~~~~~~~
|
6
|
+
|
7
|
+
See features/support/env.rb for information about configuring PageModels to integrate with the various frameworks:
|
8
|
+
|
9
|
+
PageModels.configure do |config|
|
10
|
+
config.driver = :capybara
|
11
|
+
config.integrate :rails
|
12
|
+
config.integrate :cucumber
|
13
|
+
config.integrate :rspec
|
14
|
+
end
|
15
|
+
|
16
|
+
env.rb also loads all everything in the pagemodels directory. GoogleSearchPage and GoogleResultsPage provide examples of page models which override PageModels::Base.
|
17
|
+
|
18
|
+
~~~~~~~~~~
|
19
|
+
|
20
|
+
RSpec integration exposes two convenience methods you may use in your specs:
|
21
|
+
|
22
|
+
open_page(page_model) - switches the current page model to the one provided and calls #open!
|
23
|
+
should_see_page(page_model) - switches the current page model and calls #verify!
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
|
+
|
4
|
+
require File.expand_path('../config/application', __FILE__)
|
5
|
+
require 'rake'
|
6
|
+
|
7
|
+
RailsAndCucumber::Application.load_tasks
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Transaction
|
2
|
+
attr_accessor :type, :amount, :year
|
3
|
+
|
4
|
+
def self.truncate
|
5
|
+
@@all = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.create(attrs)
|
9
|
+
txn = Transaction.new(attrs)
|
10
|
+
@@all << txn
|
11
|
+
txn
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.find_all(attrs)
|
15
|
+
@@all.select do |txn|
|
16
|
+
attrs.all? { |k, v| txn.send(k) == v }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(attrs)
|
21
|
+
self.type = attrs[:type]
|
22
|
+
self.amount = attrs[:amount]
|
23
|
+
self.year = attrs[:year]
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<h1>Acme Financial Report for <%= @year %></h1>
|
2
|
+
|
3
|
+
<% if @txns.empty? %>
|
4
|
+
<h2>There are no <%= @txn_type %> transactions for <%= @year %></h2>
|
5
|
+
<% else %>
|
6
|
+
<h2>All <%= @txn_type.titlecase %> Transactions</h2>
|
7
|
+
|
8
|
+
<table id="report">
|
9
|
+
<tr>
|
10
|
+
<th>Type</th>
|
11
|
+
<th>Amount</th>
|
12
|
+
</tr>
|
13
|
+
<% @txns.each do |txn| %>
|
14
|
+
<tr class="transaction">
|
15
|
+
<td class="type"><%= txn.type %></td>
|
16
|
+
<td class="amount"><%= txn.amount %></td>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
</table>
|
20
|
+
<% end %>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
require "action_controller/railtie"
|
4
|
+
|
5
|
+
# If you have a Gemfile, require the gems listed there, including any gems
|
6
|
+
# you've limited to :test, :development, or :production.
|
7
|
+
Bundler.require(:default, Rails.env) if defined?(Bundler)
|
8
|
+
|
9
|
+
module RailsAndCucumber
|
10
|
+
class Application < Rails::Application
|
11
|
+
|
12
|
+
# Configure the default encoding used in templates for Ruby 1.9.
|
13
|
+
config.encoding = "utf-8"
|
14
|
+
|
15
|
+
# Configure sensitive parameters which will be filtered from the log file.
|
16
|
+
config.filter_parameters += [:password]
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%
|
2
|
+
rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
|
3
|
+
rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
|
4
|
+
std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
|
5
|
+
%>
|
6
|
+
default: <%= std_opts %> features
|
7
|
+
wip: --tags @wip:3 --wip features
|
8
|
+
rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
|
@@ -0,0 +1,23 @@
|
|
1
|
+
RailsAndCucumber::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# In the development environment your application's code is reloaded on
|
5
|
+
# every request. This slows down response time but is perfect for development
|
6
|
+
# since you don't have to restart the webserver when you make code changes.
|
7
|
+
config.cache_classes = false
|
8
|
+
|
9
|
+
# Log error messages when you accidentally call methods on nil.
|
10
|
+
config.whiny_nils = true
|
11
|
+
|
12
|
+
# Show full error reports and disable caching
|
13
|
+
config.consider_all_requests_local = true
|
14
|
+
config.action_view.debug_rjs = true
|
15
|
+
config.action_controller.perform_caching = false
|
16
|
+
|
17
|
+
# Print deprecation notices to the Rails logger
|
18
|
+
config.active_support.deprecation = :log
|
19
|
+
|
20
|
+
# Only use best-standards-support built into browsers
|
21
|
+
config.action_dispatch.best_standards_support = :builtin
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
RailsAndCucumber::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb
|
3
|
+
|
4
|
+
# The test environment is used exclusively to run your application's
|
5
|
+
# test suite. You never need to work with it otherwise. Remember that
|
6
|
+
# your test database is "scratch space" for the test suite and is wiped
|
7
|
+
# and recreated between test runs. Don't rely on the data there!
|
8
|
+
config.cache_classes = true
|
9
|
+
|
10
|
+
# Log error messages when you accidentally call methods on nil.
|
11
|
+
config.whiny_nils = true
|
12
|
+
|
13
|
+
# Show full error reports and disable caching
|
14
|
+
config.consider_all_requests_local = true
|
15
|
+
config.action_controller.perform_caching = false
|
16
|
+
|
17
|
+
# Raise exceptions instead of rendering exception templates
|
18
|
+
config.action_dispatch.show_exceptions = false
|
19
|
+
|
20
|
+
# Disable request forgery protection in test environment
|
21
|
+
config.action_controller.allow_forgery_protection = false
|
22
|
+
|
23
|
+
# Use SQL instead of Active Record's schema dumper when creating the test database.
|
24
|
+
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
25
|
+
# like if you have constraints or database-specific column types
|
26
|
+
# config.active_record.schema_format = :sql
|
27
|
+
|
28
|
+
# Print deprecation notices to the stderr
|
29
|
+
config.active_support.deprecation = :stderr
|
30
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Your secret key for verifying the integrity of signed cookies.
|
4
|
+
# If you change this key, all old signed cookies will become invalid!
|
5
|
+
# Make sure the secret is at least 30 characters and all random,
|
6
|
+
# no regular words or you'll be exposed to dictionary attacks.
|
7
|
+
RailsAndCucumber::Application.config.secret_token = '223801ad784b8e3e5beea705d599a50bfd6efefaf64b367356d4b808b500cade554c7b2d3efa831dcc931bad3a0d15ed889652e42069b12726b7181f49c44dad'
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
RailsAndCucumber::Application.config.session_store :cookie_store, :key => '_rails_and_cucumber_session'
|
4
|
+
|
5
|
+
# Use the database for sessions instead of the cookie-based default,
|
6
|
+
# which shouldn't be used to store highly confidential information
|
7
|
+
# (create the session table with "rails generate session_migration")
|
8
|
+
# RailsAndCucumber::Application.config.session_store :active_record_store
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Feature: Viewing financial reports
|
2
|
+
As an Acme Financial Reporting accountant
|
3
|
+
I want to see reports for specific types of transaction
|
4
|
+
So that I know how much commission to pay my suppliers.
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given the following transactions:
|
8
|
+
| type | amount | year |
|
9
|
+
| visa | $100 | 2011 |
|
10
|
+
| cash | $50 | 2011 |
|
11
|
+
| visa | $30 | 1999 |
|
12
|
+
| visa | $80 | 2011 |
|
13
|
+
|
14
|
+
Scenario: Viewing visa transactions for 2011
|
15
|
+
When I open the financial report page for "visa" in "2011"
|
16
|
+
Then I should only see the following transactions:
|
17
|
+
| type | amount |
|
18
|
+
| visa | $100 |
|
19
|
+
| visa | $80 |
|
20
|
+
|
21
|
+
Scenario: Viewing cash transactions for 2011
|
22
|
+
When I open the financial report page for "cash" in "2011"
|
23
|
+
Then I should only see the following transactions:
|
24
|
+
| type | amount |
|
25
|
+
| cash | $50 |
|
26
|
+
|
27
|
+
Scenario: Viewing cash transactions for 1999
|
28
|
+
When I open the financial report page for "cash" in "1999"
|
29
|
+
Then I should not see any transactions
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class FinancialReportPage < PageModels::Base
|
2
|
+
def initialize(txn_type, year)
|
3
|
+
@txn_type = txn_type.parameterize
|
4
|
+
@year = year
|
5
|
+
end
|
6
|
+
|
7
|
+
def url
|
8
|
+
financial_report_path(:txn_type => @txn_type, :year => @year)
|
9
|
+
end
|
10
|
+
|
11
|
+
def verify!
|
12
|
+
should have_content "Acme Financial Report for #{@year}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def verify_transactions(txns)
|
16
|
+
rows = all("#report .transaction")
|
17
|
+
rows.should have(txns.size).things
|
18
|
+
|
19
|
+
txns.each_with_index do |txn, i|
|
20
|
+
rows[i].find(".type").should have_content txn["type"]
|
21
|
+
rows[i].find(".amount").should have_content txn["amount"]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def verify_no_transactions
|
26
|
+
should have_content "There are no #{@txn_type} transactions for #{@year}"
|
27
|
+
all("#report .transaction").should be_empty
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Given /^the following transactions:$/ do |table|
|
2
|
+
Transaction.truncate
|
3
|
+
table.hashes.each do |hash|
|
4
|
+
Transaction.create(hash.symbolize_keys)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
Then /^I should only see the following transactions:$/ do |table|
|
9
|
+
page_model.verify_transactions(table.hashes)
|
10
|
+
end
|
11
|
+
|
12
|
+
Then /^I should not see any transactions$/ do
|
13
|
+
page_model.verify_no_transactions
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'cucumber/rails'
|
2
|
+
Capybara.default_selector = :css
|
3
|
+
ActionController::Base.allow_rescue = false
|
4
|
+
|
5
|
+
require 'pagemodels'
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__), "pagemodels", "..", "**", "*.rb")).each { |f| require f }
|
7
|
+
|
8
|
+
PageModels.configure do |config|
|
9
|
+
config.driver = :capybara
|
10
|
+
config.integrate :rails
|
11
|
+
config.integrate :cucumber
|
12
|
+
config.integrate :rspec
|
13
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
|
2
|
+
# It is recommended to regenerate this file in the future when you upgrade to a
|
3
|
+
# newer version of cucumber-rails. Consider adding your own code to a new file
|
4
|
+
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
|
5
|
+
# files.
|
6
|
+
|
7
|
+
|
8
|
+
unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
|
9
|
+
|
10
|
+
vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
|
11
|
+
$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'cucumber/rake/task'
|
15
|
+
|
16
|
+
namespace :cucumber do
|
17
|
+
Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t|
|
18
|
+
t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
|
19
|
+
t.fork = true # You may get faster startup if you set this to false
|
20
|
+
t.profile = 'default'
|
21
|
+
end
|
22
|
+
|
23
|
+
Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t|
|
24
|
+
t.binary = vendored_cucumber_bin
|
25
|
+
t.fork = true # You may get faster startup if you set this to false
|
26
|
+
t.profile = 'wip'
|
27
|
+
end
|
28
|
+
|
29
|
+
Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t|
|
30
|
+
t.binary = vendored_cucumber_bin
|
31
|
+
t.fork = true # You may get faster startup if you set this to false
|
32
|
+
t.profile = 'rerun'
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Run all features'
|
36
|
+
task :all => [:ok, :wip]
|
37
|
+
end
|
38
|
+
desc 'Alias for cucumber:ok'
|
39
|
+
task :cucumber => 'cucumber:ok'
|
40
|
+
|
41
|
+
task :default => :cucumber
|
42
|
+
|
43
|
+
task :features => :cucumber do
|
44
|
+
STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
|
45
|
+
end
|
46
|
+
|
47
|
+
# In case we don't have ActiveRecord, append a no-op task that we can depend upon.
|
48
|
+
task 'db:test:prepare' do
|
49
|
+
end
|
50
|
+
rescue LoadError
|
51
|
+
desc 'cucumber rake task not available (cucumber not installed)'
|
52
|
+
task :cucumber do
|
53
|
+
abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
|
4
|
+
if vendored_cucumber_bin
|
5
|
+
load File.expand_path(vendored_cucumber_bin)
|
6
|
+
else
|
7
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
8
|
+
require 'cucumber'
|
9
|
+
load Cucumber::BINARY
|
10
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
This example demonstrates how to use page models with RSpec to write acceptance tests for any website (in this case Google.com), using Capybara/Selenium/Firefox as a driver.
|
2
|
+
|
3
|
+
~~~~~~~~~~
|
4
|
+
|
5
|
+
See spec/spec_helper.rb for information about configuring PageModels to integrate with the various frameworks:
|
6
|
+
|
7
|
+
PageModels.configure do |config|
|
8
|
+
config.driver = :capybara
|
9
|
+
config.integrate :rspec
|
10
|
+
end
|
11
|
+
|
12
|
+
spec_helper.rb also loads all everything in the pagemodels directory. GoogleSearchPage and GoogleResultsPage provide examples of page models which override PageModels::Base.
|
13
|
+
|
14
|
+
~~~~~~~~~~
|
15
|
+
|
16
|
+
RSpec integration exposes two convenience methods you may use in your specs:
|
17
|
+
|
18
|
+
open_page(page_model) - switches the current page model to the one provided and calls #open!
|
19
|
+
should_see_page(page_model) - switches the current page model and calls #verify!
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/spec_helper")
|
2
|
+
|
3
|
+
describe "Searching Google" do
|
4
|
+
it "should show results for Ruby Page Models" do
|
5
|
+
open_page(GoogleSearchPage.new)
|
6
|
+
page_model.search_for("Ruby Page Models")
|
7
|
+
|
8
|
+
should_see_page(GoogleResultsPage.new("Ruby Page Models"))
|
9
|
+
page_model.verify_more_than_one_page_of_results
|
10
|
+
page_model.verify_special_results_option("Images")
|
11
|
+
page_model.verify_special_results_option("News")
|
12
|
+
|
13
|
+
page_model.verify_top_result("http://www.github.com/rickgrundy/pagemodels")
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class GoogleResultsPage < PageModels::Base
|
2
|
+
def initialize(query)
|
3
|
+
@query = query
|
4
|
+
end
|
5
|
+
|
6
|
+
def verify!
|
7
|
+
should have_content @query
|
8
|
+
should have_content "More search tools"
|
9
|
+
end
|
10
|
+
|
11
|
+
def verify_more_than_one_page_of_results
|
12
|
+
all("table#nav a.fl").should have_at_least(2).things
|
13
|
+
end
|
14
|
+
|
15
|
+
def verify_special_results_option(option)
|
16
|
+
within("#leftnav") do
|
17
|
+
should have_content option
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def verify_top_result(url)
|
22
|
+
find("#search cite:first").text.should == url
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class GoogleSearchPage < PageModels::Base
|
2
|
+
def url
|
3
|
+
"http://www.google.com.au/"
|
4
|
+
end
|
5
|
+
|
6
|
+
def verify!
|
7
|
+
should have_content "About Google"
|
8
|
+
should_not have_content "More search tools"
|
9
|
+
end
|
10
|
+
|
11
|
+
def search_for(query)
|
12
|
+
fill_in "q", :with => query
|
13
|
+
click_button "Google Search"
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'capybara/rspec'
|
2
|
+
require 'pagemodels'
|
3
|
+
|
4
|
+
Dir.glob(File.join(File.dirname(__FILE__), "pagemodels", "**", "*.rb")).each { |f| require f }
|
5
|
+
|
6
|
+
Capybara.default_driver = :selenium
|
7
|
+
|
8
|
+
PageModels.configure do |config|
|
9
|
+
config.driver = :capybara
|
10
|
+
config.integrate :rspec
|
11
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module PageModels
|
2
|
+
class Base
|
3
|
+
def open!
|
4
|
+
visit(url)
|
5
|
+
verify!
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(name, *args, &block)
|
9
|
+
config.driver.send(name, *args, &block)
|
10
|
+
rescue NoMethodError
|
11
|
+
super(name, *args, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def url
|
15
|
+
raise ImplementationError.new(self, __method__)
|
16
|
+
end
|
17
|
+
|
18
|
+
def verify!
|
19
|
+
raise ImplementationError.new(self, __method__)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def config
|
25
|
+
PageModels::Configuration.instance
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module PageModels
|
4
|
+
class Configuration
|
5
|
+
include Singleton
|
6
|
+
attr_writer :driver
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@driver = :capybara
|
10
|
+
@frameworks = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def integrate(framework)
|
14
|
+
@frameworks << framework
|
15
|
+
end
|
16
|
+
|
17
|
+
def integrate!
|
18
|
+
@frameworks.each { |framework| require "page_models/integration/#{framework}" }
|
19
|
+
end
|
20
|
+
|
21
|
+
def driver
|
22
|
+
case @driver
|
23
|
+
when :capybara
|
24
|
+
Capybara.current_session
|
25
|
+
else
|
26
|
+
raise ConfigurationError.new("No driver configured.")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module PageModels
|
2
|
+
def self.configure
|
3
|
+
config = PageModels::Configuration.instance
|
4
|
+
yield(config)
|
5
|
+
config.integrate!
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.create(page, args)
|
9
|
+
args = args.scan(/"([^"]+)"/).map(&:first)
|
10
|
+
page_model_class_name = page.gsub(/(?:^|[^\w])([a-z])/) { $1.upcase }
|
11
|
+
Kernel.const_get(page_model_class_name).new(*args)
|
12
|
+
end
|
13
|
+
end
|
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Given /^I open the (.+ page)(.*)$/ do |page, args|
|
2
|
+
self.page_model = PageModels.create(page, args)
|
3
|
+
page_model.open!
|
4
|
+
end
|
5
|
+
|
6
|
+
Then /^I should see the (.+ page)(.*)$/ do |page, args|
|
7
|
+
self.page_model = PageModels.create(page, args)
|
8
|
+
page_model.verify!
|
9
|
+
end
|
10
|
+
|
11
|
+
module PageModels
|
12
|
+
module CucumberIntegration
|
13
|
+
attr_accessor :page_model
|
14
|
+
end
|
15
|
+
end
|
16
|
+
World(PageModels::CucumberIntegration)
|
@@ -0,0 +1 @@
|
|
1
|
+
PageModels::Base.send(:include, Rails.application.routes.url_helpers)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
PageModels::Base.send(:include, RSpec::Matchers)
|
2
|
+
|
3
|
+
module PageModels
|
4
|
+
module RSpecIntegration
|
5
|
+
attr_accessor :page_model
|
6
|
+
|
7
|
+
def open_page(page_model)
|
8
|
+
self.page_model = page_model
|
9
|
+
page_model.open!
|
10
|
+
end
|
11
|
+
|
12
|
+
def should_see_page(page_model)
|
13
|
+
self.page_model = page_model
|
14
|
+
page_model.verify!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Object.send(:include, PageModels::RSpecIntegration)
|
data/lib/pagemodels.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Dir.glob(File.join(File.dirname(__FILE__), "page_models", "*.rb")).each { |f| require f }
|
data/pagemodels.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "page_models/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "pagemodels"
|
7
|
+
s.version = PageModels::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Rick Grundy"]
|
10
|
+
s.email = ["rick@rickgrundy.com"]
|
11
|
+
s.homepage = "http://www.github.com/rickgrundy/pagemodels"
|
12
|
+
s.summary = "Page models for your browser driving acceptance tests with optional integration for RSpec, Cucumber, and Rails."
|
13
|
+
s.description = "See http://www.github.com/rickgrundy/pagemodels"
|
14
|
+
|
15
|
+
s.rubyforge_project = "pagemodels"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency 'rspec', '>= 2.5.0'
|
23
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "../../spec_helper")
|
2
|
+
|
3
|
+
describe PageModels::Base do
|
4
|
+
class UnimplementedPageModel < PageModels::Base
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestPageModel < PageModels::Base
|
8
|
+
def url
|
9
|
+
"/test-page"
|
10
|
+
end
|
11
|
+
|
12
|
+
def verify!
|
13
|
+
true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "template methods which must be implemented by your page models" do
|
18
|
+
it "should raise an error if page models do not implement #url" do
|
19
|
+
lambda { UnimplementedPageModel.new.url }.should raise_error(PageModels::ImplementationError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should raise an error if page models do not implement #verify!" do
|
23
|
+
lambda { UnimplementedPageModel.new.verify! }.should raise_error(PageModels::ImplementationError)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "delegating methods to the driver for less verbose page models" do
|
28
|
+
before(:each) do
|
29
|
+
@driver = Object.new
|
30
|
+
PageModels::Configuration.instance.stub(:driver).and_return(@driver)
|
31
|
+
@page_model = TestPageModel.new
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should delegate a missing method to the driver" do
|
35
|
+
@driver.should_receive(:do_something_cool).with(:please)
|
36
|
+
@page_model.do_something_cool(:please)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should should not hide method missing errors if the method does not exist on the driver" do
|
40
|
+
lambda { @page_model.do_something_else }.should raise_error(NoMethodError, "undefined method `do_something_else' for #{@page_model.inspect}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "opening a page" do
|
45
|
+
before(:each) do
|
46
|
+
@driver = Object.new
|
47
|
+
PageModels::Configuration.instance.stub(:driver).and_return(@driver)
|
48
|
+
@page_model = TestPageModel.new
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should visit the page, then call verify" do
|
52
|
+
@page_model.should_receive(:visit).with("/test-page")
|
53
|
+
@page_model.should_receive(:verify!)
|
54
|
+
@page_model.open!
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "../../spec_helper")
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
def self.current_session
|
5
|
+
@session ||= Object.new
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe PageModels::Configuration do
|
10
|
+
before(:each) do
|
11
|
+
@config = PageModels::Configuration.instance
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "providing a driver" do
|
15
|
+
it "should raise an error if no driver is configured" do
|
16
|
+
@config.driver = nil
|
17
|
+
lambda { @config.driver }.should raise_error(PageModels::ConfigurationError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should provide a Capybara session" do
|
21
|
+
@config.driver = :capybara
|
22
|
+
@config.driver.should == Capybara.current_session
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "integrating with frameworks" do
|
27
|
+
it "should require the appropriate integration files" do
|
28
|
+
@config.integrate :foo
|
29
|
+
@config.integrate :bar
|
30
|
+
|
31
|
+
@config.should_receive(:require).with("page_models/integration/foo")
|
32
|
+
@config.should_receive(:require).with("page_models/integration/bar")
|
33
|
+
|
34
|
+
@config.integrate!
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "pagemodels")
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pagemodels
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rick Grundy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-06-18 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 2.5.0
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
description: See http://www.github.com/rickgrundy/pagemodels
|
28
|
+
email:
|
29
|
+
- rick@rickgrundy.com
|
30
|
+
executables: []
|
31
|
+
|
32
|
+
extensions: []
|
33
|
+
|
34
|
+
extra_rdoc_files: []
|
35
|
+
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- README.txt
|
40
|
+
- Rakefile
|
41
|
+
- examples/rails_and_cucumber/.gitignore
|
42
|
+
- examples/rails_and_cucumber/Gemfile
|
43
|
+
- examples/rails_and_cucumber/README.txt
|
44
|
+
- examples/rails_and_cucumber/Rakefile
|
45
|
+
- examples/rails_and_cucumber/app/controllers/application_controller.rb
|
46
|
+
- examples/rails_and_cucumber/app/controllers/financial_reports_controller.rb
|
47
|
+
- examples/rails_and_cucumber/app/models/transaction.rb
|
48
|
+
- examples/rails_and_cucumber/app/views/financial_reports/show.html.erb
|
49
|
+
- examples/rails_and_cucumber/app/views/layouts/application.html.erb
|
50
|
+
- examples/rails_and_cucumber/config/application.rb
|
51
|
+
- examples/rails_and_cucumber/config/boot.rb
|
52
|
+
- examples/rails_and_cucumber/config/cucumber.yml
|
53
|
+
- examples/rails_and_cucumber/config/environment.rb
|
54
|
+
- examples/rails_and_cucumber/config/environments/development.rb
|
55
|
+
- examples/rails_and_cucumber/config/environments/test.rb
|
56
|
+
- examples/rails_and_cucumber/config/initializers/secret_token.rb
|
57
|
+
- examples/rails_and_cucumber/config/initializers/session_store.rb
|
58
|
+
- examples/rails_and_cucumber/config/routes.rb
|
59
|
+
- examples/rails_and_cucumber/features/financial_reporting.feature
|
60
|
+
- examples/rails_and_cucumber/features/pagemodels/financial_report_page.rb
|
61
|
+
- examples/rails_and_cucumber/features/step_definitions/financial_reporting_steps.rb
|
62
|
+
- examples/rails_and_cucumber/features/support/env.rb
|
63
|
+
- examples/rails_and_cucumber/lib/tasks/cucumber.rake
|
64
|
+
- examples/rails_and_cucumber/script/cucumber
|
65
|
+
- examples/rails_and_cucumber/script/rails
|
66
|
+
- examples/rspec_and_capybara/Gemfile
|
67
|
+
- examples/rspec_and_capybara/README.txt
|
68
|
+
- examples/rspec_and_capybara/Rakefile
|
69
|
+
- examples/rspec_and_capybara/spec/google_search_spec.rb
|
70
|
+
- examples/rspec_and_capybara/spec/pagemodels/google_results_page.rb
|
71
|
+
- examples/rspec_and_capybara/spec/pagemodels/google_search_page.rb
|
72
|
+
- examples/rspec_and_capybara/spec/spec_helper.rb
|
73
|
+
- lib/page_models/base.rb
|
74
|
+
- lib/page_models/configuration.rb
|
75
|
+
- lib/page_models/core.rb
|
76
|
+
- lib/page_models/errors.rb
|
77
|
+
- lib/page_models/integration/capybara.rb
|
78
|
+
- lib/page_models/integration/cucumber.rb
|
79
|
+
- lib/page_models/integration/rails.rb
|
80
|
+
- lib/page_models/integration/rspec.rb
|
81
|
+
- lib/page_models/version.rb
|
82
|
+
- lib/pagemodels.rb
|
83
|
+
- pagemodels.gemspec
|
84
|
+
- spec/page_models/base_spec.rb
|
85
|
+
- spec/page_models/configuration_spec.rb
|
86
|
+
- spec/spec_helper.rb
|
87
|
+
has_rdoc: true
|
88
|
+
homepage: http://www.github.com/rickgrundy/pagemodels
|
89
|
+
licenses: []
|
90
|
+
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0"
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project: pagemodels
|
111
|
+
rubygems_version: 1.5.0
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Page models for your browser driving acceptance tests with optional integration for RSpec, Cucumber, and Rails.
|
115
|
+
test_files:
|
116
|
+
- spec/page_models/base_spec.rb
|
117
|
+
- spec/page_models/configuration_spec.rb
|
118
|
+
- spec/spec_helper.rb
|