page_magic 2.0.0.alpha1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -2
  3. data/.zsh_config +5 -5
  4. data/Dockerfile +2 -1
  5. data/Gemfile +2 -1
  6. data/Gemfile.lock +9 -5
  7. data/Makefile +7 -3
  8. data/README.md +16 -4
  9. data/VERSION +1 -1
  10. data/lib/active_support/core_ext/object/to_query.rb +6 -6
  11. data/lib/page_magic.rb +15 -16
  12. data/lib/page_magic/class_methods.rb +1 -1
  13. data/lib/page_magic/comparator.rb +37 -0
  14. data/lib/page_magic/comparator/fuzzy.rb +23 -0
  15. data/lib/page_magic/comparator/literal.rb +22 -0
  16. data/lib/page_magic/comparator/null.rb +26 -0
  17. data/lib/page_magic/comparator/parameter_map.rb +52 -0
  18. data/lib/page_magic/drivers.rb +2 -2
  19. data/lib/page_magic/element.rb +19 -8
  20. data/lib/page_magic/element/locators.rb +4 -4
  21. data/lib/page_magic/element/not_found.rb +38 -0
  22. data/lib/page_magic/element/query.rb +19 -27
  23. data/lib/page_magic/element/query/multiple_results.rb +21 -0
  24. data/lib/page_magic/element/query/prefetched_result.rb +26 -0
  25. data/lib/page_magic/element/query/single_result.rb +20 -0
  26. data/lib/page_magic/element/selector.rb +38 -16
  27. data/lib/page_magic/element/selector/methods.rb +18 -0
  28. data/lib/page_magic/element/selector/model.rb +21 -0
  29. data/lib/page_magic/element_context.rb +5 -21
  30. data/lib/page_magic/element_definition_builder.rb +17 -24
  31. data/lib/page_magic/elements.rb +62 -102
  32. data/lib/page_magic/elements/config.rb +103 -0
  33. data/lib/page_magic/elements/inheritance_hooks.rb +15 -0
  34. data/lib/page_magic/elements/types.rb +25 -0
  35. data/lib/page_magic/exceptions.rb +3 -0
  36. data/lib/page_magic/instance_methods.rb +2 -2
  37. data/lib/page_magic/mapping.rb +79 -0
  38. data/lib/page_magic/session.rb +10 -32
  39. data/lib/page_magic/session_methods.rb +1 -1
  40. data/lib/page_magic/transitions.rb +49 -0
  41. data/lib/page_magic/utils/string.rb +4 -0
  42. data/lib/page_magic/utils/url.rb +20 -0
  43. data/lib/page_magic/watcher.rb +10 -17
  44. data/lib/page_magic/watchers.rb +28 -15
  45. data/spec/page_magic/class_methods_spec.rb +64 -37
  46. data/spec/page_magic/comparator/fuzzy_spec.rb +44 -0
  47. data/spec/page_magic/comparator/literal_spec.rb +41 -0
  48. data/spec/page_magic/comparator/null_spec.rb +35 -0
  49. data/spec/page_magic/comparator/parameter_map_spec.rb +75 -0
  50. data/spec/page_magic/driver_spec.rb +25 -29
  51. data/spec/page_magic/drivers/poltergeist_spec.rb +4 -7
  52. data/spec/page_magic/drivers/rack_test_spec.rb +4 -9
  53. data/spec/page_magic/drivers/selenium_spec.rb +9 -12
  54. data/spec/page_magic/drivers_spec.rb +36 -29
  55. data/spec/page_magic/element/locators_spec.rb +26 -25
  56. data/spec/page_magic/element/not_found_spec.rb +24 -0
  57. data/spec/page_magic/element/query/multiple_results_spec.rb +14 -0
  58. data/spec/page_magic/element/query/single_result_spec.rb +21 -0
  59. data/spec/page_magic/element/query_spec.rb +26 -47
  60. data/spec/page_magic/element/selector_spec.rb +118 -110
  61. data/spec/page_magic/element_context_spec.rb +46 -88
  62. data/spec/page_magic/element_definition_builder_spec.rb +12 -71
  63. data/spec/page_magic/element_spec.rb +256 -0
  64. data/spec/page_magic/elements/config_spec.rb +200 -0
  65. data/spec/page_magic/elements_spec.rb +87 -138
  66. data/spec/page_magic/instance_methods_spec.rb +63 -63
  67. data/spec/page_magic/mapping_spec.rb +181 -0
  68. data/spec/page_magic/session_methods_spec.rb +27 -25
  69. data/spec/page_magic/session_spec.rb +109 -198
  70. data/spec/page_magic/transitions_spec.rb +43 -0
  71. data/spec/page_magic/utils/string_spec.rb +20 -27
  72. data/spec/page_magic/utils/url_spec.rb +9 -0
  73. data/spec/page_magic/wait_methods_spec.rb +14 -22
  74. data/spec/page_magic/watcher_spec.rb +22 -0
  75. data/spec/page_magic/watchers_spec.rb +56 -62
  76. data/spec/page_magic_spec.rb +27 -24
  77. data/spec/spec_helper.rb +7 -3
  78. data/spec/support/shared_examples.rb +15 -17
  79. metadata +48 -15
  80. data/lib/page_magic/element/query_builder.rb +0 -61
  81. data/lib/page_magic/element/selector_methods.rb +0 -16
  82. data/lib/page_magic/matcher.rb +0 -130
  83. data/spec/element_spec.rb +0 -251
  84. data/spec/page_magic/element/query_builder_spec.rb +0 -110
  85. data/spec/page_magic/matcher_spec.rb +0 -338
  86. data/spec/support/shared_contexts/files_context.rb +0 -9
  87. data/spec/support/shared_contexts/nested_elements_html_context.rb +0 -18
  88. data/spec/support/shared_contexts/rack_application_context.rb +0 -11
  89. data/spec/support/shared_contexts/webapp_fixture_context.rb +0 -41
  90. data/spec/watcher_spec.rb +0 -64
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4eec3ec93f7cd6ba430ba78860160822632cdc8949da2aea83afddc3366ea3d3
4
- data.tar.gz: e3b3634979f0499bd0db1012a209a2d12cce94b7c0b870b1e91d3f8048e3f92b
3
+ metadata.gz: 92b6df866c2bbcae9351e24417bf141c50101f96b74ce6a1225318998c30da9b
4
+ data.tar.gz: 2a605e1c74eda006717474066d6824806a20f35ca05ddeef75d684951ebea257
5
5
  SHA512:
