wraith 2.8.1 → 3.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 322bea139215b0b76a3fbee69b95ca2e715b2229
4
- data.tar.gz: d0c66b25dafb3df3fe601dad9a618c2e924c573c
3
+ metadata.gz: 9eb43d65349986285e6d089a4ed007f7d58247b6
4
+ data.tar.gz: 8a807791ed5348d4538495c6637ab1e2a6a11efd
5
5
  SHA512:
6
- metadata.gz: dd04184a6fc39dd9cedb1a8f099abb4567d740b3650b69ef31ef7c53eea2db97e8cb49e96eb29452e82dfb725695155458b4c3bd96924e3e73062d0e3e7933b2
7
- data.tar.gz: 22cd83978f44aecb5bbaaf9b72792d9114c6104c9bfd79e41bc884aeb9be49da52d1b9059ea6d723894bfe6983586f420b2df65355a7d23c63b3ba6e68550ab2
6
+ metadata.gz: 2460efd5b9be376c0fefeb69926d5c8d7cc05728718f8c2703f2cfb3c827825f701c0dea044424a99ba62ec8e9355fb956b71293e71d8ea9a06a500ea383bedd
7
+ data.tar.gz: 5a0fcdb92530cb4a46f34e57f90374c1ba229a634e5087d64d85386f1fd146b58bf00ce79d38b4fb15cced586f66faa3be1dcfe1f645fc51fbfb399d068a79ab
@@ -147,7 +147,9 @@ class Wraith::GalleryGenerator
147
147
  generate_html(@location, directories, slideshow_template, dest, with_path)
148
148
 
149
149
  puts "Gallery generated"
150
- check_failed_shots
150
+ failed = check_failed_shots
151
+ prompt_user_to_open_gallery dest
152
+ exit 1 if failed
151
153
  end
152
154
 
153
155
  def check_failed_shots
@@ -167,12 +169,17 @@ class Wraith::GalleryGenerator
167
169
  end
168
170
  end
169
171
 
170
- exit 1
172
+ return false
171
173
  else
172
174
  true
173
175
  end
174
176
  end
175
177
 
178
+ def prompt_user_to_open_gallery(dest)
179
+ puts "\nView the gallery in your browser:"
180
+ puts "\t file://" + `pwd`.chomp + '/' + dest
181
+ end
182
+
176
183
  class ErbBinding < OpenStruct
177
184
  def get_binding
178
185
  binding
