wraith 2.8.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|