Module: Kracker
- Defined in:
- lib/kracker/svg.rb,
lib/kracker/element.rb,
lib/kracker/kracker.rb,
lib/kracker/version.rb,
lib/kracker/analysis.rb,
lib/kracker/locations.rb,
lib/kracker/zooka/image.rb,
lib/kracker/zooka/pixel.rb,
lib/kracker/rails/engine.rb,
lib/kracker/zooka/analyzer.rb,
lib/kracker/zooka/tolerance.rb,
lib/kracker/zooka/error_pixel_transform.rb
Defined Under Namespace
Modules: Rails, Zooka Classes: DOMElement
Constant Summary collapse
- VERSION =
'0.0.5'.freeze
Class Method Summary collapse
- .create_comparison_directories ⇒ Object
- .current_file_location ⇒ Object
- .current_file_location=(location) ⇒ Object
- .current_filename(test_root) ⇒ Object
- .diff_file_location ⇒ Object
- .diff_file_location=(location) ⇒ Object
- .diff_filename(test_root) ⇒ Object
- .master_file_location ⇒ Object
- .master_file_location=(location) ⇒ Object
- .master_filename(test_root) ⇒ Object
Instance Method Summary collapse
- #analyze(master_data, current_data, test_root = nil) ⇒ Object
- #blessing_copy_string(test_root) ⇒ Object
- #create_diff_file(set_current_not_master, set_master_not_current, set_changed_master, test_root) ⇒ Object
- #format__not_in_current ⇒ Object
- #format__not_in_master ⇒ Object
- #format__same_but_different ⇒ Object
- #generate_svg(rectangles) ⇒ Object
- #get_set_of_same_but_different(set1, set2) ⇒ Object
- #get_window_size_from_rectangles(rectangles) ⇒ Object
- #make_analysis_failure_report(analysis_data) ⇒ Object
- #make_missing_master_failure_report(test_root) ⇒ Object
- #make_svg(set_master_not_current, set_current_not_master, set_changed_master) ⇒ Object
- #map_current_file(test_root) ⇒ Object
- #master_file_exists?(test_root) ⇒ Boolean
- #page_map_same?(test_root) ⇒ Boolean
- #pairs_that_are_close_enough(set1, set2) ⇒ Object
- #perform_mapping_operation ⇒ Object
- #purge_old_files_before_test(test_root) ⇒ Object
- #read_map_file(filename) ⇒ Object
- #save_set_info(test_root, suffix, data_set) ⇒ Object
- #svg_end ⇒ Object
- #svg_start(width, height) ⇒ Object
Class Method Details
.create_comparison_directories ⇒ Object
31 32 33 34 35 |
# File 'lib/kracker/locations.rb', line 31 def self.create_comparison_directories ::FileUtils.mkdir_p(@master_file_location) ::FileUtils.mkdir_p(@diff_file_location) ::FileUtils.mkdir_p(@current_file_location) end |
.current_file_location ⇒ Object
27 28 29 |
# File 'lib/kracker/locations.rb', line 27 def self.current_file_location @current_file_location end |
.current_file_location=(location) ⇒ Object
23 24 25 |
# File 'lib/kracker/locations.rb', line 23 def self.current_file_location=(location) @current_file_location = location end |
.current_filename(test_root) ⇒ Object
41 42 43 |
# File 'lib/kracker/locations.rb', line 41 def self.current_filename(test_root) File.join(self.current_file_location, "#{test_root}.yaml") end |
.diff_file_location ⇒ Object
19 20 21 |
# File 'lib/kracker/locations.rb', line 19 def self.diff_file_location @diff_file_location end |
.diff_file_location=(location) ⇒ Object
15 16 17 |
# File 'lib/kracker/locations.rb', line 15 def self.diff_file_location=(location) @diff_file_location = location end |
.diff_filename(test_root) ⇒ Object
45 46 47 |
# File 'lib/kracker/locations.rb', line 45 def self.diff_filename(test_root) File.join(self.diff_file_location, "#{test_root}_diff.html") end |
.master_file_location ⇒ Object
11 12 13 |
# File 'lib/kracker/locations.rb', line 11 def self.master_file_location @master_file_location end |
.master_file_location=(location) ⇒ Object
7 8 9 |
# File 'lib/kracker/locations.rb', line 7 def self.master_file_location=(location) @master_file_location = location end |
.master_filename(test_root) ⇒ Object
37 38 39 |
# File 'lib/kracker/locations.rb', line 37 def self.master_filename(test_root) File.join(self.master_file_location, "#{test_root}_master.yaml") end |
Instance Method Details
#analyze(master_data, current_data, test_root = nil) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/kracker/analysis.rb', line 3 def analyze(master_data, current_data, test_root = nil) output_hash = {} master_set = master_data.to_set current_set = current_data.to_set set_current_not_master = current_set - master_set set_master_not_current = master_set - current_set set_changed_master = Set.new changed_element_pairs = [] if set_master_not_current.count > 0 || set_current_not_master.count > 0 ok_pairs = pairs_that_are_close_enough(set_current_not_master, set_master_not_current) ok_pairs.each do |item1, item2| set_current_not_master.delete(item1) set_master_not_current.delete(item2) end changed_element_pairs = get_set_of_same_but_different(set_current_not_master, set_master_not_current) changed_element_pairs.each do |item1, item2| set_current_not_master.delete(item1) set_current_not_master.delete(item2) set_master_not_current.delete(item1) set_master_not_current.delete(item2) end changed_element_pairs.select!{ |pair| !DOMElement.new(pair[0]).close_enough?(DOMElement.new(pair[1])) } changed_element_pairs.each do |pair| set_changed_master.add(pair.first) end end all_same = set_current_not_master.count == 0 && set_master_not_current.count == 0 && changed_element_pairs.count == 0 create_diff_file(set_current_not_master, set_master_not_current, set_changed_master, test_root) if test_root && !all_same output_hash[:not_in_master] = set_current_not_master output_hash[:not_in_current] = set_master_not_current output_hash[:changed_element_pairs] = changed_element_pairs output_hash[:same] = all_same output_hash[:test_root] = test_root output_hash end |
#blessing_copy_string(test_root) ⇒ Object
137 138 139 |
# File 'lib/kracker/analysis.rb', line 137 def blessing_copy_string(test_root) "cp #{Kracker.current_filename(test_root)} #{Kracker.master_filename(test_root)}" end |
#create_diff_file(set_current_not_master, set_master_not_current, set_changed_master, test_root) ⇒ Object
74 75 76 77 78 79 80 81 |
# File 'lib/kracker/analysis.rb', line 74 def create_diff_file(set_current_not_master, set_master_not_current, set_changed_master, test_root) filename = Kracker.diff_filename(test_root) svg = make_svg(set_current_not_master, set_master_not_current, set_changed_master) File.open(filename, 'w') { |file| file.write(svg) } save_set_info(test_root, 'current_not_master', set_current_not_master) save_set_info(test_root, 'master_not_current', set_master_not_current) save_set_info(test_root, 'changed_master', set_changed_master) end |
#format__not_in_current ⇒ Object
55 56 57 58 59 60 61 62 |
# File 'lib/kracker/svg.rb', line 55 def format__not_in_current { :stroke => 'red', :fill => 'white', :stroke_width => '1', :opacity => '0.5' } end |
#format__not_in_master ⇒ Object
46 47 48 49 50 51 52 53 |
# File 'lib/kracker/svg.rb', line 46 def format__not_in_master { :stroke => 'blue', :fill => 'white', :stroke_width => '1', :opacity => '0.5' } end |
#format__same_but_different ⇒ Object
63 64 65 66 67 68 69 70 |
# File 'lib/kracker/svg.rb', line 63 def format__same_but_different { :stroke => 'orange', :fill => 'white', :stroke_width => '1', :opacity => '0.5' } end |
#generate_svg(rectangles) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 |
# File 'lib/kracker/svg.rb', line 3 def generate_svg(rectangles) width, height = get_window_size_from_rectangles(rectangles) s = svg_start(width, height) rectangles.each do |rectangle| rectangle_string = " <rect id='#{rectangle[:js_id]}' x = '#{rectangle['left']}' y = '#{rectangle['top']}' width = '#{rectangle['width']}' height = '#{rectangle['height']}' fill = '#{rectangle[:fill]}' stroke = '#{rectangle[:stroke]}' stroke-width = '#{rectangle[:stroke_width]}' fill-opacity = '#{rectangle[:opacity]}' />\n" s += rectangle_string end s += svg_end s += "\n" end |
#get_set_of_same_but_different(set1, set2) ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/kracker/analysis.rb', line 91 def get_set_of_same_but_different(set1, set2) same_but_different_pairs = [] set1.each do |item1| element1 = DOMElement.new(item1) set2.each do |item2| element2 = DOMElement.new(item2) if element1.same_element?(element2) same_but_different_pairs << [item1, item2] #unless element1.close_enough?(element2) end end end same_but_different_pairs end |
#get_window_size_from_rectangles(rectangles) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/kracker/svg.rb', line 16 def get_window_size_from_rectangles(rectangles) width = 0 height = 0 rectangles.each do |rectangle| rectangle_right = rectangle['left'].to_i + rectangle['width'].to_i rectangle_bottom = rectangle['top'].to_i + rectangle['height'].to_i width = rectangle_right if rectangle_right > width height = rectangle_bottom if rectangle_bottom > height end [width, height] end |
#make_analysis_failure_report(analysis_data) ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/kracker/analysis.rb', line 119 def make_analysis_failure_report(analysis_data) return '' if analysis_data[:same] msg = ["\n------- DOM Comparison Failure ------"] msg << "Elements not in master: #{analysis_data[:not_in_master].count}" msg << "Elements not in current: #{analysis_data[:not_in_current].count}" msg << "Changed elements: #{analysis_data[:changed_element_pairs].count}" msg << "Files:" msg << "\tcurrent: #{Kracker.current_filename(analysis_data[:test_root])}" msg << "\tmaster: #{Kracker.master_filename(analysis_data[:test_root])}" msg << "\tdifference: #{Kracker.diff_filename(analysis_data[:test_root])}" msg << "Bless this current data set:" msg << "\t#{blessing_copy_string(analysis_data[:test_root])}" msg<< "-------------------------------------" msg.join("\n") end |
#make_missing_master_failure_report(test_root) ⇒ Object
105 106 107 108 109 110 111 112 113 |
# File 'lib/kracker/kracker.rb', line 105 def make_missing_master_failure_report(test_root) msg = ["\n------- DOM Comparison Failure ------"] msg << "Master file does not exist. To make a new master from" msg << "the current page, use this command:" msg << "\t#{blessing_copy_string(test_root)}" msg<< "-------------------------------------" msg.join("\n") end |
#make_svg(set_master_not_current, set_current_not_master, set_changed_master) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/kracker/analysis.rb', line 51 def make_svg(set_master_not_current, set_current_not_master, set_changed_master) js_id = 0 set_master_not_current.each do |item| item[:js_id] = js_id js_id += 1 end set_current_not_master.each do |item| item[:js_id] = js_id js_id += 1 end set_changed_master.each do |item| item[:js_id] = js_id js_id += 1 end rectangles = set_current_not_master.map { |item| item.merge(format__not_in_master) } rectangles << set_master_not_current.map { |item| item.merge(format__not_in_current) } rectangles << set_changed_master.map { |item| item.merge(format__same_but_different) } rectangles.flatten! generate_svg(rectangles) end |
#map_current_file(test_root) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/kracker/kracker.rb', line 40 def map_current_file(test_root) filename = Kracker.current_filename(test_root) result = [true, ''] begin data = perform_mapping_operation.to_yaml File.open(filename, 'w') { |file| file.write(data) } rescue Exception => e result = [false, "map current file error: #{e.}"] end result end |
#master_file_exists?(test_root) ⇒ Boolean
98 99 100 101 102 103 |
# File 'lib/kracker/kracker.rb', line 98 def master_file_exists?(test_root) filename = Kracker.master_filename(test_root) result = File.exist?(filename) msg = result ? '' : make_missing_master_failure_report(test_root) [result, msg] end |
#page_map_same?(test_root) ⇒ Boolean
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/kracker/kracker.rb', line 4 def page_map_same?(test_root) purge_old_files_before_test(test_root) result, msg = map_current_file(test_root) return [result, msg] unless result result, msg = master_file_exists?(test_root) return [result, msg] unless result result, msg, current_data = read_map_file(Kracker.current_filename(test_root)) return [result, msg] unless result result, msg, master_data = read_map_file(Kracker.master_filename(test_root)) return [result, msg] unless result analysis_data = analyze(master_data, current_data, test_root) msg = make_analysis_failure_report(analysis_data) result = analysis_data[:same] File.delete Kracker.current_filename(test_root) if result [result, msg] end |
#pairs_that_are_close_enough(set1, set2) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/kracker/analysis.rb', line 105 def pairs_that_are_close_enough(set1, set2) ok_pairs = [] set1.each do |item1| element1 = DOMElement.new(item1) set2.each do |item2| element2 = DOMElement.new(item2) if element1.same_element?(element2) && element1.close_enough?(element2) ok_pairs << [item1, item2] end end end ok_pairs end |
#perform_mapping_operation ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/kracker/kracker.rb', line 54 def perform_mapping_operation js = <<-JS var kracker = { treeUp: function() { var treeWalker = document.createTreeWalker( document.body, NodeFilter.SHOW_ELEMENT, { acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } }, false ); var nodeList = []; while(treeWalker.nextNode()){ var cn = treeWalker.currentNode; var node_details = { "height" : cn.clientHeight, "width" : cn.clientWidth, "id" : cn.id, "tag" : cn.tagName, "class" : cn.className, //"html" : cn.innerHTML, "top" : cn.offsetTop, "left" : cn.offsetLeft, "visible" : kracker.isVisible(cn) } nodeList.push(node_details); } return(nodeList); }, isVisible: function(elem) { return elem.offsetWidth > 0 || elem.offsetHeight > 0; } }; return kracker.treeUp(); JS page.driver.browser.execute_script(js) end |
#purge_old_files_before_test(test_root) ⇒ Object
115 116 117 118 119 120 |
# File 'lib/kracker/kracker.rb', line 115 def purge_old_files_before_test(test_root) File.delete Kracker.current_filename(test_root) if File.exist?(Kracker.current_filename(test_root)) filename_pattern = File.join(Kracker.diff_file_location, "#{test_root}__*__diff.yaml") Dir[filename_pattern].each { |file| file.delete(file) if File.exist?(file) } end |
#read_map_file(filename) ⇒ Object
29 30 31 32 33 34 35 36 37 38 |
# File 'lib/kracker/kracker.rb', line 29 def read_map_file(filename) results = [true, '', nil] begin results[2] = YAML::load( File.open( filename ) ) rescue Exception => e results = [false, "Error reading data from file: #{filename}", nil] end results end |
#save_set_info(test_root, suffix, data_set) ⇒ Object
83 84 85 86 87 88 89 |
# File 'lib/kracker/analysis.rb', line 83 def save_set_info(test_root, suffix, data_set) filename = File.join(Kracker.diff_file_location, "#{test_root}__#{suffix}__diff.yaml") data_array = data_set.to_a File.open(filename, 'w') { |file| file.write(data_array.to_yaml) } end |
#svg_end ⇒ Object
39 40 41 42 43 44 |
# File 'lib/kracker/svg.rb', line 39 def svg_end s = [' </svg>'] s << '' s.join("\n") end |
#svg_start(width, height) ⇒ Object
30 31 32 33 34 35 36 37 |
# File 'lib/kracker/svg.rb', line 30 def svg_start(width, height) s = ["<?xml version='1.0' standalone='no'?>"] s << " <!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>" s << " <svg version = '1.1' width='#{width}px' height='#{height}px' border='2px' style='background-color:#FFFFFF;border:1px solid black;'>" s << '' s.join("\n") end |