diffux-core 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 80f32154fc059c048c223e8e2ca3646a802a8859
4
- data.tar.gz: 7452b31f9989d95cbc3799d5bcacbe1e4dcd99b7
3
+ metadata.gz: 8362662564dad77a53ca282a389cbad52a5ed59c
4
+ data.tar.gz: 9ca2065b9f022ad5202f1a26e15c334b3bc2ea74
5
5
  SHA512:
6
- metadata.gz: 240ad46905dfd690d5c3fcafc82eff833ba0c0128a3e786c08089dc40cf33b720efda4f9d971e70f2767eb975829d7a5971981983c5b5be2acaf352ae923a383
7
- data.tar.gz: 60e6f38b354ad99791fad9c333ed52e9e038f7eee7ac823c3eebcd92ee84294dfae794436f64e0717babf168e896380dfd08ee66b92564ce23957fef2fd42a3c
6
+ metadata.gz: 29e01c7448c6287d31f3b71ee141cbf08118b1c1d0262b74c503fe393e4f566dbdf03484caca80378971aa5fce09f033c0084a58d683300c7be63022710b1336
7
+ data.tar.gz: b4d1c26cc7e928ca91be9c1929c7e84cb473c42fb01ef476fa47b420e4ff2485590f6a40ef5995c79fd738f07d085ef381e219f2f9ed4d6305b3321ea10a76e2
@@ -26,6 +26,11 @@ OptionParser.new do |opts|
26
26
  options[:width] = w
27
27
  end
28
28
 
29
+ opts.on('-c', '--cropselector CROPSELECTOR',
30
+ 'Limit the snapshot to a specific element') do |cs|
31
+ options[:crop_selector] = cs
32
+ end
33
+
29
34
  opts.on('-a', '--useragent USERAGENT',
30
35
  'Set a useragent header when loading the url') do |ua|
31
36
  options[:useragent] = ua
@@ -47,10 +52,10 @@ unless options[:outfile]
47
52
  exit 1
48
53
  end
49
54
 
