phantom_jasmine 0.0.1
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.
- data/.gitignore +17 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/ext/mkrf_conf.rb +22 -0
- data/lib/jasmine/runners/phantom.rb +61 -0
- data/lib/jasmine/runners/phantom_jasmine_count.js +39 -0
- data/lib/jasmine/runners/phantom_jasmine_run.js +85 -0
- data/lib/phantom_jasmine/run_specs.rb +36 -0
- data/lib/phantom_jasmine/version.rb +3 -0
- data/lib/phantom_jasmine.rb +9 -0
- data/lib/tasks/phantom_jasmine.rake +31 -0
- data/phantom_jasmine.gemspec +24 -0
- metadata +94 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.3@phantom_jasmine --create
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ryan Dy
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# PhantomJasmine
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'phantom_jasmine'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install phantom_jasmine
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/ext/mkrf_conf.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/command.rb'
|
3
|
+
require 'rubygems/dependency_installer.rb'
|
4
|
+
|
5
|
+
begin
|
6
|
+
Gem::Command.build_args = ARGV
|
7
|
+
rescue NoMethodError
|
8
|
+
end
|
9
|
+
inst = Gem::DependencyInstaller.new
|
10
|
+
begin
|
11
|
+
if RUBY_PLATFORM.downcase.include? 'darwin'
|
12
|
+
inst.install 'phatomjs-mac', '>= 0.0.3'
|
13
|
+
end
|
14
|
+
rescue
|
15
|
+
#Exit with a non-zero value to let rubygems know something went wrong
|
16
|
+
exit(1)
|
17
|
+
end
|
18
|
+
|
19
|
+
# create dummy rakefile to indicate success
|
20
|
+
f = File.open(File.join(File.dirname(__FILE__), 'Rakefile'), 'w')
|
21
|
+
f.write("task :default\n")
|
22
|
+
f.close
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
class Jasmine::Runners::Phantom
|
4
|
+
attr_accessor :suites
|
5
|
+
|
6
|
+
def initialize(port, results_processor, result_batch_size)
|
7
|
+
@port = port
|
8
|
+
@results_processor = results_processor
|
9
|
+
@result_batch_size = result_batch_size
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
load_suite_info
|
14
|
+
@results_processor.process(results_hash, suites)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def load_suite_info
|
20
|
+
tmpfile = Tempfile.new('count')
|
21
|
+
pid = Process.spawn "#{Phantomjs.executable_path} '#{File.join(File.dirname(__FILE__), 'phantom_jasmine_count.js')}' #{@port}", :out => tmpfile.path
|
22
|
+
Process.wait pid
|
23
|
+
json = JSON.parse(tmpfile.read, :max_nesting => 100).tap { tmpfile.close }
|
24
|
+
@suites = json['suites']
|
25
|
+
@top_level_suites = json['top_level_suites']
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_suites(suites)
|
29
|
+
tmpfile = Tempfile.new('run')
|
30
|
+
commands = suites.map do |suite|
|
31
|
+
"#{Phantomjs.executable_path} '#{File.join(File.dirname(__FILE__), 'phantom_jasmine_run.js')}' #{@port} '#{suite['description']}'"
|
32
|
+
end.join(';echo ,;')
|
33
|
+
|
34
|
+
pid = Process.spawn "echo [;#{commands};echo ]", :out => tmpfile.path
|
35
|
+
[pid, tmpfile]
|
36
|
+
end
|
37
|
+
|
38
|
+
def results_hash
|
39
|
+
spec_results = {}
|
40
|
+
|
41
|
+
@top_level_suites.group_by { |suite| suite['id'] % processor_count }.map { |(k, suites)| run_suites(suites) }.each do |pid, tmpfile|
|
42
|
+
Process.wait pid
|
43
|
+
|
44
|
+
JSON.parse(tmpfile.read).each do |result|
|
45
|
+
result.each do |spec_id, spec_result|
|
46
|
+
spec_results.merge! spec_id => spec_result unless spec_result['messages'].empty?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
tmpfile.close
|
51
|
+
end
|
52
|
+
|
53
|
+
spec_results
|
54
|
+
end
|
55
|
+
|
56
|
+
def processor_count
|
57
|
+
@processor_count ||= begin
|
58
|
+
ENV['JASMINE_PARALLEL_COUNT'] || [(`sysctl -n hw.ncpu` || 4).to_i, 4].min # 8 processes seems to use too much memory (500mb each!)
|
59
|
+
end.to_i
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
(function() {
|
2
|
+
var port = phantom.args[0];
|
3
|
+
var filter = phantom.args[1];
|
4
|
+
|
5
|
+
if (!parseInt(port, 10) || phantom.args.length > 2) {
|
6
|
+
console.log('Usage: run-jasmine.js PORT [spec_name_filter]');
|
7
|
+
phantom.exit(1);
|
8
|
+
}
|
9
|
+
|
10
|
+
var page = require('webpage').create();
|
11
|
+
var fs = require('fs');
|
12
|
+
|
13
|
+
var url = 'http://localhost:' + port;
|
14
|
+
if (filter) {
|
15
|
+
url += '?spec=' + encodeURIComponent(filter);
|
16
|
+
}
|
17
|
+
|
18
|
+
page.open(url, function(status) {
|
19
|
+
if (status !== "success") {
|
20
|
+
console.log("Unable to access network");
|
21
|
+
phantom.exit(1);
|
22
|
+
} else {
|
23
|
+
var json = page.evaluate(function() {
|
24
|
+
var jasmineEnv = {
|
25
|
+
suites: jsApiReporter.suites(),
|
26
|
+
top_level_suites: jasmine.getEnv().currentRunner().topLevelSuites().map(function(suite) {
|
27
|
+
return {
|
28
|
+
id: suite.id,
|
29
|
+
description: suite.description
|
30
|
+
};
|
31
|
+
})
|
32
|
+
};
|
33
|
+
return JSON.stringify(jasmineEnv);
|
34
|
+
});
|
35
|
+
fs.write('/dev/stdout', json, 'w');
|
36
|
+
phantom.exit(0);
|
37
|
+
}
|
38
|
+
});
|
39
|
+
}).call(this);
|
@@ -0,0 +1,85 @@
|
|
1
|
+
(function() {
|
2
|
+
/**
|
3
|
+
* Wait until the test condition is true or a timeout occurs. Useful for waiting
|
4
|
+
* on a server response or for a ui change (fadeIn, etc.) to occur.
|
5
|
+
*
|
6
|
+
* @param testFx javascript condition that evaluates to a boolean,
|
7
|
+
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
|
8
|
+
* as a callback function.
|
9
|
+
* @param onReady what to do when testFx condition is fulfilled,
|
10
|
+
* it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
|
11
|
+
* as a callback function.
|
12
|
+
* @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
|
13
|
+
*/
|
14
|
+
function waitFor(testFx, onReady, timeOutMillis) {
|
15
|
+
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 6000001, //< Default Max Timeout is 3s
|
16
|
+
start = new Date().getTime(),
|
17
|
+
condition = false,
|
18
|
+
interval = setInterval(function() {
|
19
|
+
if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
|
20
|
+
// If not time-out yet and condition not yet fulfilled
|
21
|
+
condition = (typeof(testFx) === 'string' ? eval(testFx) : testFx()); //< defensive code
|
22
|
+
} else {
|
23
|
+
if (!condition) {
|
24
|
+
// If condition still not fulfilled (timeout but condition is 'false')
|
25
|
+
phantom.exit(1);
|
26
|
+
} else {
|
27
|
+
// Condition fulfilled (timeout and/or condition is 'true')
|
28
|
+
if (typeof(onReady) === 'string') {
|
29
|
+
eval(onReady);
|
30
|
+
} else {
|
31
|
+
onReady(); //< Do what it's supposed to do once the condition is fulfilled
|
32
|
+
}
|
33
|
+
clearInterval(interval); //< Stop this interval
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}, 100); //< repeat check every 100ms
|
37
|
+
}
|
38
|
+
|
39
|
+
var port = phantom.args[0];
|
40
|
+
var filter = phantom.args[1];
|
41
|
+
|
42
|
+
if (!parseInt(port, 10) || phantom.args.length > 2) {
|
43
|
+
phantom.exit(1);
|
44
|
+
}
|
45
|
+
|
46
|
+
var page = require('webpage').create();
|
47
|
+
var fs = require('fs');
|
48
|
+
|
49
|
+
var url = 'http://localhost:' + port;
|
50
|
+
if (filter) {
|
51
|
+
url += '?spec=' + encodeURIComponent(filter);
|
52
|
+
}
|
53
|
+
|
54
|
+
page.open(url, function(status) {
|
55
|
+
if (status !== "success") {
|
56
|
+
phantom.exit(1);
|
57
|
+
} else {
|
58
|
+
page.evaluate(function() {
|
59
|
+
if (window.phantomInitialized) {
|
60
|
+
return;
|
61
|
+
}
|
62
|
+
|
63
|
+
window.phantomInitialized = true;
|
64
|
+
|
65
|
+
// don't do any setTimeout garbage
|
66
|
+
jasmine.getEnv().updateInterval = null;
|
67
|
+
});
|
68
|
+
|
69
|
+
waitFor(function() {
|
70
|
+
return page.evaluate(function() {
|
71
|
+
return !jasmine.getEnv().currentRunner().queue.running;
|
72
|
+
});
|
73
|
+
}, function() {
|
74
|
+
var json = page.evaluate(function() {
|
75
|
+
var specIds = _(jasmine.getEnv().currentRunner().specs()).map(function(spec) {
|
76
|
+
return spec.id;
|
77
|
+
});
|
78
|
+
return JSON.stringify(jsApiReporter.resultsForSpecs(specIds));
|
79
|
+
});
|
80
|
+
fs.write('/dev/stdout', json, 'w');
|
81
|
+
phantom.exit(0);
|
82
|
+
}, 1000 * 60 * 20); // wait 20 minutes (CI can be slow)
|
83
|
+
}
|
84
|
+
});
|
85
|
+
}).call(this);
|
@@ -0,0 +1,36 @@
|
|
1
|
+
$:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'jasmine'
|
5
|
+
if Jasmine::Dependencies.rspec2?
|
6
|
+
require 'rspec'
|
7
|
+
else
|
8
|
+
require 'spec'
|
9
|
+
end
|
10
|
+
require 'jasmine/runners/phantom'
|
11
|
+
require 'phantomjs-mac' if RUBY_PLATFORM.downcase.include?('darwin')
|
12
|
+
|
13
|
+
jasmine_yml = File.join(Dir.pwd, 'spec', 'javascripts', 'support', 'jasmine.yml')
|
14
|
+
if File.exist?(jasmine_yml)
|
15
|
+
end
|
16
|
+
|
17
|
+
Jasmine.load_configuration_from_yaml
|
18
|
+
|
19
|
+
config = Jasmine.config
|
20
|
+
|
21
|
+
server = Jasmine::Server.new(config.port, Jasmine::Application.app(config))
|
22
|
+
t = Thread.new do
|
23
|
+
begin
|
24
|
+
server.start
|
25
|
+
rescue ChildProcess::TimeoutError
|
26
|
+
end
|
27
|
+
# # ignore bad exits
|
28
|
+
end
|
29
|
+
t.abort_on_exception = true
|
30
|
+
Jasmine::wait_for_listener(config.port, "jasmine server")
|
31
|
+
puts "jasmine server started."
|
32
|
+
|
33
|
+
results_processor = Jasmine::ResultsProcessor.new(config)
|
34
|
+
results = Jasmine::Runners::Phantom.new(config.port, results_processor, config.result_batch_size).run
|
35
|
+
formatter = Jasmine::RspecFormatter.new
|
36
|
+
formatter.format_results(results)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
namespace :jasmine do
|
2
|
+
desc "Run continuous integration tests with phantom"
|
3
|
+
task :phantom => ["jasmine:require_json", "jasmine:require"] do
|
4
|
+
if Jasmine::Dependencies.rspec2?
|
5
|
+
require "rspec"
|
6
|
+
require "rspec/core/rake_task"
|
7
|
+
else
|
8
|
+
require "spec"
|
9
|
+
require 'spec/rake/spectask'
|
10
|
+
end
|
11
|
+
|
12
|
+
run_specs = ["#{File.join(File.dirname(__FILE__), '..', 'phantom_jasmine', 'run_specs.rb')}"]
|
13
|
+
if Jasmine::Dependencies.rspec2?
|
14
|
+
RSpec::Core::RakeTask.new(:jasmine_continuous_integration_runner) do |t|
|
15
|
+
t.rspec_opts = ["--colour", "--format", ENV['JASMINE_SPEC_FORMAT'] || "progress"]
|
16
|
+
t.verbose = true
|
17
|
+
if Jasmine::Dependencies.rails_3_asset_pipeline?
|
18
|
+
t.rspec_opts += ["-r #{File.expand_path(File.join(::Rails.root, 'config', 'environment'))}"]
|
19
|
+
end
|
20
|
+
t.pattern = run_specs
|
21
|
+
end
|
22
|
+
else
|
23
|
+
Spec::Rake::SpecTask.new(:jasmine_continuous_integration_runner) do |t|
|
24
|
+
t.spec_opts = ["--color", "--format", ENV['JASMINE_SPEC_FORMAT'] || "specdoc"]
|
25
|
+
t.verbose = true
|
26
|
+
t.spec_files = run_specs
|
27
|
+
end
|
28
|
+
end
|
29
|
+
Rake::Task["jasmine_continuous_integration_runner"].invoke
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'phantom_jasmine/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "phantom_jasmine"
|
8
|
+
gem.version = PhantomJasmine::VERSION
|
9
|
+
gem.authors = ["Ryan Dy"]
|
10
|
+
gem.email = ["ryan.dy@gmail.com"]
|
11
|
+
gem.description = %q{Adds a new rake task jasmine:phantom that runs specs in parallel using phantoms js.}
|
12
|
+
gem.summary = %q{an extension for running jasmine with phantom js in parallel}
|
13
|
+
gem.homepage = "https://github.com/rdy/phantom_jasmine"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.extensions = ['ext/mkrf_conf.rb']
|
21
|
+
|
22
|
+
gem.add_dependency %q{jasmine}, '>= 1.2'
|
23
|
+
gem.add_dependency %q{phantomjs-mac}, '>= 0.0.3'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: phantom_jasmine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Dy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: jasmine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.2'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: phantomjs-mac
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.0.3
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.0.3
|
46
|
+
description: Adds a new rake task jasmine:phantom that runs specs in parallel using
|
47
|
+
phantoms js.
|
48
|
+
email:
|
49
|
+
- ryan.dy@gmail.com
|
50
|
+
executables: []
|
51
|
+
extensions:
|
52
|
+
- ext/mkrf_conf.rb
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- .rvmrc
|
57
|
+
- Gemfile
|
58
|
+
- LICENSE.txt
|
59
|
+
- README.md
|
60
|
+
- Rakefile
|
61
|
+
- ext/mkrf_conf.rb
|
62
|
+
- lib/jasmine/runners/phantom.rb
|
63
|
+
- lib/jasmine/runners/phantom_jasmine_count.js
|
64
|
+
- lib/jasmine/runners/phantom_jasmine_run.js
|
65
|
+
- lib/phantom_jasmine.rb
|
66
|
+
- lib/phantom_jasmine/run_specs.rb
|
67
|
+
- lib/phantom_jasmine/version.rb
|
68
|
+
- lib/tasks/phantom_jasmine.rake
|
69
|
+
- phantom_jasmine.gemspec
|
70
|
+
homepage: https://github.com/rdy/phantom_jasmine
|
71
|
+
licenses: []
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.8.24
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: an extension for running jasmine with phantom js in parallel
|
94
|
+
test_files: []
|