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.
Files changed (63) hide show
  1. data/History.txt +44 -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 +72 -0
  18. data/lib/app_generators/taza/templates/config.yml.erb +3 -0
  19. data/lib/app_generators/taza/templates/rakefile.rb.erb +3 -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 +5 -0
  23. data/lib/extensions/object.rb +24 -0
  24. data/lib/extensions/string.rb +11 -0
  25. data/lib/taza/browser.rb +33 -0
  26. data/lib/taza/entity.rb +34 -0
  27. data/lib/taza/fixture.rb +66 -0
  28. data/lib/taza/flow.rb +40 -0
  29. data/lib/taza/page.rb +95 -0
  30. data/lib/taza/settings.rb +47 -0
  31. data/lib/taza/site.rb +145 -0
  32. data/lib/taza/tasks.rb +50 -0
  33. data/lib/taza.rb +35 -0
  34. data/spec/array_spec.rb +16 -0
  35. data/spec/browser_spec.rb +63 -0
  36. data/spec/entity_spec.rb +9 -0
  37. data/spec/fixture_spec.rb +34 -0
  38. data/spec/fixtures_spec.rb +21 -0
  39. data/spec/flow_generator_spec.rb +50 -0
  40. data/spec/hash_spec.rb +12 -0
  41. data/spec/object_spec.rb +29 -0
  42. data/spec/page_generator_spec.rb +56 -0
  43. data/spec/page_spec.rb +82 -0
  44. data/spec/partial_generator_spec.rb +38 -0
  45. data/spec/project_generator_spec.rb +41 -0
  46. data/spec/sandbox/config/config.yml +1 -0
  47. data/spec/sandbox/config/site_name.yml +5 -0
  48. data/spec/sandbox/config.yml +3 -0
  49. data/spec/sandbox/fixtures/examples.yml +8 -0
  50. data/spec/sandbox/fixtures/users.yml +2 -0
  51. data/spec/sandbox/flows/batman.rb +5 -0
  52. data/spec/sandbox/flows/robin.rb +4 -0
  53. data/spec/sandbox/pages/foo/bar.rb +9 -0
  54. data/spec/sandbox/pages/foo/partials/partial_the_reckoning.rb +2 -0
  55. data/spec/settings_spec.rb +88 -0
  56. data/spec/site_generator_spec.rb +57 -0
  57. data/spec/site_spec.rb +229 -0
  58. data/spec/spec_helper.rb +57 -0
  59. data/spec/string_spec.rb +7 -0
  60. data/spec/taza_bin_spec.rb +14 -0
  61. data/spec/taza_spec.rb +12 -0
  62. data/spec/taza_tasks_spec.rb +41 -0
  63. metadata +181 -0
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'taza'
3
+
4
+ module <%= name.camelize %>
5
+ include ForwardInitialization
6
+
7
+ class <%= name.camelize %> < ::Taza::Site
8
+
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ ---
2
+ isolation:
3
+ :url: http://www.google.com
@@ -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,3 @@
1
+ ---
2
+ :browser: :firefox
3
+ :driver: :selenium
@@ -0,0 +1,3 @@
1
+ <%= "#Generated at #{Time.now}" %>
2
+ require 'rubygems'
3
+ require 'taza/tasks'
@@ -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,5 @@
1
+ class Hash
2
+ def convert_hash_keys_to_methods(fixture) # :nodoc:
3
+ Taza::Entity.new(self,fixture)
4
+ end
5
+ 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
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'activesupport'
3
+
4
+ class String
5
+ # pluralizes a string and turns it into a symbol
6
+ # Example:
7
+ # "apple".pluralize_to_sym # => :apples
8
+ def pluralize_to_sym
9
+ self.pluralize.to_sym
10
+ end
11
+ end
@@ -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
+
@@ -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
@@ -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,&params[: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