6
- metadata.gz: afe8591e16f7afaa2e464b48ac9eabff046a140df8558dee5bb51aa3eac0ccb43c43cbb43eb7af9d7a2529f242f1cc87b7f63160c5c70decb3bbc9d2cd8d060a
7
- data.tar.gz: 95802bd6ab8e1acca9f0d8142452469a743177cdbbf3a44e679016960a23bfe56b453ad53db758bd9ce9edc82f388f90a03c72f76341c24ff517995678e9f2eb
6
+ metadata.gz: 773b643dcf348bd77718e53e924754dd47d23e2edc1bbc1c904a82d332a66b00f9d7285c409a91be37d7ecca27cdbb11f62d6b938ea47e7a9396a2dd97a724d3
7
+ data.tar.gz: 7864c97e2e3b196809835ad8a9d4ede8fd44a7ad84276a3bd06d72fb706b2400437ded32301f5e5bb299d13cbfbe2314d606c57fc1de809dfa396e3d8070de85
data/.rubocop.yml CHANGED
@@ -1,7 +1,10 @@
1
- Metrics/LineLength:
1
+ require: rubocop-rspec
2
+
3
+ Layout/LineLength:
2
4
  Max: 120
3
5
 
4
6
  AllCops:
7
+ NewCops: enable
5
8
  TargetRubyVersion: 2.7