@@ -0,0 +1,45 @@
1
+ module.exports = function (commandLineDimensions) {
2
+ // remove quotes from dimensions string
3
+ commandLineDimensions = commandLineDimensions.replace(/'/gi, '');
4
+
5
+ function getWidthAndHeight(dimensions) {
6
+ dimensions = /(\d*)x?((\d*))?/i.exec(dimensions);
7
+ return {
8
+ 'viewportWidth': parseInt(dimensions[1]),
9
+ 'viewportHeight': parseInt(dimensions[2] || 1500)
10
+ };
11
+ }
12
+
13
+ var multipleDimensions = commandLineDimensions.split(','),
14
+ dimensionsToPass;
15
+
16
+ if (multipleDimensions.length > 1) {
17
+ dimensionsToPass = multipleDimensions.map(function (cliDimensions) {
18
+ return getWidthAndHeight(cliDimensions);
19
+ });
20
+ }
21
+ else {
22
+ dimensionsToPass = getWidthAndHeight(commandLineDimensions);
23
+ }
24
+
25
+ return {
26
+ dimensions: dimensionsToPass,
27
+ takingMultipleScreenshots: function (dimensions) {
28
+ return dimensions.length && dimensions.length > 1;
29
+ },
30
+ replaceImageNameWithDimensions: function (image_name, currentDimensions) {
31
+ // shots/clickable_guide__after_click/MULTI_casperjs_english.png
32
+ // ->
33
+ // shots/clickable_guide__after_click/1024x359_casperjs_english.png
34
+ var dirs = image_name.split('/'),
35
+ filename = dirs[dirs.length - 1],
36
+ filenameParts = filename.split('_'),
37
+ newFilename;
38
+
39
+ filenameParts[0] = currentDimensions.viewportWidth + 'x' + currentDimensions.viewportHeight;
40
+ dirs.pop(); // remove MULTI_casperjs_english.png
41
+ newFilename = dirs.join('/') + '/' + filenameParts.join('_');
42
+ return newFilename;
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,112 @@
1
+ module.exports = function (config) {
2
+
3
+ // config
4
+ var systemArgs = config.systemArgs,
5
+ javascriptEnabled = config.javascriptEnabled;
6
+
7
+ // modules
8
+ var page = require('webpage').create(),
9
+ helper = require('./_helper.js')(systemArgs[2]);
10
+
11
+ // command line arguments
12
+ var url = systemArgs[1],
13
+ dimensions = helper.dimensions,
14
+ image_name = systemArgs[3],
15
+ selector = systemArgs[4],
16
+ globalBeforeCaptureJS = systemArgs[5],
17
+ pathBeforeCaptureJS = systemArgs[6],
18
+ dimensionsProcessed = 0,
19
+ currentDimensions;
20
+
21
+ globalBeforeCaptureJS = globalBeforeCaptureJS === 'false' ? false : globalBeforeCaptureJS;
22
+ pathBeforeCaptureJS = pathBeforeCaptureJS === 'false' ? false : pathBeforeCaptureJS;
23
+
24
+ var current_requests = 0;
25
+ var last_request_timeout;
26
+ var final_timeout;
27
+
28
+ if (helper.takingMultipleScreenshots(dimensions)) {
29
+ currentDimensions = dimensions[0];
30
+ image_name = helper.replaceImageNameWithDimensions(image_name, currentDimensions);
31
+ }
32
+ else {
33
+ currentDimensions = dimensions;
34
+ }
35
+
36
+ page.viewportSize = { width: currentDimensions.viewportWidth, height: currentDimensions.viewportHeight};
37
+ page.settings = { loadImages: true, javascriptEnabled: javascriptEnabled };
38
+
39
+ // If you want to use additional phantomjs commands, place them here
40
+ page.settings.userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.17';
41
+
42
+ page.onResourceRequested = function(req) {
43
+ current_requests += 1;
44
+ };
45
+
46
+ page.onResourceReceived = function(res) {
47
+ if (res.stage === 'end') {
48
+ current_requests -= 1;
49
+ debounced_render();
50
+ }
51
+ };
52
+
53
+ page.open(url, function(status) {
54
+ if (status !== 'success') {
55
+ console.log('Error with page ' + url);
56
+ phantom.exit();
57
+ }
58
+ });
59
+
60
+ function runSetupJavaScriptThenCaptureImage() {
61
+ if (globalBeforeCaptureJS) {
62
+ require(globalBeforeCaptureJS)(page);
63
+ }
64
+ if (pathBeforeCaptureJS) {
65
+ require(pathBeforeCaptureJS)(page);
66
+ }
67
+ captureImage();
68
+ }
69
+
70
+ function captureImage() {
71
+
72
+ console.log('Snapping ' + url + ' at: ' + currentDimensions.viewportWidth + 'x' + currentDimensions.viewportHeight);
73
+ page.clipRect = {
74
+ top: 0,
75
+ left: 0,
76
+ height: currentDimensions.viewportHeight,
77
+ width: currentDimensions.viewportWidth
78
+ };
79
+ page.render(image_name);
80
+
81
+ dimensionsProcessed++;
82
+ if (helper.takingMultipleScreenshots(dimensions) && dimensionsProcessed < dimensions.length) {
83
+ currentDimensions = dimensions[dimensionsProcessed];
84
+ image_name = helper.replaceImageNameWithDimensions(image_name, currentDimensions);
85
+ setTimeout(captureImage, 1000);
86
+ }
87
+ else {
88
+ // prevent CI from failing from 'Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL' errors
89
+ // see https://github.com/n1k0/casperjs/issues/1068
90
+ setTimeout(function(){
91
+ phantom.exit();
92
+ }, 10);
93
+ }
94
+ }
95
+
96
+ function debounced_render() {
97
+ clearTimeout(last_request_timeout);
98
+ clearTimeout(final_timeout);
99
+
100
+ // If there's no more ongoing resource requests, wait for 1 second before
101
+ // rendering, just in case the page kicks off another request
102
+ if (current_requests < 1) {
103
+ clearTimeout(final_timeout);
104
+ last_request_timeout = setTimeout(runSetupJavaScriptThenCaptureImage, 1000);
105
+ }
106
+
107
+ // Sometimes, straggling requests never make it back, in which
108
+ // case, timeout after 5 seconds and render the page anyway
109
+ final_timeout = setTimeout(runSetupJavaScriptThenCaptureImage, 5000);
110
+ }
111
+
112
+ }
@@ -0,0 +1,81 @@
1
+ // modules
2
+ var system = require('system'),
3
+ casper = require('casper').create(),
4
+ helper = requireRelative('_helper.js')(casper.cli.get(1));
5
+
6
+ // command line arguments
7
+ var url = casper.cli.get(0),
8
+ dimensions = helper.dimensions,
9
+ image_name = casper.cli.get(2),
10
+ selector = casper.cli.get(3),
11
+ globalBeforeCaptureJS = casper.cli.get(4),
12
+ pathBeforeCaptureJS = casper.cli.get(5),
13
+ dimensionsProcessed = 0,
14
+ currentDimensions;
15
+
16
+ // functions
17
+ function requireRelative(file) {
18
+ // PhantomJS will automatically `require` relatively, but CasperJS needs some extra help. Hence this function.
19
+ // 'templates/javascript/casper.js' -> 'templates/javascript'
20
+ var currentFilePath = system.args[3].split('/');
21
+ currentFilePath.pop();
22
+ var fs = require('fs');
23
+ currentFilePath = fs.absolute(currentFilePath.join('/'));
24
+ return require(currentFilePath + '/' + file);
25
+ }
26
+ function snap() {
27
+ console.log('Snapping ' + url + ' at: ' + currentDimensions.viewportWidth + 'x' + currentDimensions.viewportHeight);
28
+
29
+ if (!selector) {
30
+ this.capture(image_name);
31
+ }
32
+ else {
33
+ this.captureSelector(image_name, selector);
34
+ }
35
+
36
+ dimensionsProcessed++;
37
+ if (helper.takingMultipleScreenshots(dimensions) && dimensionsProcessed < dimensions.length) {
38
+ currentDimensions = dimensions[dimensionsProcessed];
39
+ image_name = helper.replaceImageNameWithDimensions(image_name, currentDimensions);
40
+ casper.viewport(currentDimensions.viewportWidth, currentDimensions.viewportHeight);
41
+ casper.wait(300, function then () {
42
+ snap.bind(this)();
43
+ });
44
+ }
45
+ }
46
+
47
+ if (helper.takingMultipleScreenshots(dimensions)) {
48
+ currentDimensions = dimensions[0];
49
+ image_name = helper.replaceImageNameWithDimensions(image_name, currentDimensions);
50
+ }
51
+ else {
52
+ currentDimensions = dimensions;
53
+ }
54
+
55
+ // Casper can now do its magic
56
+ casper.start();
57
+ casper.open(url);
58
+ casper.viewport(currentDimensions.viewportWidth, currentDimensions.viewportHeight);
59
+ casper.then(function() {
60
+ if (globalBeforeCaptureJS) {
61
+ require('./' + globalBeforeCaptureJS)(this);
62
+ }
63
+ });
64
+ casper.then(function() {
65
+ if (pathBeforeCaptureJS) {
66
+ require('./' + pathBeforeCaptureJS)(this);
67
+ }
68
+ });
69
+ // waits for all images to download before taking screenshots
70
+ // (broken images are a big cause of Wraith failures!)
71
+ // Credit: http://reff.it/8m3HYP
72
+ casper.waitFor(function() {
73
+ return this.evaluate(function() {
74
+ var images = document.getElementsByTagName('img');
75
+ return Array.prototype.every.call(images, function(i) { return i.complete; });
76
+ });
77
+ }, function then () {
78
+ snap.bind(this)();
79
+ });
80
+
81
+ casper.run();
File without changes
@@ -5,8 +5,8 @@ require "shellwords"
5
5
  class Wraith::SaveImages
6
6
  attr_reader :wraith, :history, :meta
7
7
 
8
- def initialize(config, history = false)
9
- @wraith = Wraith::Wraith.new(config)
8
+ def initialize(config, history = false, yaml_passed = false)
9
+ @wraith = Wraith::Wraith.new(config, yaml_passed)
10
10
  @history = history
11
11
  @meta = SaveMetadata.new(@wraith, history)
12
12
  end
@@ -21,26 +21,51 @@ class Wraith::SaveImages
21
21
  end
22
22
 
23
23
  def save_images
24
+ jobs = define_jobs
25
+ parallel_task(jobs)
26
+ end
27
+
28
+ def define_jobs
24
29
  jobs = []
25
30
  check_paths.each do |label, options|
26
31
  settings = CaptureOptions.new(options, wraith)
27
32
 
28
- wraith.widths.each do |width|
29
- base_file_name = meta.file_names(width, label, meta.base_label)
30
- compare_file_name = meta.file_names(width, label, meta.compare_label)
31
-
32
- jobs << [label, settings.path, width, settings.base_url, base_file_name, settings.selector, wraith.before_capture, settings.before_capture]
33
- jobs << [label, settings.path, width, settings.compare_url, compare_file_name, settings.selector, wraith.before_capture, settings.before_capture] unless settings.compare_url.nil?
33
+ if wraith.resize
34
+ jobs = jobs + define_individual_job(label, settings, wraith.widths)
35
+ else
36
+ wraith.widths.each do |width|
37
+ jobs = jobs + define_individual_job(label, settings, width)
38
+ end
34
39
  end
35
40
  end
36
- parallel_task(jobs)
41
+ jobs
42
+ end
43
+
44
+ def define_individual_job(label, settings, width)
45
+ base_file_name = meta.file_names(width, label, meta.base_label)
46
+ compare_file_name = meta.file_names(width, label, meta.compare_label)
47
+
48
+ jobs = []
49
+ jobs << [label, settings.path, prepare_widths_for_cli(width), settings.base_url, base_file_name, settings.selector, wraith.before_capture, settings.before_capture]
50
+ jobs << [label, settings.path, prepare_widths_for_cli(width), settings.compare_url, compare_file_name, settings.selector, wraith.before_capture, settings.before_capture] unless settings.compare_url.nil?
51
+
52
+ jobs
53
+ end
54
+
55
+ def prepare_widths_for_cli(width)
56
+ if width.kind_of? Array
57
+ # prepare for the command line. [30,40,50] => "'30','40','50'"
58
+ width = width.map{ |i| "'#{i}'" }.join(',')
59
+ end
60
+ width
37
61
  end
38
62
 
39
63
  def capture_page_image(browser, url, width, file_name, selector, global_before_capture, path_before_capture)
40
- command = "#{browser} #{wraith.phantomjs_options} '#{wraith.snap_file}' '#{url}' '#{width}' '#{file_name}' '#{selector}' '#{global_before_capture}' '#{path_before_capture}'"
64
+
65
+ command = "#{browser} #{wraith.phantomjs_options} '#{wraith.snap_file}' '#{url}' \"#{width}\" '#{file_name}' '#{selector}' '#{global_before_capture}' '#{path_before_capture}'"
41
66
 
42
67
  # @TODO - uncomment the following line when we add a verbose mode
43
- # puts command
68
+ #puts command
44
69
  run_command command
45
70
  end
46
71
 
@@ -68,6 +93,10 @@ class Wraith::SaveImages
68
93
  max_attempts.times do |i|
69
94
  capture_page_image meta.engine, url, width, filename, selector, global_before_capture, path_before_capture
70
95
 
96
+ if wraith.resize
97
+ return # @TODO - need to check if the image was generated, as per the reload example below
98
+ end
99
+
71
100
  return if File.exist? filename
72
101
 
73
102
  puts "Failed to capture image #{filename} on attempt number #{i + 1} of #{max_attempts}"
@@ -142,12 +171,11 @@ class SaveMetadata
142
171
  history ? "_latest" : ""
143
172
  end
144
173
 
145
- def engine_label
146
- wraith.engine.key(engine)
147
- end
148
-
149
174
  def file_names(width, label, domain_label)
150
- "#{wraith.directory}/#{label}/#{width}_#{engine_label}_#{domain_label}.png"
175
+ if width.kind_of? Array
176
+ width = 'MULTI'
177
+ end
178
+ "#{wraith.directory}/#{label}/#{width}_#{engine}_#{domain_label}.png"
151
179
  end
152
180
 
153
181
  def base_label
@@ -159,6 +187,6 @@ class SaveMetadata
159
187
  end
160
188
 
161
189
  def engine
162
- wraith.engine.each { |_label, browser| return browser }
190
+ wraith.engine
163
191
  end
164
192
  end
@@ -1,3 +1,3 @@
1
1
  module Wraith
2
- VERSION = "2.8.1"
2
+ VERSION = "3.0.0"
3
3
  end
data/lib/wraith/wraith.rb CHANGED
@@ -3,15 +3,20 @@ require "yaml"
3
3
  class Wraith::Wraith
4
4
  attr_accessor :config
5
5
 
6
- def initialize(config_name)
6
+ def initialize(config, yaml_passed = false)
7
+ @config = yaml_passed ? config : open_config_file(config)
8
+ rescue
9
+ puts "unable to find config at #{config}"
10
+ exit 1
11
+ end
12
+
13
+ def open_config_file(config_name)
7
14
  if File.exist?(config_name) && File.extname(config_name) == ".yaml"
8
- @config = YAML.load(File.open(config_name))
15
+ config = File.open config_name
9
16
  else
10
- @config = YAML.load(File.open("configs/#{config_name}.yaml"))
17
+ config = File.open "configs/#{config_name}.yaml"
11
18
  end
12
- rescue
13
- puts "unable to find config at #{config_name}"
14
- exit 1
19
+ YAML.load config
15
20
  end
16
21
 
17
22
  def directory
@@ -23,8 +28,30 @@ class Wraith::Wraith
23
28
  @config["history_dir"]
24
29
  end
25
30
 
31
+ def engine
32
+ engine = @config["browser"]
33
+ # Legacy support for those using the old style "browser: \n phantomjs: 'casperjs'" configs
34
+ if engine.is_a? Hash
35
+ engine = engine.values.first
36
+ end
37
+ engine
38
+ end
39
+
26
40
  def snap_file
27
- @config["snap_file"] ? @config["snap_file"] : File.expand_path("lib/wraith/javascript/snap.js")
41
+ @config["snap_file"] || snap_file_from_engine(engine)
42
+ end
43
+
44
+ def snap_file_from_engine(engine)
45
+ path_to_js_templates = File.dirname(__FILE__) + '/javascript'
46
+ case engine
47
+ when "phantomjs"
48
+ path_to_js_templates + "/phantom.js"
49
+ when "casperjs"
50
+ path_to_js_templates + "/casper.js"
51
+ # @TODO - add a SlimerJS option
52
+ else
53
+ abort "Wraith does not recognise the browser engine '#{engine}'"
54
+ end
28
55
  end
29
56
 
30
57
  def before_capture
@@ -35,6 +62,11 @@ class Wraith::Wraith
35
62
  @config["screen_widths"]
36
63
  end
37
64
 
65
+ def resize
66
+ # @TODO make this default to true, once it's been tested a bit more thoroughly
67
+ @config["resize_or_reload"] ? (@config["resize_or_reload"] == "resize") : false
68
+ end
69
+
38
70
  def domains
39
71
  @config["domains"]
40
72
  end
@@ -75,10 +107,6 @@ class Wraith::Wraith
75
107
  @config["paths"]
76
108
  end
77
109
 
78
- def engine
79
- @config["browser"]
80
- end
81
-
82
110
  def fuzz
83
111
  @config["fuzz"]
84
112
  end