taza 0.5.0 → 0.8.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/History.txt +33 -0
- data/Manifest.txt +39 -9
- data/README.txt +29 -7
- data/Rakefile +72 -13
- data/bin/taza +16 -3
- data/generators/flow/flow_generator.rb +57 -0
- data/generators/flow/templates/flow.rb.erb +12 -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/site/site_generator.rb +55 -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 +76 -0
- data/lib/app_generators/taza/templates/config.yml.erb +3 -0
- data/lib/{taza/generators → app_generators/taza}/templates/rakefile.rb.erb +0 -0
- data/lib/app_generators/taza/templates/spec_helper.rb.erb +11 -0
- data/lib/taza.rb +44 -5
- data/lib/taza/browser.rb +40 -0
- data/lib/taza/browsers/ie_watir.rb +8 -0
- data/lib/taza/browsers/safari_watir.rb +8 -0
- data/lib/taza/flow.rb +45 -0
- data/lib/taza/page.rb +66 -19
- data/lib/taza/settings.rb +36 -0
- data/lib/taza/site.rb +122 -11
- data/lib/taza/tasks.rb +26 -34
- data/spec/browser_spec.rb +72 -0
- data/spec/flow_generator_spec.rb +70 -0
- data/spec/page_generator_spec.rb +57 -0
- data/spec/page_spec.rb +82 -0
- data/spec/platform/osx/browser_spec.rb +14 -0
- data/spec/platform/windows/browser_spec.rb +14 -0
- data/spec/project_generator_spec.rb +42 -0
- data/spec/sandbox/config.yml +3 -0
- data/spec/sandbox/config/config.yml +1 -0
- data/spec/sandbox/config/site_name.yml +5 -0
- data/spec/sandbox/flows/batman.rb +2 -0
- data/spec/sandbox/flows/robin.rb +4 -0
- data/spec/sandbox/pages/foo/bar.rb +9 -0
- data/spec/settings_spec.rb +88 -0
- data/spec/site_generator_spec.rb +53 -0
- data/spec/site_spec.rb +239 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/taza_bin_spec.rb +14 -0
- data/spec/taza_spec.rb +12 -0
- data/spec/taza_tasks_spec.rb +27 -0
- data/spec/unit_helper_spec.rb +14 -0
- metadata +103 -13
- data/lib/taza/generators.rb +0 -4
- data/lib/taza/generators/base.rb +0 -33
- data/lib/taza/generators/page.rb +0 -22
- data/lib/taza/generators/project.rb +0 -18
- data/lib/taza/generators/site.rb +0 -24
- data/lib/taza/generators/templates/page.rb.erb +0 -6
- data/lib/taza/generators/templates/site.rb.erb +0 -6
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubigen'
|
3
|
+
require 'activesupport'
|
4
|
+
|
5
|
+
class SiteGenerator < RubiGen::Base
|
6
|
+
default_options :author => nil
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
def initialize(runtime_args, runtime_options = {})
|
10
|
+
super
|
11
|
+
usage if args.empty?
|
12
|
+
@name = args.shift
|
13
|
+
extract_options
|
14
|
+
end
|
15
|
+
|
16
|
+
def manifest
|
17
|
+
record do |m|
|
18
|
+
site_path = File.join('lib','sites')
|
19
|
+
m.template "site.rb.erb", File.join(site_path,"#{name.underscore}.rb")
|
20
|
+
m.directory File.join(site_path,"#{name.underscore}")
|
21
|
+
m.directory File.join(site_path,("#{name.underscore}"),"flows")
|
22
|
+
m.directory File.join(site_path,("#{name.underscore}"),"pages")
|
23
|
+
m.directory File.join('spec','functional',name.underscore)
|
24
|
+
m.template "site.yml.erb", File.join('config',"#{name.underscore}.yml")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
def banner
|
30
|
+
<<-EOS
|
31
|
+
Creates a taza site.
|
32
|
+
|
33
|
+
USAGE: #{$0} #{spec.name} name
|
34
|
+
EOS
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_options!(opts)
|
38
|
+
# opts.separator ''
|
39
|
+
# opts.separator 'Options:'
|
40
|
+
# For each option below, place the default
|
41
|
+
# at the top of the file next to "default_options"
|
42
|
+
# opts.on("-a", "--author=\"Your Name\"", String,
|
43
|
+
# "Some comment about this option",
|
44
|
+
# "Default: none") { |options[:author]| }
|
45
|
+
# opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_options
|
49
|
+
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
50
|
+
# Templates can access these value via the attr_reader-generated methods, but not the
|
51
|
+
# raw instance variable value.
|
52
|
+
# @author = options[:author]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,76 @@
|
|
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
|
+
# Ensure appropriate folder(s) exists
|
22
|
+
|
23
|
+
BASEDIRS.each { |path| m.directory path }
|
24
|
+
m.directory File.join('lib','sites')
|
25
|
+
m.directory File.join('lib','flows')
|
26
|
+
m.directory File.join('spec','functional')
|
27
|
+
m.directory File.join('spec','integration')
|
28
|
+
|
29
|
+
m.template "rakefile.rb.erb", "rakefile"
|
30
|
+
m.template "config.yml.erb", File.join("config","config.yml")
|
31
|
+
m.template "spec_helper.rb.erb", File.join("spec","spec_helper.rb")
|
32
|
+
|
33
|
+
# Create stubs
|
34
|
+
# m.template_copy_each ["template.rb", "template2.rb"]
|
35
|
+
# m.file "file", "some_file_copied"
|
36
|
+
# m.file_copy_each ["path/to/file", "path/to/file2"]
|
37
|
+
|
38
|
+
m.dependency "install_rubigen_scripts", [destination_root, 'taza'],
|
39
|
+
:shebang => options[:shebang], :collision => :force
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
def banner
|
45
|
+
<<-EOS
|
46
|
+
USAGE: #{spec.name} path/for/your/test/project [options]
|
47
|
+
EOS
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_options!(opts)
|
51
|
+
opts.separator ''
|
52
|
+
opts.separator 'Options:'
|
53
|
+
# For each option below, place the default
|
54
|
+
# at the top of the file next to "default_options"
|
55
|
+
# opts.on("-a", "--author=\"Your Name\"", String,
|
56
|
+
# "Some comment about this option",
|
57
|
+
# "Default: none") { |options[:author]| }
|
58
|
+
opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
59
|
+
end
|
60
|
+
|
61
|
+
def extract_options
|
62
|
+
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
63
|
+
# Templates can access these value via the attr_reader-generated methods, but not the
|
64
|
+
# raw instance variable value.
|
65
|
+
# @author = options[:author]
|
66
|
+
end
|
67
|
+
|
68
|
+
# Installation skeleton. Intermediate directories are automatically
|
69
|
+
# created so don't sweat their absence here.
|
70
|
+
BASEDIRS = %w(
|
71
|
+
lib
|
72
|
+
config
|
73
|
+
script
|
74
|
+
spec
|
75
|
+
)
|
76
|
+
end
|
File without changes
|
@@ -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
|
data/lib/taza.rb
CHANGED
@@ -1,13 +1,52 @@
|
|
1
|
-
require 'taza/generators'
|
2
1
|
require 'taza/page'
|
3
2
|
require 'taza/site'
|
4
|
-
require 'taza/
|
3
|
+
require 'taza/browser'
|
4
|
+
require 'taza/settings'
|
5
|
+
require 'taza/flow'
|
5
6
|
|
6
7
|
module Taza
|
7
|
-
VERSION = '0.
|
8
|
-
|
8
|
+
VERSION = '0.8.0'
|
9
|
+
|
9
10
|
def self.windows?
|
10
11
|
PLATFORM.include?("mswin")
|
11
12
|
end
|
12
|
-
|
13
|
+
def self.osx?
|
14
|
+
PLATFORM.include?("darwin")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ForwardInitialization
|
19
|
+
module ClassMethods
|
20
|
+
def new(*args,&block)
|
21
|
+
const_get("#{name.split("::").last}").new(*args,&block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.included(klass)
|
26
|
+
klass.extend(ClassMethods)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# instance_exec comes with >1.8.7 thankfully
|
31
|
+
if VERSION <= '1.8.6'
|
32
|
+
class Object
|
33
|
+
module InstanceExecHelper; end
|
34
|
+
include InstanceExecHelper
|
35
|
+
def instance_exec(*args, &block)
|
36
|
+
begin
|
37
|
+
old_critical, Thread.critical = Thread.critical, true
|
38
|
+
n = 0
|
39
|
+
n += 1 while respond_to?(mname="__instance_exec#{n}")
|
40
|
+
InstanceExecHelper.module_eval{ define_method(mname, &block) }
|
41
|
+
ensure
|
42
|
+
Thread.critical = old_critical
|
43
|
+
end
|
44
|
+
begin
|
45
|
+
ret = send(mname, *args)
|
46
|
+
ensure
|
47
|
+
InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
|
48
|
+
end
|
49
|
+
ret
|
50
|
+
end
|
51
|
+
end
|
13
52
|
end
|
data/lib/taza/browser.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'taza/browsers/ie_watir'
|
2
|
+
require 'taza/browsers/safari_watir'
|
3
|
+
|
4
|
+
module Taza
|
5
|
+
class Browser
|
6
|
+
|
7
|
+
# Create a browser instance depending on configuration. Configuration should be read in via Taza::Settings.config.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
# browser = Taza::Browser.create(Taza::Settings.config)
|
11
|
+
#
|
12
|
+
def self.create(params={})
|
13
|
+
self.send("create_#{params[:driver]}".to_sym,params)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def self.create_watir(params)
|
20
|
+
method = "create_watir_#{params[:browser]}"
|
21
|
+
raise BrowserUnsupportedError unless self.respond_to?(method)
|
22
|
+
watir = self.send(method)
|
23
|
+
watir
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create_selenium(params)
|
27
|
+
require 'selenium'
|
28
|
+
Selenium::SeleniumDriver.new(params[:server_ip],params[:server_port],'*' + params[:browser].to_s,params[:timeout])
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.create_watir_firefox
|
32
|
+
require 'firewatir'
|
33
|
+
FireWatir::Firefox.new()
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class BrowserUnsupportedError < StandardError
|
40
|
+
end
|
data/lib/taza/flow.rb
ADDED
@@ -0,0 +1,45 @@
|
|
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
|
+
# class CreateAnAccount < Taza::Flow
|
16
|
+
# alias :widgets_of_the_future :site
|
17
|
+
#
|
18
|
+
# def run(params={})
|
19
|
+
# widgets_of_the_future.home_page.create_an_account_link.click
|
20
|
+
# widgets_of_the_future.create_an_account_page do |cap|
|
21
|
+
# cap.email.set params[:email]
|
22
|
+
# cap.password.set params[:password]
|
23
|
+
# cap.submit.click
|
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.flow :create_an_account, :email => "i.am@the.widget.store.com", :password => "secret"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
class Flow
|
39
|
+
attr_reader :site
|
40
|
+
|
41
|
+
def initialize(site_instance)
|
42
|
+
@site = site_instance
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/taza/page.rb
CHANGED
@@ -1,21 +1,66 @@
|
|
1
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
|
2
16
|
class Page
|
17
|
+
attr_accessor :browser
|
3
18
|
class << self
|
4
|
-
|
19
|
+
def elements # :nodoc:
|
20
|
+
@elements ||= {}
|
21
|
+
end
|
22
|
+
def filters # :nodoc:
|
23
|
+
@filters ||= Hash.new { [] }
|
24
|
+
end
|
5
25
|
end
|
6
26
|
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
10
34
|
def self.element(name,&block)
|
11
35
|
self.elements[name] = block
|
12
36
|
end
|
13
37
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
19
64
|
end
|
20
65
|
end
|
21
66
|
|
@@ -23,25 +68,27 @@ module Taza
|
|
23
68
|
add_element_methods
|
24
69
|
end
|
25
70
|
|
26
|
-
def add_element_methods
|
71
|
+
def add_element_methods # :nodoc:
|
27
72
|
self.class.elements.each do |element_name,element_block|
|
28
73
|
filters = self.class.filters[element_name] + self.class.filters[:all]
|
29
|
-
add_element_method(:filters => filters, :
|
74
|
+
add_element_method(:filters => filters, :element_name => element_name, :element_block => element_block)
|
30
75
|
end
|
31
76
|
end
|
32
77
|
|
33
|
-
def add_element_method(params)
|
78
|
+
def add_element_method(params) # :nodoc:
|
34
79
|
self.class.class_eval do
|
35
|
-
define_method(params[:
|
36
|
-
params
|
37
|
-
|
38
|
-
raise FilterError, "#{filter_name} returned false for #{params[:method_name]}"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
params[:method_block].call
|
80
|
+
define_method(params[:element_name]) do |*args|
|
81
|
+
check_filters(params)
|
82
|
+
self.instance_exec(*args,¶ms[:element_block])
|
42
83
|
end
|
43
84
|
end
|
44
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
|
45
92
|
end
|
46
93
|
|
47
94
|
class FilterError < StandardError; end
|