6
9
  Exclude:
7
10
  - 'lib/active_support/**/*'
@@ -33,4 +36,4 @@ Style/PercentLiteralDelimiters:
33
36
  '%I': '[]'
34
37
  '%r': '{}'
35
38
  '%w': '[]'
36
- '%W': '[]'
39
+ '%W': '[]'
data/.zsh_config CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bash
2
- #alias bundle="docker run -v ${HOME}/.gitconfig:/root/.gitconfig -v $(pwd):/page_magic -t lvl-up/page-magic bundle"
3
- #alias ruby="bundle exec ruby"
4
- #alias rake="bundle exec rake"
5
- #alias rubocop="bundle exec rubocop"
6
- #alias gem="docker run -v $(pwd):/page_magic -t lvl-up/page-magic gem"
2
+ alias bundle="docker run -v $(pwd):/page_magic -t lvl-up/page-magic bundle"
3
+ alias ruby="bundle exec ruby"
4
+ alias rake="bundle exec rake"
5
+ alias rubocop="bundle exec rubocop"
6
+ alias gem="docker run -v $(pwd):/page_magic -t lvl-up/page-magic gem"
data/Dockerfile CHANGED
@@ -7,4 +7,5 @@ COPY . $APP_HOME
7
7
  WORKDIR $APP_HOME
8
8
 
9
9
  RUN apk --update --no-cache add build-base git
10
- RUN bundle install
10
+ RUN bundle install
11
+ RUN rm -rf $APP_HOME
data/Gemfile CHANGED
@@ -3,7 +3,7 @@
3
3
  source 'https://rubygems.org'
4
4
 
5
5
  gem 'activesupport'
6
- gem 'capybara', ">=3.0"
6
+ gem 'capybara', '>=3.0'
7
7
 
8
8
  group :test do
9
9
  gem 'poltergeist'
@@ -18,6 +18,7 @@ group :development do
18
18
  gem 'jeweler'
19
19
  gem 'redcarpet'
20
20
  gem 'rubocop', require: 'rubocop/rake_task'
21
+ gem 'rubocop-rspec', require: false
21
22
  gem 'ruby-debug-ide', require: false
22
23
  gem 'yard', '~> 0.8'
23
24
  end
data/Gemfile.lock CHANGED
@@ -72,7 +72,7 @@ GEM
72
72
  multi_xml (~> 0.5)
73
73
  rack (>= 1.2, < 3)
74
74
  parallel (1.20.1)
75
- parser (3.0.1.0)
75
+ parser (3.0.1.1)
76
76
  ast (~> 2.4.1)
77
77
  poltergeist (1.18.1)
78
78
  capybara (>= 2.1, < 4)
@@ -105,17 +105,20 @@ GEM
105
105
  diff-lcs (>= 1.2.0, < 2.0)
106
106
  rspec-support (~> 3.10.0)
107
107
  rspec-support (3.10.2)
108
- rubocop (1.12.1)
108
+ rubocop (1.15.0)
109
109
  parallel (~> 1.10)
110
110
  parser (>= 3.0.0.0)
111
111
  rainbow (>= 2.2.2, < 4.0)
112
112
  regexp_parser (>= 1.8, < 3.0)
113
113
  rexml
114
- rubocop-ast (>= 1.2.0, < 2.0)
114
+ rubocop-ast (>= 1.5.0, < 2.0)
115
115
  ruby-progressbar (~> 1.7)
116
116
  unicode-display_width (>= 1.4.0, < 3.0)
117
- rubocop-ast (1.4.1)
118
- parser (>= 2.7.1.5)
117
+ rubocop-ast (1.5.0)
118
+ parser (>= 3.0.1.1)
119
+ rubocop-rspec (2.1.0)
120
+ rubocop (~> 1.0)
121
+ rubocop-ast (>= 1.1.0)
119
122
  ruby-debug-ide (0.7.2)
