diffux-core 0.0.1 → 0.0.2

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 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: