scudco-taza 0.8.1
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/History.txt +44 -0
- data/Manifest.txt +61 -0
- data/README +79 -0
- data/README.textile +1 -0
- data/VERSION.yml +4 -0
- data/bin/taza +17 -0
- data/generators/flow/flow_generator.rb +57 -0
- data/generators/flow/templates/flow.rb.erb +9 -0
- data/generators/page/page_generator.rb +58 -0
- data/generators/page/templates/functional_page_spec.rb.erb +8 -0
- data/generators/page/templates/page.rb.erb +8 -0
- data/generators/partial/partial_generator.rb +57 -0
- data/generators/partial/templates/partial.rb.erb +7 -0
- data/generators/site/site_generator.rb +56 -0
- data/generators/site/templates/site.rb.erb +10 -0
- data/generators/site/templates/site.yml.erb +3 -0
- data/lib/app_generators/taza/taza_generator.rb +72 -0
- data/lib/app_generators/taza/templates/config.yml.erb +3 -0
- data/lib/app_generators/taza/templates/rakefile.rb.erb +3 -0
- data/lib/app_generators/taza/templates/spec_helper.rb.erb +11 -0
- data/lib/extensions/array.rb +10 -0
- data/lib/extensions/hash.rb +5 -0
- data/lib/extensions/object.rb +24 -0
- data/lib/extensions/string.rb +11 -0
- data/lib/taza/browser.rb +33 -0
- data/lib/taza/entity.rb +34 -0
- data/lib/taza/fixture.rb +66 -0
- data/lib/taza/flow.rb +40 -0
- data/lib/taza/page.rb +95 -0
- data/lib/taza/settings.rb +47 -0
- data/lib/taza/site.rb +145 -0
- data/lib/taza/tasks.rb +50 -0
- data/lib/taza.rb +35 -0
- data/spec/array_spec.rb +16 -0
- data/spec/browser_spec.rb +63 -0
- data/spec/entity_spec.rb +9 -0
- data/spec/fixture_spec.rb +34 -0
- data/spec/fixtures_spec.rb +21 -0
- data/spec/flow_generator_spec.rb +50 -0
- data/spec/hash_spec.rb +12 -0
- data/spec/object_spec.rb +29 -0
- data/spec/page_generator_spec.rb +56 -0
- data/spec/page_spec.rb +82 -0
- data/spec/partial_generator_spec.rb +38 -0
- data/spec/project_generator_spec.rb +41 -0
- data/spec/sandbox/config/config.yml +1 -0
- data/spec/sandbox/config/site_name.yml +5 -0
- data/spec/sandbox/config.yml +3 -0
- data/spec/sandbox/fixtures/examples.yml +8 -0
- data/spec/sandbox/fixtures/users.yml +2 -0
- data/spec/sandbox/flows/batman.rb +5 -0
- data/spec/sandbox/flows/robin.rb +4 -0
- data/spec/sandbox/pages/foo/bar.rb +9 -0
- data/spec/sandbox/pages/foo/partials/partial_the_reckoning.rb +2 -0
- data/spec/settings_spec.rb +88 -0
- data/spec/site_generator_spec.rb +57 -0
- data/spec/site_spec.rb +229 -0
- data/spec/spec_helper.rb +57 -0
- data/spec/string_spec.rb +7 -0
- data/spec/taza_bin_spec.rb +14 -0
- data/spec/taza_spec.rb +12 -0
- data/spec/taza_tasks_spec.rb +41 -0
- metadata +181 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubigen'
|
3
|
+
class TazaGenerator < RubiGen::Base
|
4
|
+
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
|
5
|
+
Config::CONFIG['ruby_install_name'])
|
6
|
+
|
7
|
+
default_options :author => nil
|
8
|
+
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
def initialize(runtime_args, runtime_options = {})
|
12
|
+
super
|
13
|
+
usage if args.empty?
|
14
|
+
@destination_root = File.expand_path(args.shift)
|
15
|
+
@name = base_name
|
16
|
+
extract_options
|
17
|
+
end
|
18
|
+
|
19
|
+
def manifest
|
20
|
+
record do |m|
|
21
|
+
create_directories(m)
|
22
|
+
m.template "rakefile.rb.erb", "rakefile"
|
23
|
+
m.template "config.yml.erb", File.join("config","config.yml")
|
24
|
+
m.template "spec_helper.rb.erb", File.join("spec","spec_helper.rb")
|
25
|
+
m.dependency "install_rubigen_scripts", [destination_root, 'taza'],
|
26
|
+
:shebang => options[:shebang], :collision => :force
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_directories(m)
|
31
|
+
BASEDIRS.each { |path| m.directory path }
|
32
|
+
m.directory File.join('lib','sites')
|
33
|
+
m.directory File.join('lib','flows')
|
34
|
+
m.directory File.join('spec','functional')
|
35
|
+
m.directory File.join('spec','integration')
|
36
|
+
m.directory File.join('spec','story')
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
def banner
|
41
|
+
<<-EOS
|
42
|
+
USAGE: #{spec.name} path/for/your/test/project [options]
|
43
|
+
EOS
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_options!(opts)
|
47
|
+
opts.separator ''
|
48
|
+
opts.separator 'Options:'
|
49
|
+
# For each option below, place the default
|
50
|
+
# at the top of the file next to "default_options"
|
51
|
+
# opts.on("-a", "--author=\"Your Name\"", String,
|
52
|
+
# "Some comment about this option",
|
53
|
+
# "Default: none") { |options[:author]| }
|
54
|
+
opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
55
|
+
end
|
56
|
+
|
57
|
+
def extract_options
|
58
|
+
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
59
|
+
# Templates can access these value via the attr_reader-generated methods, but not the
|
60
|
+
# raw instance variable value.
|
61
|
+
# @author = options[:author]
|
62
|
+
end
|
63
|
+
|
64
|
+
# Installation skeleton. Intermediate directories are automatically
|
65
|
+
# created so don't sweat their absence here.
|
66
|
+
BASEDIRS = %w(
|
67
|
+
lib
|
68
|
+
config
|
69
|
+
script
|
70
|
+
spec
|
71
|
+
)
|
72
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
ENV['TAZA_ENV'] = "isolation" if ENV['TAZA_ENV'].nil?
|
2
|
+
require 'rubygems'
|
3
|
+
require 'spec'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
lib_path = File.expand_path("#{File.dirname(__FILE__)}/../lib/sites")
|
7
|
+
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
|
8
|
+
|
9
|
+
Spec::Runner.configure do |config|
|
10
|
+
config.mock_with :mocha
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Array
|
2
|
+
# Returns true if the two arrays elements are equal ignoring order
|
3
|
+
# Example:
|
4
|
+
# [1,2].equivalent([2,1]) # => true
|
5
|
+
# [1,2,3].equivalent([2,1]) # => false
|
6
|
+
def equivalent?(other_array)
|
7
|
+
merged_array = self & other_array
|
8
|
+
merged_array.size == self.size && merged_array.size == other_array.size
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# instance_exec comes with >1.8.7 thankfully
|
2
|
+
if VERSION <= '1.8.6'
|
3
|
+
class Object
|
4
|
+
module InstanceExecHelper; end
|
5
|
+
include InstanceExecHelper
|
6
|
+
# instance_exec method evaluates a block of code relative to the specified object, with parameters whom come from outside the object.
|
7
|
+
def instance_exec(*args, &block)
|
8
|
+
begin
|
9
|
+
old_critical, Thread.critical = Thread.critical, true
|
10
|
+
n = 0
|
11
|
+
n += 1 while respond_to?(mname="__instance_exec#{n}")
|
12
|
+
InstanceExecHelper.module_eval{ define_method(mname, &block) }
|
13
|
+
ensure
|
14
|
+
Thread.critical = old_critical
|
15
|
+
end
|
16
|
+
begin
|
17
|
+
ret = send(mname, *args)
|
18
|
+
ensure
|
19
|
+
InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
|
20
|
+
end
|
21
|
+
ret
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/taza/browser.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Taza
|
2
|
+
class Browser
|
3
|
+
|
4
|
+
# Create a browser instance depending on configuration. Configuration should be read in via Taza::Settings.config.
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
# browser = Taza::Browser.create(Taza::Settings.config)
|
8
|
+
#
|
9
|
+
def self.create(params={})
|
10
|
+
self.send("create_#{params[:driver]}".to_sym,params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.browser_class(params)
|
14
|
+
self.send("#{params[:driver]}_#{params[:browser]}".to_sym)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def self.create_watir(params)
|
20
|
+
require 'watir'
|
21
|
+
Watir::Browser.default = params[:browser].to_s
|
22
|
+
Watir::Browser.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.create_selenium(params)
|
26
|
+
require 'selenium'
|
27
|
+
Selenium::SeleniumDriver.new(params[:server_ip],params[:server_port],'*' + params[:browser].to_s,params[:timeout])
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
data/lib/taza/entity.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Taza
|
2
|
+
class Entity
|
3
|
+
#Creates a entity, pass in a hash to be methodized and the fixture to look up other fixtures (not entirely happy with this abstraction)
|
4
|
+
def initialize(hash,fixture)
|
5
|
+
@hash = hash
|
6
|
+
@fixture = fixture
|
7
|
+
define_methods_for_hash_keys
|
8
|
+
end
|
9
|
+
|
10
|
+
#This method converts hash keys into methods onto the entity
|
11
|
+
def define_methods_for_hash_keys
|
12
|
+
@hash.keys.each do |key|
|
13
|
+
create_method(key) do
|
14
|
+
get_value_for_entry(key)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
#This method will lookup another fixture if a pluralized fixture exists otherwise return the value in the hash
|
20
|
+
def get_value_for_entry(key) # :nodoc:
|
21
|
+
if @fixture.pluralized_fixture_exists?(key)
|
22
|
+
@fixture.get_fixture_entity(key.pluralize_to_sym,@hash[key])
|
23
|
+
else
|
24
|
+
@hash[key]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def create_method(name, &block) # :nodoc:
|
30
|
+
self.class.send(:define_method, name, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/lib/taza/fixture.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module Taza
|
2
|
+
class Fixture # :nodoc:
|
3
|
+
|
4
|
+
def initialize # :nodoc:
|
5
|
+
@fixtures = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def load_all # :nodoc:
|
9
|
+
Dir.glob(fixtures_pattern) do |file|
|
10
|
+
entitized_fixture = {}
|
11
|
+
YAML.load_file(file).each do |key, value|
|
12
|
+
entitized_fixture[key] = value.convert_hash_keys_to_methods(self)
|
13
|
+
end
|
14
|
+
@fixtures[File.basename(file,'.yml').to_sym] = entitized_fixture
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def fixture_names # :nodoc:
|
19
|
+
@fixtures.keys
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_fixture_entity(fixture_file_key,entity_key) # :nodoc:
|
23
|
+
@fixtures[fixture_file_key][entity_key]
|
24
|
+
end
|
25
|
+
|
26
|
+
def pluralized_fixture_exists?(singularized_fixture_name) # :nodoc:
|
27
|
+
fixture_names.include?(singularized_fixture_name.pluralize_to_sym)
|
28
|
+
end
|
29
|
+
|
30
|
+
def fixtures_pattern # :nodoc:
|
31
|
+
File.join(base_path, 'fixtures','*.yml')
|
32
|
+
end
|
33
|
+
|
34
|
+
def base_path # :nodoc:
|
35
|
+
File.join('.','spec')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# The module that will mixin methods based on the fixture files in your 'spec/fixtures'
|
40
|
+
#
|
41
|
+
# Example:
|
42
|
+
# describe "something" do
|
43
|
+
# it "should test something" do
|
44
|
+
# users(:jane_smith).first_name.should eql("jane")
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# where there is a spec/fixtures/users.yml file containing a entry of:
|
49
|
+
# jane_smith:
|
50
|
+
# first_name: jane
|
51
|
+
# last_name: smith
|
52
|
+
module Fixtures
|
53
|
+
def Fixtures.included(other_module) # :nodoc:
|
54
|
+
fixture = Fixture.new
|
55
|
+
fixture.load_all
|
56
|
+
fixture.fixture_names.each do |fixture_name|
|
57
|
+
self.class_eval do
|
58
|
+
define_method(fixture_name) do |entity_key|
|
59
|
+
fixture.get_fixture_entity(fixture_name,entity_key.to_s)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
data/lib/taza/flow.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Taza
|
2
|
+
# Flows provide a way to write and manage common actions on a site.
|
3
|
+
# For instance, on an e-commerce site you may have multiple tests where a user is supposed to create a
|
4
|
+
# new account and add a product to the shopping bag. In this case you could have two flows. create_an_account
|
5
|
+
# and add_product_to_bag.
|
6
|
+
#
|
7
|
+
# Here's how you would get this started where your site is called Widgets of the Future:
|
8
|
+
# $ ./script/generate flow create_an_account widgets_of_the_future
|
9
|
+
# $ ./script/generate flow add_product_to_bag widgets_of_the_future
|
10
|
+
#
|
11
|
+
# This will generate flows for you in lib/sites/widgets_of_the_future/flows/
|
12
|
+
#
|
13
|
+
# From here you can create the logic needed to perform these flows without ever referencing a browser object:
|
14
|
+
#
|
15
|
+
# module WidgetsOfTheFuture
|
16
|
+
# class WidgetsOfTheFuture < Taza::Site
|
17
|
+
# def create_an_account_flow(params={})
|
18
|
+
# home_page.create_an_account_link.click
|
19
|
+
# create_an_account_page do |cap|
|
20
|
+
# cap.email.set params[:email]
|
21
|
+
# cap.password.set params[:password]
|
22
|
+
# cap.submit.click
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# Then inside a spec or test you could run this flow like:
|
30
|
+
#
|
31
|
+
# describe "Widgets of the Future" do
|
32
|
+
# it "should do widgety things so that we can make more monies" do
|
33
|
+
# WidgetsOfTheFuture.new do |w|
|
34
|
+
# w.create_an_account_flow :email => "i.am@the.widget.store.com", :password => "secret"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
class Flow
|
39
|
+
end
|
40
|
+
end
|
data/lib/taza/page.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
module Taza
|
2
|
+
# An abstraction of a web page, place the elements you care about accessing in here as well as specify the filters that apply when trying to access the element.
|
3
|
+
#
|
4
|
+
# Example:
|
5
|
+
# require 'taza'
|
6
|
+
# class HomePage < Taza::Page
|
7
|
+
# element(:foo) {browser.element_by_xpath('some xpath')}
|
8
|
+
# filter :title_given, :foo
|
9
|
+
#
|
10
|
+
# def title_given
|
11
|
+
# browser.title.nil?
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# homepage.foo will return the element specified in the block if the filter returned true
|
16
|
+
class Page
|
17
|
+
attr_accessor :browser
|
18
|
+
class << self
|
19
|
+
def elements # :nodoc:
|
20
|
+
@elements ||= {}
|
21
|
+
end
|
22
|
+
def filters # :nodoc:
|
23
|
+
@filters ||= Hash.new { [] }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# A element on a page
|
28
|
+
#
|
29
|
+
# Watir Example:
|
30
|
+
# class HomePage < Taza::Page
|
31
|
+
# element(:foo) {browser.element_by_xpath('some xpath')}
|
32
|
+
# end
|
33
|
+
# homepage.foo.click
|
34
|
+
def self.element(name,&block)
|
35
|
+
self.elements[name] = block
|
36
|
+
end
|
37
|
+
|
38
|
+
# A filter for elemenet(s) on a page
|
39
|
+
# Example:
|
40
|
+
# class HomePage < Taza::Page
|
41
|
+
# element(:foo) {browser.element_by_xpath('some xpath')}
|
42
|
+
# filter :title_given, :foo
|
43
|
+
# #a filter will apply to all elements if none are specified
|
44
|
+
# filter :some_filter
|
45
|
+
# #a filter will also apply to all elements if the symbol :all is given
|
46
|
+
# filter :another_filter, :all
|
47
|
+
#
|
48
|
+
# def some_filter
|
49
|
+
# true
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# def some_filter
|
53
|
+
# true
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# def title_given
|
57
|
+
# browser.title.nil?
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
def self.filter(method_name, *elements)
|
61
|
+
elements = [:all] if elements.empty?
|
62
|
+
elements.each do |element|
|
63
|
+
self.filters[element] = self.filters[element] << method_name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize
|
68
|
+
add_element_methods
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_element_methods # :nodoc:
|
72
|
+
self.class.elements.each do |element_name,element_block|
|
73
|
+
filters = self.class.filters[element_name] + self.class.filters[:all]
|
74
|
+
add_element_method(:filters => filters, :element_name => element_name, :element_block => element_block)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_element_method(params) # :nodoc:
|
79
|
+
self.class.class_eval do
|
80
|
+
define_method(params[:element_name]) do |*args|
|
81
|
+
check_filters(params)
|
82
|
+
self.instance_exec(*args,¶ms[:element_block])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def check_filters(params) # :nodoc:
|
88
|
+
params[:filters].each do |filter_method|
|
89
|
+
raise FilterError, "#{filter_method} returned false for #{params[:element_name]}" unless send(filter_method)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class FilterError < StandardError; end
|
95
|
+
end
|