120
123
  rake (>= 0.8.1)
121
124
  ruby-progressbar (1.11.0)
@@ -164,6 +167,7 @@ DEPENDENCIES
164
167
  redcarpet
165
168
  rspec
166
169
  rubocop
170
+ rubocop-rspec
167
171
  ruby-debug-ide
168
172
  simplecov
169
173
  sinatra
data/Makefile CHANGED
@@ -1,13 +1,17 @@
1
1
  .PHONY: help
2
2
  DOCKER_IMAGE = lvl-up/page-magic
3
+ MOUNT_DIR = /page_magic
3
4
 
4
5
  help:
5
6
  @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
6
7
 
7
- build: ## build project docker image
8
+ docker: ## build project docker image
8
9
  docker build -t $(DOCKER_IMAGE) .
9
10
 
10
11
  test: ## Run tests
11
- docker run -v $(PWD):/usr/src/app -t $(DOCKER_IMAGE) bundle exec rspec
12
+ docker run -v $(PWD):$(MOUNT_DIR) -w $(MOUNT_DIR) -t $(DOCKER_IMAGE) bundle exec rspec
12
13
 
13
- all: test
14
+ build: docker ## build gem
15
+ rake build
16
+
17
+ all: docker test build ## run all targets before building gem
data/README.md CHANGED
@@ -59,7 +59,7 @@ Check it out :)
59
59
  - [Page mapping](#page-mapping)
60
60
  - [Mapping against query string parameters](#mapping-against-query-string-parameters)
61
61
  - [Mapping against fragment identifiers](#mapping-against-fragment-identifiers)
62
- - [Loading pages from source](#loading-pages-from-source)
62
+ - [Loading pages/elements from source](#loading-pages/elements-from-source)
63
63
  - [Watchers](#watchers)
64
64
  - [Method watchers](#method-watchers)
65
65
  - [Simple watchers](#simple-watchers)
@@ -381,16 +381,27 @@ against URL fragments.
381
381
  browser.define_page_mappings PageMagic.mapping(fragment: string_or_regex) => ResultsPage
382
382
  ```
383
383
 
384
- # Loading pages from source
384
+ # Loading pages/elements from source
385
385
  PageMagic supports loading page objects using html source. This technique can be useful for getting quick feedback that
386
- your templates correctly render based on your view objects. I.e you can test your templates in isolation.
386
+ your templates correctly render based on your view objects. I.e you can test your templates and partials/fragments in isolation.
387
387
  ```ruby
388
388
  class MyPage
389
389
  include PageMagic
390
+ element(:link, id: 'link_id')
390
391
  #element definitions
391
392
  end
392
393
 
393
394
  page_instance = Page.load(html_string)
395
+ page_instance.link.text # returns the link text
396
+
397
+
398
+ class CustomElement < PageMagic::Element
399
+ element(:link, id: 'link_id')
400
+ #element definitions
401
+ end
402
+
403
+ page_element = CustomElement.load(html_string)
404
+ page_element.link.text # returns the link text
394
405
  ```
395
406
 
396
407
  # Watchers
@@ -453,7 +464,8 @@ You can register any Capybara compliant driver as follows
453
464
  Webkit = PageMagic::Driver.new(:webkit) do |app, options, browser_alias_chosen|
454
465
  # Write the code necessary to initialise the driver you have chosen
455
466
  require 'capybara/webkit'
456
- Capybara::Webkit::Driver.new(app, options)
467
+ Capybara::Webkit::Driver.new(app,
468
+ )
457
469
  end
458
470
 
459
471
  #2. Register driver
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0.alpha1
1
+ 2.0.0
@@ -59,14 +59,14 @@ end
59
59
  class Hash
60
60
  # Returns a string representation of the receiver suitable for use as a URL
61
61
  # query string:
62
- #
63
- # {name: 'David', nationality: 'Danish'}.to_query
64
- # # => "name=David&nationality=Danish"
62
+ # @example
63
+ # {name: 'David', nationality: 'Danish'}.to_query
64
+ # # => "name=David&nationality=Danish"
65
65
  #
66
66
  # An optional namespace can be passed to enclose key names:
67
- #
68
- # {name: 'David', nationality: 'Danish'}.to_query('user')
69
- # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
67
+ # @example
68
+ # {name: 'David', nationality: 'Danish'}.to_query('user')
69
+ # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
70
70
  #
71
71
  # The string pairs "key=value" that conform the query string
72
72
  # are sorted lexicographically in ascending order.
data/lib/page_magic.rb CHANGED
@@ -1,18 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $LOAD_PATH.unshift(File.dirname(__FILE__).to_s)
4
3
  require 'capybara'
5
- require 'page_magic/exceptions'
6
- require 'page_magic/wait_methods'
7
- require 'page_magic/watchers'
8
- require 'page_magic/session'
9
- require 'page_magic/session_methods'
10
- require 'page_magic/elements'
11
- require 'page_magic/element_context'
12
- require 'page_magic/element'
13
- require 'page_magic/class_methods'
14
- require 'page_magic/instance_methods'
15
- require 'page_magic/drivers'
4
+ require_relative 'page_magic/exceptions'
5
+ require_relative 'page_magic/wait_methods'
6
+ require_relative 'page_magic/watchers'
7
+ require_relative 'page_magic/session'
8
+ require_relative 'page_magic/session_methods'
9
+ require_relative 'page_magic/elements'
10
+ require_relative 'page_magic/element_context'
11
+ require_relative 'page_magic/element'
12
+ require_relative 'page_magic/class_methods'
13
+ require_relative 'page_magic/instance_methods'
14
+ require_relative 'page_magic/drivers'
16
15
 
17
16
  # module PageMagic - PageMagic is an api for modelling pages in a website.
18
17
  module PageMagic
@@ -20,9 +19,9 @@ module PageMagic
20
19
 
21
20
  # @!method matcher
22
21
  # define match critera for loading a page object class
23
- # @see Matcher#initialize
24
- # @return [Matcher]
25
- def_delegator Matcher, :new, :matcher
22
+ # @see Mapping#initialize
23
+ # @return [Mapping]
24
+ def_delegator Mapping, :new, :matcher
26
25
 
27
26
  class << self
28
27
  # @return [Drivers] registered drivers
@@ -43,7 +42,7 @@ module PageMagic
43
42
  # PageMagic.mapping '/', parameters: {project: 'page_magic'}, fragment: 'display'
44
43
  # @see Matchers#initialize
45
44
  def mapping(path = nil, parameters: nil, fragment: nil)
46
- Matcher.new(path, parameters: parameters, fragment: fragment)
45
+ Mapping.new(path, parameters: parameters, fragment: fragment)
47
46
  end
48
47
 
49
48
  # Visit this page based on the class level registered url
@@ -30,7 +30,7 @@ module PageMagic
30
30
 
31
31
  # Visit this page based on the class level registered url
32
32
  # @param [Object] application rack application (optional)
33
- # @param [Symbol] browser name of browser
33
+ # @param [Symbol] browser name of browser driver to use
34
34
  # @param [Hash] options browser driver specific options
35
35
  # @return [Session] active session configured to be using an instance of the page object modeled by this class
36
36
  def visit(application: nil, browser: :rack_test, options: {})
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'comparator/fuzzy'
4
+ require_relative 'comparator/literal'
5
+ require_relative 'comparator/parameter_map'
6
+ require_relative 'comparator/null'
7
+
8
+ module PageMagic
9
+ # class Comparator - used for comparing components used for mapping pages
10
+ class Comparator
11
+ class << self
12
+ def for(comparator)
13
+ klass = { Regexp => Fuzzy, Hash => ParameterMap, NilClass => Null }.fetch(comparator.class, Literal)
14
+ klass.new(comparator)
15
+ end
16
+ end
17
+
18
+ attr_reader :comparator, :fuzzy
19
+
20
+ def initialize(comparator, fuzzy)
21
+ @comparator = comparator
22
+ @fuzzy = fuzzy
23
+ end
24
+
25
+ def fuzzy?
26
+ fuzzy
27
+ end
28
+
29
+ def to_s
30
+ comparator.to_s
31
+ end
32
+
33
+ def ==(other)
34
+ comparator == other.comparator
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PageMagic
4
+ class Comparator
5
+ # class Fuzzy - used for modeling and comparing components that are 'fuzzy' i.e. respond to `=~` e.g. a Regexp
6
+ class Fuzzy < Comparator
7
+ def initialize(comparator)
8
+ super(comparator, true)
9
+ end
10
+
11
+ def match?(value)
12
+ comparator =~ value ? true : false
13
+ end
14
+
15
+ def <=>(other)
16
+ return -1 if other.is_a?(Null)
17
+ return 1 unless other.fuzzy?
18
+
19
+ 0
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PageMagic
4
+ class Comparator
5
+ # class Literal - used for modeling and comparing thing directly. E.g. strings
6
+ class Literal < Comparator
7
+ def initialize(comparator)
8
+ super(comparator, false)
9
+ end
10
+
11
+ def match?(value)
12
+ comparator == value
13
+ end
14
+
15
+ def <=>(other)
16
+ return 1 if other.fuzzy? || other.is_a?(Null)
17
+
18
+ 0
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PageMagic
4
+ class Comparator
5
+ # models mapping used to relate pages to uris
6
+ class Null < Comparator
7
+ def initialize(_comparator = nil)
8
+ super(nil, false)
9
+ end
10
+
11
+ def match?(_value)
12
+ true
13
+ end
14
+
15
+ def <=>(other)
16
+ return 0 if other.is_a?(Null)
17
+
18
+ 1
19
+ end
20
+
21
+ def present?
22
+ false
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PageMagic
4
+ class Comparator
5
+ # class Map - used to model parameter matching requirements
6
+ class ParameterMap < Comparator
7
+ def initialize(map)
8
+ comparator = normalise(map).keys.each_with_object({}) do |key, params|
9
+ params[key] = Comparator.for(map[key])
10
+ end
11
+
12
+ fuzzy = comparator.values.any?(&:fuzzy?)
13
+ super(comparator, fuzzy)
14
+ end
15
+
16
+ def <=>(other)
17
+ return 0 if empty? && other.empty?
18
+ return 1 if other.empty?
19
+ if (comparator.keys.size <=> other.comparator.keys.size).zero?
20
+ return literal_matchers.size <=> other.literal_matchers.size
21
+ end
22
+
23
+ 0
24
+ end
25
+
26
+ def empty?
27
+ comparator.empty?
28
+ end
29
+
30
+ def literal_matchers
31
+ comparator.values.find_all { |matcher| !matcher.fuzzy? }
32
+ end
33
+
34
+ def match?(params)
35
+ params_copy = normalise(params)
36
+ comparator.each do |key, value|
37
+ param = params_copy[key]
38
+ return false unless value&.match?(param)
39
+ end
40
+ true
41
+ end
42
+
43
+ private
44
+
45
+ def normalise(hash)
46
+ hash.keys.each_with_object({}) do |key, map|
47
+ map[key.to_sym] = hash[key]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'page_magic/driver'
4
- require 'page_magic/utils/string'
3
+ require_relative 'driver'
4
+ require_relative 'utils/string'
5
5
  module PageMagic
6
6
  # class Drivers - creates an object that can be used to hold driver definitions
7
7
  # These PageMagic gets the user's chosen driver from this object.