diffux_ci 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/bin/diffux_ci +6 -0
- data/lib/diffux_ci_runner.rb +38 -18
- data/lib/diffux_ci_utils.rb +10 -3
- data/lib/diffux_ci_version.rb +1 -1
- data/lib/public/diffux_ci-runner.js +33 -18
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 792c6b08f42ae6f8715b7283bbd5e48de674281d
|
4
|
+
data.tar.gz: fe881d359ff8ac648c74802f0092ff862184ac1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 777f67034c3e7cd0bb60f246892cebebfb982602acddbd957f004f98b73cb8e06a273ae4c77002f55eca5b4128eade1b76f200a4872489f50d4dff1eee0bb105
|
7
|
+
data.tar.gz: ec413e930adecf64943f5f95d7f9d6bd519e63fa37c063b07297e2933249ae9ba9c328cbc0b0c40fe5f60b584eaaee91d4c2e7211475904ff6eb31b98f196692
|
data/bin/diffux_ci
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'diffux_ci_utils'
|
4
4
|
require 'diffux_ci_action'
|
5
5
|
require 'diffux_ci_uploader'
|
6
|
+
require 'diffux_ci_version'
|
6
7
|
require 'fileutils'
|
7
8
|
|
8
9
|
action = ARGV[0] || 'run'
|
@@ -39,6 +40,9 @@ when 'upload_diffs'
|
|
39
40
|
# `upload_diffs` returns a URL to a static html file
|
40
41
|
puts DiffuxCIUploader.new.upload_diffs
|
41
42
|
|
43
|
+
when '--version'
|
44
|
+
puts "diffux_ci version #{DiffuxCI::VERSION}"
|
45
|
+
|
42
46
|
when '--help'
|
43
47
|
puts <<-EOS
|
44
48
|
Commands:
|
@@ -49,6 +53,8 @@ Commands:
|
|
49
53
|
approve
|
50
54
|
reject
|
51
55
|
upload_diffs
|
56
|
+
--help
|
57
|
+
--version
|
52
58
|
EOS
|
53
59
|
else
|
54
60
|
abort "Unknown action \"#{action}\""
|
data/lib/diffux_ci_runner.rb
CHANGED
@@ -20,21 +20,28 @@ def resolve_viewports(example)
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
23
|
+
def init_driver
|
24
|
+
tries = 0
|
25
|
+
begin
|
26
|
+
driver = Selenium::WebDriver.for DiffuxCIUtils.config['driver'].to_sym
|
27
|
+
rescue Selenium::WebDriver::Error::WebDriverError => e
|
28
|
+
# "unable to obtain stable firefox connection in 60 seconds"
|
29
|
+
#
|
30
|
+
# This seems to happen sporadically for some versions of Firefox, so we want
|
31
|
+
# to retry a couple of times it in case it will work the second time around.
|
32
|
+
tries += 1
|
33
|
+
retry if tries <= 3
|
34
|
+
raise e
|
35
|
+
end
|
36
|
+
|
37
|
+
driver.manage.timeouts.script_timeout = 3 # move to config?
|
38
|
+
|
39
|
+
driver
|
34
40
|
end
|
35
41
|
|
42
|
+
driver = init_driver
|
43
|
+
|
36
44
|
begin
|
37
|
-
driver.manage.timeouts.script_timeout = 3 # move to config?
|
38
45
|
driver.navigate.to DiffuxCIUtils.construct_url('/')
|
39
46
|
|
40
47
|
# Check for errors during startup
|
@@ -98,10 +105,23 @@ begin
|
|
98
105
|
|
99
106
|
# Crop the screenshot to the size of the rendered element
|
100
107
|
screenshot = ChunkyPNG::Image.from_blob(driver.screenshot_as(:png))
|
108
|
+
|
109
|
+
# In our JavScript we are rounding up, which can sometimes give us a
|
110
|
+
# dimensions that are larger than the screenshot dimensions. We need to
|
111
|
+
# guard against that here.
|
112
|
+
crop_width = [
|
113
|
+
[rendered['width'], 1].max,
|
114
|
+
screenshot.width - rendered['left']
|
115
|
+
].min
|
116
|
+
crop_height = [
|
117
|
+
[rendered['height'], 1].max,
|
118
|
+
screenshot.height - rendered['top']
|
119
|
+
].min
|
120
|
+
|
101
121
|
screenshot.crop!(rendered['left'],
|
102
122
|
rendered['top'],
|
103
|
-
|
104
|
-
|
123
|
+
crop_width,
|
124
|
+
crop_height)
|
105
125
|
|
106
126
|
print "Checking \"#{description}\" at [#{viewport['name']}]... "
|
107
127
|
|
@@ -123,13 +143,13 @@ begin
|
|
123
143
|
# image to disk. This will allow it to be reviewed by someone.
|
124
144
|
diff_path = DiffuxCIUtils.path_to(
|
125
145
|
description, viewport['name'], 'diff.png')
|
126
|
-
comparison[:diff_image].save(diff_path)
|
146
|
+
comparison[:diff_image].save(diff_path, :fast_rgb)
|
127
147
|
|
128
148
|
candidate_path = DiffuxCIUtils.path_to(
|
129
149
|
description, viewport['name'], 'candidate.png')
|
130
|
-
screenshot.save(candidate_path)
|
150
|
+
screenshot.save(candidate_path, :fast_rgb)
|
131
151
|
|
132
|
-
puts "#{comparison[:diff_in_percent].round(1)}% (#{
|
152
|
+
puts "#{comparison[:diff_in_percent].round(1)}% (#{candidate_path})"
|
133
153
|
else
|
134
154
|
# No visual difference was found, so we don't need to do any more
|
135
155
|
# work.
|
@@ -143,7 +163,7 @@ begin
|
|
143
163
|
unless File.directory?(dirname = File.dirname(baseline_path))
|
144
164
|
FileUtils.mkdir_p(dirname)
|
145
165
|
end
|
146
|
-
screenshot.save(baseline_path)
|
166
|
+
screenshot.save(baseline_path, :fast_rgb)
|
147
167
|
puts "First snapshot created (#{baseline_path})"
|
148
168
|
end
|
149
169
|
end
|
data/lib/diffux_ci_utils.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'erb'
|
3
|
+
require 'uri'
|
3
4
|
|
4
5
|
class DiffuxCIUtils
|
5
6
|
def self.config
|
6
|
-
config_file_name = ENV['DIFFUX_CI_CONFIG_FILE'] || '.diffux_ci.yaml'
|
7
7
|
@@config ||= {
|
8
8
|
'snapshots_folder' => './snapshots',
|
9
9
|
'source_files' => [],
|
@@ -24,7 +24,12 @@ class DiffuxCIUtils
|
|
24
24
|
'height' => 444
|
25
25
|
}
|
26
26
|
}
|
27
|
-
}.merge(
|
27
|
+
}.merge(config_from_file)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.config_from_file
|
31
|
+
config_file_name = ENV['DIFFUX_CI_CONFIG_FILE'] || '.diffux_ci.yaml'
|
32
|
+
YAML.load(ERB.new(File.read(config_file_name)).result)
|
28
33
|
end
|
29
34
|
|
30
35
|
def self.normalize_description(description)
|
@@ -41,10 +46,12 @@ class DiffuxCIUtils
|
|
41
46
|
end
|
42
47
|
|
43
48
|
def self.construct_url(absolute_path, params = {})
|
49
|
+
query = URI.encode_www_form(params) unless params.empty?
|
50
|
+
|
44
51
|
URI::HTTP.build(host: 'localhost',
|
45
52
|
port: config['port'],
|
46
53
|
path: absolute_path,
|
47
|
-
query:
|
54
|
+
query: query).to_s
|
48
55
|
end
|
49
56
|
|
50
57
|
def self.current_snapshots
|
data/lib/diffux_ci_version.rb
CHANGED
@@ -49,11 +49,18 @@ window.diffux = {
|
|
49
49
|
}
|
50
50
|
},
|
51
51
|
|
52
|
+
isElementVisible: function(element) {
|
53
|
+
// element.offsetParent is a cheap way to determine visibility for most
|
54
|
+
// elements, but it doesn't work for elements with fixed positioning so we
|
55
|
+
// will need to fall back to the more expensive getComputedStyle.
|
56
|
+
return element.offsetParent ||
|
57
|
+
window.getComputedStyle(element).display !== 'none';
|
58
|
+
},
|
59
|
+
|
52
60
|
clearVisibleElements: function() {
|
53
61
|
var allElements = document.querySelectorAll('body > *');
|
54
62
|
for (var element of allElements) {
|
55
|
-
|
56
|
-
if (style.display !== 'none') {
|
63
|
+
if (this.isElementVisible(element)) {
|
57
64
|
element.parentNode.removeChild(element);
|
58
65
|
}
|
59
66
|
}
|
@@ -75,7 +82,7 @@ window.diffux = {
|
|
75
82
|
*/
|
76
83
|
tryAsync: function(func) {
|
77
84
|
return new Promise(function(resolve, reject) {
|
78
|
-
//
|
85
|
+
// Safety valve: if the function does not finish after 3s, then something
|
79
86
|
// went haywire and we need to move on.
|
80
87
|
var timeout = setTimeout(function() {
|
81
88
|
reject(new Error('Async callback was not invoked within timeout.'));
|
@@ -131,8 +138,8 @@ window.diffux = {
|
|
131
138
|
processElem: function(elem) {
|
132
139
|
try {
|
133
140
|
// TODO: elem.getDOMNode is deprecated in React, so we need to convert
|
134
|
-
// this to
|
135
|
-
// into the examples.
|
141
|
+
// this to ReactDOM.findDOMNode(elem) at some point, or push this
|
142
|
+
// requirement into the examples.
|
136
143
|
if (elem.getDOMNode) {
|
137
144
|
// Soft-dependency to React here. If the thing returned has a
|
138
145
|
// `getDOMNode` method, call it to get the real DOM node.
|
@@ -141,23 +148,31 @@ window.diffux = {
|
|
141
148
|
|
142
149
|
this.currentRenderedElement = elem;
|
143
150
|
|
144
|
-
var
|
145
|
-
var height = elem.offsetHeight;
|
146
|
-
var top = elem.offsetTop;
|
147
|
-
var left = elem.offsetLeft;
|
148
|
-
|
151
|
+
var rect;
|
149
152
|
if (this.currentExample.options.snapshotEntireScreen) {
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
153
|
+
rect = {
|
154
|
+
width: window.innerWidth,
|
155
|
+
height: window.innerHeight,
|
156
|
+
top: 0,
|
157
|
+
left: 0,
|
158
|
+
};
|
159
|
+
} else {
|
160
|
+
// We use elem.getBoundingClientRect() instead of offsetTop and its ilk
|
161
|
+
// because elem.getBoundingClientRect() is more accurate and it also
|
162
|
+
// takes CSS transformations and other things of that nature into
|
163
|
+
// account whereas offsetTop and company do not.
|
164
|
+
//
|
165
|
+
// Note that this method returns floats, so we need to round those off
|
166
|
+
// to integers before returning.
|
167
|
+
rect = elem.getBoundingClientRect();
|
154
168
|
}
|
169
|
+
|
155
170
|
return {
|
156
171
|
description: this.currentExample.description,
|
157
|
-
width: width,
|
158
|
-
height: height,
|
159
|
-
top: top,
|
160
|
-
left: left
|
172
|
+
width: Math.ceil(rect.width),
|
173
|
+
height: Math.ceil(rect.height),
|
174
|
+
top: Math.floor(rect.top),
|
175
|
+
left: Math.floor(rect.left),
|
161
176
|
};
|
162
177
|
} catch (error) {
|
163
178
|
return this.handleError(error);
|