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 +4 -4
- data/lib/wraith/gallery.rb +9 -2
- data/lib/wraith/javascript/_helper.js +45 -0
- data/lib/wraith/javascript/_phantom__common.js +112 -0
- data/lib/wraith/javascript/casper.js +81 -0
- data/{templates → lib/wraith}/javascript/phantom--nojs.js +0 -0
- data/{templates → lib/wraith}/javascript/phantom.js +0 -0
- data/lib/wraith/save_images.rb +45 -17
- data/lib/wraith/version.rb +1 -1
- data/lib/wraith/wraith.rb +39 -11
- data/spec/{helpers.rb → _helpers.rb} +5 -4
- data/spec/before_capture_spec.rb +81 -0
- data/spec/config_spec.rb +139 -0
- data/spec/configs/test_config--casper.yaml +2 -2
- data/spec/configs/test_config--phantom.yaml +3 -3
- data/spec/gallery_spec.rb +38 -0
- data/{templates/javascript/casper.js → spec/js/custom_snap_file.js} +5 -1
- data/spec/resize_reload_spec.rb +55 -0
- data/spec/save_images_spec.rb +54 -0
- data/templates/configs/component.yaml +4 -7
- data/templates/configs/multiple_domains.yaml +2 -8
- data/templates/configs/spider.yaml +13 -19
- data/templates/javascript/beforeCapture--casper_example.js +10 -3
- data/templates/javascript/beforeCapture--phantom_example.js +29 -2
- metadata +51 -42
- data/spec/wraith_spec.rb +0 -209
- data/templates/javascript/README.md +0 -5
- data/templates/javascript/_getDimensions.js +0 -7
- data/templates/javascript/_phantom__common.js +0 -122
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9eb43d65349986285e6d089a4ed007f7d58247b6
|
4
|
+
data.tar.gz: 8a807791ed5348d4538495c6637ab1e2a6a11efd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2460efd5b9be376c0fefeb69926d5c8d7cc05728718f8c2703f2cfb3c827825f701c0dea044424a99ba62ec8e9355fb956b71293e71d8ea9a06a500ea383bedd
|
7
|
+
data.tar.gz: 5a0fcdb92530cb4a46f34e57f90374c1ba229a634e5087d64d85386f1fd146b58bf00ce79d38b4fb15cced586f66faa3be1dcfe1f645fc51fbfb399d068a79ab
|
data/lib/wraith/gallery.rb
CHANGED
@@ -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
|
-
|
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
|
File without changes
|
data/lib/wraith/save_images.rb
CHANGED
@@ -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.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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
|
190
|
+
wraith.engine
|
163
191
|
end
|
164
192
|
end
|
data/lib/wraith/version.rb
CHANGED
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(
|
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
|
-
|
15
|
+
config = File.open config_name
|
9
16
|
else
|
10
|
-
|
17
|
+
config = File.open "configs/#{config_name}.yaml"
|
11
18
|
end
|
12
|
-
|
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"]
|
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
|