jasmine-rails 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -6,19 +6,20 @@ This project is intended to make it a little easier to integrate [Jasmine](https
6
6
 
7
7
  By bundling this gem and configuring your project, you can expect to:
8
8
 
9
- * Be able to run Jasmine specs from the command line (*and fast*) with John Bintz's excellent [jasmine-headless-webkit](http://johnbintz.github.com/jasmine-headless-webkit/)
10
- * Be able to run Jasmine specs in a browser (wherever you choose to mount the jasmine-rails engine)
9
+ * Be able to run Jasmine specs in a browser (powered by Rails engine mounted into your application)
10
+ * Be able to run Jasmine specs from the command line (powered by
11
+ [PhantomJS](http://phantomjs.org/))
11
12
  * Write specs or source in [CoffeeScript](http://jashkenas.github.com/coffee-script/), leveraging the [asset pipeline](http://railscasts.com/episodes/279-understanding-the-asset-pipeline) to pre-process it
12
13
 
13
14
  ## Prerequisites
14
15
 
15
- Install qt for its headless webkit widget. The easiest way (on a Mac) that I've found is to use [homebrew](https://github.com/mxcl/homebrew):
16
+ Install phantomjs in order to run tests headless on the command line. The easiest way (on a Mac) that I've found is to use [homebrew](https://github.com/mxcl/homebrew):
16
17
 
17
- brew install qt
18
+ brew install phantomjs
18
19
 
19
- For help installing the qt libs on other platforms, the I'd recommend [perusing capybara-webkit driver's documentation](https://github.com/thoughtbot/capybara-webkit), becuse it has the same dependency.
20
+ If you're not on a Mac, fear not, as [installing PhantomJS](http://phantomjs.org) is pretty painless for most environments. The important thing is that the binary be somewhere on your PATH.
20
21
 
21
- ## Adding & configuring the gem
22
+ ## Installation
22
23
 
23
24
  First, add jasmine-rails to your Gemfile, like so
24
25
 
@@ -28,54 +29,77 @@ First, add jasmine-rails to your Gemfile, like so
28
29
 
29
30
  Next, run `bundle install`.
30
31
 
32
+ Now, just mount jasmine-rails into your application by adding something like this to your routes.rb. The engine can be mounted to any path that you choose.
33
+
34
+ ``` ruby
35
+ mount JasmineRails::Engine => "/specs" if defined?(JasmineRails)
36
+ ```
37
+
38
+ ## Configuration
39
+
31
40
  In order to run any specs, you'll need a Jasmine configuration in `spec/javascripts/support/jasmine.yml`. [Here's an example](https://github.com/searls/jasmine-rails/tree/master/spec/dummy/spec/javascripts/support) from this repo's [dummy project](https://github.com/searls/jasmine-rails/tree/master/spec/dummy).
32
41
 
33
42
  ``` yaml
43
+ # path to parent directory of src_files
44
+ # relative path from Rails.root
45
+ # defaults to app/assets/javascripts
46
+ src_dir: "app/assets/javascripts"
47
+
48
+ # list of file expressions to include as source files
49
+ # relative path from scr_dir
34
50
  src_files:
35
51
  - "application.{js,coffee}"
36
52
 
37
- stylesheets:
53
+ # path to parent directory of spec_files
54
+ # relative path from Rails.root
55
+ # defaults to spec/javascripts
56
+ spec_dir: spec/javascripts
38
57
 
58
+ # list of file expressions to include as helpers into spec runner
59
+ # relative path from spec_dir
39
60
  helpers:
40
61
  - "helpers/**/*.{js,coffee}"
41
62
 
63
+ # list of file expressions to include as specs into spec runner
64
+ # relative path from spec_dir
42
65
  spec_files:
43
66
  - "**/*[Ss]pec.{js,coffee}"
44
-
45
- src_dir: "app/assets/javascripts"
46
-
47
- spec_dir: spec/javascripts
48
-
49
- asset_paths:
50
- - "vendor/assets/javascripts"
51
67
  ```
52
68
 
53
- ### Writing asset manifests
69
+ ## Asset Pipeline Support
54
70
 
55
- I prefer to have just one asset manifest per project, as the `jasmine.yml` file above suggests. One way to accomplish that is to require your `vendor` (and, if necessary, `lib`) manifests within your application manifest. For an example, check out the repo's [dummy project](https://github.com/searls/jasmine-rails/tree/master/spec/dummy).
71
+ The jasmine-rails gem *fully* supports the Rails asset pipeline which means you can:
72
+ * use `coffee_script` or other Javascript precompilers for source or
73
+ test files
74
+ * use sprockets directives to control inclusion/exclusion of dependent
75
+ files
76
+ * leverage asset pipeline search paths to include assets from various
77
+ sources/gems
56
78
 
57
- Here's `app/assets/javascripts/application.js`
79
+ **If you choose to use the asset pipeline support, many of the `jasmine.yml`
80
+ configurations become unnecessary** and you can rely on the Rails asset
81
+ pipeline to do the hard work of controlling what files are included in
82
+ your testsuite.
58
83
 
59
- ``` javascript
60
- //= require vendor
61
- //= require_tree .
84
+ ```yaml
85
+ # minimalist jasmine.yml configuration when leveraging asset pipeline
86
+ spec_files:
87
+ - "**/*[Ss]pec.{js,coffee}"
62
88
  ```
63
89
 
64
- And here's `vendor/assets/javascripts/vendor.js` (as referenced on the first line of `application.js` above)
65
-
66
- ``` javascript
67
- //= require jquery
68
- //= require jquery_ujs
69
- //= require_tree .
90
+ ```javascript
91
+ //= require helpers/spec_helper (includes spec/javascripts/helpers/spec_helper.js)
92
+ //= require foo (includes app/assets/javascripts/foo.js)
93
+ describe('Foo', function() {
94
+ it('does something');
95
+ });
70
96
  ```
71
97
 
72
- Assets in gems come along for the ride, as well. Additionally, you can follow a similar scheme to import any JavaScript libs you might reference from a `lib/assets/javascripts/lib.js` manifest file.
73
-
74
98
  ## Running from the command line
75
99
 
76
100
  If you were to run:
77
101
 
78
- bundle exec jasmine-headless-webkit --color
102
+ bundle exec rake spec:javascript
79
103
 
80
104
  You'd hopefully see something like:
81
105
 
@@ -83,19 +107,16 @@ You'd hopefully see something like:
83
107
 
84
108
  PASS: 0 tests, 0 failures, 0.001 secs.
85
109
 
86
- I encourage you to explore John Bintz's excellent [jasmine-headless-webkit's documentation](http://johnbintz.github.com/jasmine-headless-webkit/) for more ideas, like creating a Rake task or running it on a display-less CI server.
110
+ You can filter execution by passing the `SPEC` option as well:
111
+
112
+ bundle exec rake spec:javascript SPEC=my_test
87
113
 
88
114
  If you experience an error at this point, the most likely cause is JavaScript being loaded out of order, or otherwise conflicting with other existing JavaScript in your project. See "Debugging" below.
89
115
 
90
116
  ## Running from your browser
91
117
 
92
- Just mount jasmine-rails by adding something like this to your routes.rb:
93
-
94
- ``` ruby
95
- mount JasmineRails::Engine => "/specs" unless Rails.env.production?
96
- ```
97
-
98
- Now when you run `bundle exec rails s`, and navigate to [http://localhost:3000/specs](http://localhost:3000/specs), you should see a Jasmine spec runner in your browser.
118
+ Startup your Rails server (ex: `bundle exec rails s`), and navigate to the path you have configured in your routes.rb file (ex: [http://localhost:3000/specs](http://localhost:3000/specs)).
119
+ The Jasmine spec runner should appear and start running your testsuite instantly.
99
120
 
100
121
  ## Debugging
101
122
 
@@ -103,39 +124,17 @@ Now when you run `bundle exec rails s`, and navigate to [http://localhost:3000/s
103
124
 
104
125
  In my workflow, I like to work with specs in the command line until I hit a snag and could benefit from debugging in [Web Inspector](http://www.webkit.org/blog/1091/more-web-inspector-updates/) or [Firebug](http://getfirebug.com/) to figure out what's going on.
105
126
 
106
- [When debugging, if you've disabled the asset pipeline's debug mode in dev/test, you may need to append the query param `?debug_assets=true` like so: [http://localhost:3000/specs?debug_assets=true](http://localhost:3000/specs?debug_assets=true). The asset pipeline will include individual `script` tags for each of your scripts when in debug mode, which migh tmake debugging easier.]
107
-
108
127
  ### From the command line
109
128
 
110
- Even though they both read from the same config file, it's certainly possible that your specs will pass in the browser and fail from the command line. In this case, you can try to debug or analyze what's going on by using the "--keep" flag from jasmine-headless-webkit.
111
-
112
- By running:
129
+ Even though they both read from the same config file, it's certainly possible that your specs will pass in the browser and fail from the command line. In this case, you can try to debug or analyze what's going on loading the headless runner.html file into your browser environment. The generated runner.html file is written out to `spec/tmp/runner.html` after each run.
113
130
 
114
- bundle exec jasmine-headless-webkit --keep
131
+ ### Ajax / XHRs
115
132
 
116
- If the tests fail, jasmine-headless-webkit will leave its generated spec runner HTML file persisted in your rails root folder. It'll be named something like "jhw.48160.html".
133
+ As a general rule, Jasmine is designed for unit testing, and as a result real network requests are not appropriate for tests written in Jasmine. (Isolation strategies can include spying on asynchronous libraries and then synchronously testing callback behavior, as [demonstrated in this gist](https://gist.github.com/searls/946704)).
117
134
 
118
- ## Guard
119
-
120
- [Guard](https://github.com/guard/guard) is a great tool for triggering spec runs when files change. To use it, you can bundle these gems:
121
-
122
- group :development do
123
- ...
124
- gem 'guard-jasmine-headless-webkit'
125
- ...
126
- end
127
-
128
- In my Guardfile, this configuration is working well for me:
129
-
130
- spec_location = "spec/javascripts/%s_spec"
131
-
132
- guard 'jasmine-headless-webkit' do
133
- watch(%r{^app/views/.*\.jst$})
134
- watch(%r{^public/javascripts/(.*)\.js$}) { |m| newest_js_file(spec_location % m[1]) }
135
- watch(%r{^.*/assets/javascripts/(.*)\.(js|coffee)$}) { |m| newest_js_file(spec_location % m[1]) }
136
- watch(%r{^spec/javascripts/(.*)_spec\..*}) { |m| newest_js_file(spec_location % m[1]) }
137
- end
135
+ If your application code issues XHR requests during your test run, please note that **XHR requests for the local filesystem** are blocked by default for most browsers for security reasons. To debug local XHR requests (for example, if you jasmine-jquery fixtures), you will need to enable local filesystem requests in your browser.
138
136
 
139
- Finally, to run guard, just:
137
+ Example for Google Chrome (in Mac OS X):
138
+ open -a "Google Chrome" spec/tmp/runner.html --args --allow-file-access-from-files
140
139
 
141
- bundle exec guard
140
+ Again, it's the opinion of the present author that this shouldn't be necessary in any situation but legacy rescue of an existing test suite. With respect specifically to HTML fixtures, please consider [jasmine-fixture](https://github.com/searls/jasmine-fixture) and [my rationale](http://searls.testdouble.com/posts/2011-12-11-jasmine-fixtures.html) for it.
data/Rakefile CHANGED
@@ -9,17 +9,14 @@ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
9
9
  load 'rails/tasks/engine.rake'
10
10
  Bundler::GemHelper.install_tasks
11
11
 
12
- task :cd_to_dummy do
13
- Dir.chdir(File.expand_path("../spec/dummy", __FILE__))
14
- end
15
-
16
- require 'jasmine-headless-webkit'
17
- Jasmine::Headless::Task.new(:dummy_headless_jasmine) do |t|
18
- t.colors = true
19
- t.keep_on_error = true
12
+ task :run_jasmine_rake_in_dummy do
13
+ system <<-BASH
14
+ cd spec/dummy
15
+ bundle exec rake spec:javascript
16
+ BASH
20
17
  end
21
18
 
22
19
  require 'rspec/core/rake_task'
23
- RSpec::Core::RakeTask.new(:dummy_spec)
20
+ RSpec::Core::RakeTask.new(:run_browser_spec_in_dummy)
24
21
 
25
- task :default => [:cd_to_dummy, :dummy_headless_jasmine, :dummy_spec]
22
+ task :default => [:run_jasmine_rake_in_dummy, :run_browser_spec_in_dummy]
@@ -1,7 +1,7 @@
1
1
  module JasmineRails
2
2
  class SpecRunnerController < ApplicationController
3
3
  def index
4
- params[:debug_assets] = true
4
+ JasmineRails.reload_jasmine_config
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,30 @@
1
+ require 'jasmine-core'
2
+
3
+ module JasmineRails
4
+ module SpecRunnerHelper
5
+ # return list of css files to include in spec runner
6
+ # all files are fetched through the Rails asset pipeline
7
+ # includes:
8
+ # * core jasmine css files
9
+ def jasmine_css_files
10
+ Jasmine::Core.css_files
11
+ end
12
+
13
+ # return list of javascript files needed for jasmine testsuite
14
+ # all files are fetched through the Rails asset pipeline
15
+ # includes:
16
+ # * core jasmine libraries
17
+ # * (optional) jasmine-console-reporter.js for CLI output
18
+ # * jasmine-boot.js test runner
19
+ # * jasmine-specs.js built by asset pipeline which merges application specific libraries and specs
20
+ def jasmine_js_files
21
+ files = Jasmine::Core.js_files
22
+ if params[:console]
23
+ files << 'jasmine-console-reporter.js'
24
+ end
25
+ files << 'jasmine-boot.js'
26
+ files << 'jasmine-specs.js'
27
+ files
28
+ end
29
+ end
30
+ end
@@ -4,41 +4,11 @@
4
4
  <meta content="text/html;charset=UTF-8" http-equiv="Content-Type"/>
5
5
  <title>Jasmine Specs</title>
6
6
 
7
- <%= stylesheet_link_tag *JasmineRails::JhwAdapter.new.css_files %>
8
- <%= javascript_include_tag *JasmineRails::JhwAdapter.new.js_files %>
9
-
10
- <!-- executing jasmine's runner -->
11
- <script type="text/javascript">
12
- (function() {
13
- var jasmineEnv = jasmine.getEnv();
14
- jasmineEnv.updateInterval = 1000;
15
-
16
- var htmlReporter = new jasmine.HtmlReporter();
17
-
18
- jasmineEnv.addReporter(htmlReporter);
19
-
20
- jasmineEnv.specFilter = function(spec) {
21
- return htmlReporter.specFilter(spec);
22
- };
23
-
24
- var currentWindowOnload = window.onload;
25
-
26
- window.onload = function() {
27
- if (currentWindowOnload) {
28
- currentWindowOnload();
29
- }
30
- execJasmine();
31
- };
32
-
33
- function execJasmine() {
34
- jasmineEnv.execute();
35
- }
36
-
37
- })();
38
- </script>
7
+ <%= stylesheet_link_tag *jasmine_css_files %>
8
+ <%= javascript_include_tag *jasmine_js_files %>
39
9
  </head>
40
10
  <body>
41
11
  <div id="jasmine_content"></div>
42
12
  <%= yield %>
43
13
  </body>
44
- </html>
14
+ </html>
@@ -1,6 +1,3 @@
1
- require 'jasmine-core' ##<--TODO why is this here?
2
- require 'jasmine' ##<--TODO why is this here?
3
-
4
1
  JasmineRails::Engine.routes.draw do
5
2
  root :to => "spec_runner#index"
6
3
  end
@@ -0,0 +1,27 @@
1
+ var jsApiReporter;
2
+ (function() {
3
+ var jasmineEnv = jasmine.getEnv();
4
+
5
+ jsApiReporter = new jasmine.JsApiReporter();
6
+ jasmineEnv.addReporter(jsApiReporter);
7
+
8
+ var htmlReporter = new jasmine.HtmlReporter();
9
+ jasmineEnv.addReporter(htmlReporter);
10
+ jasmineEnv.specFilter = function(spec) {
11
+ return htmlReporter.specFilter(spec);
12
+ };
13
+
14
+ if (jasmine.ConsoleReporter) {
15
+ jasmineEnv.addReporter(new jasmine.ConsoleReporter());
16
+ }
17
+
18
+ function execJasmine() {
19
+ jasmineEnv.execute();
20
+ }
21
+
22
+ if (window.addEventListener) { // W3C
23
+ window.addEventListener('load', execJasmine, false);
24
+ } else if (window.attachEvent) { // MSIE
25
+ window.attachEvent('onload', execJasmine);
26
+ }
27
+ })();
@@ -0,0 +1,110 @@
1
+ /**
2
+ Jasmine Reporter that outputs test results to the browser console.
3
+ Useful for running in a headless environment such as PhantomJs, ZombieJs etc.
4
+
5
+ Usage:
6
+ // From your html file that loads jasmine:
7
+ jasmine.getEnv().addReporter(new jasmine.ConsoleReporter());
8
+ jasmine.getEnv().execute();
9
+ */
10
+
11
+ (function(jasmine, console) {
12
+ if (!jasmine) {
13
+ throw "jasmine library isn't loaded!";
14
+ }
15
+
16
+ var ANSI = {}
17
+ ANSI.color_map = {
18
+ "green" : 32,
19
+ "red" : 31
20
+ }
21
+
22
+ ANSI.colorize_text = function(text, color) {
23
+ var color_code = this.color_map[color];
24
+ return "\033[" + color_code + "m" + text + "\033[0m";
25
+ }
26
+
27
+ var ConsoleReporter = function() {
28
+ if (!console || !console.log) { throw "console isn't present!"; }
29
+ this.status = this.statuses.stopped;
30
+ };
31
+
32
+ var proto = ConsoleReporter.prototype;
33
+ proto.statuses = {
34
+ stopped : "stopped",
35
+ running : "running",
36
+ fail : "fail",
37
+ success : "success"
38
+ };
39
+
40
+ proto.reportRunnerStarting = function(runner) {
41
+ this.status = this.statuses.running;
42
+ this.start_time = (new Date()).getTime();
43
+ this.executed_specs = 0;
44
+ this.passed_specs = 0;
45
+ this.log("Starting...");
46
+ };
47
+
48
+ proto.reportRunnerResults = function(runner) {
49
+ var failed = this.executed_specs - this.passed_specs;
50
+ var spec_str = this.executed_specs + (this.executed_specs === 1 ? " spec, " : " specs, ");
51
+ var fail_str = failed + (failed === 1 ? " failure in " : " failures in ");
52
+ var color = (failed > 0)? "red" : "green";
53
+ var dur = (new Date()).getTime() - this.start_time;
54
+
55
+ this.log("");
56
+ this.log("Finished");
57
+ this.log("-----------------");
58
+ this.log(spec_str + fail_str + (dur/1000) + "s.", color);
59
+
60
+ this.status = (failed > 0)? this.statuses.fail : this.statuses.success;
61
+
62
+ /* Print something that signals that testing is over so that headless browsers
63
+ like PhantomJs know when to terminate. */
64
+ this.log("");
65
+ this.log("ConsoleReporter finished");
66
+ };
67
+
68
+
69
+ proto.reportSpecStarting = function(spec) {
70
+ this.executed_specs++;
71
+ };
72
+
73
+ proto.reportSpecResults = function(spec) {
74
+ if (spec.results().skipped) {
75
+ return;
76
+ }
77
+ if (spec.results().passed()) {
78
+ this.passed_specs++;
79
+ return;
80
+ }
81
+
82
+ var resultText = spec.suite.description + " : " + spec.description;
83
+ this.log(resultText, "red");
84
+
85
+ var items = spec.results().getItems()
86
+ for (var i = 0; i < items.length; i++) {
87
+ var item = items[i];
88
+ var output = ' ' + item.message;
89
+ this.log(output, "red");
90
+ }
91
+ };
92
+
93
+ proto.reportSuiteResults = function(suite) {
94
+ if (!suite.parentSuite) { return; }
95
+ var results = suite.results();
96
+ if (results.totalCount === 0) {
97
+ return;
98
+ }
99
+ var failed = results.totalCount - results.passedCount;
100
+ var color = (failed > 0)? "red" : "green";
101
+ this.log(suite.description + ": " + results.passedCount + " of " + results.totalCount + " passed.", color);
102
+ };
103
+
104
+ proto.log = function(str, color) {
105
+ var text = (color != undefined)? ANSI.colorize_text(str, color) : str;
106
+ console.log(text)
107
+ };
108
+
109
+ jasmine.ConsoleReporter = ConsoleReporter;
110
+ })(jasmine, console);
@@ -0,0 +1,14 @@
1
+ <%
2
+ # depend on spec dirs to automatically flush asset cache
3
+ # when new tests or directories are added
4
+ JasmineRails.each_spec_dir do |directory|
5
+ depend_on directory
6
+ end
7
+
8
+ # bundle all jasmine specs using asset pipeline
9
+ # so asset pipeline can properly filter out duplicates
10
+ # via dependency tree
11
+ JasmineRails.spec_files.each do |file|
12
+ require_asset(file.to_s)
13
+ end
14
+ %>
@@ -1,5 +1,84 @@
1
1
  require "jasmine_rails/engine"
2
- require "jasmine_rails/jhw_adapter"
3
2
 
4
3
  module JasmineRails
4
+ class << self
5
+ # return the relative path to access the spec runner
6
+ # for the host Rails application
7
+ # ex: /jasmine
8
+ def route_path
9
+ route = Rails.application.routes.named_routes[:jasmine_rails]
10
+ raise 'JasmineRails::Engine has not been mounted into routes.rb' unless route
11
+ path = route.path
12
+
13
+ # Rails 3.1 support
14
+ if path.is_a?(String)
15
+ path
16
+ else
17
+ path.spec.to_s
18
+ end
19
+ end
20
+
21
+ def spec_dir
22
+ path = jasmine_config['spec_dir'] || 'spec/javascripts'
23
+ Rails.root.join(path)
24
+ end
25
+
26
+ # returns list of all files to be included into the jasmine testsuite
27
+ # includes:
28
+ # * application src_files
29
+ # * spec helpers
30
+ # * spec_files
31
+ def spec_files
32
+ files = []
33
+ files += filter_files src_dir, jasmine_config['src_files']
34
+ files += filter_files spec_dir, jasmine_config['helpers']
35
+ files += filter_files spec_dir, jasmine_config['spec_files']
36
+ files
37
+ end
38
+
39
+ # iterate over all directories used as part of the testsuite (including subdirectories)
40
+ def each_spec_dir(&block)
41
+ each_dir spec_dir.to_s, &block
42
+ each_dir src_dir.to_s, &block
43
+ end
44
+
45
+ # clear out cached jasmine config file
46
+ # it would be nice to automatically flush when the jasmine.yml file changes instead
47
+ # of having this programatic API
48
+ def reload_jasmine_config
49
+ @config = nil
50
+ end
51
+
52
+ private
53
+
54
+ def src_dir
55
+ path = jasmine_config['src_dir'] || 'app/assets/javascripts'
56
+ Rails.root.join(path)
57
+ end
58
+
59
+ def jasmine_config
60
+ @config ||= begin
61
+ path = Rails.root.join('spec', 'javascripts', 'support', 'jasmine.yml')
62
+ YAML.load_file(path)
63
+ end
64
+ end
65
+
66
+ def each_dir(root, &block)
67
+ yield root
68
+ Dir[root + '/*'].each do |file|
69
+ if File.directory?(file)
70
+ each_dir(file, &block)
71
+ end
72
+ end
73
+ end
74
+
75
+ def filter_files(root_dir, patterns)
76
+ files = patterns.to_a.collect do |pattern|
77
+ Dir.glob(root_dir.join(pattern)).sort
78
+ end
79
+ files = files.flatten
80
+ files = files.collect {|f| f.gsub(root_dir.to_s + '/', '') }
81
+ files || []
82
+ end
83
+ end
5
84
  end
@@ -1,5 +1,12 @@
1
+ require 'jasmine-core'
2
+
1
3
  module JasmineRails
2
4
  class Engine < Rails::Engine
3
5
  isolate_namespace JasmineRails
6
+
7
+ initializer :assets do |config|
8
+ Rails.application.config.assets.paths << Jasmine::Core.path
9
+ Rails.application.config.assets.paths << JasmineRails.spec_dir
10
+ end
4
11
  end
5
12
  end
@@ -0,0 +1,30 @@
1
+ # Rails Asset Patch extension used to write assets out an offline asset directory
2
+ # for future use
3
+ # example:
4
+ # ActionView::AssetPaths.send :include, JasmineRails::OfflineAssetPaths
5
+ module JasmineRails
6
+ module OfflineAssetPaths
7
+ mattr_accessor :disabled
8
+ extend ActiveSupport::Concern
9
+ included do
10
+ alias_method_chain :compute_public_path, :offline_asset
11
+ end
12
+
13
+ def compute_public_path_with_offline_asset(source, dir, options={})
14
+ return compute_public_path_without_offline_asset(source, dir, options) if JasmineRails::OfflineAssetPaths.disabled
15
+ return source if source.starts_with?('/')
16
+ content = Rails.application.assets[source].to_s
17
+ source_path = offline_asset_dir.join(source)
18
+
19
+ FileUtils.mkdir_p File.dirname(source_path)
20
+ Rails.logger.debug "Compiling #{source} to #{source_path}"
21
+ File.open(source_path, 'w') {|f| f << content }
22
+ "assets/#{source}"
23
+ end
24
+
25
+ private
26
+ def offline_asset_dir
27
+ Rails.root.join('spec/tmp/assets')
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module JasmineRails
2
- VERSION = "0.3.3"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -1,4 +1,28 @@
1
- # desc "Explaining what the task does"
2
- # task :jasmine-rails do
3
- # # Task goes here
4
- # end
1
+ namespace :spec do
2
+ def run_cmd(cmd)
3
+ puts "$ #{cmd}"
4
+ unless system(cmd)
5
+ raise "Error executing command: #{cmd}"
6
+ end
7
+ end
8
+
9
+ desc "run test with phantomjs"
10
+ task :javascript => :environment do
11
+ require 'jasmine_rails/offline_asset_paths'
12
+ ActionView::AssetPaths.send :include, JasmineRails::OfflineAssetPaths
13
+ spec_filter = ENV['SPEC']
14
+ app = ActionController::Integration::Session.new(Rails.application)
15
+ path = JasmineRails.route_path
16
+ app.get path, :console => 'true', :spec => spec_filter
17
+ JasmineRails::OfflineAssetPaths.disabled = true
18
+ raise "Error generating jasmine runner: #{app.response.status_message}" unless app.response.status == 200
19
+ html = app.response.body
20
+ runner_path = Rails.root.join('spec/tmp/runner.html')
21
+ File.open(runner_path, 'w') {|f| f << html}
22
+
23
+ run_cmd "phantomjs #{File.join(File.dirname(__FILE__), 'runner.js')} file://#{runner_path.to_s}?spec=#{spec_filter}"
24
+ end
25
+
26
+ # alias
27
+ task :javascripts => :javascript
28
+ end
@@ -0,0 +1,76 @@
1
+ (function() {
2
+ // handler for any page javascript errors
3
+ var errorHandler = function(msg, trace) {
4
+ var msgStack = ['ERROR: ' + msg];
5
+ if (trace) {
6
+ msgStack.push('TRACE:');
7
+ trace.forEach(function(t) {
8
+ msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function + '")' : ''));
9
+ });
10
+ }
11
+ console.error(msgStack.join('\n'));
12
+ phantom.exit(1);
13
+ };
14
+ phantom.onError = errorHandler;
15
+
16
+ var system = require('system');
17
+ var args = system.args;
18
+
19
+ if (args.length !== 2) {
20
+ console.log("Need a url as the argument");
21
+ phantom.exit(1);
22
+ }
23
+
24
+ var page = new WebPage();
25
+
26
+ // log messages to stdout
27
+ page.onConsoleMessage = function(msg) {
28
+ console.log(msg);
29
+ };
30
+
31
+ // listen for event from parent page
32
+ page.onCallback = function(data) {
33
+ if (data.event === 'exit') {
34
+ phantom.exit(data.exitCode);
35
+ } else if (data.event === 'writeFile') {
36
+ var fs = require("fs");
37
+ fs.write(data.filename, data.text, 'w');
38
+ } else {
39
+ console.log('unkown event callback: ' + data);
40
+ }
41
+ };
42
+
43
+ // log javascript errors
44
+ page.onError = errorHandler;
45
+
46
+ // setup listeners for jasmine events
47
+ page.onInitialized = function() {
48
+ return page.evaluate(function() {
49
+ return window.onload = function() {
50
+ jsApiReporter.exitCode = 0;
51
+ jsApiReporter.reportSpecResults = function(spec) {
52
+ if (spec.results().failedCount > 0) {
53
+ jsApiReporter.exitCode = 1;
54
+ }
55
+ };
56
+ jsApiReporter.reportRunnerResults = function() {
57
+ setTimeout(function() {
58
+ window.callPhantom({
59
+ event: 'exit',
60
+ exitCode: jsApiReporter.exitCode
61
+ });
62
+ }, 1);
63
+ };
64
+ };
65
+ });
66
+ };
67
+
68
+ var address = args[1];
69
+ console.log('Running: ' + address);
70
+ page.open(address, function(status) {
71
+ if (status !== "success") {
72
+ console.log("can't load the address!");
73
+ return phantom.exit(1);
74
+ }
75
+ });
76
+ })();
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jasmine-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-03-06 00:00:00.000000000 Z
14
+ date: 2013-04-18 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rails
@@ -30,7 +30,7 @@ dependencies:
30
30
  - !ruby/object:Gem::Version
31
31
  version: 3.1.0
32
32
  - !ruby/object:Gem::Dependency
33
- name: jasmine
33
+ name: jasmine-core
34
34
  requirement: !ruby/object:Gem::Requirement
35
35
  none: false
36
36
  requirements:
@@ -45,22 +45,6 @@ dependencies:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.3'
48
- - !ruby/object:Gem::Dependency
49
- name: jasmine-headless-webkit
50
- requirement: !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
53
- - - ! '>='
54
- - !ruby/object:Gem::Version
55
- version: '0'
56
- type: :runtime
57
- prerelease: false
58
- version_requirements: !ruby/object:Gem::Requirement
59
- none: false
60
- requirements:
61
- - - ! '>='
62
- - !ruby/object:Gem::Version
63
- version: '0'
64
48
  description: Provides a Jasmine Spec Runner that plays nicely with Rails 3.1 assets
65
49
  and sets up jasmine-headless-webkit
66
50
  email:
@@ -73,15 +57,19 @@ extra_rdoc_files: []
73
57
  files:
74
58
  - app/controllers/jasmine_rails/application_controller.rb
75
59
  - app/controllers/jasmine_rails/spec_runner_controller.rb
60
+ - app/helpers/jasmine_rails/spec_runner_helper.rb
76
61
  - app/views/jasmine_rails/spec_runner/index.html.erb
77
62
  - app/views/layouts/jasmine_rails/spec_runner.html.erb
78
- - config/initializers/sprockets.rb
79
63
  - config/routes.rb
64
+ - lib/assets/javascripts/jasmine-boot.js
65
+ - lib/assets/javascripts/jasmine-console-reporter.js
66
+ - lib/assets/javascripts/jasmine-specs.js.erb
80
67
  - lib/jasmine-rails.rb
81
68
  - lib/jasmine_rails/engine.rb
82
- - lib/jasmine_rails/jhw_adapter.rb
69
+ - lib/jasmine_rails/offline_asset_paths.rb
83
70
  - lib/jasmine_rails/version.rb
84
71
  - lib/tasks/jasmine-rails_tasks.rake
72
+ - lib/tasks/runner.js
85
73
  - MIT-LICENSE
86
74
  - Rakefile
87
75
  - README.md
@@ -1,3 +0,0 @@
1
- assets = Rails.application.assets
2
- assets.append_path Jasmine::Core.path
3
- JasmineRails::JhwAdapter.new.asset_paths.each { |path| assets.append_path(path) }
@@ -1,84 +0,0 @@
1
- require 'jasmine-headless-webkit'
2
-
3
- module JasmineRails
4
-
5
- class JhwAdapter
6
-
7
- def initialize
8
- @options = Jasmine::Headless::Options.new
9
- @runner = instantiate_runner
10
- Jasmine::Headless::CacheableAction.enabled = @options[:enable_cache]
11
- end
12
-
13
- def css_files
14
- @css_files_list ||= CssFilesList.new(
15
- :config => @runner.jasmine_config,
16
- :only => @options[:files],
17
- :seed => @options[:seed]
18
- ).logical_paths
19
- end
20
-
21
- def js_files
22
- @js_files_list ||= JsFilesList.new(
23
- :config => @runner.jasmine_config,
24
- :only => @options[:files],
25
- :seed => @options[:seed]
26
- ).logical_paths
27
- end
28
-
29
- def asset_paths
30
- jasmine_config = YAML.load_file(@options[:jasmine_config])
31
- [
32
- jasmine_config["src_dir"],
33
- jasmine_config["spec_dir"],
34
- jasmine_config["asset_paths"]
35
- ].flatten.compact
36
- end
37
-
38
- def instantiate_runner
39
- begin
40
- Jasmine::Headless::Runner.new(@options)
41
- rescue Jasmine::Headless::NoRunnerError
42
- require 'fileutils'
43
- FileUtils.touch(Jasmine::Headless::Runner::RUNNER)
44
- Jasmine::Headless::Runner.new(@options).tap { File.delete(Jasmine::Headless::Runner::RUNNER) }
45
- end
46
- end
47
- end
48
-
49
- class DistinctifiedFileList < Jasmine::Headless::FilesList
50
- def files
51
- required_files.collect { |asset| asset.pathname.to_s }.uniq
52
- end
53
-
54
- def logical_paths
55
- files.map { |file| Rails.application.assets[file].logical_path }
56
- end
57
- end
58
-
59
- class JsFilesList < DistinctifiedFileList
60
-
61
- def self.default_files
62
- %w{jasmine.js jasmine-html}
63
- end
64
-
65
- def self.extension_filter
66
- extensions = (%w{.js} + Sprockets.engine_extensions)
67
- %r{(#{extensions.join('|')})$}
68
- end
69
-
70
- end
71
-
72
- class CssFilesList < DistinctifiedFileList
73
-
74
- def self.default_files
75
- %w{jasmine.css}
76
- end
77
-
78
- def self.extension_filter
79
- extensions = (%w{.css .scss .sass .less})
80
- %r{(#{extensions.join('|')})$}
81
- end
82
- end
83
-
84
- end