50
- snapshot = Diffux::Snapshotter.new(
55
+ Diffux::Snapshotter.new(
51
56
  viewport_width: options[:width],
57
+ crop_selector: options[:crop_selector],
52
58
  user_agent: options[:useragent],
53
59
  outfile: options[:outfile],
54
- url: options[:url],
60
+ url: options[:url]
55
61
  ).take_snapshot!
56
-
@@ -0,0 +1,170 @@
1
+ var page = require('webpage').create(),
2
+ opts = JSON.parse(require('system').args[1]);
3
+
4
+ page.viewportSize = opts.viewportSize;
5
+ if (opts.userAgent) {
6
+ page.settings.userAgent = opts.userAgent;
7
+ } else {
8
+ page.settings.userAgent = page.settings.userAgent + ' Diffux';
9
+ }
10
+
11
+ /**
12
+ * Configure timeouts
13
+ */
14
+ page.waitTimeouts = {
15
+ initial: 1000,
16
+ afterResourceDone: 300,
17
+ fallback: 60000
18
+ };
19
+ // Don't wait more than 5 seconds on resources
20
+ page.settings.resourceTimeout = 5000;
21
+
22
+ /**
23
+ * Saves a log string. The full log will be added to the console.log in the end,
24
+ * so that consumers of this script can use that information.
25
+ */
26
+ page.allLogs = [];
27
+ page.log = function(string) {
28
+ page.allLogs.push(new Date().getTime() + ': ' + string);
29
+ };
30
+
31
+ /**
32
+ * By preventing animations from happening when we are taking the snapshots, we
33
+ * avoid timing issues that cause unwanted differences.
34
+ */
35
+ page.preventAnimations = function() {
36
+ // CSS Transitions
37
+ var css = document.createElement('style');
38
+ css.type = 'text/css';
39
+ document.head.appendChild(css);
40
+ var sheet = css.sheet;
41
+ sheet.addRule('*', '-webkit-transition: none !important;');
42
+ sheet.addRule('*', 'transition: none !important;');
43
+ sheet.addRule('*', '-webkit-animation-duration: 0 !important;');
44
+ sheet.addRule('*', 'animation-duration: 0 !important;');
45
+
46
+ // jQuery
47
+ if (window.jQuery) {
48
+ jQuery.fx.off = true;
49
+ jQuery('*').stop(true, true);
50
+ }
51
+
52
+ // Prevent things like blinking cursors by un-focusing any focused
53
+ // elements
54
+ document.activeElement.blur();
55
+ };
56
+
57
+
58
+ /**
59
+ * Waits until the page is ready and then fires a callback.
60
+ *
61
+ * This method will keep track of all resources requested (css, javascript, ajax
62
+ * requests, etc). As soon as we have no outstanding requests active, we start a
63
+ * short timer which fires the callback. If a new resource is requested in that
64
+ * short timeframe, we cancel the timer and wait for the new resource.
65
+ *
66
+ * In case something goes wrong, there's a 10 second fallback timer running in
67
+ * the background.
68
+ */
69
+ page.waitUntilReady = function(callback) {
70
+ var fireCallback = function() {
71
+ page.log('Done - page is ready.');
72
+ clearTimeout(page.resourceWaitTimer);
73
+ clearTimeout(page.fallbackWaitTimer);
74
+ callback();
75
+ };
76
+
77
+ page.resourcesActive = [];
78
+
79
+ page.onResourceRequested = function(request) {
80
+ page.log('Ready: Request started - [' + request.id + '] ' + request.url);
81
+ page.log('Active requests - ' + page.resourcesActive);
82
+ if (page.resourceWaitTimer) {
83
+ page.log('Clearing timeout.');
84
+ clearTimeout(page.resourceWaitTimer);
85
+ page.resourceWaitTimer = null;
86
+ }
87
+ page.resourcesActive.push(request.id);
88
+ };
89
+
90
+ function onResourceEnded(response) {
91
+ page.log('Ready: Resource received - [' + response.id + '] '
92
+ + response.url);
93
+ page.log('Active requests - ' + page.resourcesActive);
94
+
95
+ page.resourcesActive.splice(page.resourcesActive.indexOf(response.id), 1);
96
+
97
+ if (page.resourcesActive.length === 0) {
98
+ page.log('Potentially done, firing after short timeout.');
99
+ page.resourceWaitTimer = setTimeout(fireCallback,
100
+ page.waitTimeouts.afterResourceDone);
101
+ }
102
+ }
103
+
104
+
105
+ page.onResourceError = onResourceEnded;
106
+ page.onResourceTimout = onResourceEnded;
107
+ page.onResourceReceived = function(response) {
108
+ if (response.stage === 'end') {
109
+ onResourceEnded(response);
110
+ }
111
+ };
112
+
113
+ page.log('Starting default timeouts. ' + JSON.stringify(page.waitTimeouts));
114
+ page.resourceWaitTimer = setTimeout(fireCallback, page.waitTimeouts.initial);
115
+ page.fallbackWaitTimer = setTimeout(fireCallback, page.waitTimeouts.fallback);
116
+ };
117
+
118
+ /**
119
+ * Gets the top, left, width, and height of an element to crop and sets that to
120
+ * `page.clipRect` (a PhantomJS thing that will force `render` to only render
121
+ * that rectangle).
122
+ */
123
+ page.cropOutElement = function() {
124
+ page.log('Cropping out ' + opts.cropSelector);
125
+
126
+ page.clipRect = page.evaluate(function(selector) {
127
+ var cropElement = document.querySelector(selector);
128
+ if (!cropElement) {
129
+ return;
130
+ }
131
+ return cropElement.getBoundingClientRect();
132
+ }, opts.cropSelector);
133
+ page.log('Crop set to ' + JSON.stringify(page.clipRect));
134
+ };
135
+
136
+ /**
137
+ * Main place for taking the screenshot. Will exit the script when done.
138
+ */
139
+ page.takeDiffuxSnapshot = function() {
140
+ // Try to prevent animations from running, to reduce variation in
141
+ // snapshots.
142
+ page.evaluate(page.preventAnimations);
143
+
144
+ // Check if the snapshot image should be cropped.
145
+ if (opts.cropSelector) {
146
+ page.cropOutElement();
147
+ }
148
+ // Save a PNG of the rendered page
149
+ page.render(opts.outfile);
150
+
151
+ // Capture metadata
152
+ var response = page.evaluate(function() {
153
+ return { title: document.title };
154
+ });
155
+
156
+ response.opts = opts;
157
+ response.log = page.allLogs.join('\n');
158
+ response.status = status;
159
+
160
+ // The phantomjs gem can read what is written to STDOUT which includes
161
+ // console.log, so we can use that to pass information from phantomjs back
162
+ // to the app.
163
+ console.log(JSON.stringify(response));
164
+
165
+ phantom.exit();
166
+ };
167
+
168
+ page.open(opts.address, function(status) {
169
+ page.waitUntilReady(page.takeDiffuxSnapshot);
170
+ });
@@ -66,10 +66,6 @@ module Diffux
66
66
  # no default implementation
67
67
  end
68
68
 
69
- # Could be simplified as ChunkyPNG::Color::MAX * 2, but this format mirrors
70
- # the math in #pixel_diff_score
71
- MAX_EUCLIDEAN_DISTANCE = Math.sqrt(ChunkyPNG::Color::MAX**2 * 4)
72
-
73
69
  # Compute a score that represents the difference between 2 pixels
74
70
  #
75
71
  # This method simply takes the Euclidean distance between the RGBA channels
@@ -86,12 +82,8 @@ module Diffux
86
82
  # @return [Float] number between 0 and 1 where 1 is completely different
87
83
  # and 0 is no difference
88
84
  def pixel_diff_score(pixel_after, pixel_before)
89
- Math.sqrt(
90
- (r(pixel_after) - r(pixel_before))**2 +
91
- (g(pixel_after) - g(pixel_before))**2 +
92
- (b(pixel_after) - b(pixel_before))**2 +
93
- (a(pixel_after) - a(pixel_before))**2
94
- ) / MAX_EUCLIDEAN_DISTANCE
85
+ ChunkyPNG::Color::euclidean_distance_rgba(pixel_after, pixel_before) /
86
+ ChunkyPNG::Color::MAX_EUCLIDEAN_DISTANCE_RGBA
95
87
  end
96
88
 
97
89
  # @param diff_score [Float]
@@ -8,7 +8,8 @@ module Diffux
8
8
  # for a given URL and viewoprt, and then saving that snapshot to a file and
9
9
  # storing any metadata on the Snapshot object.
10
10
  class Snapshotter
11
- SCRIPT_PATH = File.join(File.dirname(__FILE__), 'script/take-snapshot.js').to_s
11
+ SCRIPT_PATH = File.join(File.dirname(__FILE__),
12
+ 'script/take-snapshot.js').to_s
12
13
 
13
14
  # @param url [String} the URL to snapshot
14
15
  # @param viewport_width [Integer] the width of the screen used when
@@ -16,15 +17,22 @@ module Diffux
16
17
  # @param outfile [File] where to store the snapshot PNG.
17
18
  # @param user_agent [String] an optional useragent string to used when
18
19
  # requesting the page.
20
+ # @param crop_selector [String] an optional string containing a CSS
21
+ # selector. If this is present, and the page contains something matching
22
+ # it, the resulting snapshot image will only contain that element. If the
23
+ # page contains multiple elements mathing the selector, only the first
24
+ # element will be used.
19
25
  def initialize(url: raise, viewport_width: raise,
20
- outfile: raise, user_agent: nil)
26
+ outfile: raise, user_agent: nil,
27
+ crop_selector: nil)
21
28
  @viewport_width = viewport_width
