dom_glancy 1.0.1 → 1.1.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/Gemfile +4 -0
  4. data/README.md +5 -0
  5. data/app/controllers/dom_glancy_controller.rb +9 -12
  6. data/app/views/dom_glancy/about.html.erb +2 -2
  7. data/app/views/dom_glancy/path_config.html.erb +10 -8
  8. data/app/views/dom_glancy/show.html.erb +3 -18
  9. data/app/views/layouts/dom_glancy.html.erb +10 -19
  10. data/app/views/shared/_dom_glancy_nav.html.erb +1 -1
  11. data/app/views/shared/_dom_set.html.erb +17 -2
  12. data/lib/assets/javascripts/dom_glancy/dom_glancy.js +37 -0
  13. data/{app/assets/stylesheets → lib/assets/stylesheets/dom_glancy}/1236_grid.css +0 -0
  14. data/{app/assets/stylesheets → lib/assets/stylesheets/dom_glancy}/720_grid.css +0 -0
  15. data/{app/assets/stylesheets → lib/assets/stylesheets/dom_glancy}/986_grid.css +0 -0
  16. data/{app/assets/stylesheets → lib/assets/stylesheets/dom_glancy}/dom_glancy.css +35 -4
  17. data/{app/assets/stylesheets → lib/assets/stylesheets/dom_glancy}/normalize.css +0 -0
  18. data/lib/dom_glancy.rb +6 -2
  19. data/lib/dom_glancy/analysis_reporter.rb +39 -0
  20. data/lib/dom_glancy/analyzer.rb +139 -0
  21. data/lib/dom_glancy/change_anlyzer.rb +22 -0
  22. data/lib/dom_glancy/dom_glancy.rb +35 -83
  23. data/lib/dom_glancy/element.rb +63 -12
  24. data/lib/dom_glancy/file_name_builder.rb +21 -0
  25. data/lib/dom_glancy/map_file.rb +14 -0
  26. data/lib/dom_glancy/page_mapper.rb +81 -0
  27. data/lib/dom_glancy/svg.rb +41 -2
  28. data/lib/dom_glancy/version.rb +1 -1
  29. data/test/page_objects/dom_glancy/show_page.rb +6 -0
  30. data/test/selenium/mapping_test.rb +28 -5
  31. data/test/selenium/viewer_test.rb +2 -2
  32. data/test/selenium_test_helper.rb +26 -43
  33. data/test/test_app/app/assets/stylesheets/local_app.css +9 -1
  34. data/test/test_app/app/views/local/index.html.erb +11 -1
  35. data/test/test_helper.rb +7 -5
  36. data/test/test_helpers/artifacts_helpers.rb +54 -0
  37. data/test/test_helpers/location_helpers.rb +5 -3
  38. data/test/test_objects/options_file_1.yaml +2145 -0
  39. data/test/test_objects/options_file_2.yaml +2177 -0
  40. data/test/test_objects/test_objects.rb +57 -6
  41. data/test/unit/analysis_reporter_test.rb +28 -0
  42. data/test/unit/analyzer_test.rb +146 -0
  43. data/test/unit/change_analyzer_test.rb +72 -0
  44. data/test/unit/dom_glancy_test.rb +16 -11
  45. data/test/unit/element_test.rb +56 -0
  46. data/test/unit/file_name_builder_test.rb +28 -0
  47. data/test/unit/map_file_test.rb +47 -0
  48. data/test/unit/page_mapper_test.rb +27 -0
  49. data/test/unit/svg_test.rb +17 -0
  50. metadata +35 -13
  51. data/app/assets/javascripts/application.js +0 -7
  52. data/lib/dom_glancy/analysis.rb +0 -146
  53. data/lib/dom_glancy/locations.rb +0 -16
  54. data/test/unit/analysis_test.rb +0 -110
