capybara-harness 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.rbc
3
3
  .bundle
4
4
  .idea
5
+ .rvmrc
5
6
  .config
6
7
  .yardoc
7
8
  Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -17,6 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
19
 
20
+ gem.add_development_dependency('rspec')
20
21
  gem.add_runtime_dependency('capybara', '>= 1.1')
21
22
  gem.add_runtime_dependency(%q<activesupport>, [">= 3.0"])
22
23
  end
@@ -3,11 +3,10 @@ require "capybara/dsl"
3
3
  require "capybara/harness/version"
4
4
  require "capybara/harness/dom_harness"
5
5
  require "capybara/harness/dom/attribute"
6
- require "capybara/harness/dom/configuration"
7
6
  require "capybara/harness/dom/field"
8
- require "capybara/harness/dom/field_set"
9
- require "capybara/harness/dom/form"
7
+ require "capybara/harness/dom/reader"
10
8
  require "capybara/harness/dom/subject"
9
+ require "capybara/harness/dom/writer"
11
10
 
12
11
 
13
12
  module Capybara
@@ -2,19 +2,19 @@ module Capybara::Harness::Dom
2
2
  class Attribute
3
3
  include Capybara::DSL
4
4
 
5
- attr_accessor :name, :contents
5
+ attr_accessor :name, :derived_value_block
6
6
 
7
7
  def initialize(name, options = {})
8
8
  self.name = name
9
- self.contents = options.delete(:contents)
9
+ self.derived_value_block = options.delete(:derived_value_block)
10
10
  end
11
11
 
12
- def extract_value(values = {})
13
- values = HashWithIndifferentAccess.new(values)
14
- if contents
15
- contents.call(values)
12
+ def derive_value(values = {})
13
+ puts "Finding value for #{name}"
14
+ if derived_value_block
15
+ derived_value_block.call(values)
16
16
  else
17
- values[name].to_s
17
+ values.fetch(name, "")
18
18
  end
19
19
  end
20
20
  end
@@ -0,0 +1,70 @@
1
+ module Capybara::Harness::Dom
2
+ class Reader
3
+ include Capybara::DSL
4
+
5
+ attr_accessor :attributes, :finder_attr_name, :name
6
+
7
+ def initialize
8
+ self.attributes = {}
9
+ end
10
+
11
+ def attribute(name, options = {}, &block)
12
+ self.finder_attr_name = name.to_sym if options.delete(:finder)
13
+ options.merge!(:derived_value_block => block)
14
+ attributes[name] = Capybara::Harness::Dom::Attribute.new(name, options)
15
+ end
16
+
17
+ # Public: Scans the DOM and finds the node that represents the subject.
18
+ def find_element(values = {})
19
+ page.find(".#{name} .#{finder_attr_name}", :text => finder_attr.derive_value(values)).find(:xpath, ".//ancestor::*[@class='#{name}']")
20
+ end
21
+
22
+ # Public: Scans the DOM and finds the node that represents the subject's list element.
23
+ def find_list
24
+ find("##{selector.to_s.pluralize}")
25
+ end
26
+
27
+ def find_element_through_list(values = {})
28
+ find_list.find_element(values)
29
+ end
30
+
31
+ # Public: Returns true if the subject's element is in the page's subject list.
32
+ def in_the_list?
33
+ return false unless list.has_css?(".#{selector} .#{finder_attr_name}", :text => finder_attr)
34
+ has_attrs?(element(list))
35
+ end
36
+
37
+ # Public: Returns true if the subject's element is located first in its list.
38
+ def first_in_the_list?
39
+ node = list.first(".#{selector}")
40
+ return false if node.nil?
41
+ has_attrs?(node)
42
+ end
43
+
44
+ # Public: Returns true if the subject's element is located last in its list.
45
+ def last_in_the_list?
46
+ node = list.all(".#{selector}").last
47
+ return false if node.nil?
48
+ has_attrs?(node)
49
+ end
50
+
51
+ def has_attrs?(values = {})
52
+ node = find_element(values)
53
+ attributes.each do |attr_name, attr|
54
+ text = attr.derive_value(values)
55
+ return false unless node.has_css?(".#{attr_name}", :text => text)
56
+ end
57
+
58
+ true
59
+ end
60
+
61
+ private
62
+
63
+ # Private: Returns the value of the finder attribute for this subject.
64
+ def finder_attr
65
+ attributes[finder_attr_name]
66
+ end
67
+
68
+
69
+ end
70
+ end
@@ -2,30 +2,12 @@ module Capybara::Harness::Dom
2
2
  class Subject
