makevoid-taza 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/History.txt +74 -0
  2. data/Manifest.txt +61 -0
  3. data/README +79 -0
  4. data/README.textile +1 -0
  5. data/VERSION.yml +4 -0
  6. data/bin/taza +17 -0
  7. data/generators/flow/flow_generator.rb +57 -0
  8. data/generators/flow/templates/flow.rb.erb +9 -0
  9. data/generators/page/page_generator.rb +58 -0
  10. data/generators/page/templates/functional_page_spec.rb.erb +8 -0
  11. data/generators/page/templates/page.rb.erb +8 -0
  12. data/generators/partial/partial_generator.rb +57 -0
  13. data/generators/partial/templates/partial.rb.erb +7 -0
  14. data/generators/site/site_generator.rb +56 -0
  15. data/generators/site/templates/site.rb.erb +10 -0
  16. data/generators/site/templates/site.yml.erb +3 -0
  17. data/lib/app_generators/taza/taza_generator.rb +74 -0
  18. data/lib/app_generators/taza/templates/config.yml.erb +3 -0
  19. data/lib/app_generators/taza/templates/rakefile.rb.erb +10 -0
  20. data/lib/app_generators/taza/templates/spec_helper.rb.erb +11 -0
  21. data/lib/extensions/array.rb +10 -0
  22. data/lib/extensions/hash.rb +15 -0
  23. data/lib/extensions/object.rb +33 -0
  24. data/lib/extensions/string.rb +11 -0
  25. data/lib/taza.rb +24 -0
  26. data/lib/taza/browser.rb +53 -0
  27. data/lib/taza/entity.rb +55 -0
  28. data/lib/taza/fixture.rb +68 -0
  29. data/lib/taza/fixtures.rb +24 -0
  30. data/lib/taza/flow.rb +40 -0
  31. data/lib/taza/page.rb +128 -0
  32. data/lib/taza/settings.rb +33 -0
  33. data/lib/taza/site.rb +150 -0
  34. data/lib/taza/tasks.rb +54 -0
  35. data/spec/array_spec.rb +17 -0
  36. data/spec/browser_spec.rb +86 -0
  37. data/spec/entity_spec.rb +35 -0
  38. data/spec/fixture_spec.rb +51 -0
  39. data/spec/fixtures_spec.rb +47 -0
  40. data/spec/flow_generator_spec.rb +50 -0
  41. data/spec/hash_spec.rb +15 -0
  42. data/spec/object_spec.rb +29 -0
  43. data/spec/page_generator_spec.rb +56 -0
  44. data/spec/page_module_spec.rb +165 -0
  45. data/spec/page_spec.rb +105 -0
  46. data/spec/partial_generator_spec.rb +38 -0
  47. data/spec/project_generator_spec.rb +56 -0
  48. data/spec/sandbox/config.yml +3 -0
  49. data/spec/sandbox/config/config.yml +1 -0
  50. data/spec/sandbox/config/site_name.yml +5 -0
  51. data/spec/sandbox/fixtures/examples.yml +15 -0
  52. data/spec/sandbox/fixtures/foo_site/bars.yml +2 -0
  53. data/spec/sandbox/fixtures/foos.yml +3 -0
  54. data/spec/sandbox/fixtures/users.yml +3 -0
  55. data/spec/sandbox/flows/batman.rb +5 -0
  56. data/spec/sandbox/flows/robin.rb +4 -0
  57. data/spec/sandbox/pages/foo/bar.rb +9 -0
  58. data/spec/sandbox/pages/foo/bay.rb +10 -0
  59. data/spec/sandbox/pages/foo/baz.rb +11 -0
  60. data/spec/sandbox/pages/foo/partials/partial_the_reckoning.rb +2 -0
  61. data/spec/settings_spec.rb +92 -0
  62. data/spec/site_fixtures_spec.rb +17 -0
  63. data/spec/site_generator_spec.rb +56 -0
  64. data/spec/site_spec.rb +268 -0
  65. data/spec/spec_helper.rb +57 -0
  66. data/spec/string_spec.rb +8 -0
  67. data/spec/taza_bin_spec.rb +13 -0
  68. data/spec/taza_tasks_spec.rb +56 -0
  69. data/taza.gemspec +46 -0
  70. metadata +196 -0
