prism_checker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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