3
3
  include Capybara::DSL
4
4
 
5
- attr_accessor :selector, :attributes, :finder_attr_name, :values, :form
5
+ attr_accessor :dom_reader, :dom_writer, :values
6
6
 
7
- def initialize(configuration, values = {})
8
- self.selector = configuration.selector
9
- self.finder_attr_name = configuration.finder_attr_name
10
- self.attributes = configuration.attributes
11
- self.form = configuration.form
12
- reset!(values)
13
- end
14
-
15
- # Public: Returns the value of the finder attribute for this subject.
16
- def finder_attr
17
- values[finder_attr_name] || ''
18
- end
19
-
20
- # Public: Scans the DOM and finds the node that represents the subject.
21
- def element(root = nil)
22
- root = root || page
23
- root.find(".#{selector} .#{finder_attr_name}", :text => finder_attr).find(:xpath, ".//ancestor::*[@class='#{selector}']")
24
- end
25
-
26
- # Public: Scans the DOM and finds the node that represents the subject's list element.
27
- def list
28
- find("##{selector.to_s.pluralize}")
7
+ def initialize(dom_reader, dom_writer, values = {})
8
+ self.dom_reader = dom_reader
9
+ self.dom_writer = dom_writer
10
+ self.values = values
29
11
  end
30
12
 
31
13
  # Public: Scans the DOM and finds the node that represents the subject's form element and fills it with the supplied
@@ -35,59 +17,39 @@ module Capybara::Harness::Dom
35
17
  #
36
18
  # Returns nothing of interest.
37
19
  def fill_form(new_values = {})
38
- new_values = HashWithIndifferentAccess.new(new_values)
39
- form.fill(new_values)
20
+ dom_writer.fill(new_values)
40
21
  reset!(new_values)
41
22
  end
42
23
 
43
24
  # Public: Returns true if the subject's element is present on the page.
44
25
  def on_the_page?
45
- has_attrs?(element)
26
+ dom_reader.has_attrs?(self.values)
46
27
  end
47
28
 
48
- # Public: Returns true if the subject's element is in the page's subject list.
49
- def in_the_list?
50
- return false unless list.has_css?(".#{selector} .#{finder_attr_name}", :text => finder_attr)
51
- has_attrs?(element(list))
29
+ def element
30
+ @element ||= dom_reader.find_element(self.values)
52
31
  end
53
32
 
54
- # Public: Returns true if the subject's element is located first in its list.
55
- def first_in_the_list?
56
- node = list.first(".#{selector}")
57
- return false if node.nil?
58
- has_attrs?(node)
33
+ def list
34
+ @list ||= dom_reader.find_list
59
35
  end
60
36
 
61
- # Public: Returns true if the subject's element is located last in its list.
62
- def last_in_the_list?
63
- node = list.all(".#{selector}").last
64
- return false if node.nil?
65
- has_attrs?(node)
37
+ def in_the_list?
38
+ return false unless list.has_css?(".#{selector} .#{finder_attr_name}", :text => finder_attr)
39
+ has_attrs?(element(list))
66
40
  end
67
41
 
68
42
  # Public: Finds and clicks the element's link that is assigned the data attribute for the supplied action. Common actions