@@ -0,0 +1,22 @@
1
+ module DomGlancy
2
+ class ChangeAnalyzer
3
+ attr_accessor :change_factors
4
+
5
+ def initialize(change_factors = [])
6
+ @change_factors = Array.new(change_factors)[0..4]
7
+
8
+ @change_factors << 0 if @change_factors.length == 0
9
+ @change_factors << 1 if @change_factors.length == 1
10
+ @change_factors << 1.2 if @change_factors.length == 2
11
+ @change_factors << 2 if @change_factors.length == 3
12
+ @change_factors << 5 if @change_factors.length == 4
13
+ end
14
+
15
+ def compare(element1, element2)
16
+ change_info = element1.change_info(element2)
17
+ deltas = change_info.map { |changed| (element1.send(changed.to_sym) - element2.send(changed.to_sym)).abs }
18
+ comparison_value = deltas.inject { |sum, n| n + n * deltas.count * @change_factors[deltas.count] }
19
+ comparison_value
20
+ end
21
+ end
22
+ end
@@ -2,114 +2,65 @@ module DomGlancy
2
2
  class DomGlancy
3
3
  def page_map_same?(test_root)
4
4
  purge_old_files_before_test(test_root)
5
+ fnb = ::DomGlancy::FileNameBuilder.new(test_root)
5
6
 
6
- result, msg = map_current_file(test_root)
7
+ result, msg = ::DomGlancy::PageMapper.new.run(test_root)
7
8
  return [result, msg] unless result
8
9
 
9
10
  result, msg = master_file_exists?(test_root)
10
11
  return [result, msg] unless result
11
12
 
12
- result, msg, current_data = read_map_file(DomGlancy.current_filename(test_root))
13
+ result, msg, current_data = ::DomGlancy::MapFile.new.read(fnb.current)
13
14
  return [result, msg] unless result
14
15
 
15
- result, msg, master_data = read_map_file(DomGlancy.master_filename(test_root))
16
+ result, msg, master_data = ::DomGlancy::MapFile.new.read(fnb.master)
16
17
  return [result, msg] unless result
17
18
 
18
- analysis_data = analyze(master_data, current_data, test_root)
19
+ analyzer = ::DomGlancy::Analyzer.new(master_data, current_data, test_root)
20
+ analysis_data = analyzer.analyze
19
21
 
20
- msg = make_analysis_failure_report(analysis_data)
21
- result = analysis_data[:same]
22
-
23
- File.delete DomGlancy.current_filename(test_root) if result
24
-
25
- [result, msg]
26
- end
27
-
28
-
29
- def read_map_file(filename)
30
- results = [true, '', nil]
31
- begin
32
- results[2] = YAML::load( File.open( filename ) )
33
- rescue Exception => e
34
- results = [false, "Error reading data from file: #{filename}", nil]
22
+ unless analysis_data[:same]
23
+ analysis_reporter = ::DomGlancy::AnalysisReporter.new(test_root, analyzer.set_current_not_master, analyzer.set_master_not_current, analyzer.set_changed_master, analyzer.changed_element_pairs)
24
+ analysis_reporter.create_diff_file
35
25
  end
36
26
 
37
- results
38
- end
39
-
40
- def map_current_file(test_root)
41
- filename = DomGlancy.current_filename(test_root)
27
+ msg = console_failure_string(analysis_data)
28
+ result = analysis_data[:same]
42
29
 
43
- result = [true, '']
44
- begin
45
- data = perform_mapping_operation.to_yaml
46
- File.open(filename, 'w') { |file| file.write(data) }
47
- rescue Exception => e
48
- result = [false, "map current file error: #{e.message}"]
49
- end
30
+ File.delete fnb.current if result
50
31
 
51
- result
32
+ [result, msg]
52
33
  end
53
34
 
54
- def resize_browser_for_scrollbar
55
- original_dimensions = Capybara.current_session.driver.browser.manage.window.size
56
- width = Capybara.current_session.evaluate_script('window.innerWidth - document.documentElement.clientWidth').to_i
35
+ private
57
36
 
58
- Capybara.current_session.driver.browser.manage.window.resize_to(original_dimensions.width + width, original_dimensions.height) if width > 0
37
+ def console_failure_string(analysis_data)
38
+ return '' if analysis_data[:same]
59
39
 
60
- result = yield
40
+ fnb = ::DomGlancy::FileNameBuilder.new(analysis_data[:test_root])
61
41
 