@@ -0,0 +1,24 @@
1
+ require 'taza/fixture'
2
+
3
+ module Taza
4
+ dirs = Dir.glob(File.join(Fixture.base_path,'*/'))
5
+ dirs.unshift Fixture.base_path
6
+ dirs.each do |dir|
7
+ mod = dir.sub(Fixture.base_path,File.join(File.basename(Fixture.base_path),'')).camelize.sub(/::$/,'')
8
+ self.class_eval <<-EOS
9
+ module #{mod}
10
+ def self.included(other_module)
11
+ fixture = Fixture.new
12
+ fixture.load_fixtures_from('#{dir}')
13
+ fixture.fixture_names.each do |fixture_name|
14
+ self.class_eval do
15
+ define_method(fixture_name) do |entity_key|
16
+ fixture.get_fixture_entity(fixture_name,entity_key.to_s)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ EOS
23
+ end
24
+ end
@@ -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
@@ -0,0 +1,128 @@
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
+ if !@module.nil?
36
+ self.elements[@module] = Hash.new if self.elements[@module].nil?
37
+ self.elements[@module] = self.elements[@module].merge({ name => block })
38
+ elsif !self.elements[name].nil?
39
+ raise ElementError,"Duplicate definations for Element - #{name} on Page - #{self.to_s}"
40
+ else
41
+ self.elements[name] = block
42
+ end
43
+ end
44
+
45
+ # A filter for elemenet(s) on a page
46
+ # Example:
47
+ # class HomePage < Taza::Page
48
+ # element(:foo) {browser.element_by_xpath('some xpath')}
49
+ # filter :title_given, :foo
50
+ # #a filter will apply to all elements if none are specified
51
+ # filter :some_filter
52
+ # #a filter will also apply to all elements if the symbol :all is given
53
+ # filter :another_filter, :all
54
+ #
55
+ # def some_filter
56
+ # true
57
+ # end
58
+ #
59
+ # def some_filter
60
+ # true
61
+ # end
62
+ #
63
+ # def title_given
64
+ # browser.title.nil?
65
+ # end
66
+ # end
67
+ def self.filter(method_name, *elements)
68
+ elements = [:all] if elements.empty?
69
+ elements.each do |element|
70
+ self.filters[element] = self.filters[element] << method_name
71
+ end
72
+ end
73
+
74
+ def self.page_module(name,&block)
75
+ @module = name
76
+ yield(block)
77
+ @module = nil
78
+ end
79
+
80
+ def self.page_module_filter(method_name, page_module_name, *elements)
81
+ elements = [page_module_name] if elements.empty?
82
+ elements.each do |element|
83
+ self.filters[element] = self.filters[element] << method_name
84
+ end
85
+ end
86
+
87
+ def initialize(page_module = nil)
88
+ add_element_methods(page_module)
89
+ @active_filters = []
90
+ end
91
+
92
+ def add_element_methods(page_module = nil) # :nodoc:
93
+ self.class.elements.each do |element_name,element_block|
94
+ if (element_block.is_a?(Hash) && !page_module.nil? && page_module==element_name)
95
+ element_block.each do |key,value|
96
+ filters = self.class.filters[element_name] + self.class.filters[:all] + self.class.filters[key]
97
+ add_element_method(:filters => filters, :element_name => key, :element_block => value)
98
+ end
99
+ else
100
+ filters = self.class.filters[element_name] + self.class.filters[:all]
101
+ add_element_method(:filters => filters, :element_name => element_name, :element_block => element_block)
102
+ end
103
+ end
104
+ end
105
+
106
+ def add_element_method(params) # :nodoc:
107
+ metaclass.class_eval do
108
+ define_method(params[:element_name]) do |*args|
109
+ check_filters(params)
110
+ self.instance_exec(*args,&params[:element_block])
111
+ end
112
+ end
113
+ end
114
+
115
+ def check_filters(params) # :nodoc:
116
+ params[:filters].each do |filter_method|
117
+ unless @active_filters.include?(filter_method)
118
+ @active_filters << filter_method
119
+ raise FilterError, "#{filter_method} returned false for #{params[:element_name]}" unless send(filter_method)
120
+ @active_filters.delete(filter_method)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ class FilterError < StandardError; end
127
+ class ElementError < StandardError; end
128
+ end
@@ -0,0 +1,33 @@
1
+ require 'activesupport'
2
+ require 'taza/options'
3
+
4
+ module Taza
5
+ class Settings
6
+ # Taza::Settings.Config('google')
7
+ def self.config(site_name)
8
+ site_file(site_name).merge(Options.new.execute)
9
+ end
10
+
11
+ # Loads the config file for the entire project and returns the hash.
12
+ # Does not override settings from the ENV variables.
13
+ def self.config_file
14
+ YAML.load_file(config_file_path)
15
+ end
16
+
17
+ def self.config_file_path # :nodoc:
18
+ File.join(config_folder,'config.yml')
19
+ end
20
+
21
+ def self.config_folder # :nodoc:
22
+ File.join(path,'config')
23
+ end
24
+
25
+ def self.site_file(site_name) # :nodoc:
26
+ YAML.load_file(File.join(config_folder,"#{site_name.underscore}.yml"))[ENV['TAZA_ENV']]
27
+ end
28
+
29
+ def self.path # :nodoc:
30
+ '.'
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,150 @@
1
+ require 'rubygems'
2
+ require 'activesupport'
3
+
4
+ module Taza
5
+ # An abstraction of a website, but more really a container for a sites pages.
6
+ #
7
+ # You can generate a site by performing the following command:
8
+ # $ ./script/generate site google
9
+ #
10
+ # This will generate a site file for google, a flows folder, and a pages folder in lib
11
+ #
12
+ # Example:
13
+ #
14
+ # require 'taza'
15
+ #
16
+ # class Google < Taza::Site
17
+ #
18
+ # end
19
+ class Site
20
+ @@before_browser_closes = Proc.new() {}
21
+ @@donot_close_browser = false
22
+ # Use this to do something with the browser before it closes, but note that it is a class method which
23
+ # means that this will get called for any instance of a site.
24
+ #
25
+ # Here's an example of how you might use it to print the DOM output of a browser before it closes:
26
+ #
27
+ # Taza::Site.before_browser_closes do |browser|
28
+ # puts browser.html
29
+ # end
30
+ def self.before_browser_closes(&block)
31
+ @@before_browser_closes = block
32
+ end
33
+
34
+ def self.donot_close_browser
35
+ @@donot_close_browser = true
36
+ end
37
+ attr_accessor :browser
38
+
39
+ # A site can be called a few different ways
40
+ #
41
+ # The following example creates a new browser object and closes it:
42
+ # Google.new do
43
+ # google.search.set "taza"
44
+ # google.submit.click
45
+ # end
46
+ #
47
+ # This example will create a browser object but not close it:
48
+ # Google.new.search.set "taza"
49
+ #
50
+ # Sites can take a couple of parameters in the constructor:
51
+ # :browser => a browser object to act on instead of creating one automatically
52
+ # :url => the url of where to start the site
53
+ def initialize(params={},&block)
54
+ @module_name = self.class.parent.to_s
55
+ @class_name = self.class.to_s.split("::").last
56
+ define_site_pages
57
+ define_flows
58
+ config = Settings.config(@class_name)
59
+ if params[:browser]
60
+ @browser = params[:browser]
61
+ else
62
+ @browser = Browser.create(config)
63
+ @i_created_browser = true
64
+ end
65
+ @browser.goto(params[:url] || config[:url])
66
+ execute_block_and_close_browser(browser,&block) if block_given?
67
+ end
68
+
69
+ def execute_block_and_close_browser(browser)
70
+ begin
71
+ yield self
72
+ rescue => site_block_exception
73
+ ensure
74
+ begin
75
+ @@before_browser_closes.call(browser)
76
+ rescue => before_browser_closes_block_exception
77
+ "" # so basically rcov has a bug where it would insist this block is uncovered when empty
78
+ end
79
+ close_browser_and_raise_if site_block_exception || before_browser_closes_block_exception
80
+ end
81
+ end
82
+
83
+ def self.settings # :nodoc:
84
+ Taza::Settings.site_file(self.name.to_s.split("::").last)
85
+ end
86
+
87
+ def close_browser_and_raise_if original_error # :nodoc:
88
+ begin
89
+ @browser.close if (@i_created_browser && !@@donot_close_browser)
90
+ ensure
91
+ raise original_error if original_error
92
+ end
93
+ end
94
+
95
+ def define_site_pages # :nodoc:
96
+ Dir.glob(pages_path) do |file|
97
+ require file
98
+ page_name = File.basename(file,'.rb')
99
+ page_class = "#{@module_name}::#{page_name.camelize}"
100
+ self.class.class_eval <<-EOS
101
+ def #{page_name}(page_module = nil)
102
+ page = '#{page_class}'.constantize.new(page_module)
103
+ page.browser = @browser
104
+ yield page if block_given?
105
+ page
106
+ end
107
+ EOS
108
+ end
109
+ end
110
+
111
+ def define_flows # :nodoc:
112
+ Dir.glob(flows_path) do |file|
113
+ require file
114
+ end
115
+ end
116
+
117
+ # This is used to call a flow belonging to the site
118
+ #
119
+ # Example:
120
+ # Google.new do |google|
121
+ # google.flow(:perform_search, :query => "taza")
122
+ # end
123
+ #
124
+ # Where the flow would be defined under lib/sites/google/flows/perform_search.rb and look like:
125
+ # class PerformSearch < Taza::Flow
126
+ # alias :google :site
127
+ #
128
+ # def run(params={})
129
+ # google.search.set params[:query]
130
+ # google.submit.click
131
+ # end
132
+ # end
133
+
134
+ def pages_path # :nodoc:
135
+ File.join(path,'pages','**','*.rb')
136
+ end
137
+
138
+ def flows_path # :nodoc:
139
+ File.join(path,'flows','*.rb')
140
+ end
141
+
142
+ def path # :nodoc:
143
+ File.join(base_path,'lib','sites',@class_name.underscore)
144
+ end
145
+
146
+ def base_path # :nodoc:
147
+ '.'
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'taglob'
4
+ require 'spec/rake/spectask'
5
+
6
+ def tags
7
+ ENV['TAGS']
8
+ end
9
+
10
+ module Taza
11
+ module Rake
12
+ class Tasks
13
+ attr_accessor :spec_opts
14
+
15
+ def initialize
16
+ yield self if block_given?
17
+ define
18
+ end
19
+
20
+ def define_spec_task(name,glob_path)
21
+ Spec::Rake::SpecTask.new name do |t|
22
+ t.spec_files = Dir.taglob(glob_path,tags)
23
+ t.spec_opts << spec_opts
24
+ end
25
+ end
26
+
27
+ def define
28
+ namespace :spec do
29
+ Dir.glob('./spec/*/').each do |dir|
30
+ recurse_to_create_rake_tasks(dir)
31
+ end
32
+ end
33
+ end
34
+
35
+ def recurse_to_create_rake_tasks(dir)
36
+ basename = File.basename(dir)
37
+ spec_pattern = File.join(dir,"**","*_spec.rb")
38
+ if (not Dir.glob(spec_pattern).empty?)
39
+ define_spec_task(basename,spec_pattern)
40
+ namespace basename do
41
+ Dir.glob(File.join(dir,"*_spec.rb")).each do |spec_file|
42
+ spec_name = File.basename(spec_file,'_spec.rb')
43
+ define_spec_task(spec_name,spec_file)
44
+ end
45
+ Dir.glob(File.join(dir,"*/")).each do |sub_dir|
46
+ recurse_to_create_rake_tasks(sub_dir)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec/spec_helper'
2
+ require 'extensions/array'
3
+
4
+ describe 'Array Extensions' do
5
+ it "should know if elements are not equivilent to a subset of those elements" do
6
+ [1,2,3].should_not be_equivalent([2,3])
7
+ end
8
+ it "should know if elements are not equivilent to a larger set including those elements" do
9
+ [1,2,3].should_not be_equivalent([1,2,3,4])
10
+ end
11
+ it "should know it is equivalent if the same order" do
12
+ [1,2,3].should be_equivalent([1,2,3])
13
+ end
14
+ it "should know it is equivalent if the different orders" do
15
+ [1,2,3].should be_equivalent([2,1,3])
16
+ end
17
+ end