69
43
  # include :edit or :delete.
70
44
  def click_action(action)
71
- element.find("[data-#{selector}-action='#{action}']").click
45
+ dom_reader.find_element.find("[data-action='#{action}']").click
72
46
  end
73
47
 
74
- private
75
-
76
- def has_attrs?(node)
77
- attributes.each do |attr_name, attr|
78
- text = attr.extract_value(values)
79
- return false unless node.has_css?(".#{attr_name}", :text => text)
80
- end
81
-
82
- true
48
+ def reset!(new_values = {})
49
+ self.values = new_values
50
+ @element = nil
51
+ @list = nil
83
52
  end
84
53
 
85
- def reset!(subject_values = {})
86
- self.values = {}
87
- attributes.each do |name, attribute|
88
- values[name] = attribute.extract_value(subject_values)
89
- end
90
- self.values = HashWithIndifferentAccess.new(self.values.merge(subject_values))
91
- end
92
54
  end
93
55
  end
@@ -1,9 +1,8 @@
1
1
  module Capybara::Harness::Dom
2
- class FieldSet
2
+ class Writer
3
3
  attr_accessor :name, :fields
4
4
 
5
- def initialize(name)
6
- self.name = name
5
+ def initialize
7
6
  self.fields = []
8
7
  end
9
8
 
@@ -16,17 +15,8 @@ module Capybara::Harness::Dom
16
15
  end
17
16
 
18
17
  def fill(attrs = {})
19
- if name
20
- within("##{name}") { fill_fields(attrs) }
21
- else
22
- fill_fields(attrs)
23
- end
24
- end
25
-
26
- private
27
-
28
- def fill_fields(attrs)
29
18
  fields.each { |f| f.fill(attrs) }
30
19
  end
20
+
31
21
  end
32
22
  end
@@ -20,36 +20,48 @@ class Capybara::Harness::DomHarness
20
20
  :click_action
21
21
 
22
22
  def initialize(values = {})
23
- self.subject = Capybara::Harness::Dom::Subject.new(self.class.configuration, values)
24
- create_aliases!
23
+ self.subject = Capybara::Harness::Dom::Subject.new(self.class.dom_reader, self.class.dom_writer, values)
24
+ create_aliases!(self.class.dom_reader.name)
25
25
  end
26
26
 
27
- def self.configuration
28
- @configuration = Capybara::Harness::Dom::Configuration.new(self) unless @configuration
29
- @configuration
30
- end
31
-
32
- def self.dom_selector(name)
33
- self.configuration.selector = name
34
- end
27
+ [:reader, :writer].each do |m|
28
+ method_name = "dom_#{m}"
29
+ instance_variable_name = "@#{method_name}"
30
+ class_name = "Capybara::Harness::Dom::#{m.capitalize}"
35
31
 
36
- def self.define_form(name = nil, &block)
37
- self.configuration.set_form(name, block)
38
- end
32
+ define_singleton_method method_name do
33
+ unless instance_variable_get(instance_variable_name)
34
+ instance_variable_set(instance_variable_name, constantize(class_name).new)
35
+ end
36
+ instance_variable_get(instance_variable_name)
37
+ end
39
38
 
40
- def self.dom_attr(name, options = {})
41
- self.configuration.add_attribute(name, options)
39
+ define_singleton_method("define_#{m}") do |name = nil, &block|
40
+ send(method_name).name = name
41
+ block.call(send(method_name)) unless block.nil?
42
+ end
42
43
  end
43
44
 
44
45
  private
45
46
 
46
- def create_aliases!
47
+ def self.constantize(camel_cased_word)
48
+ names = camel_cased_word.split('::')
49
+ names.shift if names.empty? || names.first.empty?
50
+
51
+ constant = Object
52
+ names.each do |name|
53
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
54
+ end
55
+ constant
56
+ end
57
+
58
+ def create_aliases!(name)
47
59
  singleton = class << self;