62
- Capybara.current_session.driver.browser.manage.window.resize_to(original_dimensions.width, original_dimensions.height) if width > 0
42
+ msg = ["\n------- DOM Comparison Failure ------"]
43
+ msg << "Elements not in master: #{analysis_data[:not_in_master].count}"
44
+ msg << "Elements not in current: #{analysis_data[:not_in_current].count}"
45
+ msg << "Changed elements: #{analysis_data[:changed_element_pairs].count}"
46
+ msg << "Files:"
47
+ msg << "\tcurrent: #{fnb.current}"
48
+ msg << "\tmaster: #{fnb.master}"
49
+ msg << "\tdifference: #{fnb.diff}"
50
+ msg << "Bless this current data set:"
51
+ msg << "\t#{blessing_copy_string(analysis_data[:test_root])}"
52
+ msg<< "-------------------------------------"
63
53
 
64
- result
54
+ msg.join("\n")
65
55
  end
66
56
 
67
- def perform_mapping_operation
68
- page_map_js = <<-JS
69
- var dom_glancy = {
70
-
71
- treeUp: function() {
72
- var treeWalker = document.createTreeWalker(
73
- document.body,
74
- NodeFilter.SHOW_ELEMENT,
75
- { acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
76
- false
77
- );
78
-
79
- var nodeList = [];
80
-
81
- while(treeWalker.nextNode()){
82
- var cn = treeWalker.currentNode;
83
- var node_details = {
84
- "height" : cn.clientHeight,
85
- "width" : cn.clientWidth,
86
- "id" : cn.id,
87
- "tag" : cn.tagName,
88
- "class" : cn.className,
89
- "top" : cn.offsetTop,
90
- "left" : cn.offsetLeft,
91
- "visible" : dom_glancy.isVisible(cn)
92
- }
93
- nodeList.push(node_details);
94
- }
95
-
96
- return(nodeList);
97
- },
98
-
99
- isVisible: function(elem) {
100
- return elem.offsetWidth > 0 || elem.offsetHeight > 0;
101
- }
102
- };
103
- return dom_glancy.treeUp();
104
- JS
105
-
106
- resize_browser_for_scrollbar do
107
- Capybara.current_session.driver.browser.execute_script(page_map_js)
108
- end
57
+ def blessing_copy_string(test_root)
58
+ fnb = ::DomGlancy::FileNameBuilder.new(test_root)
59
+ "cp #{fnb.current} #{fnb.master}"
109
60
  end
110
61
 
111
62
  def master_file_exists?(test_root)
112
- filename = DomGlancy.master_filename(test_root)
63
+ filename = ::DomGlancy::FileNameBuilder.new(test_root).master
113
64
  result = File.exist?(filename)
114
65
  msg = result ? '' : make_missing_master_failure_report(test_root)
115
66
  [result, msg]
@@ -126,7 +77,8 @@ module DomGlancy
126
77
  end
127
78
 
128
79
  def purge_old_files_before_test(test_root)
129
- File.delete DomGlancy.current_filename(test_root) if File.exist?(DomGlancy.current_filename(test_root))
80
+ old_current_file = ::DomGlancy::FileNameBuilder.new(test_root).current
81
+ File.delete old_current_file if File.exist?(old_current_file)
130
82
 
131
83
  filename_pattern = File.join(::DomGlancy.configuration.diff_file_location, "#{test_root}__*__diff.yaml")
132
84
  Dir[filename_pattern].each { |file| file.delete(file) if File.exist?(file) }
@@ -1,5 +1,4 @@
1
1
  module DomGlancy
2
-
3
2
  class DOMElement
4
3
  ## element looks like this in archive.
5
4
  # {"id"=>"", "height"=>238, "visible"=>true, "tag"=>"DIV", "width"=>720, "class"=>"grid", "left"=>43, "top"=>14}
@@ -16,16 +15,16 @@ module DomGlancy
16
15
  attr_accessor :similarity
17
16
 
18
17
  def initialize(h = {})
19
- @tag = h[:tag] || h['tag']
20
- @left = h[:left] || h['left']
21
- @top = h[:top] || h['top']
22
- @height = h[:height] || h['height']
23
- @width = h[:width] || h['width']
24
- @klass = h[:class] || h['class']
25
- @id = h[:id] || h['id']
26
- @style = h[:style] || h['style']
27
- @visible = h[:visible] || h['visible']
28
- @similarity = h[:similarity] || h['similarity'] || 0
18
+ @tag = h['tag']
19
+ @left = h['left']
20
+ @top = h['top']
21
+ @height = h['height']
22
+ @width = h['width']
23
+ @klass = h['class']
24
+ @id = h['id']
25
+ @style = h['style']
26
+ @visible = h['visible']
27
+ @similarity = h['similarity'] || 0
29
28
  end
30
29
 
31
30
  def same_element?(anOther)
@@ -38,7 +37,7 @@ module DomGlancy
38
37
  same = same_element?(anOther) &&
39
38
  similar_size?(anOther, 0) &&
40
39
  similar_location?(anOther, 0) &&
41
- same_size?(anOther) &&
40
+ same_size?(anOther) &&
42
41
  same_visibility?(anOther)
43
42
  end
44
43
 
@@ -60,6 +59,22 @@ module DomGlancy
60
59
  similar && (@left - anOther.left).abs <= similarity
61
60
  end
62
61
 
62
+ def similar_top?(anOther, similarity = 0)
63
+ (@top - anOther.top).abs <= similarity
64
+ end
65
+
66
+ def similar_left?(anOther, similarity = 0)
67
+ (@left - anOther.left).abs <= similarity
68
+ end
69
+
70
+ def similar_width?(anOther, similarity = 0)
71
+ (@width - anOther.width).abs <= similarity
72
+ end
73
+
74
+ def similar_height?(anOther, similarity = 0)
75
+ (@height - anOther.height).abs <= similarity
76
+ end
77
+
63
78
  def same_tag?(anOther)
64
79
  @tag == anOther.tag
65
80
  end
@@ -88,5 +103,41 @@ module DomGlancy
88
103
  @style == anOther.style
89
104
  end
90
105
 
106
+ def similarity_level(anOther)
107
+ level = 0
108
+ if same_element?(anOther) && same_style?(anOther)
109
+ level += 1 if similar_location?(anOther, @similarity) and !same_location?(anOther)
110
+ level += 1 if similar_size?(anOther, @similarity) and !same_size?(anOther)
111
+ end
112
+ level
113
+ end
114
+
115
+ def change_level(anOther)
116
+ change_info(anOther).length
117
+ end
118
+
119
+ def change_info(anOther)
120
+ info = []
121
+ if same_element?(anOther)
122
+ info << 'left' unless similar_left?(anOther, @similarity)
123
+ info << 'top' unless similar_top?(anOther, @similarity)
124
+ info << 'height' unless similar_height?(anOther, @similarity)
125
+ info << 'width' unless similar_width?(anOther, @similarity)
126
+ end
127
+ info
128
+ end
129
+
130
+ def to_hash
131
+ {
132
+ 'id' => @id,
133
+ 'height' => @height,
134
+ 'visible' => @visible,
135
+ 'tag' => @tag,
136
+ 'width' => @width,
137
+ 'class' => @klass,
138
+ 'left' => @left,
139
+ 'top' => @top
140
+ }
141
+ end
91
142
  end
92
143
  end
@@ -0,0 +1,21 @@
1
+ module DomGlancy
2
+ class FileNameBuilder
3
+ attr_accessor :test_root
4
+
5
+ def initialize(test_root = '')
6
+ @test_root = test_root
7
+ end
8
+
9
+ def master
10
+ File.join(::DomGlancy.configuration.master_file_location, "#{@test_root}_master.yaml")
11
+ end
12
+
13
+ def current
14
+ File.join(::DomGlancy.configuration.current_file_location, "#{@test_root}.yaml")
15
+ end
16
+
17
+ def diff
18
+ File.join(::DomGlancy.configuration.diff_file_location, "#{@test_root}_diff.html")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ module DomGlancy
2
+ class MapFile
3
+ def read(filename)
4
+ results = [true, '', nil]
5
+ begin
6
+ results[2] = YAML::load( File.open( filename ) )
7
+ rescue Exception => e
8
+ results = [false, "Error reading data from file: #{filename}", nil]
9
+ end
10
+
11
+ results
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,81 @@
1
+ module DomGlancy
2
+ class PageMapper
3
+
4
+ def run(test_root)
5
+ filename = ::DomGlancy::FileNameBuilder.new(test_root).current
6
+
7
+ result = [true, '']
8
+ begin
9
+ data = map_page.to_yaml
10
+ File.open(filename, 'w') { |file| file.write(data) }
11
+ rescue Exception => e
12
+ result = [false, "map current file error: #{e.message}"]
13
+ end
14
+
15
+ result
16
+ end
17
+
18
+ private
19
+
20
+ def map_page
21
+ page_map_js = mapping_javascript
22
+ resize_browser_for_scrollbar do
23
+ Capybara.current_session.driver.browser.execute_script(page_map_js)
24
+ end
25
+ end
26
+
27
+ def mapping_javascript
28
+ <<-JS
29
+ var dom_glancy = {
30
+
31
+ treeUp: function() {
32
+ var treeWalker = document.createTreeWalker(
33
+ document.body,
34
+ NodeFilter.SHOW_ELEMENT,
35
+ { acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
36
+ false
37
+ );
38
+
39
+ var nodeList = [];
40
+
41
+ while(treeWalker.nextNode()){
42
+ var cn = treeWalker.currentNode;
43
+ var node_details = {
44
+ "height" : cn.clientHeight,
45
+ "width" : cn.clientWidth,
46
+ "id" : cn.id,
47
+ "tag" : cn.tagName,
48
+ "class" : cn.className,
49
+ "top" : cn.offsetTop,
50
+ "left" : cn.offsetLeft,
51
+ "visible" : dom_glancy.isVisible(cn)
52
+ }
53
+ nodeList.push(node_details);
54
+ }
55
+
56
+ return(nodeList);
57
+ },
58
+
59
+ isVisible: function(elem) {
60
+ return elem.offsetWidth > 0 || elem.offsetHeight > 0;
61
+ }
62
+ };
63
+ return dom_glancy.treeUp();
64
+ JS
65
+ end
66
+
67
+ def resize_browser_for_scrollbar
68
+ original_dimensions = Capybara.current_session.driver.browser.manage.window.size
69
+ width = Capybara.current_session.evaluate_script('window.innerWidth - document.documentElement.clientWidth').to_i
70
+
71
+ Capybara.current_session.driver.browser.manage.window.resize_to(original_dimensions.width + width, original_dimensions.height) if width > 0
72
+
73
+ result = yield
74
+
75
+ Capybara.current_session.driver.browser.manage.window.resize_to(original_dimensions.width, original_dimensions.height) if width > 0
76
+
77
+ result
78
+ end
79
+
80
+ end
81
+ end
@@ -1,6 +1,20 @@
1
1
  module DomGlancy
2
- class DomGlancy
3
- def generate_svg(rectangles)
2
+ class SVG
3
+ @set_current_not_master
4
+ @set_master_not_current
5
+ @set_changed_master
6
+
7
+ def initialize(set_current_not_master, set_master_not_current, set_changed_master)
8
+ @set_current_not_master = set_current_not_master
9
+ @set_master_not_current = set_master_not_current
10
+ @set_changed_master = set_changed_master
11
+ end
12
+
13
+ def generate_svg
14
+ add_ids
15
+
16
+ rectangles = make_rectangles
17
+
4
18
  width, height = get_window_size_from_rectangles(rectangles)
5
19
  s = svg_start(width, height)
6
20
 
@@ -13,6 +27,31 @@ module DomGlancy
13
27
  s += "\n"
14
28
  end
15
29
 
30
+ private
31
+
32
+ def add_ids
33
+ js_id = 0
34
+ @set_master_not_current.each do |item|
35
+ item[:js_id] = js_id
36
+ js_id += 1
37
+ end
38
+ @set_current_not_master.each do |item|
39
+ item[:js_id] = js_id
40
+ js_id += 1
41
+ end
42
+ @set_changed_master.each do |item|
43
+ item[:js_id] = js_id
44
+ js_id += 1
45
+ end
46
+ end
47
+
48
+ def make_rectangles
49
+ rectangles = @set_current_not_master.map { |item| item.merge(format__not_in_master) }
50
+ rectangles << @set_master_not_current.map { |item| item.merge(format__not_in_current) }
51
+ rectangles << @set_changed_master.map { |item| item.merge(format__same_but_different) }
52
+ rectangles.flatten!
53
+ end
54
+
16
55
  def get_window_size_from_rectangles(rectangles)
17
56
  width = 0
18
57
  height = 0