jury 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/jury +4 -0
- data/lib/jury.rb +5 -0
- data/lib/jury/command_line_interface.rb +56 -0
- data/lib/jury/tchk.rb +26 -0
- data/template/config-example.rb +10 -0
- data/template/jury.rb +47 -0
- data/template/lib/helper.rb +20 -0
- data/template/lib/helpers/home_page_helper.rb +9 -0
- data/template/lib/page_object.rb +62 -0
- data/template/lib/path_to_helper_mapper.rb +76 -0
- data/template/url-mappings.yaml +1 -0
- metadata +62 -0
data/bin/jury
ADDED
data/lib/jury.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'jury/tchk'
|
3
|
+
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
$VALID_COMMANDS = %w[help init]
|
7
|
+
|
8
|
+
|
9
|
+
module Jury
|
10
|
+
class CommandLineInterface
|
11
|
+
include Jury::Tchk
|
12
|
+
|
13
|
+
def create_filesystem # CB(2), BB(4)
|
14
|
+
# PRECONDITION -- current_directory not inside/under template_directory
|
15
|
+
current_directory = Dir.pwd
|
16
|
+
template_directory = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'template'))
|
17
|
+
set_of_files = Dir.glob(File.join(template_directory, "*"))
|
18
|
+
FileUtils.cp_r set_of_files, current_directory
|
19
|
+
|
20
|
+
# The above copy will not create empty directories, it seems. Either that,
|
21
|
+
# or gem metadata refuses to accept that an empty template/spec directory
|
22
|
+
# holds value to me. To work around this problem, we will need to create
|
23
|
+
# this directory manually if it doesn't already exist.
|
24
|
+
spec_directory = File.join(current_directory, "spec")
|
25
|
+
FileUtils.mkdir(spec_directory) if !File.directory?(spec_directory)
|
26
|
+
end
|
27
|
+
|
28
|
+
def show_help_message # BB(3,1), BB(3,3)
|
29
|
+
puts <<EOM
|
30
|
+
USAGE: #{@argv[0]} <command> <...>
|
31
|
+
|
32
|
+
Commands supported includes:
|
33
|
+
init - initialize a new Jury instance.
|
34
|
+
help - show this message.
|
35
|
+
EOM
|
36
|
+
end
|
37
|
+
|
38
|
+
def main(argv) # US(3)
|
39
|
+
type_error if !is_array_of_T(argv, String, 1)
|
40
|
+
|
41
|
+
@argv = argv
|
42
|
+
if !argv[1].nil? then
|
43
|
+
command = argv[1].downcase
|
44
|
+
else
|
45
|
+
command = 'help'
|
46
|
+
end
|
47
|
+
|
48
|
+
case command
|
49
|
+
when 'init'
|
50
|
+
create_filesystem # BB(3,2)
|
51
|
+
else
|
52
|
+
show_help_message # BB(3,1) /\ BB(3,3)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/jury/tchk.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Jury
|
2
|
+
module Tchk
|
3
|
+
def type_error
|
4
|
+
raise Exception.new, "Type error"
|
5
|
+
end
|
6
|
+
|
7
|
+
def is_string(s)
|
8
|
+
return s.kind_of?(String)
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_array_of_T(ary, type = nil, minimum_length = 0)
|
12
|
+
is_an_array = ary.kind_of?(Array)
|
13
|
+
|
14
|
+
if !type.nil? then
|
15
|
+
type_error if !type.kind_of?(Class)
|
16
|
+
all_elements_of_type = ary.all? { |e| e.kind_of?(type) }
|
17
|
+
else
|
18
|
+
all_elements_of_type = true
|
19
|
+
end
|
20
|
+
|
21
|
+
minimum_length_met = ary.size >= minimum_length
|
22
|
+
|
23
|
+
return is_an_array && all_elements_of_type && minimum_length_met
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# This setting determines the web app installation's first page. When in-
|
2
|
+
# stantiating HomePage.new, the browser will open this URL.
|
3
|
+
|
4
|
+
$home_page = "http://staging.example.com:3000"
|
5
|
+
|
6
|
+
# If you defined a User class for your web-app, and you needed a globally de-
|
7
|
+
# fined user, e.g., for an administrator account, you could define it like
|
8
|
+
# this.
|
9
|
+
#
|
10
|
+
# $admin_user = User.new(:email => "sysop", :password => "sysop-password")
|
data/template/jury.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Include Capybara DSL
|
2
|
+
|
3
|
+
require 'capybara/rspec'
|
4
|
+
include Capybara::DSL
|
5
|
+
|
6
|
+
# Support for multiple, concurrently-running Jury instances.
|
7
|
+
|
8
|
+
begin
|
9
|
+
e = ENV['CAPYBARA_PORT_OFFSET'].to_i
|
10
|
+
rescue
|
11
|
+
e = 0
|
12
|
+
end
|
13
|
+
Capybara.server_port = 8800 + e
|
14
|
+
|
15
|
+
# Include commonly used testing tools
|
16
|
+
|
17
|
+
require 'lib/page_object'
|
18
|
+
require 'lib/helper'
|
19
|
+
require 'lib/user'
|
20
|
+
require 'lib/credit_card'
|
21
|
+
|
22
|
+
# Make all the available helpers known to Jury.
|
23
|
+
|
24
|
+
Dir["lib/helpers/*_helper.rb"].each {|file| require file}
|
25
|
+
|
26
|
+
# Import all of our configuration settings.
|
27
|
+
|
28
|
+
unless ENV['JURY_CONFIG'] then
|
29
|
+
puts <<-EOH
|
30
|
+
|
31
|
+
You must define the JURY_CONFIG environment variable first. This environment
|
32
|
+
variable refers to a specific configuration file. For example, if you have a
|
33
|
+
configuration file named config-beta.rb inside your Jury project's directory,
|
34
|
+
then you can invoke your tests like so:
|
35
|
+
|
36
|
+
JURY_CONFIG=config-beta rspec -I. # ...etc...
|
37
|
+
|
38
|
+
Similarly, if you have a configuration located outside of the Jury project's
|
39
|
+
directory, you can invoke as follows:
|
40
|
+
|
41
|
+
JURY_CONFIG=/tmp/my_config.rb rspec -I. # ..etc..
|
42
|
+
|
43
|
+
EOH
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
require ENV['JURY_CONFIG']
|
47
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Responsibilities
|
2
|
+
#
|
3
|
+
# - Maintain state common to all Helper classes.
|
4
|
+
|
5
|
+
class Helper
|
6
|
+
def initialize(args={})
|
7
|
+
args.should be_kind_of(Hash)
|
8
|
+
|
9
|
+
@session = nil
|
10
|
+
if args[:session] then
|
11
|
+
@session = args[:session]
|
12
|
+
@session.should be_kind_of(Capybara::Session)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_home_page?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Responsibilities
|
2
|
+
# - Visit URL
|
3
|
+
# - Detect and handle redirects
|
4
|
+
# - Proxy undefined methods to the appropriate helper class
|
5
|
+
# - Return current session URL
|
6
|
+
|
7
|
+
require 'lib/path_to_helper_mapper'
|
8
|
+
|
9
|
+
class PageObject
|
10
|
+
attr_reader :session
|
11
|
+
|
12
|
+
def initialize(args)
|
13
|
+
@session = nil
|
14
|
+
@helper = nil
|
15
|
+
@pthm = PathToHelperMapper.new(args)
|
16
|
+
|
17
|
+
if args[:session] then
|
18
|
+
@session = args[:session]
|
19
|
+
@session.should be_kind_of(Capybara::Session)
|
20
|
+
end
|
21
|
+
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def visit(url)
|
26
|
+
url.should be_kind_of(String)
|
27
|
+
url.size.should > 0
|
28
|
+
|
29
|
+
@session.visit(url)
|
30
|
+
choose_helper
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def current_url_without_query_parameters
|
35
|
+
@session.current_url.split(/\?/).first
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing(msg, *args, &blk)
|
39
|
+
results = @helper.send(msg, *args, &blk)
|
40
|
+
choose_helper
|
41
|
+
return results
|
42
|
+
end
|
43
|
+
|
44
|
+
def have_content?(text)
|
45
|
+
@session.have_content?(text)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def choose_helper
|
51
|
+
@helper = @pthm.helper_for_path(@session.current_path)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# Convenience class
|
57
|
+
class HomePage < PageObject
|
58
|
+
def initialize
|
59
|
+
super(:session => page, :map_filename => "url-mappings.yaml").visit($home_page)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Responsibilities:
|
2
|
+
# - Translate URL to helper object
|
3
|
+
# - Configure set of mappings used in aforementioned translation.
|
4
|
+
|
5
|
+
require 'rspec/expectations'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
include RSpec::Matchers
|
9
|
+
|
10
|
+
class String
|
11
|
+
def starts_with?(prefix)
|
12
|
+
self[0..prefix.size-1].eql?(prefix)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class PathToHelperMapper
|
17
|
+
def initialize(args={})
|
18
|
+
args.should be_kind_of(Hash)
|
19
|
+
|
20
|
+
@session = nil
|
21
|
+
if args[:session] then
|
22
|
+
@session = args[:session]
|
23
|
+
@session.should be_kind_of(Capybara::Session)
|
24
|
+
end
|
25
|
+
|
26
|
+
if args[:map_filename] then
|
27
|
+
map_filename = args[:map_filename]
|
28
|
+
map_filename.should be_kind_of(String)
|
29
|
+
map_filename.size.should > 0
|
30
|
+
mappings = File.open(map_filename, "r").read
|
31
|
+
end
|
32
|
+
|
33
|
+
if args[:map_file] then
|
34
|
+
map_file = args[:map_file]
|
35
|
+
map_file.should be_kind_of(File)
|
36
|
+
mappings = map_file.read
|
37
|
+
end
|
38
|
+
|
39
|
+
if args[:mappings] then
|
40
|
+
mappings = args[:mappings]
|
41
|
+
mappings.should be_kind_of(String)
|
42
|
+
end
|
43
|
+
|
44
|
+
mappings.should_not be_nil
|
45
|
+
|
46
|
+
@prefix_mapping = YAML.load(mappings)
|
47
|
+
@memo = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
def helper_for_path(p)
|
51
|
+
p.should be_kind_of(String)
|
52
|
+
|
53
|
+
class_name = helper_class_for_path(p)
|
54
|
+
class_object = Kernel.const_get("Helpers").const_get(class_name)
|
55
|
+
@memo[class_object] = class_object.new(:session => @session) if @memo[class_object].nil?
|
56
|
+
return @memo[class_object]
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def helper_class_for_path(p)
|
62
|
+
# Normalize URL to eliminate special cases.
|
63
|
+
p = '/' if p.size == 0
|
64
|
+
|
65
|
+
# Find all helpers that could potentially service the URL we're on.
|
66
|
+
class_mapping = @prefix_mapping.select{|k,_| p.starts_with?(k)}
|
67
|
+
|
68
|
+
# Choose the most specific handler (based on URL longest-prefix match).
|
69
|
+
class_mapping = class_mapping.sort {|a,b| b.first.size <=> a.first.size}
|
70
|
+
|
71
|
+
# Return the helper's class name.
|
72
|
+
class_name = class_mapping.first[1]
|
73
|
+
class_name.should be_kind_of(String)
|
74
|
+
return class_name
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
"/": HomePageHelper
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jury
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Samuel A. Falvo II
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-07 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! 'A minimalist acceptance testing framework using page object pattern. It
|
15
|
+
|
16
|
+
greatly simplifies the task of constructing, using, and maintaining page
|
17
|
+
|
18
|
+
objects in a Ruby/Capybara/RSpec environment.
|
19
|
+
|
20
|
+
'
|
21
|
+
email: kc5tja@arrl.net
|
22
|
+
executables:
|
23
|
+
- jury
|
24
|
+
extensions: []
|
25
|
+
extra_rdoc_files: []
|
26
|
+
files:
|
27
|
+
- lib/jury.rb
|
28
|
+
- lib/jury/command_line_interface.rb
|
29
|
+
- lib/jury/tchk.rb
|
30
|
+
- bin/jury
|
31
|
+
- template/config-example.rb
|
32
|
+
- template/jury.rb
|
33
|
+
- template/lib/helper.rb
|
34
|
+
- template/lib/helpers/home_page_helper.rb
|
35
|
+
- template/lib/page_object.rb
|
36
|
+
- template/lib/path_to_helper_mapper.rb
|
37
|
+
- template/url-mappings.yaml
|
38
|
+
homepage: http://github.com/plumdistrict/jury
|
39
|
+
licenses: []
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 1.8.17
|
59
|
+
signing_key:
|
60
|
+
specification_version: 3
|
61
|
+
summary: A minimalist acceptance testing framework using page object pattern.
|
62
|
+
test_files: []
|