48
60
  self
49
61
  end
50
62
 
51
- singleton.send(:alias_method, selector.to_sym, :element)
52
- singleton.send(:alias_method, "#{selector}_list".to_sym, :list)
63
+ singleton.send(:alias_method, name, :element)
64
+ singleton.send(:alias_method, "#{name}_list".to_sym, :list)
53
65
  end
54
66
 
55
67
  end
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Harness
3
- VERSION = "0.0.8"
3
+ VERSION = "0.0.9"
4
4
  end
5
5
  end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capybara::Harness::Dom::Attribute do
4
+
5
+ let(:values) { { first_name: 'John', last_name: 'Doe' } }
6
+
7
+ context 'when no derived value is provided' do
8
+ subject { Capybara::Harness::Dom::Attribute.new(:first_name) }
9
+
10
+ it "returns the value from the supplied array" do
11
+ subject.derive_value(values).should == 'John'
12
+ end
13
+
14
+ it "returns an empty string when there is no matching value" do
15
+ subject.derive_value({ color: 'orange'}).should == ''
16
+ end
17
+ end
18
+
19
+ context 'when an evaluation block is provided' do
20
+ subject { Capybara::Harness::Dom::Attribute.new(:name, derived_value_block: ->(attrs){ "#{attrs[:first_name]} #{attrs[:last_name]}"}) }
21
+
22
+ it "returns the value from the supplied array" do
23
+ subject.derive_value(values).should == 'John Doe'
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capybara::Harness::Dom::Reader do
4
+ subject { Capybara::Harness::Dom::Reader.new }
5
+
6
+ context 'when adding attributes' do
7
+ it "sets the attribute" do
8
+ subject.attribute :first_name
9
+ subject.attributes.values.first.name.should == :first_name
10
+ end
11
+
12
+ context 'and the finder option is set' do
13
+ before { subject.attribute :first_name, finder: true }
14
+ its(:finder_attr_name) { should == :first_name }
15
+ end
16
+
17
+ context 'and an evaluation block is supplied' do
18
+ before do
19
+ subject.attribute :first_name, finder: true do
20
+ "value"
21
+ end
22
+ end
23
+ it "sets the evaluation block on the attribute" do
24
+ subject.attributes.values.first.derived_value_block.call([]).should == "value"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ require 'capybara-harness'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-harness
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,27 +9,33 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-24 00:00:00.000000000 Z
12
+ date: 2013-01-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: capybara
16
- requirement: !ruby/object:Gem::Requirement
15
+ name: rspec
16
+ requirement: &70360036898060 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: '1.1'
22
- type: :runtime
21
+ version: '0'
22
+ type: :development
23
23
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
24
+ version_requirements: *70360036898060
25
+ - !ruby/object:Gem::Dependency
26
+ name: capybara
27
+ requirement: &70360036913400 !ruby/object:Gem::Requirement
25
28
  none: false
26
29
  requirements:
27
30
  - - ! '>='
28
31
  - !ruby/object:Gem::Version
29
32
  version: '1.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70360036913400
30
36
  - !ruby/object:Gem::Dependency
31
37
  name: activesupport
32
- requirement: !ruby/object:Gem::Requirement
38
+ requirement: &70360036912660 !ruby/object:Gem::Requirement
33
39
  none: false
34
40
  requirements:
35
41
  - - ! '>='
@@ -37,12 +43,7 @@ dependencies:
37
43
  version: '3.0'
38
44
  type: :runtime
39
45
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '3.0'
46
+ version_requirements: *70360036912660
46
47
  description: A test harness strategy to easily query and manipulate DOM elements as
47
48
  self-contained objects in the context of feature or acceptance tests.
48
49
  email:
@@ -52,6 +53,7 @@ extensions: []
52
53
  extra_rdoc_files: []
53
54
  files:
54
55
  - .gitignore
56
+ - .rspec
55
57
  - Gemfile
