page_magic 2.0.0.alpha1 → 2.0.0

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