makevoid-taza 0.8.6

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.
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