56
58
  - LICENSE.txt
57
59
  - README.md
@@ -60,13 +62,15 @@ files:
60
62
  - lib/capybara-harness.rb
61
63
  - lib/capybara/harness.rb
62
64
  - lib/capybara/harness/dom/attribute.rb
63
- - lib/capybara/harness/dom/configuration.rb
64
65
  - lib/capybara/harness/dom/field.rb
65
- - lib/capybara/harness/dom/field_set.rb
66
- - lib/capybara/harness/dom/form.rb
66
+ - lib/capybara/harness/dom/reader.rb
67
67
  - lib/capybara/harness/dom/subject.rb
68
+ - lib/capybara/harness/dom/writer.rb
68
69
  - lib/capybara/harness/dom_harness.rb
69
70
  - lib/capybara/harness/version.rb
71
+ - spec/dom/attribute_spec.rb
72
+ - spec/dom/reader_spec.rb
73
+ - spec/spec_helper.rb
70
74
  homepage: https://github.com/twmills/capybara-harness
71
75
  licenses: []
72
76
  post_install_message:
@@ -79,17 +83,26 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
83
  - - ! '>='
80
84
  - !ruby/object:Gem::Version
81
85
  version: '0'
86
+ segments:
87
+ - 0
88
+ hash: -1039635989425236426
82
89
  required_rubygems_version: !ruby/object:Gem::Requirement
83
90
  none: false
84
91
  requirements:
85
92
  - - ! '>='
86
93
  - !ruby/object:Gem::Version
87
94
  version: '0'
95
+ segments:
96
+ - 0
97
+ hash: -1039635989425236426
88
98
  requirements: []
89
99
  rubyforge_project:
90
- rubygems_version: 1.8.24
100
+ rubygems_version: 1.8.15
91
101
  signing_key:
92
102
  specification_version: 3
93
103
  summary: A test harness strategy to easily query and manipulate DOM elements as self-contained
94
104
  objects in the context of feature or acceptance tests.
95
- test_files: []
105
+ test_files:
106
+ - spec/dom/attribute_spec.rb
107
+ - spec/dom/reader_spec.rb
108
+ - spec/spec_helper.rb
@@ -1,23 +0,0 @@
1
- module Capybara::Harness::Dom
2
- class Configuration
3
-
4
- attr_accessor :selector, :finder_attr_name, :attributes, :form
5
-
6
- def initialize(klass)
7
- self.selector = klass.name.split('::').last.gsub("OnPage", '').underscore
8
- self.attributes = {}
9
- end
10
-
11
- def add_attribute(name, options = {})
12
- self.finder_attr_name = name.to_sym if options.has_key?(:finder) && options[:finder] == true
13
- self.attributes[name] = Capybara::Harness::Dom::Attribute.new(name, options)
14
- end
15
-
16
- def set_form(name = nil, block = nil)
17
- form = Capybara::Harness::Dom::Form.new(name)
18
- block.call(form) unless block.nil?
19
- self.form = form
20
- end
21
-
22
- end
23
- end
@@ -1,29 +0,0 @@
1
- module Capybara::Harness::Dom
2
- class Form
3
- attr_accessor :name, :elements
4
-
5
- def initialize(name = nil)
6
- self.name = name
7
- self.elements = []
8
- end
9
-
10
- def field(*args)
11
- options = args.last.is_a?(Hash) ? args.pop : {}
12
-
13
- args.each do |field_name|
14
- elements << Capybara::Harness::Dom::Field.new(options.merge(:name => field_name))
15
- end
16
- end
17
-
18
- def fieldset(name = nil, &block)
19
- fieldset = Capybara::Harness::Dom::FieldSet.new(name)
20
- block.call(fieldset)
21
- elements << fieldset
22
- end
23
-
24
- def fill(attrs = {})
25
- elements.each { |e| e.fill(attrs) }
26
- end
27
-
28
- end
29
- end