29
+ @crop_selector = crop_selector
22
30
  @user_agent = user_agent
23
31
  @outfile = outfile
24
32
  @url = url
25
33
  end
26
34
 
27
- # Takes a snapshot of the URL and saves it in the out_file as a PNG image.
35
+ # Takes a snapshot of the URL and saves it in the outfile as a PNG image.
28
36
  #
29
37
  # @return [Hash] a hash containing the following keys:
30
38
  # title [String] the <title> of the page being snapshotted
@@ -34,6 +42,7 @@ module Diffux
34
42
  opts = {
35
43
  address: @url,
36
44
  outfile: @outfile,
45
+ cropSelector: @crop_selector,
37
46
  viewportSize: {
38
47
  width: @viewport_width,
39
48
  height: @viewport_width,
@@ -1,4 +1,4 @@
1
1
  # Defines the gem version.
2
2
  module DiffuxCore
3
- VERSION = '0.0.1'
3
+ VERSION = '0.0.2'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: diffux-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Lencioni
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-27 00:00:00.000000000 Z
12
+ date: 2014-05-03 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: chunky_png
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 1.3.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 1.3.1
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: oily_png
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -81,6 +95,20 @@ dependencies:
81
95
  - - ">="
82
96
  - !ruby/object:Gem::Version
83
97
  version: 1.0.0
98
+ - !ruby/object:Gem::Dependency
99
+ name: codeclimate-test-reporter
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
84
112
  description: Tools for taking and comparing responsive website snapshots
85
113
  email:
86
114
  - joe.lencioni@causes.com
@@ -95,6 +123,7 @@ files:
95
123
  - bin/diffux-snapshot
96
124
  - lib/diffux_core.rb
97
125
  - lib/diffux_core/diff_cluster_finder.rb
126
+ - lib/diffux_core/script/take-snapshot.js
98
127
  - lib/diffux_core/snapshot_comparer.rb
99
128
  - lib/diffux_core/snapshot_comparison_image/after.rb
100
129
  - lib/diffux_core/snapshot_comparison_image/base.rb
@@ -128,3 +157,4 @@ signing_key:
128
157
  specification_version: 4
129
158
  summary: Diffux Core
130
159
  test_files: []
160
+ has_rdoc: