prism_checker 0.0.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 (44) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +28 -0
  3. data/README.md +673 -0
  4. data/lib/prism_checker/absence_expectation.rb +9 -0
  5. data/lib/prism_checker/check_dispatcher.rb +168 -0
  6. data/lib/prism_checker/checker.rb +83 -0
  7. data/lib/prism_checker/colorizer.rb +9 -0
  8. data/lib/prism_checker/config.rb +14 -0
  9. data/lib/prism_checker/element_wrapper.rb +59 -0
  10. data/lib/prism_checker/expectation_classifier.rb +71 -0
  11. data/lib/prism_checker/item_checker/any.rb +25 -0
  12. data/lib/prism_checker/item_checker/array.rb +27 -0
  13. data/lib/prism_checker/item_checker/checkbox.rb +29 -0
  14. data/lib/prism_checker/item_checker/element.rb +52 -0
  15. data/lib/prism_checker/item_checker/elements.rb +53 -0
  16. data/lib/prism_checker/item_checker/image.rb +22 -0
  17. data/lib/prism_checker/item_checker/input.rb +27 -0
  18. data/lib/prism_checker/item_checker/item_check/empty.rb +17 -0
  19. data/lib/prism_checker/item_checker/item_check/empty_array.rb +17 -0
  20. data/lib/prism_checker/item_checker/item_check/number.rb +17 -0
  21. data/lib/prism_checker/item_checker/item_check/regexp.rb +17 -0
  22. data/lib/prism_checker/item_checker/item_check/string.rb +25 -0
  23. data/lib/prism_checker/item_checker/item_value/array.rb +13 -0
  24. data/lib/prism_checker/item_checker/item_value/element.rb +13 -0
  25. data/lib/prism_checker/item_checker/item_value/elements.rb +13 -0
  26. data/lib/prism_checker/item_checker/item_value/image.rb +13 -0
  27. data/lib/prism_checker/item_checker/item_value/input.rb +13 -0
  28. data/lib/prism_checker/item_checker/item_value/page.rb +13 -0
  29. data/lib/prism_checker/item_checker/item_value/string.rb +13 -0
  30. data/lib/prism_checker/item_checker/item_value/textarea.rb +13 -0
  31. data/lib/prism_checker/item_checker/nil.rb +35 -0
  32. data/lib/prism_checker/item_checker/page.rb +38 -0
  33. data/lib/prism_checker/item_checker/string.rb +26 -0
  34. data/lib/prism_checker/item_checker/textarea.rb +26 -0
  35. data/lib/prism_checker/item_classifier.rb +126 -0
  36. data/lib/prism_checker/node/array.rb +26 -0
  37. data/lib/prism_checker/node/bad_expectation.rb +7 -0
  38. data/lib/prism_checker/node/base.rb +140 -0
  39. data/lib/prism_checker/node/check_fail.rb +7 -0
  40. data/lib/prism_checker/node/expectation.rb +15 -0
  41. data/lib/prism_checker/node/hash.rb +27 -0
  42. data/lib/prism_checker/report_builder.rb +78 -0
  43. data/lib/prism_checker.rb +19 -0
  44. metadata +261 -0
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemCheck
6
+ module Regexp
7
+ def check(_element, value, expectation)
8
+ value =~ expectation
9
+ end
10
+
11
+ def error_message(_element, value, expectation)
12
+ "Expected '#{value}' to match /#{expectation.source}/"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemCheck
6
+ module String
7
+ def check(_element, value, expectation)
8
+ if PrismChecker.string_comparison == :inclusion
9
+ value.to_s.include?(expectation)
10
+ else
11
+ value == expectation
12
+ end
13
+ end
14
+
15
+ def error_message(_element, value, expectation)
16
+ if PrismChecker.string_comparison == :inclusion
17
+ "Expected '#{value}' to include '#{expectation}'"
18
+ else
19
+ "Expected '#{value}' to be equal '#{expectation}'"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemValue
6
+ module Array
7
+ def value(elements)
8
+ elements.map(&:to_s).join(' ')
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemValue
6
+ module Element
7
+ def value(element)
8
+ element.text
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemValue
6
+ module Elements
7
+ def value(elements)
8
+ elements.map(&:text).join(' ')
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemValue
6
+ module Image
7
+ def value(image)
8
+ image['src']
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemValue
6
+ module Input
7
+ def value(input)
8
+ input.value
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemValue
6
+ module Page
7
+ def value(page)
8
+ page.find('body')&.text || page.text
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemValue
6
+ module String
7
+ def value(element)
8
+ element
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module ItemChecker
5
+ module ItemValue
6
+ module Textarea
7
+ def value(textarea)
8
+ textarea.value
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'item_check/string'
4
+ require_relative 'item_check/regexp'
5
+ require_relative 'item_value/string'
6
+
7
+ module PrismChecker
8
+ module ItemChecker
9
+ module Nil
10
+ class String
11
+ def self.value(_element); end
12
+
13
+ def self.check(_element, _value, _expectation)
14
+ false
15
+ end
16
+
17
+ def self.error_message(_element, _value, expectation)
18
+ "Expected '#{expectation}', got nil"
19
+ end
20
+ end
21
+
22
+ class Regexp
23
+ def self.value(_element); end
24
+
25
+ def self.check(_element, _value, _expectation)
26
+ false
27
+ end
28
+
29
+ def self.error_message(_element, _value, expectation)
30
+ "Expected '/#{expectation.source}/', got nil"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'item_value/page'
4
+ require_relative 'item_check/string'
5
+ require_relative 'item_check/regexp'
6
+
7
+ module PrismChecker
8
+ module ItemChecker
9
+ module Page
10
+ class String
11
+ extend ItemValue::Page
12
+ extend ItemCheck::String
13
+ end
14
+
15
+ class Empty
16
+ extend ItemValue::Page
17
+ extend ItemCheck::Empty
18
+ end
19
+
20
+ class Regexp
21
+ extend ItemValue::Page
22
+ extend ItemCheck::Regexp
23
+ end
24
+
25
+ class Loaded
26
+ def self.value(_element); end
27
+
28
+ def self.check(page, _value, _expectation)
29
+ page.loaded?
30
+ end
31
+
32
+ def self.error_message(_element, _value, _expectation)
33
+ 'Page is not loaded'
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'item_check/string'
4
+ require_relative 'item_check/regexp'
5
+ require_relative 'item_value/string'
6
+
7
+ module PrismChecker
8
+ module ItemChecker
9
+ module String
10
+ class String
11
+ extend ItemValue::String
12
+ extend ItemCheck::String
13
+ end
14
+
15
+ class Empty
16
+ extend ItemValue::String
17
+ extend ItemCheck::Empty
18
+ end
19
+
20
+ class Regexp
21
+ extend ItemValue::String
22
+ extend ItemCheck::Regexp
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'item_value/textarea'
4
+ require_relative 'item_check/string'
5
+ require_relative 'item_check/regexp'
6
+
7
+ module PrismChecker
8
+ module ItemChecker
9
+ module Textarea
10
+ class String
11
+ extend ItemValue::Textarea
12
+ extend ItemCheck::String
13
+ end
14
+
15
+ class Empty
16
+ extend ItemValue::Textarea
17
+ extend ItemCheck::Empty
18
+ end
19
+
20
+ class Regexp
21
+ extend ItemValue::Textarea
22
+ extend ItemCheck::Regexp
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ class ItemClassifier
5
+ @elements_map = [
6
+ %i[checkbox element_checkbox?],
7
+ %i[radio element_radio?],
8
+ %i[input element_input?],
9
+ %i[textarea element_textarea?],
10
+ %i[select element_select?],
11
+ %i[image element_image?],
12
+ %i[element element?],
13
+ %i[elements elements?],
14
+ %i[section section?],
15
+ %i[sections sections?],
16
+ %i[page page?],
17
+ %i[array array?],
18
+ %i[string string?],
19
+ %i[boolean boolean?],
20
+ %i[nil element_nil?]
21
+ ]
22
+
23
+ def self.classify(element)
24
+ @elements_map.each do |data|
25
+ type = data[0]
26
+ probe = data[1]
27
+ if probe.is_a? Symbol
28
+ return type if send(probe, element)
29
+ elsif probe.call(element)
30
+ return type
31
+ end
32
+ end
33
+
34
+ :other
35
+ end
36
+
37
+ def self.page?(element)
38
+ element.is_a?(SitePrism::Page)
39
+ end
40
+
41
+ def self.section?(element)
42
+ element.is_a?(SitePrism::Section)
43
+ end
44
+
45
+ def self.sections?(element)
46
+ element.all?(SitePrism::Section)
47
+ rescue StandardError
48
+ false
49
+ end
50
+
51
+ def self.element?(element)
52
+ element.is_a?(Capybara::Node::Element)
53
+ end
54
+
55
+ def self.elements?(element)
56
+ element.all?(Capybara::Node::Element)
57
+ rescue StandardError
58
+ false
59
+ end
60
+
61
+ def self.array?(element)
62
+ element.is_a?(::Array)
63
+ end
64
+
65
+ def self.string?(element)
66
+ element.is_a?(::String)
67
+ end
68
+
69
+ def self.element_image?(element)
70
+ return false unless element?(element)
71
+ return false unless element.tag_name == 'img'
72
+
73
+ true
74
+ end
75
+
76
+ def self.element_input?(element)
77
+ return false unless element?(element)
78
+ return false unless element.tag_name == 'input'
79
+
80
+ true
81
+ end
82
+
83
+ def self.element_textarea?(element)
84
+ return false unless element?(element)
85
+ return false unless element.tag_name == 'textarea'
86
+
87
+ true
88
+ end
89
+
90
+ def self.element_select?(element)
91
+ return false unless element?(element)
92
+ return false unless element.tag_name == 'select'
93
+
94
+ true
95
+ end
96
+
97
+ def self.element_checkbox?(element)
98
+ return false unless element?(element)
99
+ return false unless element['type'] == 'checkbox'
100
+
101
+ true
102
+ end
103
+
104
+ def self.element_radio?(element)
105
+ return false unless element?(element)
106
+ return false unless element['type'] == 'radio'
107
+
108
+ true
109
+ end
110
+
111
+ def self.boolean?(element)
112
+ return true if element.is_a?(TrueClass)
113
+ return true if element.is_a?(FalseClass)
114
+
115
+ false
116
+ end
117
+
118
+ def self.element_nil?(element)
119
+ element.nil?
120
+ end
121
+
122
+ def self.add(type, probe, position = 0)
123
+ @elements_map.insert(position, [type, probe])
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ module PrismChecker
5
+ module Node
6
+ class Array < PrismChecker::Node::Base
7
+ attr_reader :children
8
+
9
+ def initialize(checker, parent, name, expectation)
10
+ super
11
+ @children = []
12
+ end
13
+
14
+ def add_child(idx, child)
15
+ @children[idx] = child
16
+ end
17
+
18
+ def walk_through(level = 0, &block)
19
+ yield self, level
20
+ @children.each do |c|
21
+ c.walk_through(level + 1, &block)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module Node
5
+ class BadExpectation < StandardError; end
6
+ end
7
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'check_fail'
4
+ require_relative 'bad_expectation'
5
+ require_relative '../element_wrapper'
6
+ require_relative '../absence_expectation'
7
+ require_relative '../item_classifier'
8
+
9
+ module PrismChecker
10
+ module Node
11
+ class Base
12
+ attr_reader :name, :status, :error, :parent, :checker, :expectation
13
+
14
+ def initialize(checker, parent, name, expectation)
15
+ @parent = parent
16
+ @checker = checker
17
+ @name = name
18
+ @expectation = build_expectation(expectation)
19
+ @element = nil
20
+ @status = 'Not checked'
21
+ @error = nil
22
+ @timeout = Capybara.default_max_wait_time
23
+ @type = nil
24
+ @checked_element = nil
25
+ end
26
+
27
+ def build_expectation(expectation)
28
+ if expectation.is_a?(Symbol) && expectation.start_with?('absent')
29
+ delay = expectation == :absent ? 0 : Integer(expectation.to_s.split('absent').last)
30
+
31
+ return AbsenceExpectation.new(delay)
32
+ end
33
+
34
+ expectation
35
+ rescue ArgumentError
36
+ expectation
37
+ end
38
+
39
+ def root?
40
+ parent.is_a?(Checker)
41
+ end
42
+
43
+ def failure?
44
+ @status == 'Fail' || @status == 'Error'
45
+ end
46
+
47
+ def success?
48
+ @status == 'Ok'
49
+ end
50
+
51
+ def element
52
+ return @checked_element if @checked_element
53
+
54
+ if root?
55
+ @checker.item
56
+ elsif parent.is_a?(Node::Hash)
57
+ if parent.element.is_a?(Capybara::Node::Element)
58
+ ElementWrapper.new(parent.element).send(@name)
59
+ else
60
+ parent.element.send(@name)
61
+ end
62
+ elsif parent.is_a?(Node::Array)
63
+ parent.element[@name]
64
+ end
65
+ end
66
+
67
+ def wait_until_true(timeout = @timeout, &block)
68
+ SitePrism::Waiter.wait_until_true(timeout, &block)
69
+ rescue SitePrism::TimeoutError
70
+ false
71
+ end
72
+
73
+ def check_wrapper
74
+ yield
75
+ @status = 'Ok'
76
+ rescue Node::CheckFail => e
77
+ @error = e
78
+ @status = 'Fail'
79
+ raise
80
+ rescue StandardError => e
81
+ @error = e
82
+ @status = 'Error'
83
+ raise
84
+ end
85
+
86
+ def check_absence
87
+ sleep expectation.delay
88
+
89
+ check_wrapper do
90
+ result = wait_until_true(0.1) do
91
+ parent.element.public_send("has_no_#{name}?")
92
+ end
93
+
94
+ raise Node::CheckFail, 'Element is present' unless result
95
+ end
96
+ end
97
+
98
+ def path
99
+ result = []
100
+ p = self
101
+
102
+ while p.is_a? Base
103
+ result << p.name
104
+ p = p.parent
105
+ end
106
+
107
+ result.reverse
108
+ end
109
+
110
+ def type(element)
111
+ @type ||= ItemClassifier.classify(element)
112
+ end
113
+
114
+ def check
115
+ return check_absence if expectation.is_a?(AbsenceExpectation)
116
+
117
+ check_wrapper do
118
+ element = self.element
119
+ element_type = type(element)
120
+ checkers = CheckDispatcher.checkers(self, element, expectation, element_type)
121
+ value = nil
122
+ checkers.each do |checker|
123
+ result = wait_until_true do
124
+ element = self.element if element.is_a? ::Array
125
+
126
+ value = checker.value(element)
127
+ checker.check(element, value, expectation)
128
+ end
129
+
130
+ unless result
131
+ raise Node::CheckFail, checker.error_message(element, value, expectation)
132
+ end
133
+ end
134
+
135
+ @checked_element = element
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrismChecker
4
+ module Node
5
+ class CheckFail < StandardError; end
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative '../item_classifier'
5
+ require_relative '../check_dispatcher'
6
+
7
+ module PrismChecker
8
+ module Node
9
+ class Expectation < PrismChecker::Node::Base
10
+ def walk_through(level = 0)
11
+ yield self, level
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module PrismChecker
6
+ module Node
7
+ class Hash < PrismChecker::Node::Base
8
+ attr_reader :children
9
+
10
+ def initialize(checker, parent, name, expectation)
11
+ super
12
+ @children = {}
13
+ end
14
+
15
+ def add_child(name, child)
16
+ @children[name] = child
17
+ end
18
+
19
+ def walk_through(level = 0, &block)
20
+ yield self, level
21
+ @children.each_value do |child|
22
+ child.walk_through(level + 1, &block)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end