capybara-harness 0.0.8 → 0.0.9

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