Compare commits
No commits in common. "nicoder/patch-1" and "master" have entirely different histories.
nicoder/pa
...
master
24
.gitignore
vendored
24
.gitignore
vendored
@ -1,11 +1,19 @@
|
|||||||
.sass-cache/
|
*.gem
|
||||||
_site/
|
.bundle
|
||||||
.idea/*
|
Gemfile.lock
|
||||||
|
pkg/*
|
||||||
|
Makefile
|
||||||
|
specrunner.moc
|
||||||
|
specrunner.o
|
||||||
|
ext/jasmine-webkit-specrunner/jasmine-webkit-specrunner
|
||||||
|
*.o
|
||||||
|
moc_*.*
|
||||||
|
.DS_Store
|
||||||
|
hydra-runner.log
|
||||||
|
jhw-test
|
||||||
.jhw-cache/
|
.jhw-cache/
|
||||||
ext/
|
_site/
|
||||||
pkg/
|
jhw.*.html
|
||||||
coverage/
|
coverage/
|
||||||
tmp/
|
tmp/
|
||||||
vendor/
|
cache dir/
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
|
89
CHANGELOG.md
Normal file
89
CHANGELOG.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
## 0.7.2
|
||||||
|
|
||||||
|
* Improved finding of CoffeeScript spec line locations
|
||||||
|
* Improved Runner reporting of which expectations failed
|
||||||
|
* Initial vendored helper support, paving the way for Sprockets integratioon (maybe!)
|
||||||
|
* Add 1.9.3-rc1 test support and fixes
|
||||||
|
* Add console.peek()
|
||||||
|
|
||||||
|
## 0.7.1
|
||||||
|
|
||||||
|
* Bugfix for missing digest/sha1 import
|
||||||
|
|
||||||
|
## 0.7.0
|
||||||
|
|
||||||
|
* Major C++ cleanup, now much more modular
|
||||||
|
* Greatly improved object inspection and printing provided by jsDump and beautify-js
|
||||||
|
|
||||||
|
## 0.6.3
|
||||||
|
|
||||||
|
* Ensure Rubygems is available before doing version comparison
|
||||||
|
* Fix other build problems
|
||||||
|
* Better output for jQuery nodes
|
||||||
|
|
||||||
|
## 0.6.2
|
||||||
|
|
||||||
|
* Clean up C++ and test running
|
||||||
|
|
||||||
|
## 0.6.1
|
||||||
|
|
||||||
|
* Ensure YAML is loaded before use
|
||||||
|
* Make sure specs can't break out of the page they're running in
|
||||||
|
* Fix compilation on FreeBSD
|
||||||
|
|
||||||
|
## 0.6.0
|
||||||
|
|
||||||
|
* File and line number information for failing specs
|
||||||
|
* Try to build the runner if it's missing
|
||||||
|
* Kill warnings and streamline includes
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
* Run all tests after focused run if `console.log` was used
|
||||||
|
* Ensure Rake task works outside of Rails
|
||||||
|
* Ensure focused tests aren't run when CLI called with no files
|
||||||
|
* Support globs in focused test filters
|
||||||
|
* Raise exceptions on Rake task failures
|
||||||
|
* Update to use Jasmine 1.1
|
||||||
|
|
||||||
|
## 0.4.2
|
||||||
|
|
||||||
|
* Fix Rails 3.1 Railtie so it's included properly
|
||||||
|
* Fix compilation of runner on Linux
|
||||||
|
* Run files that are outside of the project's scope
|
||||||
|
|
||||||
|
## 0.4.1
|
||||||
|
|
||||||
|
* Fix CoffeeScript concatenation bug
|
||||||
|
* Report CoffeeScript errors better
|
||||||
|
|
||||||
|
## 0.4.0
|
||||||
|
|
||||||
|
* Change how tests are counted for totals
|
||||||
|
* Run targeted and full tests in the same runner instance for speed!
|
||||||
|
* Concatenate adjacent CoffeeScript files before compilation for more speed!
|
||||||
|
* Ensure files are not required twice
|
||||||
|
* Break out runner usage from CLI so that it can be resued in Rake tasks and elsewhere
|
||||||
|
* Add a Rails 3.1 task to precompile all assets with a specific "MD5 hash"
|
||||||
|
|
||||||
|
## 0.2.3
|
||||||
|
|
||||||
|
* Better messages for JavaScript errors
|
||||||
|
* `console.pp` added for more in-depth object inspection
|
||||||
|
|
||||||
|
## 0.2.2
|
||||||
|
|
||||||
|
* Write out a reporting file that can be used for Guard notification
|
||||||
|
|
||||||
|
## 0.2.1
|
||||||
|
|
||||||
|
* Avoid a Railtie so JHW works outside of Rails
|
||||||
|
|
||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
* Add a Rake task and a default task for Rails
|
||||||
|
* Global runner configuration via ~/.jasmine-headless-webkit
|
||||||
|
* Custom Jasmine reporter for better user feedback
|
||||||
|
* Specify the specs to be run, instead of always running them all
|
||||||
|
* Move README to gh-pages site
|
||||||
|
|
33
Gemfile
33
Gemfile
@ -1,3 +1,30 @@
|
|||||||
gem 'jekyll'
|
source :rubygems
|
||||||
gem 'liquid', '2.2.2'
|
|
||||||
gem 'redcarpet'
|
# Specify your gem's dependencies in jasmine-headless-webkit.gemspec
|
||||||
|
gemspec
|
||||||
|
|
||||||
|
gem 'rspec'
|
||||||
|
gem 'fakefs', :require => nil
|
||||||
|
gem 'guard'
|
||||||
|
|
||||||
|
gem 'guard-rspec'
|
||||||
|
gem 'guard-shell'
|
||||||
|
gem 'guard-coffeescript'
|
||||||
|
gem 'guard-cucumber'
|
||||||
|
|
||||||
|
require 'rbconfig'
|
||||||
|
case RbConfig::CONFIG['host_os']
|
||||||
|
when /darwin/
|
||||||
|
when /linux/
|
||||||
|
gem 'libnotify'
|
||||||
|
end
|
||||||
|
|
||||||
|
gem 'mocha'
|
||||||
|
|
||||||
|
gem 'cucumber'
|
||||||
|
|
||||||
|
gem 'jquery-rails', '~> 1.0.0'
|
||||||
|
gem 'ejs'
|
||||||
|
|
||||||
|
gem 'guard-jasmine-headless-webkit', :git => 'git://github.com/johnbintz/guard-jasmine-headless-webkit.git'
|
||||||
|
|
||||||
|
30
Gemfile.lock
30
Gemfile.lock
@ -1,30 +0,0 @@
|
|||||||
GEM
|
|
||||||
specs:
|
|
||||||
albino (1.3.3)
|
|
||||||
posix-spawn (>= 0.3.6)
|
|
||||||
classifier (1.3.3)
|
|
||||||
fast-stemmer (>= 1.0.0)
|
|
||||||
directory_watcher (1.4.1)
|
|
||||||
fast-stemmer (1.0.0)
|
|
||||||
jekyll (0.11.0)
|
|
||||||
albino (>= 1.3.2)
|
|
||||||
classifier (>= 1.3.1)
|
|
||||||
directory_watcher (>= 1.1.1)
|
|
||||||
kramdown (>= 0.13.2)
|
|
||||||
liquid (>= 1.9.0)
|
|
||||||
maruku (>= 0.5.9)
|
|
||||||
kramdown (0.13.3)
|
|
||||||
liquid (2.2.2)
|
|
||||||
maruku (0.6.0)
|
|
||||||
syntax (>= 1.0.0)
|
|
||||||
posix-spawn (0.3.6)
|
|
||||||
redcarpet (1.17.2)
|
|
||||||
syntax (1.0.0)
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
ruby
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
jekyll
|
|
||||||
liquid (= 2.2.2)
|
|
||||||
redcarpet
|
|
43
Guardfile
43
Guardfile
@ -1,6 +1,41 @@
|
|||||||
guard 'livereload' do
|
|
||||||
watch('index.md')
|
# Add files and commands to this file, like the example:
|
||||||
watch(%r{^images/})
|
# watch('file/path') { `command(s)` }
|
||||||
watch(%r{^stylesheets/})
|
#
|
||||||
|
|
||||||
|
guard 'coffeescript', :input => 'vendor/assets/coffeescripts', :output => 'vendor/assets/javascripts'
|
||||||
|
|
||||||
|
guard 'shell' do
|
||||||
|
watch(%r{ext/jasmine-webkit-specrunner/.*\.(cpp|h|pro|pri)}) { |m|
|
||||||
|
if !m[0]['moc_']
|
||||||
|
compile
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
# A sample Guardfile
|
||||||
|
# More info at https://github.com/guard/guard#readme
|
||||||
|
|
||||||
|
guard 'rspec', :version => 2, :all_on_start => false do
|
||||||
|
watch(%r{^spec/.+_spec\.rb})
|
||||||
|
watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
||||||
|
watch(%r{^bin/(.+)}) { |m| "spec/bin/#{m[1]}_spec.rb" }
|
||||||
|
watch('spec/spec_helper.rb') { "spec" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
guard 'cucumber', :cli => '-r features --format pretty' do
|
||||||
|
watch(%r{^features/.+\.feature$})
|
||||||
|
watch(%r{^features/support/.+$}) { 'features' }
|
||||||
|
watch(%r{^features/steps/(.+)_steps\.rb$}) { 'features' }
|
||||||
|
end
|
||||||
|
|
||||||
|
guard 'jasmine-headless-webkit', :all_on_start => false do
|
||||||
|
watch(%r{^spec/javascripts/.+_spec\.coffee})
|
||||||
|
watch(%r{^jasmine/(.+)\.coffee$}) { |m| "spec/javascripts/#{m[1]}_spec.coffee" }
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile
|
||||||
|
system %{cd ext/jasmine-webkit-specrunner && ruby extconf.rb}
|
||||||
|
end
|
||||||
|
|
||||||
|
compile
|
||||||
|
|
||||||
|
46
README.md
Normal file
46
README.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
_This project is dead. You should use [Karma](http://karma-runner.github.io/) instead. I do._
|
||||||
|
|
||||||
|
# Jasmine Headless WebKit runner
|
||||||
|
|
||||||
|
Run your specs at sonic boom speed! No pesky reload button or page rendering slowdowns!
|
||||||
|
|
||||||
|
http://johnbintz.github.com/jasmine-headless-webkit/ has the most up-to-date information on using
|
||||||
|
this project. You can see the source of that site on the gh-pages branch.
|
||||||
|
|
||||||
|
## For those who want to hack on the project...
|
||||||
|
|
||||||
|
The best way to get everything running that you need for development and testing is
|
||||||
|
to use Guard:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
bundle install
|
||||||
|
bundle exec guard
|
||||||
|
... build Qt runner ...
|
||||||
|
... compile CoffeeScript to JS ...
|
||||||
|
... run RSpec and JHW ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
* Copyright (c) 2011 John Bintz
|
||||||
|
* Original Qt WebKit runner Copyright (c) 2010 Sencha Inc.
|
||||||
|
* Jasmine JavaScript library Copyright (c) 2008-2011 Pivotal Labs
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
65
Rakefile
Normal file
65
Rakefile
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
include Rake::DSL if defined?(Rake::DSL)
|
||||||
|
|
||||||
|
require 'bundler'
|
||||||
|
Bundler::GemHelper.install_tasks
|
||||||
|
|
||||||
|
require 'rspec/core/rake_task'
|
||||||
|
|
||||||
|
RSpec::Core::RakeTask.new(:spec)
|
||||||
|
|
||||||
|
$: << File.expand_path('../lib', __FILE__)
|
||||||
|
|
||||||
|
require 'jasmine-headless-webkit'
|
||||||
|
require 'jasmine/headless/task'
|
||||||
|
|
||||||
|
Jasmine::Headless::Task.new
|
||||||
|
|
||||||
|
PLATFORMS = %w{1.9.2 1.9.3}
|
||||||
|
|
||||||
|
def rvm_bundle(command = '')
|
||||||
|
Bundler.with_clean_env do
|
||||||
|
system %{bash -c 'unset BUNDLE_BIN_PATH && unset BUNDLE_GEMFILE && rvm #{PLATFORMS.join(',')} do bundle #{command}'}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SpecFailure < StandardError; end
|
||||||
|
class BundleFailure < StandardError; end
|
||||||
|
|
||||||
|
namespace :spec do
|
||||||
|
desc "Run on three Rubies"
|
||||||
|
task :platforms do
|
||||||
|
rvm_bundle
|
||||||
|
rvm_bundle "exec rspec spec"
|
||||||
|
rvm_bundle "exec cucumber"
|
||||||
|
raise SpecError.new if $?.exitstatus != 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
task :default => [ 'spec:platforms', 'jasmine:headless' ]
|
||||||
|
|
||||||
|
desc "Build the runner"
|
||||||
|
task :build_runner do
|
||||||
|
Dir.chdir 'ext/jasmine-webkit-specrunner' do
|
||||||
|
system %{ruby extconf.rb}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Generate vendored JS"
|
||||||
|
task :generate_js do
|
||||||
|
require 'sprockets'
|
||||||
|
|
||||||
|
source = 'vendor/assets/coffeescripts'
|
||||||
|
target = 'vendor/assets/javascripts'
|
||||||
|
|
||||||
|
env = Sprockets::Environment.new { |s| s.append_path 'vendor/assets/coffeescripts' }
|
||||||
|
|
||||||
|
Dir[File.join(File.expand_path(source), '*.coffee')].each do |file|
|
||||||
|
file_target = file.gsub(source, target).gsub('.coffee', '.js')
|
||||||
|
puts "#{file} => #{file_target}"
|
||||||
|
|
||||||
|
File.open(file_target, 'wb') do |fh|
|
||||||
|
fh.print env.find_asset(File.expand_path(file)).to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,4 +0,0 @@
|
|||||||
markdown: redcarpet
|
|
||||||
auto: true
|
|
||||||
server: true
|
|
||||||
pygments: true
|
|
@ -1,16 +0,0 @@
|
|||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>{{ page.title }}</title>
|
|
||||||
<link href='http://fonts.googleapis.com/css?family=Neuton' rel='stylesheet' type='text/css'>
|
|
||||||
<link href='http://fonts.googleapis.com/css?family=Crimson+Text' rel='stylesheet' type='text/css'>
|
|
||||||
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="container">
|
|
||||||
<div id="inner-container">
|
|
||||||
{{ content }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
11
bin/jasmine-headless-webkit
Executable file
11
bin/jasmine-headless-webkit
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
require 'rubygems'
|
||||||
|
|
||||||
|
$: << File.expand_path('../../lib', __FILE__)
|
||||||
|
|
||||||
|
require 'jasmine-headless-webkit'
|
||||||
|
require 'coffee-script'
|
||||||
|
|
||||||
|
Jasmine::Headless::CommandLine.run!
|
||||||
|
|
26
config.rb
26
config.rb
@ -1,26 +0,0 @@
|
|||||||
require 'susy'
|
|
||||||
# Require any additional compass plugins here.
|
|
||||||
|
|
||||||
|
|
||||||
# Set this to the root of your project when deployed:
|
|
||||||
http_path = "/"
|
|
||||||
css_dir = "stylesheets"
|
|
||||||
sass_dir = "sass"
|
|
||||||
images_dir = "images"
|
|
||||||
javascripts_dir = "javascripts"
|
|
||||||
|
|
||||||
# You can select your preferred output style here (can be overridden via the command line):
|
|
||||||
# output_style = :expanded or :nested or :compact or :compressed
|
|
||||||
|
|
||||||
# To enable relative paths to assets via compass helper functions. Uncomment:
|
|
||||||
# relative_assets = true
|
|
||||||
|
|
||||||
# To disable debugging comments that display the original location of your selectors. Uncomment:
|
|
||||||
# line_comments = false
|
|
||||||
|
|
||||||
|
|
||||||
# If you prefer the indented syntax, you might want to regenerate this
|
|
||||||
# project again passing --syntax sass, or you can uncomment this:
|
|
||||||
# preferred_syntax = :sass
|
|
||||||
# and then run:
|
|
||||||
# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
|
|
2
config/cucumber.yml
Normal file
2
config/cucumber.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
default: -r features
|
||||||
|
|
22
ext/jasmine-webkit-specrunner/Info.plist
Normal file
22
ext/jasmine-webkit-specrunner/Info.plist
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
|
||||||
|
<plist version="0.9">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string></string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleGetInfoString</key>
|
||||||
|
<string>Created by Qt/QMake</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>specrunner</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.yourcompany.specrunner</string>
|
||||||
|
<key>NOTE</key>
|
||||||
|
<string>This file was generated by Qt/QMake.</string>
|
||||||
|
<key>LSUIElement</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
5
ext/jasmine-webkit-specrunner/Makefile.dummy
Normal file
5
ext/jasmine-webkit-specrunner/Makefile.dummy
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
build:
|
||||||
|
true
|
||||||
|
install:
|
||||||
|
true
|
||||||
|
|
15
ext/jasmine-webkit-specrunner/Page.cpp
Normal file
15
ext/jasmine-webkit-specrunner/Page.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <QtGui>
|
||||||
|
#include <QtWebKit>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Page.h"
|
||||||
|
|
||||||
|
Page::Page() : QWebPage() {}
|
||||||
|
|
||||||
|
void Page::javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID) {
|
||||||
|
emit handleError(message, lineNumber, sourceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Page::javaScriptAlert(QWebFrame *, const QString &) {}
|
||||||
|
bool Page::javaScriptConfirm(QWebFrame *, const QString &) { return false; }
|
||||||
|
bool Page::javaScriptPrompt(QWebFrame *, const QString &, const QString &, QString *) { return false; }
|
20
ext/jasmine-webkit-specrunner/Page.h
Normal file
20
ext/jasmine-webkit-specrunner/Page.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef JHW_PAGE
|
||||||
|
#define JHW_PAGE
|
||||||
|
|
||||||
|
#include <QtGui>
|
||||||
|
#include <QtWebKit>
|
||||||
|
|
||||||
|
class Page: public QWebPage {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
Page();
|
||||||
|
protected:
|
||||||
|
void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID);
|
||||||
|
void javaScriptAlert(QWebFrame *, const QString &);
|
||||||
|
bool javaScriptConfirm(QWebFrame *, const QString &);
|
||||||
|
bool javaScriptPrompt(QWebFrame *, const QString &, const QString &, QString *);
|
||||||
|
signals:
|
||||||
|
void handleError(const QString & message, int lineNumber, const QString & sourceID);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
208
ext/jasmine-webkit-specrunner/Runner.cpp
Normal file
208
ext/jasmine-webkit-specrunner/Runner.cpp
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
#include <QtGui>
|
||||||
|
#include <QtWebKit>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
#include "Runner.h"
|
||||||
|
#include "Page.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
Runner::Runner() : QObject()
|
||||||
|
, runs(0)
|
||||||
|
, hasErrors(false)
|
||||||
|
, _hasSpecFailure(false)
|
||||||
|
, usedConsole(false)
|
||||||
|
, isFinished(false)
|
||||||
|
, useColors(false)
|
||||||
|
, quiet(false)
|
||||||
|
{
|
||||||
|
page.settings()->enablePersistentStorage();
|
||||||
|
ticker.setInterval(TIMER_TICK);
|
||||||
|
|
||||||
|
connect(&ticker, SIGNAL(timeout()), this, SLOT(timerEvent()));
|
||||||
|
connect(&page, SIGNAL(loadFinished(bool)), this, SLOT(watch(bool)));
|
||||||
|
connect(&page, SIGNAL(handleError(const QString &, int, const QString &)), this, SLOT(handleError(const QString &, int, const QString &)));
|
||||||
|
connect(page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(addJHW()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::addFile(const QString &spec) {
|
||||||
|
runnerFiles.enqueue(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::go() {
|
||||||
|
ticker.stop();
|
||||||
|
page.setPreferredContentsSize(QSize(1024, 600));
|
||||||
|
addJHW();
|
||||||
|
|
||||||
|
loadSpec();
|
||||||
|
}
|
||||||
|
void Runner::addJHW() {
|
||||||
|
page.mainFrame()->addToJavaScriptWindowObject("JHW", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::handleError(const QString &message, int lineNumber, const QString &sourceID) {
|
||||||
|
QString messageEscaped = QString(message);
|
||||||
|
QString sourceIDEscaped = QString(sourceID);
|
||||||
|
|
||||||
|
messageEscaped.replace(QString("\""), QString("\\\""));
|
||||||
|
sourceIDEscaped.replace(QString("\""), QString("\\\""));
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << lineNumber;
|
||||||
|
|
||||||
|
QString command("JHW._handleError(\"" + messageEscaped + "\", " + QString(ss.str().c_str()) + ", \"" + sourceIDEscaped + "\"); false;");
|
||||||
|
|
||||||
|
page.mainFrame()->evaluateJavaScript(command);
|
||||||
|
|
||||||
|
hasErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::loadSpec()
|
||||||
|
{
|
||||||
|
QVectorIterator<QString> iterator(reportFiles);
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
QFile *outputFile = new QFile(iterator.next());
|
||||||
|
outputFile->open(QIODevice::WriteOnly);
|
||||||
|
outputFiles.enqueue(outputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString runnerFile = runnerFiles.dequeue();
|
||||||
|
|
||||||
|
page.mainFrame()->load(runnerFile);
|
||||||
|
ticker.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::watch(bool ok) {
|
||||||
|
if (!ok) {
|
||||||
|
std::cerr << "Can't load " << qPrintable(page.mainFrame()->url().toString()) << ", the file may be broken." << std::endl;
|
||||||
|
std::cerr << "Out of curiosity, did your tests try to submit a form and you haven't prevented that?" << std::endl;
|
||||||
|
std::cerr << "Try running your tests in your browser with the Jasmine server and see what happens." << std::endl;
|
||||||
|
QApplication::instance()->exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
page.mainFrame()->evaluateJavaScript(QString("JHW._setColors(") + (useColors ? QString("true") : QString("false")) + QString("); false;"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::setColors(bool colors) {
|
||||||
|
useColors = colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::hasUsedConsole() {
|
||||||
|
usedConsole = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::hasError() {
|
||||||
|
hasErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::hasSpecFailure() {
|
||||||
|
_hasSpecFailure = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::setReportFiles(QStack<QString> &files) {
|
||||||
|
reportFiles = files;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::timerPause() {
|
||||||
|
ticker.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::timerDone() {
|
||||||
|
ticker.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::ping() {
|
||||||
|
runs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::setSeed(QString s) {
|
||||||
|
seed = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::setQuiet(bool q) {
|
||||||
|
quiet = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Runner::getSeed() {
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Runner::isQuiet() {
|
||||||
|
return quiet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::print(const QString &fh, const QString &content) {
|
||||||
|
if (fh == "stdout") {
|
||||||
|
std::cout << qPrintable(content);
|
||||||
|
std::cout.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fh == "stderr") {
|
||||||
|
std::cerr << qPrintable(content);
|
||||||
|
std::cerr.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fh.contains("report")) {
|
||||||
|
int index = (int)fh.split(":").last().toUInt();
|
||||||
|
|
||||||
|
QTextStream ts(outputFiles.at(index));
|
||||||
|
ts << qPrintable(content);
|
||||||
|
ts.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::finishSuite() {
|
||||||
|
isFinished = true;
|
||||||
|
runs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Runner::timerEvent() {
|
||||||
|
++runs;
|
||||||
|
|
||||||
|
if (hasErrors && runs > 2)
|
||||||
|
QApplication::instance()->exit(1);
|
||||||
|
|
||||||
|
if (isFinished && runs > 2) {
|
||||||
|
while (!outputFiles.isEmpty()) {
|
||||||
|
outputFiles.dequeue()->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int exitCode = 0;
|
||||||
|
if (_hasSpecFailure || hasErrors) {
|
||||||
|
exitCode = 1;
|
||||||
|
} else {
|
||||||
|
if (usedConsole) {
|
||||||
|
exitCode = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool runAgain = true;
|
||||||
|
|
||||||
|
if (runnerFiles.count() == 0) {
|
||||||
|
runAgain = false;
|
||||||
|
} else {
|
||||||
|
if (exitCode == 1) {
|
||||||
|
runAgain = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runAgain) {
|
||||||
|
isFinished = false;
|
||||||
|
loadSpec();
|
||||||
|
} else {
|
||||||
|
QApplication::instance()->exit(exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runs > MAX_LOOPS) {
|
||||||
|
std::cerr << "WARNING: too many runs and the test is still not finished!" << std::endl;
|
||||||
|
QApplication::instance()->exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
73
ext/jasmine-webkit-specrunner/Runner.h
Normal file
73
ext/jasmine-webkit-specrunner/Runner.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#ifndef JHW_RUNNER
|
||||||
|
#define JHW_RUNNER
|
||||||
|
|
||||||
|
#include <QtGui>
|
||||||
|
#include <QtWebKit>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <QQueue>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "Page.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class Runner: public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum { TIMER_TICK = 200, MAX_LOOPS = 50 };
|
||||||
|
|
||||||
|
Runner();
|
||||||
|
void setColors(bool colors);
|
||||||
|
void setReportFiles(QStack<QString> &files);
|
||||||
|
void setSeed(QString s);
|
||||||
|
void setQuiet(bool q);
|
||||||
|
|
||||||
|
void addFile(const QString &spec);
|
||||||
|
void go();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void timerPause();
|
||||||
|
void timerDone();
|
||||||
|
void hasUsedConsole();
|
||||||
|
void hasError();
|
||||||
|
void hasSpecFailure();
|
||||||
|
|
||||||
|
bool isQuiet();
|
||||||
|
QString getSeed();
|
||||||
|
|
||||||
|
void print(const QString &fh, const QString &content);
|
||||||
|
void finishSuite();
|
||||||
|
void ping();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void watch(bool ok);
|
||||||
|
void addJHW();
|
||||||
|
void timerEvent();
|
||||||
|
void handleError(const QString & message, int lineNumber, const QString & sourceID);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Page page;
|
||||||
|
QTimer ticker;
|
||||||
|
int runs;
|
||||||
|
bool hasErrors;
|
||||||
|
bool _hasSpecFailure;
|
||||||
|
bool usedConsole;
|
||||||
|
bool isFinished;
|
||||||
|
bool useColors;
|
||||||
|
bool quiet;
|
||||||
|
|
||||||
|
QString seed;
|
||||||
|
|
||||||
|
QQueue<QString> runnerFiles;
|
||||||
|
QStack<QString> reportFiles;
|
||||||
|
|
||||||
|
void loadSpec();
|
||||||
|
|
||||||
|
QQueue<QFile *> outputFiles;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
8
ext/jasmine-webkit-specrunner/common.pri
Normal file
8
ext/jasmine-webkit-specrunner/common.pri
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
QMAKE_INFO_PLIST = Info.plist
|
||||||
|
QT += network webkit
|
||||||
|
|
||||||
|
SOURCES = Page.cpp Runner.cpp
|
||||||
|
HEADERS = Page.h Runner.h
|
||||||
|
|
10
ext/jasmine-webkit-specrunner/extconf.rb
Normal file
10
ext/jasmine-webkit-specrunner/extconf.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
require 'fileutils'
|
||||||
|
|
||||||
|
$: << File.expand_path("../../../lib", __FILE__)
|
||||||
|
|
||||||
|
require 'qt/qmake'
|
||||||
|
|
||||||
|
system %{make clean}
|
||||||
|
Qt::Qmake.make!('jasmine-headless-webkit', 'specrunner.pro')
|
||||||
|
|
||||||
|
FileUtils.cp File.expand_path('../Makefile.dummy', __FILE__), File.expand_path('../Makefile', __FILE__)
|
83
ext/jasmine-webkit-specrunner/specrunner.cpp
Normal file
83
ext/jasmine-webkit-specrunner/specrunner.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Sencha Inc.
|
||||||
|
Copyright (c) 2011 John Bintz
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Runner.h"
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
|
||||||
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
|
||||||
|
#error Use Qt 4.7 or later version
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
bool showColors = false;
|
||||||
|
bool isQuiet = false;
|
||||||
|
QString seed;
|
||||||
|
QStack<QString> reporterFiles;
|
||||||
|
|
||||||
|
int c, index;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "cr:s:q")) != -1) {
|
||||||
|
switch(c) {
|
||||||
|
case 'c':
|
||||||
|
showColors = true;
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
isQuiet = true;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
reporterFiles.push(QString(optarg));
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
seed = QString(optarg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind == argc) {
|
||||||
|
std::cerr << "Run Jasmine's SpecRunner headlessly" << std::endl << std::endl;
|
||||||
|
std::cerr << " specrunner [-c] [-s seed] [-r report file ...] specrunner.html ..." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
app.setApplicationName("jasmine-headless-webkit");
|
||||||
|
Runner runner;
|
||||||
|
|
||||||
|
runner.setColors(showColors);
|
||||||
|
runner.setQuiet(isQuiet);
|
||||||
|
runner.setReportFiles(reporterFiles);
|
||||||
|
runner.setSeed(seed);
|
||||||
|
|
||||||
|
for (index = optind; index < argc; index++) {
|
||||||
|
runner.addFile(QString::fromLocal8Bit(argv[index]));
|
||||||
|
}
|
||||||
|
|
||||||
|
runner.go();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
|
5
ext/jasmine-webkit-specrunner/specrunner.pro
Normal file
5
ext/jasmine-webkit-specrunner/specrunner.pro
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include(common.pri)
|
||||||
|
|
||||||
|
SOURCES += specrunner.cpp
|
||||||
|
TARGET = jasmine-webkit-specrunner
|
||||||
|
|
7
features/bin/failure.feature
Normal file
7
features/bin/failure.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - Failure
|
||||||
|
Scenario: Run a failing test
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/failure/failure.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 1
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 1 failure, no console usage
|
||||||
|
|
7
features/bin/files.feature
Normal file
7
features/bin/files.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - Files
|
||||||
|
Scenario: List the files a test suite will use
|
||||||
|
Given I have a test suite
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/success/success.yml -l`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the output should include "spec/jasmine/success/success.js"
|
||||||
|
And the output should include "spec/jasmine/success/success_spec.js"
|
18
features/bin/filtered_run/both_runs.feature
Normal file
18
features/bin/filtered_run/both_runs.feature
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Feature: Bin - Filtered Run - Both Runs
|
||||||
|
Background:
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
|
||||||
|
Scenario: Run one and fail
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/filtered_failure/filtered_failure.yml -f File:spec/report.txt ./spec/jasmine/filtered_failure/failure_spec.js`
|
||||||
|
Then the exit status should be 1
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 1 failure, no console usage
|
||||||
|
|
||||||
|
Scenario: Run both and succeed
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/filtered_success/filtered_success.yml -f File:spec/report.txt ./spec/jasmine/filtered_success/success_one_spec.js`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 2 total, 0 failures, no console usage
|
||||||
|
|
||||||
|
Scenario: Run both with console.log
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/filtered_success_with_console/filtered_success.yml -f File:spec/report.txt ./spec/jasmine/filtered_success_with_console/success_one_spec.js`
|
||||||
|
Then the exit status should be 2
|
||||||
|
And the report file "spec/report.txt" should have 2 total, 0 failures, yes console usage
|
14
features/bin/filtered_run/no_full_run.feature
Normal file
14
features/bin/filtered_run/no_full_run.feature
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Feature: Bin - No Full Run
|
||||||
|
Background:
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
|
||||||
|
Scenario: Only run the filtered run
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/filtered_success/filtered_success.yml -f File:spec/report.txt --no-full-run ./spec/jasmine/filtered_success/success_one_spec.js`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 0 failure, no console usage
|
||||||
|
|
||||||
|
Scenario: Use a file outside of the normal test run
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/filtered_success/filtered_success.yml -f File:spec/report.txt ./spec/jasmine/filtered_success/success_other_file.js`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 0 failure, no console usage
|
||||||
|
|
7
features/bin/help.feature
Normal file
7
features/bin/help.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - Help
|
||||||
|
Scenario: Display the Help
|
||||||
|
Given I have a test suite
|
||||||
|
When I run `bin/jasmine-headless-webkit -h`
|
||||||
|
Then I should get help output
|
||||||
|
And the exit status should be 0
|
||||||
|
|
8
features/bin/quiet_messages.feature
Normal file
8
features/bin/quiet_messages.feature
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Feature: Bin - Quiet Messages
|
||||||
|
Scenario: Run a test that would cause a lot of messages to be displayed and silence them all
|
||||||
|
Given I have a test suite
|
||||||
|
When I run `bin/jasmine-headless-webkit -q -j spec/jasmine/noisy/noisy.yml`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the output should not include "[Skipping File]"
|
||||||
|
And the output should not include "You should mock"
|
||||||
|
|
8
features/bin/runner_out.feature
Normal file
8
features/bin/runner_out.feature
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Feature: Bin - Runner Out
|
||||||
|
Scenario: Write out the runner to a specified file
|
||||||
|
Given I have a test suite
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/success/success.yml --runner-out spec/runner.html`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the file "spec/runner.html" should contain a JHW runner
|
||||||
|
When I delete the file "spec/runner.html"
|
||||||
|
|
7
features/bin/spec_files_with_same_basename.feature
Normal file
7
features/bin/spec_files_with_same_basename.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - Two spec files with same basename
|
||||||
|
Scenario: Run both files
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/two_spec_files_same_basename/jasmine.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 2 total, 0 failures, no console usage
|
||||||
|
|
20
features/bin/success.feature
Normal file
20
features/bin/success.feature
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Feature: Bin - Success
|
||||||
|
Scenario: Run a successful test with long format definition
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit --seed 1234 -j spec/jasmine/success/success.yml --format File --out spec/report.txt`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 0 failures, no console usage
|
||||||
|
And the report file "spec/report.txt" should have seed 1234
|
||||||
|
|
||||||
|
Scenario: Run a successful test with legacy file reporting
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/success/success.yml --report spec/report.txt`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 0 failures, no console usage
|
||||||
|
|
||||||
|
Scenario: Run a successful test with shortened format definition
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/success/success.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 0 failures, no console usage
|
||||||
|
|
5
features/bin/success_with_js_error.feature
Normal file
5
features/bin/success_with_js_error.feature
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Feature: Bin - Success with JS Error
|
||||||
|
Scenario: Succeed
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/success_with_error/success_with_error.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 1
|
7
features/bin/tries_to_leave_page.feature
Normal file
7
features/bin/tries_to_leave_page.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - Try to Leave Page
|
||||||
|
Scenario: Fail on trying to leave the page
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/leave_page/leave_page.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 1
|
||||||
|
And the report file "spec/report.txt" should exist
|
||||||
|
|
7
features/bin/try_to_click_a_button.feature
Normal file
7
features/bin/try_to_click_a_button.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - Try to Click A Button
|
||||||
|
Scenario: Don't leave page when clicking a button
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/click_button/click_button.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 0 total, 0 failures, no console usage
|
||||||
|
|
11
features/bin/two_files_from_src_files.feature
Normal file
11
features/bin/two_files_from_src_files.feature
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Feature: Two files from source files
|
||||||
|
Scenario: Files are ordered directly
|
||||||
|
Given I have a test suite
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/two_files_from_src_files/jasmine.yml -l`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the following files should be loaded in order:
|
||||||
|
| vendor/vendor-file.js |
|
||||||
|
| vendor/vendor.js |
|
||||||
|
| app/app-file.js |
|
||||||
|
| app/app.js |
|
||||||
|
|
7
features/bin/with_coffeescript_error.feature
Normal file
7
features/bin/with_coffeescript_error.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - With CoffeeScript error
|
||||||
|
Scenario: Fail on CoffeeScript error
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/coffeescript_error/coffeescript_error.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 1
|
||||||
|
And the report file "spec/report.txt" should not exist
|
||||||
|
|
7
features/bin/with_console_log.feature
Normal file
7
features/bin/with_console_log.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Use console.log
|
||||||
|
Scenario: Run a successful test that uses console.log
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/console_log/console_log.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 2
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 0 failures, yes console usage
|
||||||
|
|
7
features/bin/with_server.feature
Normal file
7
features/bin/with_server.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - With Server
|
||||||
|
Scenario: Run using an HTTP server
|
||||||
|
Given there is no existing "spec/report.txt" file
|
||||||
|
When I run `bin/jasmine-headless-webkit --use-server -j spec/jasmine/success/success.yml -f File:spec/report.txt`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 0 failures, no console usage
|
||||||
|
|
7
features/bin/with_window_prompt.feature
Normal file
7
features/bin/with_window_prompt.feature
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Feature: Bin - With window.prompt()
|
||||||
|
Scenario: Alert the user that window.prompt() needs to be stubbed
|
||||||
|
Given I have a test suite
|
||||||
|
When I run `bin/jasmine-headless-webkit -j spec/jasmine/window_prompt/window_prompt.yml`
|
||||||
|
Then the exit status should be 0
|
||||||
|
And the output should include "You should mock window.prompt"
|
||||||
|
|
24
features/reporters.feature
Normal file
24
features/reporters.feature
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
Feature: Reporters
|
||||||
|
In order to allow for multiple types of output
|
||||||
|
I should be able to
|
||||||
|
Manage reporters and decide which ones to use
|
||||||
|
|
||||||
|
Scenario: Use default reporters
|
||||||
|
Given I have the default runner options
|
||||||
|
When I get a runner
|
||||||
|
And I get a template writer
|
||||||
|
Then the template should use the "Console" reporter to "stdout"
|
||||||
|
And the command to run the runner should not include a report file
|
||||||
|
|
||||||
|
Scenario: Use a file reporter
|
||||||
|
Given I have the default runner options
|
||||||
|
And I have the following reporters:
|
||||||
|
| Name | File |
|
||||||
|
| Console | |
|
||||||
|
| File | file |
|
||||||
|
When I get a runner
|
||||||
|
And I get a template writer
|
||||||
|
Then the template should use the "Console" reporter to "stdout"
|
||||||
|
And the template should use the "File" reporter to "report:0"
|
||||||
|
And the command to run the runner should include the report file "file"
|
||||||
|
|
34
features/runner.feature
Normal file
34
features/runner.feature
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
Feature: Using the Runner directly
|
||||||
|
Scenario: Succeed
|
||||||
|
Given I have the following runner options:
|
||||||
|
"""
|
||||||
|
:jasmine_config: spec/jasmine/success/success.yml
|
||||||
|
:reporters:
|
||||||
|
- [ 'File', 'spec/report.txt' ]
|
||||||
|
"""
|
||||||
|
When I get a runner
|
||||||
|
And I run the runner
|
||||||
|
Then the runner should have an exit status of 0
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 0 failures, no console usage
|
||||||
|
|
||||||
|
Scenario: JavaScript Error
|
||||||
|
Given I have the following runner options:
|
||||||
|
"""
|
||||||
|
:jasmine_config: spec/jasmine/success_with_error/success_with_error.yml
|
||||||
|
"""
|
||||||
|
When I get a runner
|
||||||
|
And I run the runner
|
||||||
|
Then the runner should have an exit status of 1
|
||||||
|
|
||||||
|
Scenario: Failure
|
||||||
|
Given I have the following runner options:
|
||||||
|
"""
|
||||||
|
:jasmine_config: spec/jasmine/failure/failure.yml
|
||||||
|
:reporters:
|
||||||
|
- [ 'File', 'spec/report.txt' ]
|
||||||
|
"""
|
||||||
|
When I get a runner
|
||||||
|
And I run the runner
|
||||||
|
Then the runner should have an exit status of 1
|
||||||
|
And the report file "spec/report.txt" should have 1 total, 1 failure, no console usage
|
||||||
|
|
2
features/steps/given/i_have_test_suite.rb
Normal file
2
features/steps/given/i_have_test_suite.rb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Given /^I have a test suite$/ do
|
||||||
|
end
|
4
features/steps/given/no_existing_file.rb
Normal file
4
features/steps/given/no_existing_file.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Given /^there is no existing "([^"]*)" file$/ do |file|
|
||||||
|
FileUtils.rm_rf file
|
||||||
|
end
|
||||||
|
|
4
features/steps/given/options/i_have_defaults.rb
Normal file
4
features/steps/given/options/i_have_defaults.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Given /^I have the default runner options$/ do
|
||||||
|
@options = Jasmine::Headless::Options.new
|
||||||
|
end
|
||||||
|
|
10
features/steps/given/options/i_have_reporters.rb
Normal file
10
features/steps/given/options/i_have_reporters.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Given /^I have the following reporters:$/ do |table|
|
||||||
|
@options[:reporters] = []
|
||||||
|
|
||||||
|
table.hashes.each do |hash|
|
||||||
|
reporter = [ hash['Name'] ]
|
||||||
|
reporter << hash['File'] if !hash['File'].empty?
|
||||||
|
|
||||||
|
@options[:reporters] << reporter
|
||||||
|
end
|
||||||
|
end
|
3
features/steps/given/options/i_have_runner_options.rb
Normal file
3
features/steps/given/options/i_have_runner_options.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Given /^I have the following runner options:$/ do |string|
|
||||||
|
@options = YAML.load(string)
|
||||||
|
end
|
3
features/steps/then/bin/exit_status_should_be.rb
Normal file
3
features/steps/then/bin/exit_status_should_be.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Then /^the exit status should be (\d+)$/ do |exitstatus|
|
||||||
|
$?.exitstatus.should == exitstatus.to_i
|
||||||
|
end
|
4
features/steps/then/bin/file_should_contain_runner.rb
Normal file
4
features/steps/then/bin/file_should_contain_runner.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Then /^the file "([^"]*)" should contain a JHW runner$/ do |file|
|
||||||
|
File.read(file).should include('jasmine.HeadlessReporter')
|
||||||
|
end
|
||||||
|
|
10
features/steps/then/bin/following_files_loaded_in_order.rb
Normal file
10
features/steps/then/bin/following_files_loaded_in_order.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Then /^the following files should be loaded in order:$/ do |table|
|
||||||
|
files = table.raw.flatten
|
||||||
|
|
||||||
|
@output.lines.collect(&:strip).each do |line|
|
||||||
|
files.shift if line[files.first]
|
||||||
|
end
|
||||||
|
|
||||||
|
files.should be_empty
|
||||||
|
end
|
||||||
|
|
4
features/steps/then/bin/i_should_get_help_output.rb
Normal file
4
features/steps/then/bin/i_should_get_help_output.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Then /^I should get help output$/ do
|
||||||
|
@output.should include("Usage:")
|
||||||
|
end
|
||||||
|
|
3
features/steps/then/bin/output_should_include.rb
Normal file
3
features/steps/then/bin/output_should_include.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Then /^the output should include "([^"]*)"$/ do |string|
|
||||||
|
@output.should include(string)
|
||||||
|
end
|
4
features/steps/then/bin/output_should_not_include.rb
Normal file
4
features/steps/then/bin/output_should_not_include.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Then /^the output should not include "([^"]*)"$/ do |string|
|
||||||
|
@output.should_not include(string)
|
||||||
|
end
|
||||||
|
|
4
features/steps/then/reporting/report_does_not_exist.rb
Normal file
4
features/steps/then/reporting/report_does_not_exist.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Then /^the report file "([^"]*)" should not exist$/ do |file|
|
||||||
|
File.file?(file).should be_false
|
||||||
|
end
|
||||||
|
|
3
features/steps/then/reporting/report_should_exist.rb
Normal file
3
features/steps/then/reporting/report_should_exist.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Then /^the report file "([^"]*)" should exist$/ do |file|
|
||||||
|
File.file?(file).should be_true
|
||||||
|
end
|
7
features/steps/then/reporting/report_should_have.rb
Normal file
7
features/steps/then/reporting/report_should_have.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Then /^the report file "(.*)" should have (\d+) total, (\d+) failures?, (no|yes) console usage$/ do |file, total, failures, console_usage|
|
||||||
|
report = Jasmine::Headless::Report.load(file)
|
||||||
|
|
||||||
|
report.total.should == total.to_i
|
||||||
|
report.failed.should == failures.to_i
|
||||||
|
report.has_used_console?.should == (console_usage == 'yes')
|
||||||
|
end
|
4
features/steps/then/reporting/report_should_have_seed.rb
Normal file
4
features/steps/then/reporting/report_should_have_seed.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Then /^the report file "([^"]*)" should have seed (\d+)$/ do |file, seed|
|
||||||
|
report = Jasmine::Headless::Report.load(file)
|
||||||
|
report.seed.should == seed.to_i
|
||||||
|
end
|
3
features/steps/then/runner/it_should_have_exit_status.rb
Normal file
3
features/steps/then/runner/it_should_have_exit_status.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Then /^the runner should have an exit status of (\d+)$/ do |exit_status|
|
||||||
|
@result.should == exit_status.to_i
|
||||||
|
end
|
@ -0,0 +1,4 @@
|
|||||||
|
Then /^the command to run the runner should include the report file "([^"]*)"$/ do |file|
|
||||||
|
@runner.jasmine_command.should include("-r #{file}")
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,3 @@
|
|||||||
|
Then /^the command to run the runner should not include a report file$/ do
|
||||||
|
@runner.jasmine_command.should_not include('-r')
|
||||||
|
end
|
6
features/steps/then/templates/it_should_use_reporter.rb
Normal file
6
features/steps/then/templates/it_should_use_reporter.rb
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Then /^the template should use the "([^"]*)" reporter to "([^"]*)"$/ do |reporter, target|
|
||||||
|
output = @template_writer.render
|
||||||
|
|
||||||
|
output.should include(%{jasmine.HeadlessReporter.#{reporter}("#{target}")})
|
||||||
|
end
|
||||||
|
|
3
features/steps/when/i_delete_file.rb
Normal file
3
features/steps/when/i_delete_file.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
When /^I delete the file "([^"]*)"$/ do |file|
|
||||||
|
FileUtils.rm_f(file)
|
||||||
|
end
|
4
features/steps/when/i_get_runner.rb
Normal file
4
features/steps/when/i_get_runner.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
When /^I get a runner$/ do
|
||||||
|
@runner = Jasmine::Headless::Runner.new(@options)
|
||||||
|
end
|
||||||
|
|
4
features/steps/when/i_get_template_writer.rb
Normal file
4
features/steps/when/i_get_template_writer.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
When /^I get a template writer$/ do
|
||||||
|
@template_writer = Jasmine::Headless::TemplateWriter.new(@runner)
|
||||||
|
end
|
||||||
|
|
4
features/steps/when/i_run_executable.rb
Normal file
4
features/steps/when/i_run_executable.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
When /^I run `(.*)`$/ do |command|
|
||||||
|
@output = `#{command}`
|
||||||
|
end
|
||||||
|
|
4
features/steps/when/i_run_runner.rb
Normal file
4
features/steps/when/i_run_runner.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
When /^I run the runner$/ do
|
||||||
|
@result = @runner.run
|
||||||
|
end
|
||||||
|
|
7
features/support/env.rb
Normal file
7
features/support/env.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
require 'jasmine-headless-webkit'
|
||||||
|
|
||||||
|
After do
|
||||||
|
FileUtils.rm_f 'spec/report.txt'
|
||||||
|
FileUtils.rm_f 'spec/runner.html'
|
||||||
|
end
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
BIN
images/f5.png
BIN
images/f5.png
Binary file not shown.
Before Width: | Height: | Size: 90 KiB |
671
index.md
671
index.md
@ -1,671 +0,0 @@
|
|||||||
---
|
|
||||||
title: jasmine-headless-webkit -- The fastest way to run your Jasmine specs!
|
|
||||||
layout: default
|
|
||||||
---
|
|
||||||
# Jasmine Headless WebKit
|
|
||||||
## Run your Jasmine specs at sonic boom speed!
|
|
||||||
|
|
||||||
<img src="images/f5.png" alt="Colored Output" />
|
|
||||||
[Jasmine](http://pivotal.github.com/jasmine/) is great. I love it. But running Jasmine when you need to test code that will run
|
|
||||||
in a browser environment can be problematic and slow:
|
|
||||||
|
|
||||||
* The [Jasmine gem](https://github.com/pivotal/jasmine-gem)'s server makes getting up and testing very fast, but F5-ing your browser for each test run is distracting.
|
|
||||||
* Jasmine CI uses Selenium, which speeds up the process a bit, but you're still rendering pixels in a browser, albeit with the option of rendering those pixels in a lot of different browsers at once.
|
|
||||||
* Node.js, EnvJS, and Rhino solutions for running Jasmine are great for anything that will never run in a real browser. I'm a big believer of running code destined for a browser in a browser itself, not a simulator.
|
|
||||||
* [Evergreen](https://github.com/jnicklas/evergreen) makes Jasmine testing in a Rails app as easy as pie, but not everyone writes for Rails.
|
|
||||||
|
|
||||||
But there's a solution for fast, accurate browser-based testing. with a focus on continuous testing,
|
|
||||||
using one of the most popular browser cores, and that dovetails perfectly into the Jasmine gem's already established protocols.
|
|
||||||
|
|
||||||
## Enter `jasmine-headless-webkit`
|
|
||||||
|
|
||||||
`jasmine-headless-webkit` uses the [QtWebKit widget](http://trac.webkit.org/wiki/QtWebKit) to run your specs without needing to render a pixel. It's nearly
|
|
||||||
as fast as running in a JavaScript engine like Node.js, and, since it's a real browser environment, all the modules
|
|
||||||
you would normally use, like jQuery and Backbone.js, work without any modifications. If you write your tests correctly,
|
|
||||||
they'll even work when running in the Jasmine gem's server with no changes to your code.
|
|
||||||
|
|
||||||
`jasmine-headless-webkit` also streamlines your workflow in other ways:
|
|
||||||
|
|
||||||
* It integrates with [Guard](https://github.com/guard/guard) for a continuous testing setup when using [`guard-jasmine-headless-webkit`](https://github.com/guard/guard-jasmine-headless-webkit).
|
|
||||||
* It integrates with [Sprockets](https://github.com/sstephenson/sprockets) to handle code requires & preprocessing and JavaScript templates.
|
|
||||||
* It compiles [CoffeeScript](http://jashkenas.github.com/coffee-script/), both for your tests and for your application logic.
|
|
||||||
* It can be configured like RSpec, and its output is very similar to RSpec's output, so you don't need to learn too much new stuff to use and integrate it.
|
|
||||||
* It provides cleaner debugging and backtrace output than a lot of other console-based test tools provide.
|
|
||||||
* It's *fast*.
|
|
||||||
|
|
||||||
## Is this for me?
|
|
||||||
|
|
||||||
That depends on what you need:
|
|
||||||
|
|
||||||
* If you're new to JavaScript testing, drop in [Pivotal's Jasmine gem](https://github.com/pivotal/jasmine-gem) and point your browser at http://localhost:8888/.
|
|
||||||
* If you're used to how the Jasmine gem works and want to move to a faster solution geared toward continuous testing, you're in the right place!
|
|
||||||
* If you want an even simpler config and access to all of your Rails routes and resources for a quasi-integration testing setup, use [Evergreen](https://github.com/jnicklas/evergreen).
|
|
||||||
You even get your choice of browser drivers for free (as opposed to just Selenium or WebKit) as well as headless testing!
|
|
||||||
* If you want true integration testing, where you test the whole application stack, use Cucumber and/or Capybara.
|
|
||||||
* If you're not using Rails and still want to unit test, the Jasmine gem or `jasmine-headless-webkit` is what you want.
|
|
||||||
|
|
||||||
'round here, we focus on unit testing and mocking external interfaces. No using your app's views or routes, no hitting the app server to
|
|
||||||
get resources, just mocking and stubbing the JavaScript code all by itself.
|
|
||||||
|
|
||||||
## How do I use this wonderful toy?
|
|
||||||
|
|
||||||
You can use it standalone:
|
|
||||||
|
|
||||||
gem install jasmine-headless-webkit
|
|
||||||
|
|
||||||
Or you can use it with Bundler:
|
|
||||||
|
|
||||||
gem 'jasmine-headless-webkit'
|
|
||||||
|
|
||||||
However you install it, you'll get a `jasmine-headless-webkit` executable. You'll also need to set up your project
|
|
||||||
to use the Jasmine gem:
|
|
||||||
|
|
||||||
gem install jasmine
|
|
||||||
jasmine init
|
|
||||||
|
|
||||||
Once you're good enough, you can make the `spec/javascripts/support/jasmine.yml` file yourself and skip the Pivotal Jasmine gem entirely.
|
|
||||||
It's what the cool kids do.
|
|
||||||
|
|
||||||
### What do I need to get it working?
|
|
||||||
|
|
||||||
Installation requires Qt 4.7. `jasmine-headless-webkit` has been tested in the following environments:
|
|
||||||
|
|
||||||
* Mac OS X 10.6 and 10.7, with MacPorts Qt, Homebrew Qt and Nokia Qt.mpkg
|
|
||||||
* Kubuntu 110.04, 10.10 and 10.04
|
|
||||||
* Ubuntu 11.04 and 9.10
|
|
||||||
* Arch Linux
|
|
||||||
|
|
||||||
If it works in yours, [leave me a message on GitHub](https://github.com/johnbintz) or
|
|
||||||
[fork this site](https://github.com/johnbintz/jasmine-headless-webkit/tree/gh-pages) and add your setup.
|
|
||||||
|
|
||||||
## Qt 4.7.X
|
|
||||||
|
|
||||||
The gem is compiled using `qt4-qmake` and you will need Qt 4.7.x or greater.
|
|
||||||
The version you have installed should be detected correctly, and the appropriate message for installing Qt should
|
|
||||||
be given if it's wrong. If it's not, please file a new issue!
|
|
||||||
|
|
||||||
### Manually checking the Qt version
|
|
||||||
|
|
||||||
Test that `qt4-qmake` it is installed and verify your version.
|
|
||||||
qmake --version
|
|
||||||
|
|
||||||
If you have the Qt 4.7.x or greater, you are ready to install jasmine-headless-webkit.
|
|
||||||
QMake version 2.01a
|
|
||||||
Using Qt version 4.7.2 in /usr/lib
|
|
||||||
|
|
||||||
If you receive a different message, you can install `qt4-qmake` using one of the following commands as root:
|
|
||||||
|
|
||||||
### Ubuntu 11.04
|
|
||||||
|
|
||||||
{% highlight bash %}
|
|
||||||
sudo apt-get install libqt4-dev
|
|
||||||
sudo apt-get install qt4-qmake
|
|
||||||
sudo update-alternatives --config qmake # and select Qt 4's qmake
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
### Ubuntu 9.10
|
|
||||||
|
|
||||||
Running `sudo apt-get install libqt4-dev` and `sudo apt-get install qt4-qmake` will install qt4,
|
|
||||||
but it installs **version 4.5.2**, which will not be able to compile
|
|
||||||
**jasmine-headless-webkit**, as it requires Qt 4.7.X or greater.
|
|
||||||
|
|
||||||
You will need to compile qt4-qmake from source
|
|
||||||
[Qt version 4.7.0](http://get.qt.nokia.com/qt/source/qt-everywhere-opensource-src-4.7.0.tar.gz).
|
|
||||||
There are excellent [directions](http://doc.qt.nokia.com/latest/install-x11.html) on how to compile
|
|
||||||
the source code. You will need to ensure Qt is exported to your `$PATH` before using qmake, as the source code will
|
|
||||||
install to `/usr/local/Trolltech/`.
|
|
||||||
|
|
||||||
### Mac OS X 10.6 & 10.7
|
|
||||||
|
|
||||||
#### MacPorts
|
|
||||||
|
|
||||||
{% highlight bash %}
|
|
||||||
sudo port install qt4-mac
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
#### Homebrew
|
|
||||||
|
|
||||||
{% highlight bash %}
|
|
||||||
brew install qt
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
__(you may need to use `--build-from-source` on Lion)__
|
|
||||||
|
|
||||||
### My OS isn't on here!
|
|
||||||
[`capybara-webkit`](https://github.com/thoughtbot/capybara-webkit) has the best instructions for installing Qt on various other
|
|
||||||
systems that may not be covered here.
|
|
||||||
|
|
||||||
### How does it work?
|
|
||||||
|
|
||||||
`jasmine-headless-webkit` generates a static HTML file that includes the Jasmine JavaScript library from the Jasmine
|
|
||||||
gem, your application and spec files, and any helpers you may need. The runner then creates a WebKit widget that
|
|
||||||
loads the HTML file, runs the tests, and grabs the results of the test to show back to you. Awesome!
|
|
||||||
|
|
||||||
`jasmine-headless-webkit` uses the same `jasmine.yml` file that the Jasmine gem uses to define where particular
|
|
||||||
files for the testing process are located:
|
|
||||||
|
|
||||||
{% highlight yaml %}
|
|
||||||
src_files:
|
|
||||||
- "**/*"
|
|
||||||
helpers:
|
|
||||||
- helpers/**/*
|
|
||||||
spec_files:
|
|
||||||
- "**/*_spec.*"
|
|
||||||
src_dir: app/assets/javascripts
|
|
||||||
spec_dir: spec/javascripts
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
It also brings in the same copy of the Jasmine library that the Jasmine gem includes, so if you're testing in both environments,
|
|
||||||
you're guaranteed to get the same results in your tests.
|
|
||||||
|
|
||||||
#### `*.coffee` in my `jasmine.yml` file?!
|
|
||||||
|
|
||||||
Yes, `jasmine-headless-webkit` will support `*.coffee` files in `jasmine.yml`, which the normal Jasmine server currently
|
|
||||||
does not support out of the box. Once there's official support, you'll be able to easily switch between `jasmine-headless-webkit`
|
|
||||||
and the Jasmine test server when you're using CoffeeScript. CoffeeScript files are compiled and injected into the generated HTML
|
|
||||||
files.
|
|
||||||
|
|
||||||
Never done Jasmine in CoffeeScript? It looks like this:
|
|
||||||
|
|
||||||
{% highlight coffeescript %}
|
|
||||||
describe 'Component', ->
|
|
||||||
describe 'StorylineNode', ->
|
|
||||||
model = null
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
model = new ComponentStorylineNode({id: 1})
|
|
||||||
|
|
||||||
it 'should not be new', ->
|
|
||||||
expect(model.isNew()).toEqual(false)
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
...and it turns into this...
|
|
||||||
|
|
||||||
{% highlight js %}
|
|
||||||
describe('Component', function() {
|
|
||||||
return describe('StorylineNode', function() {
|
|
||||||
var model;
|
|
||||||
model = null;
|
|
||||||
beforeEach(function() {
|
|
||||||
return model = new ComponentStorylineNode({
|
|
||||||
id: 1
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return it('should not be new', function() {
|
|
||||||
return expect(model.isNew()).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
#### Server interaction
|
|
||||||
|
|
||||||
Since there's no Jasmine server running, there's no way to grab test files from the filesystem via Ajax.
|
|
||||||
If you need to test server interaction, do one of the following:
|
|
||||||
|
|
||||||
* Stub your server responses using [Sinon.JS](http://sinonjs.org/), the recommended way.
|
|
||||||
* Use [PhantomJS](http://www.phantomjs.org/) against a running copy of a Jasmine server, instead of this project.
|
|
||||||
|
|
||||||
#### Sprockets support
|
|
||||||
|
|
||||||
Nearly all of Sprockets is accessible to your test suite when using `jasmine-headless-webkit`.
|
|
||||||
It's easier to list the parts that aren't accessible:
|
|
||||||
|
|
||||||
* `*.erb` files are not processed at all (and are actually ignored) because it's assumed the contents of those files depend on an
|
|
||||||
outside source, like a Rails app. That integration puts testing those files squarely in the "integration testing" realm, so
|
|
||||||
it's not valid to support them in a unit testing tool.
|
|
||||||
* No CSS compilation happens, so no Sass or LESS.
|
|
||||||
|
|
||||||
If any gems have `vendor/assets/javascripts` in their list of files, such as `jquery-rails`, those are put in the asset
|
|
||||||
path along with the paths you define in `src_dir`:
|
|
||||||
|
|
||||||
{% highlight yaml %}
|
|
||||||
src_dir:
|
|
||||||
- app/assets/javascripts
|
|
||||||
- vendor/assets/javascripts
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
_Technically, `spec_dir` is in your asset path, too, but Jasmine's typical behavior of including `helpers` before `spec_dir` should
|
|
||||||
give you all the include power you need for defining specs._
|
|
||||||
|
|
||||||
If you want to keep `src_dir` as a string for backwards compatibility, you can add additional asset paths with, you guessed it, `asset_paths`:
|
|
||||||
|
|
||||||
{% highlight yaml %}
|
|
||||||
src_dir: app/assets/javascripts
|
|
||||||
|
|
||||||
asset_paths:
|
|
||||||
- vendor/assets/javascripts
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
`asset_paths` are added to the Sprockets asset paths after `src_dir`.
|
|
||||||
|
|
||||||
In order for Sprockets support to work as intended, you should define your `src_files` and `spec_files` as such:
|
|
||||||
|
|
||||||
{% highlight yaml %}
|
|
||||||
src_files:
|
|
||||||
- "**/*.*"
|
|
||||||
spec_files:
|
|
||||||
- "**/*[Ss]pec.*"
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
This will include everything that Sprockets understands in all your `src_dir` and `spec_dir` paths. At that point, use Sprockets `require`
|
|
||||||
statements to define the include order of your files. Using the `--list` option on the command line to list the load order of files, combined
|
|
||||||
with the `--runner-out` option to write HTML runner files to a place where the browser can easily get to them, is very helpful when moving to
|
|
||||||
a Sprockets-managed project.
|
|
||||||
|
|
||||||
JavaScript Templates are supported too, including [haml-sprockets](https://github.com/dharanasoft/haml-sprockets). Use them as you would any other
|
|
||||||
JavaScript file, and ensure the load order is right, and the necessary code in the JST namespace will be created.
|
|
||||||
|
|
||||||
Since any gem with `vendor/assets/javascripts` is usable, that means Jasmine-specific gems are possible now. [jasmine-spec-extras](https://github.com/johnbintz/jasmine-spec-extras)
|
|
||||||
is the first such gem, which provides `jasmine-jquery`, `sinon`, and any other useful Jasmine helpers, vendored into the gem so you can easily include
|
|
||||||
them into your project without having to manually manage them yourself:
|
|
||||||
|
|
||||||
{% highlight coffeescript %}
|
|
||||||
#= require sinon
|
|
||||||
#= require backbone
|
|
||||||
|
|
||||||
describe "Spy thing", ->
|
|
||||||
it 'should fire a callback', ->
|
|
||||||
collection = new Backbone.Collection()
|
|
||||||
spy = sinon.spy()
|
|
||||||
collection.bind('reset', spy)
|
|
||||||
collection.reset()
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
If you have to use ERB to inject information into the JavaScript or CoffeeScript files in your project, I recommend that you move those
|
|
||||||
injections to a file that is included separately from the code, or include them in `application.*.erb` like this:
|
|
||||||
|
|
||||||
{% highlight coffeescript %}
|
|
||||||
# File: app/assets/javascripts/application.coffee.erb
|
|
||||||
|
|
||||||
#= require 'jquery'
|
|
||||||
#= require 'my_library'
|
|
||||||
|
|
||||||
MyLibrary.root_url = <%= api_root_path %>
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
Sprockets support is still pretty new, so as myself and others discover the best way to set up code that can be used in both places, those
|
|
||||||
practices will be outlined here.
|
|
||||||
|
|
||||||
#### Caching, caching, caching
|
|
||||||
|
|
||||||
`jasmine-headless-webkit` does two things that are CPU intensive (besides running tests): compiling CoffeeScript and analyzing
|
|
||||||
spec files to get line number information for nicer spec failure messages (_did I mention you get really nice spec failure
|
|
||||||
messages with `jasmine-headless-webkit`, too?_). These two operations are cached into the `.jhw-cache/` folder from where the
|
|
||||||
runner is executed. When this cache is combined with running tests continuously using Guard, runtime overhead is reduced to almost
|
|
||||||
nothing.
|
|
||||||
|
|
||||||
Of course, being a cache, it takes time to warm up. The first time you run `jasmine-headless-webkit` on a big project, it can take
|
|
||||||
several seconds to warm the cache. After that, enjoy an almost 20% speedup in runtime (tested on exactly one project's runtime,
|
|
||||||
YMMV).
|
|
||||||
|
|
||||||
#### What else works?
|
|
||||||
|
|
||||||
`alert()` and `confirm()` work, though the latter always returns `true`. You should be mocking calls to `confirm()`,
|
|
||||||
of course:
|
|
||||||
|
|
||||||
{% highlight js %}
|
|
||||||
spyOn(window, 'confirm').andReturn(false)
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
`console.log()` also works. It uses one of three methods for serializing what you've provided:
|
|
||||||
|
|
||||||
* If the object given responds to `toJSON`, `jasmine-headless-webkit` uses `JSON.stringify(object.toJSON())`.
|
|
||||||
* If the object is a jQuery object, it is serialized with `jQuery('<div>').append(object).html()`
|
|
||||||
and pretty-printed using the HTML beautifier from [JS Beautifier](https://github.com/einars/js-beautify).
|
|
||||||
* If none of these apply, it uses a hacked-up version of [jsDump](https://github.com/NV/jsDump) that ignores
|
|
||||||
Functions on objects and prevents cyclical references.
|
|
||||||
|
|
||||||
If you need a heavy-weight object printer, you also have `console.pp()`, which uses Jasmine's built-in pretty-printer if available, and falls back to `JSON.stringify()` if it's not.
|
|
||||||
|
|
||||||
You also get an additional method, `console.peek()`, which calls `console.log()` with the provided parameter, then passes the parameter back along so you
|
|
||||||
can continue to work with it. It's the equivalent of `.tap { |o| p o }` in Ruby.
|
|
||||||
|
|
||||||
## Running the runner
|
|
||||||
|
|
||||||
{% highlight bash %}
|
|
||||||
jasmine-headless-webkit [ -c / --colors ]
|
|
||||||
[ --no-colors ]
|
|
||||||
[ --no-full-run ]
|
|
||||||
[ --keep ]
|
|
||||||
[ -l / --list ]
|
|
||||||
[ --report <report file> ]
|
|
||||||
[ --runner-out <html file> ]
|
|
||||||
[ --use-server ]
|
|
||||||
[ --server-port <port number> ]
|
|
||||||
[ -j / --jasmine-config <path to jasmine.yml> ]
|
|
||||||
[ --seed <random seed> ]
|
|
||||||
<spec files to run>
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
The runner will return one of three exit codes:
|
|
||||||
|
|
||||||
* __0__ means your tests passed sucessfully.
|
|
||||||
* __1__ means you had a failure in your tests.
|
|
||||||
* __2__ means your tests passed, but you used `console.log()` somewhere.
|
|
||||||
|
|
||||||
### Setting default options
|
|
||||||
|
|
||||||
Much like RSpec, you can define the default options for each run of the runner. Place your global options into a
|
|
||||||
`~/.jasmine-headless-webkit` file and your per-project settings in a `.jasmine-headless-webkit` file at the root of
|
|
||||||
the project.
|
|
||||||
|
|
||||||
### Listng what files `jasmine-headless-webkit` will include
|
|
||||||
|
|
||||||
If your tests are not picking up a file you thought they should be, or they're being included in the wrong order,
|
|
||||||
run with the `-l` flag to get a list of the files that `jasmine-headless-webkit` will include in the generated HTML file.
|
|
||||||
*Very* handy for making sure your Sprockets requires are working correctly.
|
|
||||||
|
|
||||||
### Coloring the output
|
|
||||||
|
|
||||||
`jasmine-headless-webkit` will not color output by default. This makes it easier to integrate with CI servers. If you want
|
|
||||||
colored output, use the `-c` flag. With colored output, your tests will look like this:
|
|
||||||
|
|
||||||
<img class="large" src="images/colored-output.png" alt="Colored Output" />
|
|
||||||
|
|
||||||
If you have colors turned on globally, you can turn them off per-project or per-run with `--no-colors`.
|
|
||||||
|
|
||||||
### Preserving compiled output on errors
|
|
||||||
|
|
||||||
CoffeeScript logic errors can be hard to track down. Keep the generated HTML files with the `--keep` flag and you'll
|
|
||||||
get `specrunner.$$.html` files in your working directory.
|
|
||||||
|
|
||||||
### Writing out a machine-readable report
|
|
||||||
|
|
||||||
Use the `--report` option to create a detailed report file:
|
|
||||||
|
|
||||||
PASS||Statement||One||file.js:23
|
|
||||||
FAIL||Statement||Two||file.js:23
|
|
||||||
CONSOLE||Yes
|
|
||||||
ERROR||Uh oh||file.js:23
|
|
||||||
TOTAL||1||2||3||T
|
|
||||||
|
|
||||||
[`guard-jasmine-headless-webkit`](http://github.com/guard/guard-jasmine-headless-webkit/) uses this for the Growl notifications.
|
|
||||||
You can also use it in your own setups, to run specs remotely and stick the results into a CI system. You can use
|
|
||||||
`Jasmine::Headless::Report` to interpret the file and transform the output.
|
|
||||||
|
|
||||||
### Using a different `jasmine.yml` file
|
|
||||||
|
|
||||||
If for some reason you're not using the default path for a `jasmine.yml` file (which is `spec/javascripts/support/jasmine.yml`),
|
|
||||||
you can provide that path with `-j`.
|
|
||||||
|
|
||||||
### Randomizing the order of spec files
|
|
||||||
|
|
||||||
Spec files are shuffled into a random order before each run. This lets you find issues where spec files may depend on state
|
|
||||||
established in prior executed spec files -- a bad thing. After each run, you'll get the random seed used to randomize the files:
|
|
||||||
|
|
||||||
`Test ordering seed: --seed 1234`
|
|
||||||
|
|
||||||
If you're getting weird results related to the particular order of a run of specs, pass that same seed value back in
|
|
||||||
and get to work!
|
|
||||||
|
|
||||||
### Running only certain spec files
|
|
||||||
|
|
||||||
By default, if no files are passed into `jasmine-headless-webkit`, all possible spec files in the `spec_files` definition
|
|
||||||
will be run. You can limit the run to only certain files by passing those to `jasmine-headless-webkit`:
|
|
||||||
|
|
||||||
{% highlight bash %}
|
|
||||||
jasmine-headless-webkit spec/javascripts/models/node_viewer.coffee
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
### Serving files from an HTTP server
|
|
||||||
|
|
||||||
The `--use-server` flag will start up a simple WEBrick server for serving files to the WebKit runner, as opposed to serving
|
|
||||||
them from the filesystem. This also lets you test things like HTML5 history stuff and other things that require an `http://`
|
|
||||||
URL when loading files. Normally, the port this server runs on is random, but you can specify it with `--server-port`.
|
|
||||||
|
|
||||||
#### Filtered runs and full runs
|
|
||||||
|
|
||||||
Typically, targeted spec running is done by a tool like Guard, and the order of running goes like this:
|
|
||||||
|
|
||||||
* Run the filtered spec
|
|
||||||
* If it fails, stop processing and alert the user
|
|
||||||
* If it succeeds, run all specs and alert on success or failure
|
|
||||||
|
|
||||||
Having your test running tool re-run `jasmine-headless-webkit` is fast, but there's still the cost of instantiating QtWebKit and Ruby
|
|
||||||
with each run. Versions of `jasmine-headless-webkit` 0.3.0 and greater will do this for you, keeping the widget in memory and running
|
|
||||||
Jasmine tests on first the filtered suite, and then the complete suite. The results you'll get are for the last run that's executed, which
|
|
||||||
is typically what you want to know anyway. Newer versions of `guard-jasmine-headless-webkit` also support this behavior. This trims
|
|
||||||
valuable seconds off of testing with every run, saving you enough time every day to run to the coffee shop and get some delicious brew!
|
|
||||||
|
|
||||||
If you don't want this behavior, pass in `--no-full-run` and filtered runs will be the only thing that runs when you request one.
|
|
||||||
|
|
||||||
### Writing the HTML runner to another location
|
|
||||||
|
|
||||||
If you want to use the runner file in other places, use the `--runner-out` parameter with the name of the target file.
|
|
||||||
The HTML produced uses the Jasmine `HtmlReporter` if not loaded in `jasmine-headless-webkit`, so you should be able
|
|
||||||
to just open it in a browser and have it work.
|
|
||||||
|
|
||||||
If you always want the reporter written to a particular location, you can define that location in `jasmine.yml`:
|
|
||||||
|
|
||||||
{% highlight yaml %}
|
|
||||||
runner_output: "runner.html"
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
## Running the runner from a Ruby program
|
|
||||||
|
|
||||||
You can call the runner from Ruby:
|
|
||||||
|
|
||||||
{% highlight ruby %}
|
|
||||||
require 'jasmine-headless-webkit'
|
|
||||||
|
|
||||||
status_code = Jasmine::Headless::Runner.run(
|
|
||||||
:colors => false,
|
|
||||||
#=> true to get colors
|
|
||||||
:remove_html_file => true,
|
|
||||||
#=> false to keep specrunners on failure
|
|
||||||
:jasmine_config => 'spec/javascripts/support/jasmine.yml',
|
|
||||||
#=> run a different config
|
|
||||||
:report => false,
|
|
||||||
#=> filename if a report file should be written
|
|
||||||
:full_run => true,
|
|
||||||
#=> false to not run a full run after a targeted run
|
|
||||||
:files => ['file_one_spec.js', 'file_two_spec.coffee']
|
|
||||||
#=> files to use for a targeted run, [] to run all
|
|
||||||
)
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
## Automated testing during development
|
|
||||||
|
|
||||||
`jasmine-headless-webkit` works best when it's running all the time, re-running tests when you update the appropriate files.
|
|
||||||
If you use [Guard](https://github.com/guard/guard/), install [`guard-jasmine-headless-webkit`](http://github.com/guard/guard-jasmine-headless-webkit/)
|
|
||||||
and run `guard init jasmine-headless-webkit` to add the necessary bits to your `Guardfile` to test a Rails 3.1 (or a well-structured Rails 3.0) app.
|
|
||||||
|
|
||||||
### guard-rails-assets
|
|
||||||
|
|
||||||
With Sprockets support now in `jasmine-headless-webkit`, there's less of a need for most users for `guard-rails-assets`, unless you really need to get
|
|
||||||
at those ERB files in your project. [`guard-rails-assets`](http://github.com/dnagir/guard-rails-assets) is what you want to use in this case.
|
|
||||||
It will watch your app's code for changes and rebuild your pipelined JS code, ready to be tested with `jasmine-headless-webkit`:
|
|
||||||
|
|
||||||
{% highlight ruby %}
|
|
||||||
guard 'rails-assets' do
|
|
||||||
watch(%r{^app/assets/javascripts/(.*)\.(js|coffee)$})
|
|
||||||
end
|
|
||||||
|
|
||||||
guard 'jasmine-headless-webkit' do
|
|
||||||
watch(%r{^public/assets/.*\.js$})
|
|
||||||
watch(%r{^spec/javascripts/.*\.coffee$})
|
|
||||||
end
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
### Jammit for JS templates
|
|
||||||
|
|
||||||
If you're still using Jammit it shove your JS templates into one file, you can use a Guard for that, too! [`guard-jammit`](http://github.com/guard/guard-jammit)
|
|
||||||
provides Jammit watching support, but the current version (as of 2011-06-18) does not support some changes to Jammit's internals. Use [my fork](http://github.com/johnbintz/guard-jammit)
|
|
||||||
until that gets fixed.
|
|
||||||
|
|
||||||
{% highlight ruby %}
|
|
||||||
guard 'jammit' do
|
|
||||||
watch(%r{^app/views/.*\.jst$$})
|
|
||||||
end
|
|
||||||
|
|
||||||
guard 'jasmine-headless-webkit' do
|
|
||||||
watch(%r{^public/assets/.*\.js$})
|
|
||||||
watch(%r{^spec/javascripts/.*\.coffee$})
|
|
||||||
end
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
## Rake tasks
|
|
||||||
|
|
||||||
You can create a Rake task for your headless Jasmine specs:
|
|
||||||
|
|
||||||
{% highlight ruby %}
|
|
||||||
require 'jasmine-headless-webkit'
|
|
||||||
|
|
||||||
Jasmine::Headless::Task.new('jasmine:headless') do |t|
|
|
||||||
t.colors = true
|
|
||||||
t.keep_on_error = true
|
|
||||||
t.jasmine_config = 'this/is/the/path.yml'
|
|
||||||
end
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
If you've bundled `jasmine-headless-webkit` in with Rails, you'll also get a basic task for running your
|
|
||||||
Jasmine specs. Be sure to include the gem in the development group so you get with a normal call to `rake -T`:
|
|
||||||
|
|
||||||
{% highlight ruby %}
|
|
||||||
group :test, :development do
|
|
||||||
gem 'jasmine-headless-webkit'
|
|
||||||
end
|
|
||||||
{% endhighlight %}
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
# rake -T
|
|
||||||
|
|
||||||
rake jasmine:headless # Run Jasmine specs headlessly
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
This is the same as running `jasmine-headless-webkit -c`.
|
|
||||||
|
|
||||||
## Continuous integration & testing using Xvfb
|
|
||||||
|
|
||||||
Since most continuous integration servers do not have a display, you will need to use
|
|
||||||
Xvfb or virtual framebuffer Xserver for Version 11. If you elect not to use Xvfb, you will
|
|
||||||
need to have a browser and graphical display to run `jasmine-headless-webkit -c`.
|
|
||||||
|
|
||||||
Reference: [Xvfb Manpages](http://manpages.ubuntu.com/manpages/natty/man1/Xvfb.1.html)
|
|
||||||
|
|
||||||
### Install Xvfb
|
|
||||||
sudo apt-get install xvfb
|
|
||||||
|
|
||||||
### Resolve missing dependencies
|
|
||||||
To resolve missing dependencies, you will need to know what to install.
|
|
||||||
$ Xvfb :99 -ac
|
|
||||||
You will see a long list of warning messages:
|
|
||||||
|
|
||||||
[dix] Could not init font path element /usr/share/fonts/X11/misc,
|
|
||||||
removing from list!
|
|
||||||
[dix] Could not init font path element /usr/share/fonts/X11/cyrillic,
|
|
||||||
removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/100dpi/:unscaled, removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/75dpi/:unscaled, removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/Type1, removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/100dpi, removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/75dpi, removing from list!
|
|
||||||
sh: /usr/bin/xkbcomp: not found
|
|
||||||
(EE) Error compiling keymap (server-42)
|
|
||||||
(EE) XKB: Couldn't compile keymap
|
|
||||||
[config/dbus] couldn't take over org.x.config:
|
|
||||||
org.freedesktop.DBus.Error.AccessDenied
|
|
||||||
(Connection ":1.74" is not allowed to
|
|
||||||
own the service "org.x.config.display99"
|
|
||||||
due to security policies in the configuration file)
|
|
||||||
|
|
||||||
Installing the following packages would resolve the above warning messages. Your
|
|
||||||
missing packages may be different depending on the packages you have installed.
|
|
||||||
sudo apt-get install x11-xkb-utils
|
|
||||||
sudo apt-get install xfonts-100dpi xfonts-75dpi
|
|
||||||
sudo apt-get install xfonts-scalable xfonts-cyrillic
|
|
||||||
sudo apt-get install xserver-xorg-core
|
|
||||||
|
|
||||||
Once you have resolved these dependencies, you should see:
|
|
||||||
[dix] Could not init font path element /usr/share/fonts/X11/misc,
|
|
||||||
removing from list!
|
|
||||||
[dix] Could not init font path element /usr/share/fonts/X11/cyrillic,
|
|
||||||
removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/100dpi/:unscaled, removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/75dpi/:unscaled, removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/Type1, removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/100dpi, removing from list!
|
|
||||||
[dix] Could not init font path element
|
|
||||||
/usr/share/fonts/X11/75dpi, removing from list!
|
|
||||||
|
|
||||||
### Run with Xvfb
|
|
||||||
|
|
||||||
#### ...as a Rake task
|
|
||||||
|
|
||||||
xvfb-run rake jasmine:headless
|
|
||||||
# ...or...
|
|
||||||
xvfb-run jasmine-headless-webkit -c
|
|
||||||
|
|
||||||
Reference: [MARTIN DALE LYNESS](http://blog.martin-lyness.com/archives/installing-xvfb-on-ubuntu-9-10-karmic-koala)
|
|
||||||
|
|
||||||
#### ...seamlessly
|
|
||||||
|
|
||||||
First run Xvfb in the background:
|
|
||||||
|
|
||||||
Xvfb :0 -screen 0 1024x768x24 > /dev/null 2>&1 &
|
|
||||||
|
|
||||||
Then, set your `DISPLAY` to point at the Xvfb instance. Putting all this in your `.bash_profile` or equivalent startup
|
|
||||||
script makes this a lot easier:
|
|
||||||
|
|
||||||
xdpyinfo -display :0 &>/dev/null && export DISPLAY=:0
|
|
||||||
|
|
||||||
See [Paul Goscicki's post](http://paulgoscicki.com/archives/2011/09/run-guard-jasmine-headless-webkit-without-x-server/) for
|
|
||||||
more details on the setup. Thanks, Paul!
|
|
||||||
|
|
||||||
## RubyMine
|
|
||||||
|
|
||||||
RubyMine may throw an error when running rake spec, you will need to provide a
|
|
||||||
JavaScript runtime environment.
|
|
||||||
|
|
||||||
rake aborted!
|
|
||||||
Could not find a JavaScript runtime.
|
|
||||||
See https://github.com/sstephenson/execjs
|
|
||||||
for a list of available runtimes.
|
|
||||||
|
|
||||||
To resolve this problem, install and use the `therubyracer` gem, which is the embed V8 JavaScript interpreter into Ruby.
|
|
||||||
Additionally, you can set the `EXECJS_RUNTIME` environment variable to a [valid ExecJS runtime name](https://github.com/sstephenson/execjs/blob/master/lib/execjs/runtimes.rb#L55).
|
|
||||||
|
|
||||||
export EXECJS_RUNTIME=Node
|
|
||||||
|
|
||||||
## I have a problem or helpful suggestion, good sir.
|
|
||||||
|
|
||||||
Here's what you can do:
|
|
||||||
|
|
||||||
* Leave a ticket on [the Issues tracker](https://github.com/johnbintz/jasmine-headless-webkit/issues).
|
|
||||||
* [Fork'n'fix the code](https://github.com/johnbintz/jasmine-headless-webkit). Feel free to add a bunch of tests, too. I cowboyed this project when starting it, and I'm slowly getting back to being a good boy.
|
|
||||||
* Ping me on [Twitter](http://twitter.com/johnbintz) or on [GitHub](https://github.com/johnbintz).
|
|
||||||
|
|
||||||
## Credits & License
|
|
||||||
|
|
||||||
* Copyright (c) 2011 John Bintz
|
|
||||||
* Original Qt WebKit runner Copyright (c) 2010 Sencha Inc.
|
|
||||||
* Jasmine JavaScript library Copyright (c) 2008-2011 Pivotal Labs
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
30
jasmine-headless-webkit.gemspec
Normal file
30
jasmine-headless-webkit.gemspec
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
$:.push File.expand_path("../lib", __FILE__)
|
||||||
|
require "jasmine/headless/version"
|
||||||
|
|
||||||
|
Gem::Specification.new do |s|
|
||||||
|
s.name = "jasmine-headless-webkit"
|
||||||
|
s.version = Jasmine::Headless::VERSION
|
||||||
|
s.platform = Gem::Platform::RUBY
|
||||||
|
s.authors = ["John Bintz", "Sencha Inc.", "Pivotal Labs"]
|
||||||
|
s.email = ["john@coswellproductions.com"]
|
||||||
|
s.homepage = ""
|
||||||
|
s.summary = %q{Run Jasmine specs headlessly in a WebKit browser}
|
||||||
|
s.description = %q{Run Jasmine specs headlessly}
|
||||||
|
|
||||||
|
s.rubyforge_project = "jasmine-headless-webkit"
|
||||||
|
|
||||||
|
s.extensions = `git ls-files -- ext/**/extconf.rb`.split("\n")
|
||||||
|
s.files = `git ls-files`.split("\n") + Dir['jasmine/lib/*']
|
||||||
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
||||||
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||||
|
s.require_paths = ["lib"]
|
||||||
|
|
||||||
|
s.add_runtime_dependency 'jasmine-core'
|
||||||
|
s.add_runtime_dependency 'coffee-script'
|
||||||
|
s.add_runtime_dependency 'rainbow'
|
||||||
|
s.add_runtime_dependency 'multi_json', '>= 1.2.0'
|
||||||
|
s.add_runtime_dependency 'sprockets'
|
||||||
|
s.add_runtime_dependency 'sprockets-vendor_gems'
|
||||||
|
end
|
||||||
|
|
1
lib/autotest/discover.rb
Normal file
1
lib/autotest/discover.rb
Normal file
@ -0,0 +1 @@
|
|||||||
|
Autotest.add_discovery { 'jasmine' if File.file?('./.jasmine-headless-webkit') }
|
7
lib/autotest/jasmine.rb
Normal file
7
lib/autotest/jasmine.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
require 'autotest'
|
||||||
|
require 'autotest/jasmine_mixin'
|
||||||
|
|
||||||
|
class Autotest::Jasmine < Autotest
|
||||||
|
include JasmineMixin
|
||||||
|
end
|
||||||
|
|
111
lib/autotest/jasmine_mixin.rb
Normal file
111
lib/autotest/jasmine_mixin.rb
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
module JasmineMixin
|
||||||
|
JASMINE_PROGRAM = File.expand_path('../../../bin/jasmine-headless-webkit', __FILE__)
|
||||||
|
|
||||||
|
JAVASCRIPT_EXTENSIONS = %w{js coffee}
|
||||||
|
|
||||||
|
def self.included(klass)
|
||||||
|
klass::ALL_HOOKS << [ :run_jasmine, :ran_jasmine ]
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :is_jasmine_running, :jasmine_to_run, :jasmine_ran_once
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super()
|
||||||
|
setup_jasmine_project_mappings
|
||||||
|
jasmine_ran_once = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_to_green
|
||||||
|
begin
|
||||||
|
reset_jasmine(:no)
|
||||||
|
super if find_files_to_test
|
||||||
|
|
||||||
|
reset_jasmine(:yes)
|
||||||
|
self.last_mtime = Time.at(0) if !options[:no_full_after_start] && !jasmine_ran_once
|
||||||
|
run_jasmine if find_files_to_test
|
||||||
|
|
||||||
|
self.is_jasmine_running = :all
|
||||||
|
wait_for_changes unless all_jasmine_good
|
||||||
|
end until all_jasmine_good
|
||||||
|
|
||||||
|
reset_jasmine(:all)
|
||||||
|
end
|
||||||
|
|
||||||
|
def rerun_all_tests
|
||||||
|
reset_jasmine(:no)
|
||||||
|
super
|
||||||
|
|
||||||
|
reset_jasmine(:yes)
|
||||||
|
run_jasmine
|
||||||
|
|
||||||
|
reset_jasmine(:all)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_jasmine(method)
|
||||||
|
self.files_to_test = new_hash_of_arrays
|
||||||
|
self.is_jasmine_running = method
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_jasmine
|
||||||
|
hook :run_jasmine
|
||||||
|
|
||||||
|
self.jasmine_to_run = :all
|
||||||
|
|
||||||
|
if mtime = find_files_to_test
|
||||||
|
self.last_mtime = mtime
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
system make_jasmine_cmd
|
||||||
|
|
||||||
|
self.jasmine_to_run = ($?.exitstatus == 0) ? :none : :all
|
||||||
|
end
|
||||||
|
|
||||||
|
hook :ran_jasmine
|
||||||
|
|
||||||
|
jasmine_ran_once = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def all_jasmine_good
|
||||||
|
self.jasmine_to_run == :none
|
||||||
|
self.files_to_test = new_hash_of_arrays
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_files
|
||||||
|
Hash[super.find_all { |file, mtime|
|
||||||
|
is_js = (file[%r{\.(#{JAVASCRIPT_EXTENSIONS.join('|')})$}] != nil)
|
||||||
|
|
||||||
|
case self.is_jasmine_running
|
||||||
|
when :all
|
||||||
|
true
|
||||||
|
when :no
|
||||||
|
!is_js
|
||||||
|
when :yes
|
||||||
|
is_js
|
||||||
|
end
|
||||||
|
}]
|
||||||
|
end
|
||||||
|
|
||||||
|
def make_jasmine_cmd
|
||||||
|
self.files_to_test.empty? ? '' :
|
||||||
|
%{#{JASMINE_PROGRAM} #{self.files_to_test.keys.collect { |key| %{'#{key}'} }.join(' ')}}.tap { |o| p o }
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_jasmine_project_mappings
|
||||||
|
add_mapping(%r{spec/javascripts/.*_spec\.(js|coffee)}) { |filename, _|
|
||||||
|
filename
|
||||||
|
}
|
||||||
|
|
||||||
|
add_mapping(%r{public/javascripts/(.*)\.js}) { |_, m|
|
||||||
|
files_matching(%r{spec/javascripts/#{m[1]}_spec\..*$})
|
||||||
|
}
|
||||||
|
|
||||||
|
add_mapping(%r{app/coffeescripts/(.*)\.coffee}) { |_, m|
|
||||||
|
files_matching(%r{spec/javascripts/#{m[1]}_spec\..*$})
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_javascript_extensions(*extensions)
|
||||||
|
self.class::JAVASCRIPT_EXTENSIONS << extensions
|
||||||
|
end
|
||||||
|
end
|
7
lib/autotest/jasmine_rspec2.rb
Normal file
7
lib/autotest/jasmine_rspec2.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
require 'autotest/rspec2'
|
||||||
|
require 'autotest/jasmine_mixin'
|
||||||
|
|
||||||
|
class Autotest::JasmineRspec2 < Autotest::Rspec2
|
||||||
|
include JasmineMixin
|
||||||
|
end
|
||||||
|
|
3
lib/jasmine-headless-webkit.rb
Normal file
3
lib/jasmine-headless-webkit.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
require 'jasmine/headless'
|
||||||
|
require 'jasmine/headless/railtie' if defined?(Rails) && Rails::VERSION::MAJOR >= 3
|
||||||
|
|
61
lib/jasmine/headless.rb
Normal file
61
lib/jasmine/headless.rb
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
require 'pathname'
|
||||||
|
|
||||||
|
module Jasmine
|
||||||
|
module Headless
|
||||||
|
|
||||||
|
EXCLUDED_FORMATS = %w{less sass scss erb str}
|
||||||
|
|
||||||
|
autoload :CommandLine, 'jasmine/headless/command_line'
|
||||||
|
|
||||||
|
autoload :CoffeeScriptCache, 'jasmine/headless/coffee_script_cache'
|
||||||
|
autoload :SpecFileAnalyzer, 'jasmine/headless/spec_file_analyzer'
|
||||||
|
autoload :CacheableAction, 'jasmine/headless/cacheable_action'
|
||||||
|
autoload :VERSION, 'jasmine/headless/version'
|
||||||
|
autoload :Runner, 'jasmine/headless/runner'
|
||||||
|
autoload :Options, 'jasmine/headless/options'
|
||||||
|
autoload :Task, 'jasmine/headless/task'
|
||||||
|
|
||||||
|
autoload :FilesList, 'jasmine/headless/files_list'
|
||||||
|
autoload :UniqueAssetList, 'jasmine/headless/unique_asset_list'
|
||||||
|
|
||||||
|
autoload :TemplateWriter, 'jasmine/headless/template_writer'
|
||||||
|
|
||||||
|
autoload :FileChecker, 'jasmine/headless/file_checker'
|
||||||
|
|
||||||
|
autoload :CoffeeTemplate, 'jasmine/headless/coffee_template'
|
||||||
|
autoload :JSTemplate, 'jasmine/headless/js_template'
|
||||||
|
autoload :JSTTemplate, 'jasmine/headless/jst_template'
|
||||||
|
autoload :CSSTemplate, 'jasmine/headless/css_template'
|
||||||
|
autoload :NilTemplate, 'jasmine/headless/nil_template'
|
||||||
|
|
||||||
|
autoload :Report, 'jasmine/headless/report'
|
||||||
|
autoload :ReportMessage, 'jasmine/headless/report_message'
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def root
|
||||||
|
@root ||= Pathname(File.expand_path('../../..', __FILE__))
|
||||||
|
end
|
||||||
|
|
||||||
|
def warn(message)
|
||||||
|
output.puts message if show_warnings?
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_warnings=(show)
|
||||||
|
@show_warnings = show
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_warnings?
|
||||||
|
@show_warnings = true if @show_warnings.nil?
|
||||||
|
|
||||||
|
@show_warnings
|
||||||
|
end
|
||||||
|
|
||||||
|
def output
|
||||||
|
$stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'jasmine/headless/errors'
|
||||||
|
|
85
lib/jasmine/headless/cacheable_action.rb
Normal file
85
lib/jasmine/headless/cacheable_action.rb
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
module Jasmine::Headless
|
||||||
|
class CacheableAction
|
||||||
|
class << self
|
||||||
|
def enabled=(bool)
|
||||||
|
@enabled = bool
|
||||||
|
end
|
||||||
|
|
||||||
|
def enabled?
|
||||||
|
@enabled = true if @enabled == nil
|
||||||
|
@enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_type
|
||||||
|
raise ArgumentError.new("No cache type defined for #{self.name}") if @cache_type == nil
|
||||||
|
@cache_type
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_type=(type)
|
||||||
|
@cache_type = type
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_dir=(dir)
|
||||||
|
@cache_dir = dir
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_dir
|
||||||
|
@cache_dir ||= '.jhw-cache'
|
||||||
|
end
|
||||||
|
|
||||||
|
def for(file)
|
||||||
|
new(file).handle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :file
|
||||||
|
|
||||||
|
def initialize(file)
|
||||||
|
@file = file
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle
|
||||||
|
if CacheableAction.enabled?
|
||||||
|
if fresh?
|
||||||
|
unserialize(File.read(cache_file))
|
||||||
|
else
|
||||||
|
result = action
|
||||||
|
FileUtils.mkdir_p File.split(cache_file).first
|
||||||
|
File.open(cache_file, 'wb') { |fh| fh.print serialize(result) }
|
||||||
|
result
|
||||||
|
end
|
||||||
|
else
|
||||||
|
action
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_file
|
||||||
|
@cache_file ||= File.expand_path(relative_cache_file) + '.js'
|
||||||
|
end
|
||||||
|
|
||||||
|
def relative_cache_file
|
||||||
|
File.join(self.class.cache_dir, self.class.cache_type, file.gsub(Dir.pwd + '/', ''))
|
||||||
|
end
|
||||||
|
|
||||||
|
def fresh?
|
||||||
|
cached? && (File.mtime(file) < File.mtime(cache_file))
|
||||||
|
end
|
||||||
|
|
||||||
|
def cached?
|
||||||
|
File.exist?(cache_file)
|
||||||
|
end
|
||||||
|
|
||||||
|
def action
|
||||||
|
raise StandardError.new("Override action")
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize(data)
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
def unserialize(data)
|
||||||
|
data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
20
lib/jasmine/headless/coffee_script_cache.rb
Normal file
20
lib/jasmine/headless/coffee_script_cache.rb
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
require 'coffee_script'
|
||||||
|
require 'digest/sha1'
|
||||||
|
require 'fileutils'
|
||||||
|
|
||||||
|
module Jasmine
|
||||||
|
module Headless
|
||||||
|
class CoffeeScriptCache < CacheableAction
|
||||||
|
class << self
|
||||||
|
def cache_type
|
||||||
|
"coffee_script"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def action
|
||||||
|
CoffeeScript.compile(File.read(file))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
36
lib/jasmine/headless/coffee_template.rb
Normal file
36
lib/jasmine/headless/coffee_template.rb
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
require 'tilt/template'
|
||||||
|
require 'rainbow'
|
||||||
|
|
||||||
|
module Jasmine::Headless
|
||||||
|
class CoffeeTemplate < Tilt::Template
|
||||||
|
include Jasmine::Headless::FileChecker
|
||||||
|
|
||||||
|
self.default_mime_type = 'application/javascript'
|
||||||
|
|
||||||
|
def prepare ; end
|
||||||
|
|
||||||
|
def evaluate(scope, locals, &block)
|
||||||
|
if bad_format?(file)
|
||||||
|
alert_bad_format(file)
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
cache = Jasmine::Headless::CoffeeScriptCache.new(file)
|
||||||
|
source = cache.handle
|
||||||
|
if cache.cached?
|
||||||
|
%{<script type="text/javascript" src="#{cache.cache_file}"></script>
|
||||||
|
<script type="text/javascript">window.CSTF['#{File.split(cache.cache_file).last}'] = '#{file}';</script>}
|
||||||
|
else
|
||||||
|
%{<script type="text/javascript">#{source}</script>}
|
||||||
|
end
|
||||||
|
rescue CoffeeScript::CompilationError => ne
|
||||||
|
puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), file.color(:yellow), "#{ne.message}".color(:white) ]
|
||||||
|
raise ne
|
||||||
|
rescue StandardError => e
|
||||||
|
puts "[%s] Error in compiling file: %s" % [ 'coffeescript'.color(:red), file.color(:yellow) ]
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
31
lib/jasmine/headless/command_line.rb
Normal file
31
lib/jasmine/headless/command_line.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module Jasmine::Headless
|
||||||
|
class CommandLine
|
||||||
|
class << self
|
||||||
|
def run!
|
||||||
|
require 'coffee-script'
|
||||||
|
require 'rainbow'
|
||||||
|
|
||||||
|
begin
|
||||||
|
options = Options.from_command_line
|
||||||
|
runner = Runner.new(options)
|
||||||
|
|
||||||
|
if options[:do_list]
|
||||||
|
FilesList.reset!
|
||||||
|
|
||||||
|
files_list = FilesList.new(:config => runner.jasmine_config)
|
||||||
|
files_list.files.each { |file| puts file }
|
||||||
|
else
|
||||||
|
exit runner.run
|
||||||
|
end
|
||||||
|
rescue CoffeeScript::CompilationError
|
||||||
|
exit 1
|
||||||
|
rescue StandardError => e
|
||||||
|
$stderr.puts "[%s] %s (%s)" % [ "jasmine-headless-webkit".color(:red), e.message.color(:white), e.class.name.color(:yellow) ]
|
||||||
|
$stderr.puts e.backtrace.collect { |line| " #{line}" }.join("\n")
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
19
lib/jasmine/headless/css_template.rb
Normal file
19
lib/jasmine/headless/css_template.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require 'tilt/template'
|
||||||
|
|
||||||
|
module Jasmine::Headless
|
||||||
|
class CSSTemplate < Tilt::Template
|
||||||
|
include Jasmine::Headless::FileChecker
|
||||||
|
self.default_mime_type = 'text/css'
|
||||||
|
|
||||||
|
def prepare ; end
|
||||||
|
|
||||||
|
def evaluate(scope, locals, &block)
|
||||||
|
if bad_format?(file)
|
||||||
|
alert_bad_format(file)
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
file ? %{<link rel="stylesheet" href="#{file}" type="text/css" />} : data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
16
lib/jasmine/headless/errors.rb
Normal file
16
lib/jasmine/headless/errors.rb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module Jasmine
|
||||||
|
module Headless
|
||||||
|
class NoRunnerError < StandardError
|
||||||
|
def message
|
||||||
|
"The jasmine-headless-webkit specrunner (jasmine-webkit-specrunner) could not be found! Try reinstalling the gem."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestFailure < StandardError; end
|
||||||
|
class ConsoleLogUsage < StandardError ; end
|
||||||
|
|
||||||
|
class JasmineConfigNotFound < Errno::ENOENT ; end
|
||||||
|
class InvalidReport < StandardError ; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
25
lib/jasmine/headless/file_checker.rb
Normal file
25
lib/jasmine/headless/file_checker.rb
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
module Jasmine::Headless::FileChecker
|
||||||
|
def excluded_formats
|
||||||
|
::Jasmine::Headless::EXCLUDED_FORMATS
|
||||||
|
end
|
||||||
|
|
||||||
|
def bad_format?(file)
|
||||||
|
return if file.nil?
|
||||||
|
|
||||||
|
excluded_formats.any? do |format|
|
||||||
|
file[%r{\.#{format}(\.|$)}]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def alert_bad_format(file)
|
||||||
|
Jasmine::Headless.warn("[%s] %s: %s" % [ 'Skipping File'.color(:red), file.color(:yellow), "unsupported format".color(:white) ])
|
||||||
|
end
|
||||||
|
|
||||||
|
def alert_if_bad_format?(file)
|
||||||
|
if result = bad_format?(file)
|
||||||
|
alert_bad_format(file)
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
332
lib/jasmine/headless/files_list.rb
Normal file
332
lib/jasmine/headless/files_list.rb
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
require 'jasmine-core'
|
||||||
|
require 'time'
|
||||||
|
require 'multi_json'
|
||||||
|
require 'set'
|
||||||
|
require 'sprockets'
|
||||||
|
require 'sprockets/engines'
|
||||||
|
require 'sprockets-vendor_gems'
|
||||||
|
|
||||||
|
module Jasmine::Headless
|
||||||
|
class FilesList
|
||||||
|
include FileChecker
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def asset_paths
|
||||||
|
@asset_paths ||= Sprockets.find_gem_vendor_paths(:for => 'javascripts')
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset!
|
||||||
|
@asset_paths = nil
|
||||||
|
@registered_engines = {}
|
||||||
|
|
||||||
|
# register haml-sprockets and handlebars_assets if it's available...
|
||||||
|
%w{haml-sprockets handlebars_assets}.each do |library|
|
||||||
|
begin
|
||||||
|
require library
|
||||||
|
rescue LoadError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ENV['JHW_ENV']
|
||||||
|
begin
|
||||||
|
require 'bundler'
|
||||||
|
|
||||||
|
Bundler.require(ENV['JHW_ENV'].to_sym)
|
||||||
|
rescue LoadError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@sprockets_environment = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def registered_engines
|
||||||
|
@registered_engines ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_engine(file_extension, template_class)
|
||||||
|
registered_engines[file_extension] = template_class
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_engines!
|
||||||
|
registered_engines.each do |file_extension, template_class|
|
||||||
|
Sprockets.register_engine file_extension, template_class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_files
|
||||||
|
%w{jasmine.js jasmine-html jasmine.css jasmine-extensions
|
||||||
|
intense headless_reporter_result jasmine.HeadlessReporter
|
||||||
|
jasmine.HeadlessReporter.ConsoleBase
|
||||||
|
jsDump beautify-html}
|
||||||
|
end
|
||||||
|
|
||||||
|
def extension_filter
|
||||||
|
extensions = (%w{.js .css} + Sprockets.engine_extensions)
|
||||||
|
|
||||||
|
%r{(#{extensions.join('|')})$}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
PLEASE_WAIT_IM_WORKING_TIME = 2
|
||||||
|
|
||||||
|
attr_reader :options, :required_files, :potential_files_to_filter
|
||||||
|
|
||||||
|
def initialize(options = {})
|
||||||
|
@options = options
|
||||||
|
|
||||||
|
Kernel.srand(options[:seed]) if options[:seed]
|
||||||
|
|
||||||
|
@required_files = UniqueAssetList.new
|
||||||
|
@potential_files_to_filter = []
|
||||||
|
|
||||||
|
register_engines!
|
||||||
|
|
||||||
|
load_initial_assets
|
||||||
|
|
||||||
|
use_config if config?
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_engines!
|
||||||
|
begin
|
||||||
|
require spec_helper
|
||||||
|
rescue LoadError
|
||||||
|
end
|
||||||
|
self.class.register_engines!
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_initial_assets
|
||||||
|
self.class.default_files.each do |file|
|
||||||
|
begin
|
||||||
|
add_path(file)
|
||||||
|
rescue InvalidUniqueAsset => e
|
||||||
|
raise StandardError.new("Not an asset: #{file}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
(options[:reporters] || []).each do |reporter, identifier, file|
|
||||||
|
add_path("jasmine.HeadlessReporter.#{reporter}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def files
|
||||||
|
required_files.flatten.collect { |asset| asset.pathname.to_s }.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def spec_files
|
||||||
|
filter_for_requested_specs(
|
||||||
|
files.find_all { |file| spec_dir.any? { |dir| file[dir] } }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filtered_files
|
||||||
|
filter_for_requested_specs(files)
|
||||||
|
end
|
||||||
|
|
||||||
|
def search_paths
|
||||||
|
return @search_paths if @search_paths
|
||||||
|
|
||||||
|
@search_paths = [ Jasmine::Core.path, Jasmine::Headless.root.join('vendor/assets/javascripts').to_s ]
|
||||||
|
@search_paths += self.class.asset_paths
|
||||||
|
@search_paths += src_dir.collect { |dir| File.expand_path(dir) }
|
||||||
|
@search_paths += asset_paths.collect { |dir| File.expand_path(dir) }
|
||||||
|
@search_paths += spec_dir.collect { |dir| File.expand_path(dir) }
|
||||||
|
|
||||||
|
@search_paths.uniq!
|
||||||
|
@search_paths
|
||||||
|
end
|
||||||
|
|
||||||
|
def sprockets_environment
|
||||||
|
return @sprockets_environment if @sprockets_environment
|
||||||
|
|
||||||
|
@sprockets_environment = Sprockets::Environment.new
|
||||||
|
search_paths.each { |path| @sprockets_environment.append_path(path) }
|
||||||
|
|
||||||
|
@sprockets_environment.unregister_postprocessor('application/javascript', Sprockets::SafetyColons)
|
||||||
|
|
||||||
|
# ...and unregister ones we don't want/need
|
||||||
|
@sprockets_environment.instance_eval do
|
||||||
|
EXCLUDED_FORMATS.each do |extension|
|
||||||
|
register_engine ".#{extension}", Jasmine::Headless::NilTemplate
|
||||||
|
end
|
||||||
|
|
||||||
|
register_engine '.coffee', Jasmine::Headless::CoffeeTemplate
|
||||||
|
register_engine '.js', Jasmine::Headless::JSTemplate
|
||||||
|
register_engine '.css', Jasmine::Headless::CSSTemplate
|
||||||
|
register_engine '.jst', Jasmine::Headless::JSTTemplate
|
||||||
|
end
|
||||||
|
|
||||||
|
@sprockets_environment
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_spec_outside_scope?
|
||||||
|
if is_outside_scope = !spec_filter.empty?
|
||||||
|
is_outside_scope = spec_dir.any? do |dir|
|
||||||
|
spec_file_searches.any? do |search|
|
||||||
|
!spec_files.any? do |file|
|
||||||
|
target = File.join(dir, search)
|
||||||
|
File.fnmatch?(target, file) || File.fnmatch?(target.gsub(%{^**/}, ''), file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
is_outside_scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def filtered?
|
||||||
|
files != filtered_files
|
||||||
|
end
|
||||||
|
|
||||||
|
def files_to_html
|
||||||
|
to_html(files)
|
||||||
|
end
|
||||||
|
|
||||||
|
def filtered_files_to_html
|
||||||
|
to_html(filtered_files)
|
||||||
|
end
|
||||||
|
|
||||||
|
def spec_file_line_numbers
|
||||||
|
@spec_file_line_numbers ||= Hash[spec_files.collect { |file|
|
||||||
|
if File.exist?(file)
|
||||||
|
if !(lines = Jasmine::Headless::SpecFileAnalyzer.for(file)).empty?
|
||||||
|
[ file, lines ]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
}.compact]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def to_html(files)
|
||||||
|
alert_time = Time.now + PLEASE_WAIT_IM_WORKING_TIME
|
||||||
|
|
||||||
|
files.collect do |file|
|
||||||
|
if alert_time && alert_time < Time.now
|
||||||
|
puts "Rebuilding cache, please wait..."
|
||||||
|
alert_time = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
sprockets_environment.find_asset(file, :bundle => false).body
|
||||||
|
end.compact.reject(&:empty?)
|
||||||
|
end
|
||||||
|
|
||||||
|
def spec_filter
|
||||||
|
@spec_filter ||= (@options[:only] && @options[:only].collect { |path| expanded_dir(path) }.flatten) || []
|
||||||
|
end
|
||||||
|
|
||||||
|
SEARCH_ROOTS = {
|
||||||
|
'src_files' => 'src_dir',
|
||||||
|
'stylesheets' => 'src_dir',
|
||||||
|
'helpers' => 'spec_dir',
|
||||||
|
'spec_files' => 'spec_dir'
|
||||||
|
}
|
||||||
|
|
||||||
|
def use_config
|
||||||
|
@config = @options[:config].dup
|
||||||
|
@searches = {}
|
||||||
|
@potential_files_to_filter = []
|
||||||
|
|
||||||
|
%w{src_files stylesheets helpers spec_files}.each do |type|
|
||||||
|
if data = @config[type]
|
||||||
|
add_files(@searches[type] = data.flatten, type, send(SEARCH_ROOTS[type]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_files(patterns, type, dirs)
|
||||||
|
patterns.each do |pattern|
|
||||||
|
dirs.collect { |dir| expanded_dir(File.join(dir, pattern)) }.each do |files|
|
||||||
|
files.sort! { |a, b| Kernel.rand(3) - 1 } if type == 'spec_files'
|
||||||
|
|
||||||
|
files.each do |path|
|
||||||
|
add_path(path, type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if type == 'spec_files'
|
||||||
|
spec_filter.each { |path| add_path(path, type) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def config?
|
||||||
|
@options[:config]
|
||||||
|
end
|
||||||
|
|
||||||
|
def expanded_dir(path)
|
||||||
|
file_list = Dir.glob(path).sort
|
||||||
|
file_list.find_all { |file|
|
||||||
|
file[extension_filter] && !alert_if_bad_format?(file)
|
||||||
|
}.collect {
|
||||||
|
|file| File.expand_path(file)
|
||||||
|
}.find_all {
|
||||||
|
|path| File.file?(path)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def extension_filter
|
||||||
|
self.class.extension_filter
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_path(path, type = nil)
|
||||||
|
asset = sprockets_environment.find_asset(path)
|
||||||
|
|
||||||
|
@required_files << asset
|
||||||
|
|
||||||
|
if type == 'spec_files'
|
||||||
|
@potential_files_to_filter << path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def src_dir
|
||||||
|
@src_dir ||= config_dir_or_pwd('src_dir') + asset_paths
|
||||||
|
end
|
||||||
|
|
||||||
|
def spec_dir
|
||||||
|
@spec_dir ||= config_dir_or_pwd('spec_dir')
|
||||||
|
end
|
||||||
|
|
||||||
|
def asset_paths
|
||||||
|
@asset_paths ||= config_dir('asset_paths')
|
||||||
|
end
|
||||||
|
|
||||||
|
def spec_file_searches
|
||||||
|
@searches['spec_files']
|
||||||
|
end
|
||||||
|
|
||||||
|
def config_dir_or_pwd(dir)
|
||||||
|
if (found = config_dir(dir)).empty?
|
||||||
|
found = [ Dir.pwd ]
|
||||||
|
end
|
||||||
|
|
||||||
|
found
|
||||||
|
end
|
||||||
|
|
||||||
|
def config_dir(dir)
|
||||||
|
[ @options[:config] && @options[:config][dir] ].flatten.compact.collect { |dir| File.expand_path(dir) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_for_requested_specs(files)
|
||||||
|
files.find_all do |file|
|
||||||
|
if potential_files_to_filter.include?(file)
|
||||||
|
spec_filter.empty? || spec_filter.any? { |pattern| File.fnmatch?(pattern, file) }
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def spec_helper
|
||||||
|
File.join(spec_dir, "helpers", "spec_helper")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Jasmine::Headless
|
||||||
|
extend self
|
||||||
|
|
||||||
|
def register_engine(file_extension, template_class)
|
||||||
|
Jasmine::Headless::FilesList.register_engine(file_extension, template_class)
|
||||||
|
end
|
||||||
|
end
|
23
lib/jasmine/headless/js_template.rb
Normal file
23
lib/jasmine/headless/js_template.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
require 'tilt/template'
|
||||||
|
|
||||||
|
module Jasmine::Headless
|
||||||
|
class JSTemplate < Tilt::Template
|
||||||
|
include Jasmine::Headless::FileChecker
|
||||||
|
self.default_mime_type = 'application/javascript'
|
||||||
|
|
||||||
|
def prepare ; end
|
||||||
|
|
||||||
|
def evaluate(scope, locals, &block)
|
||||||
|
if bad_format?(file)
|
||||||
|
alert_bad_format(file)
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
if data[%r{^<script type="text/javascript"}]
|
||||||
|
data
|
||||||
|
else
|
||||||
|
file ? %{<script type="text/javascript" src="#{file}"></script>} : data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
15
lib/jasmine/headless/jst_template.rb
Normal file
15
lib/jasmine/headless/jst_template.rb
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
require 'sprockets/jst_processor'
|
||||||
|
|
||||||
|
module Jasmine::Headless
|
||||||
|
class JSTTemplate < Sprockets::JstProcessor
|
||||||
|
include Jasmine::Headless::FileChecker
|
||||||
|
def evaluate(*args)
|
||||||
|
if bad_format?(file)
|
||||||
|
alert_bad_format(file)
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
%{<script type="text/javascript">#{super}</script>}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
14
lib/jasmine/headless/nil_template.rb
Normal file
14
lib/jasmine/headless/nil_template.rb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
require 'tilt/template'
|
||||||
|
require 'rainbow'
|
||||||
|
|
||||||
|
module Jasmine::Headless
|
||||||
|
class NilTemplate < Tilt::Template
|
||||||
|
|
||||||
|
def prepare ; end
|
||||||
|
|
||||||
|
def evaluate(scope, locals, &block)
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
206
lib/jasmine/headless/options.rb
Normal file
206
lib/jasmine/headless/options.rb
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
require 'forwardable'
|
||||||
|
require 'getoptlong'
|
||||||
|
|
||||||
|
module Jasmine
|
||||||
|
module Headless
|
||||||
|
class Options
|
||||||
|
extend Forwardable
|
||||||
|
|
||||||
|
def_delegators :@options, :[], :[]=
|
||||||
|
|
||||||
|
DEFAULT_OPTIONS = {
|
||||||
|
:colors => false,
|
||||||
|
:remove_html_file => true,
|
||||||
|
:runner_output_filename => false,
|
||||||
|
:jasmine_config => 'spec/javascripts/support/jasmine.yml',
|
||||||
|
:do_list => false,
|
||||||
|
:full_run => true,
|
||||||
|
:enable_cache => true,
|
||||||
|
:files => [],
|
||||||
|
:reporters => [ [ 'Console' ] ],
|
||||||
|
:quiet => false,
|
||||||
|
:use_server => false,
|
||||||
|
:server_port => nil
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFAULTS_FILE = File.join(Dir.pwd, '.jasmine-headless-webkit')
|
||||||
|
GLOBAL_DEFAULTS_FILE = File.expand_path('~/.jasmine-headless-webkit')
|
||||||
|
|
||||||
|
REPORT_DEPRECATED_MESSAGE = "--report is deprecated. Use --format HeadlessFileReporter --out <filename>"
|
||||||
|
|
||||||
|
def self.from_command_line
|
||||||
|
options = new
|
||||||
|
options.process_command_line_args
|
||||||
|
options[:files] = ARGV
|
||||||
|
options
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(opts = {})
|
||||||
|
@options = DEFAULT_OPTIONS.dup
|
||||||
|
srand
|
||||||
|
@options[:seed] = rand(10000)
|
||||||
|
read_defaults_files
|
||||||
|
|
||||||
|
opts.each { |k, v| @options[k] = v if v }
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_option(*args)
|
||||||
|
opt, arg = args.flatten[0..1]
|
||||||
|
|
||||||
|
case opt
|
||||||
|
when '--colors', '-c'
|
||||||
|
@options[:colors] = true
|
||||||
|
when '--no-colors', '-nc'
|
||||||
|
@options[:colors] = false
|
||||||
|
when '--cache'
|
||||||
|
@options[:enable_cache] = true
|
||||||
|
when '--no-cache'
|
||||||
|
@options[:enable_cache] = false
|
||||||
|
when '--keep'
|
||||||
|
@options[:remove_html_file] = false
|
||||||
|
when '--report'
|
||||||
|
warn REPORT_DEPRECATED_MESSAGE
|
||||||
|
|
||||||
|
add_reporter('File', arg)
|
||||||
|
add_reporter('Console')
|
||||||
|
when '--runner-out'
|
||||||
|
@options[:runner_output_filename] = arg
|
||||||
|
when '--jasmine-config', '-j'
|
||||||
|
@options[:jasmine_config] = arg
|
||||||
|
when '--no-full-run'
|
||||||
|
@options[:full_run] = false
|
||||||
|
when '--list', '-l'
|
||||||
|
@options[:do_list] = true
|
||||||
|
when '--quiet', '-q'
|
||||||
|
@options[:quiet] = true
|
||||||
|
when '--seed'
|
||||||
|
@options[:seed] = arg.to_i
|
||||||
|
when '--format', '-f'
|
||||||
|
add_reporter(arg)
|
||||||
|
when '--use-server'
|
||||||
|
@options[:use_server] = true
|
||||||
|
when '--server-port'
|
||||||
|
@options[:server_port] = arg.to_i
|
||||||
|
when '--out'
|
||||||
|
add_reporter_file(arg)
|
||||||
|
when '-h', '--help'
|
||||||
|
print_help
|
||||||
|
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_defaults_files
|
||||||
|
[ GLOBAL_DEFAULTS_FILE, DEFAULTS_FILE ].each do |file|
|
||||||
|
if File.file?(file)
|
||||||
|
File.readlines(file).collect { |line| line.strip.split(' ', 2) }.each { |*args| process_option(*args) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_command_line_args
|
||||||
|
command_line_args = GetoptLong.new(
|
||||||
|
[ '--colors', '-c', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--no-colors', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--cache', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--no-cache', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--keep', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--runner-out', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
[ '--report', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
[ '--jasmine-config', '-j', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
[ '--no-full-run', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--list', '-l', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--seed', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
[ '--format', '-f', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
[ '--out', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
[ '--use-server', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '--server-port', GetoptLong::REQUIRED_ARGUMENT ],
|
||||||
|
[ '-h', '--help', GetoptLong::NO_ARGUMENT ],
|
||||||
|
[ '-q', '--quiet', GetoptLong::NO_ARGUMENT ]
|
||||||
|
)
|
||||||
|
|
||||||
|
command_line_args.each { |*args| process_option(*args) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def reporters
|
||||||
|
file_index = 0
|
||||||
|
|
||||||
|
@options[:reporters].collect do |reporter, file|
|
||||||
|
output = [ reporter ]
|
||||||
|
if file
|
||||||
|
output << "report:#{file_index}"
|
||||||
|
output << file
|
||||||
|
file_index += 1
|
||||||
|
else
|
||||||
|
output << "stdout"
|
||||||
|
end
|
||||||
|
|
||||||
|
output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def file_reporters
|
||||||
|
reporters.find_all { |reporter| reporter[1]["report:"] }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def add_reporter(name, file = nil)
|
||||||
|
if !@added_reporter
|
||||||
|
@options[:reporters] = []
|
||||||
|
@added_reporter = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if (parts = name.split(':')).length == 2
|
||||||
|
name, file = parts
|
||||||
|
end
|
||||||
|
|
||||||
|
@options[:reporters] << [ name ]
|
||||||
|
|
||||||
|
add_reporter_file(file) if file
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_reporter_file(file)
|
||||||
|
@options[:reporters].last << file
|
||||||
|
end
|
||||||
|
|
||||||
|
def print_help
|
||||||
|
options = [
|
||||||
|
[ '-c, --colors', 'Enable colors (default: disabled)' ],
|
||||||
|
[ '-nc, --no-colors', 'Disable colors' ],
|
||||||
|
[ '--cache', 'Enable cache (default: enabled)' ],
|
||||||
|
[ '--no-cache', 'Disable cache' ],
|
||||||
|
[ '--keep', 'Keep runner files on failure' ],
|
||||||
|
[ '--runner-out <filename>', 'Write runner to specified filename' ],
|
||||||
|
[ '-j, --jasmine-config <config file>', 'Jasmine Yaml config to use' ],
|
||||||
|
[ '--no-full-run', 'Do not perform a full spec run after a successful targeted spec run' ],
|
||||||
|
[ '--use-server', 'Load tests from an HTTP server instead of from filesystem' ],
|
||||||
|
[ '-l, --list', 'List files in the order they will be required' ],
|
||||||
|
[ '--seed <seed>', 'Random order seed for spec file ordering' ],
|
||||||
|
[ '-f, --format <reporter<:filename>>', 'Specify an output reporter and possibly output filename' ],
|
||||||
|
[ '--out <filename>', 'Specify output filename for last defined reporter' ],
|
||||||
|
[ '-q, --quiet', "Silence most non-test related warnings" ],
|
||||||
|
[ '-h, --help', "You're looking at it" ]
|
||||||
|
]
|
||||||
|
|
||||||
|
longest_length = options.collect(&:first).collect(&:length).max
|
||||||
|
|
||||||
|
puts <<-HELP
|
||||||
|
Usage: #{$0} [ options ] [ spec files ]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
#{options.collect { |option, description| " #{option.ljust(longest_length)} #{description}" }.join("\n")}
|
||||||
|
|
||||||
|
Available reporters:
|
||||||
|
Console Write out spec results to the console in a progress format (default)
|
||||||
|
Verbose Write out spec results to the console in a verbose format
|
||||||
|
File Write spec results in jasmine-headless-webkit ReportFile format
|
||||||
|
Tap Write spec results in TAP format
|
||||||
|
|
||||||
|
Add reporters to the jasmine.HeadlessReporter object to access them
|
||||||
|
(ex: jasmine.HeadlessReporter.Teamcity for the Teamcity reporter)
|
||||||
|
HELP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
12
lib/jasmine/headless/railtie.rb
Normal file
12
lib/jasmine/headless/railtie.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module Jasmine
|
||||||
|
module Headless
|
||||||
|
class Railtie < Rails::Railtie
|
||||||
|
rake_tasks do
|
||||||
|
Jasmine::Headless::Task.new do |t|
|
||||||
|
t.colors = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
81
lib/jasmine/headless/report.rb
Normal file
81
lib/jasmine/headless/report.rb
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
require 'forwardable'
|
||||||
|
|
||||||
|
module Jasmine::Headless
|
||||||
|
class Report
|
||||||
|
extend Forwardable
|
||||||
|
|
||||||
|
def_delegators :report, :length, :[]
|
||||||
|
def_delegators :last_total, :total, :failed, :time
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def load(file)
|
||||||
|
new(file).process
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :file, :report
|
||||||
|
|
||||||
|
def initialize(file)
|
||||||
|
@file = file
|
||||||
|
end
|
||||||
|
|
||||||
|
def process
|
||||||
|
last_message = nil
|
||||||
|
@report = File.readlines(file).collect do |line|
|
||||||
|
type, *parts = line.split('||', -1)
|
||||||
|
|
||||||
|
if !(report_klass = report_class_for(type))
|
||||||
|
if last_message.kind_of?(Jasmine::Headless::ReportMessage::Console)
|
||||||
|
last_message.message << "\n"
|
||||||
|
last_message.message << line.strip
|
||||||
|
end
|
||||||
|
else
|
||||||
|
parts.last.strip!
|
||||||
|
|
||||||
|
last_message = report_klass.new_from_parts(parts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_used_console?
|
||||||
|
@report.any? { |entry| entry.kind_of?(Jasmine::Headless::ReportMessage::Console) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_failed_on?(statement)
|
||||||
|
@report.any? { |entry|
|
||||||
|
if entry.kind_of?(Jasmine::Headless::ReportMessage::Fail)
|
||||||
|
entry.statement == statement
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?
|
||||||
|
last_total != nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def failed_files
|
||||||
|
@report.find_all { |entry|
|
||||||
|
entry.kind_of?(Jasmine::Headless::ReportMessage::Fail)
|
||||||
|
}.collect(&:filename).uniq.compact
|
||||||
|
end
|
||||||
|
|
||||||
|
def seed
|
||||||
|
if seed = report.find { |entry| entry.respond_to?(:seed) }
|
||||||
|
seed.seed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def last_total
|
||||||
|
@report.reverse.find { |entry| entry.respond_to?(:total) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def report_class_for(type)
|
||||||
|
if constant = ReportMessage.constants.find { |k| k.to_s.downcase == type.downcase }
|
||||||
|
ReportMessage.const_get(constant)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
12
lib/jasmine/headless/report_message.rb
Normal file
12
lib/jasmine/headless/report_message.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module Jasmine::Headless
|
||||||
|
module ReportMessage
|
||||||
|
autoload :Spec, 'jasmine/headless/report_message/spec'
|
||||||
|
autoload :Pass, 'jasmine/headless/report_message/pass'
|
||||||
|
autoload :Fail, 'jasmine/headless/report_message/fail'
|
||||||
|
autoload :Console, 'jasmine/headless/report_message/console'
|
||||||
|
autoload :Error, 'jasmine/headless/report_message/error'
|
||||||
|
autoload :Total, 'jasmine/headless/report_message/total'
|
||||||
|
autoload :Seed, 'jasmine/headless/report_message/seed'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
18
lib/jasmine/headless/report_message/console.rb
Normal file
18
lib/jasmine/headless/report_message/console.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
module Jasmine::Headless::ReportMessage
|
||||||
|
class Console
|
||||||
|
def self.new_from_parts(parts)
|
||||||
|
new(parts.first)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :message
|
||||||
|
|
||||||
|
def initialize(message)
|
||||||
|
@message = message
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
self.message == other.message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
20
lib/jasmine/headless/report_message/error.rb
Normal file
20
lib/jasmine/headless/report_message/error.rb
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
module Jasmine::Headless::ReportMessage
|
||||||
|
class Error
|
||||||
|
class << self
|
||||||
|
def new_from_parts(parts)
|
||||||
|
new(*parts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :message, :file_info
|
||||||
|
|
||||||
|
def initialize(message, file_info)
|
||||||
|
@message, @file_info = message, file_info
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
self.message == other.message && self.file_info == other.file_info
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
5
lib/jasmine/headless/report_message/fail.rb
Normal file
5
lib/jasmine/headless/report_message/fail.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module Jasmine::Headless::ReportMessage
|
||||||
|
class Fail < Spec
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
5
lib/jasmine/headless/report_message/pass.rb
Normal file
5
lib/jasmine/headless/report_message/pass.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module Jasmine::Headless::ReportMessage
|
||||||
|
class Pass < Spec
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
14
lib/jasmine/headless/report_message/seed.rb
Normal file
14
lib/jasmine/headless/report_message/seed.rb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module Jasmine::Headless::ReportMessage
|
||||||
|
class Seed
|
||||||
|
def self.new_from_parts(parts)
|
||||||
|
new(parts.first)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :seed
|
||||||
|
|
||||||
|
def initialize(seed)
|
||||||
|
@seed = seed.to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
28
lib/jasmine/headless/report_message/spec.rb
Normal file
28
lib/jasmine/headless/report_message/spec.rb
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
module Jasmine::Headless::ReportMessage
|
||||||
|
class Spec
|
||||||
|
def self.new_from_parts(parts)
|
||||||
|
file_info = parts.pop
|
||||||
|
|
||||||
|
new(parts.join(' '), file_info)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :statement, :file_info
|
||||||
|
|
||||||
|
def initialize(statement, file_info)
|
||||||
|
@statement, @file_info = statement, file_info
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
self.statement == other.statement && self.file_info == other.file_info
|
||||||
|
end
|
||||||
|
|
||||||
|
def filename
|
||||||
|
if name = file_info.split(":").first
|
||||||
|
name
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
31
lib/jasmine/headless/report_message/total.rb
Normal file
31
lib/jasmine/headless/report_message/total.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module Jasmine::Headless::ReportMessage
|
||||||
|
class Total
|
||||||
|
class << self
|
||||||
|
def new_from_parts(parts)
|
||||||
|
new(*parts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :total, :failed, :time, :has_js_error
|
||||||
|
|
||||||
|
def initialize(total, failed, time, has_js_error)
|
||||||
|
@total, @failed, @time = total.to_i, failed.to_i, time.to_f
|
||||||
|
|
||||||
|
@has_js_error = case has_js_error
|
||||||
|
when String
|
||||||
|
has_js_error == "T"
|
||||||
|
else
|
||||||
|
has_js_error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
other &&
|
||||||
|
self.total == other.total &&
|
||||||
|
self.failed == other.failed &&
|
||||||
|
self.time == other.time &&
|
||||||
|
self.has_js_error == other.has_js_error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
261
lib/jasmine/headless/runner.rb
Normal file
261
lib/jasmine/headless/runner.rb
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
require 'fileutils'
|
||||||
|
|
||||||
|
require 'coffee-script'
|
||||||
|
require 'rainbow'
|
||||||
|
|
||||||
|
require 'yaml'
|
||||||
|
require 'erb'
|
||||||
|
require 'sprockets'
|
||||||
|
|
||||||
|
module Jasmine
|
||||||
|
module Headless
|
||||||
|
class IndexHandler
|
||||||
|
class << self
|
||||||
|
attr_accessor :index
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(app)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
if env['PATH_INFO'] == '/'
|
||||||
|
return [ 302, { 'Location' => self.class.index }, [ 'Redirecting...' ] ]
|
||||||
|
end
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Runner
|
||||||
|
JASMINE_DEFAULTS = {
|
||||||
|
'spec_files' => [ '**/*[sS]pec.js' ],
|
||||||
|
'helpers' => [ 'helpers/**/*.js' ],
|
||||||
|
'spec_dir' => 'spec/javascripts',
|
||||||
|
'src_dir' => nil,
|
||||||
|
'stylesheets' => [],
|
||||||
|
'src_files' => [],
|
||||||
|
'backtrace' => []
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNNER_DIR = File.expand_path('../../../../ext/jasmine-webkit-specrunner', __FILE__)
|
||||||
|
RUNNER = File.join(RUNNER_DIR, 'jasmine-webkit-specrunner')
|
||||||
|
|
||||||
|
attr_reader :options
|
||||||
|
|
||||||
|
def self.run(options = {})
|
||||||
|
new(options).run
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.server_port
|
||||||
|
return @server_port if @server_port
|
||||||
|
|
||||||
|
require 'socket'
|
||||||
|
|
||||||
|
count = 100
|
||||||
|
begin
|
||||||
|
port = select_server_port
|
||||||
|
|
||||||
|
socket = TCPSocket.new(server_interface, port)
|
||||||
|
socket.close
|
||||||
|
|
||||||
|
count -= 1
|
||||||
|
|
||||||
|
raise "Could not create server port after 100 attempts!" if count == 0
|
||||||
|
rescue Errno::ECONNREFUSED
|
||||||
|
@server_port = port
|
||||||
|
|
||||||
|
break
|
||||||
|
ensure
|
||||||
|
begin
|
||||||
|
socket.close if socket
|
||||||
|
rescue IOError
|
||||||
|
end
|
||||||
|
end while true
|
||||||
|
|
||||||
|
@server_port
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.server_port=(port)
|
||||||
|
@server_port = port
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.select_server_port
|
||||||
|
21000 + rand(10000)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.server_interface
|
||||||
|
'127.0.0.1'
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.server_uri
|
||||||
|
"http://#{server_interface}:#{server_port}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.server_spec_path
|
||||||
|
self.server_uri + '/__JHW__/'
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.ensure_server(options)
|
||||||
|
return if @server
|
||||||
|
|
||||||
|
require 'webrick'
|
||||||
|
require 'thread'
|
||||||
|
require 'rack'
|
||||||
|
require 'net/http'
|
||||||
|
|
||||||
|
port = server_port
|
||||||
|
|
||||||
|
@server = Thread.new do
|
||||||
|
Jasmine::Headless.warn "Powering up!"
|
||||||
|
|
||||||
|
app = Rack::Builder.new do
|
||||||
|
use IndexHandler
|
||||||
|
|
||||||
|
map '/__JHW__' do
|
||||||
|
run Rack::File.new(Dir.pwd)
|
||||||
|
end
|
||||||
|
|
||||||
|
map '/' do
|
||||||
|
run Rack::File.new('/')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Rack::Handler::WEBrick.run(
|
||||||
|
app,
|
||||||
|
:Port => port,
|
||||||
|
:Logger => Logger.new(StringIO.new),
|
||||||
|
:AccessLog => [
|
||||||
|
[ StringIO.new, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
|
||||||
|
[ StringIO.new, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
while true do
|
||||||
|
begin
|
||||||
|
Net::HTTP.get(URI(server_uri))
|
||||||
|
break
|
||||||
|
rescue Errno::ECONNREFUSED => e
|
||||||
|
end
|
||||||
|
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(options)
|
||||||
|
options = Options.new(options) if !options.kind_of?(Options)
|
||||||
|
|
||||||
|
@options = options
|
||||||
|
end
|
||||||
|
|
||||||
|
def template_writer
|
||||||
|
@template_writer ||= TemplateWriter.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def jasmine_config
|
||||||
|
return @jasmine_config if @jasmine_config
|
||||||
|
|
||||||
|
@jasmine_config = JASMINE_DEFAULTS.dup
|
||||||
|
jasmine_config_data.each do |key, value|
|
||||||
|
@jasmine_config[key] = value if value
|
||||||
|
end
|
||||||
|
@jasmine_config
|
||||||
|
end
|
||||||
|
|
||||||
|
def jasmine_command(*targets)
|
||||||
|
command = [ RUNNER ]
|
||||||
|
|
||||||
|
command << "-s #{options[:seed]}"
|
||||||
|
command << '-c' if options[:colors]
|
||||||
|
command << '-q' if options[:quiet]
|
||||||
|
|
||||||
|
options.file_reporters.each do |reporter, identifier, file|
|
||||||
|
command << "-r #{file}"
|
||||||
|
end
|
||||||
|
|
||||||
|
command += targets
|
||||||
|
command.compact.join(' ')
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
Jasmine::Headless::CacheableAction.enabled = @options[:enable_cache]
|
||||||
|
Jasmine::Headless.show_warnings = !@options[:quiet]
|
||||||
|
FilesList.reset!
|
||||||
|
|
||||||
|
self.class.server_port = options[:server_port]
|
||||||
|
|
||||||
|
@_targets = template_writer.write
|
||||||
|
|
||||||
|
run_targets = absolute_run_targets(@_targets.dup)
|
||||||
|
|
||||||
|
if run_targets.length == 2
|
||||||
|
if (!@options[:full_run] && files_list.filtered?) || files_list.has_spec_outside_scope?
|
||||||
|
run_targets.pop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
runner = lambda { system jasmine_command(run_targets) }
|
||||||
|
|
||||||
|
if options[:use_server]
|
||||||
|
wrap_in_server(run_targets, &runner)
|
||||||
|
else
|
||||||
|
runner.call
|
||||||
|
end
|
||||||
|
|
||||||
|
@_status = $?.exitstatus
|
||||||
|
ensure
|
||||||
|
if @_targets && !runner_filename && (@options[:remove_html_file] || (@_status == 0))
|
||||||
|
@_targets.each { |target| FileUtils.rm_f target }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def absolute_run_targets(targets)
|
||||||
|
targets.flatten.collect do |target|
|
||||||
|
if options[:use_server]
|
||||||
|
target = self.class.server_spec_path + target
|
||||||
|
else
|
||||||
|
target = "file://" + File.expand_path(target)
|
||||||
|
end
|
||||||
|
target
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def runner_filename
|
||||||
|
options[:runner_output_filename] || begin
|
||||||
|
if (runner_output = jasmine_config['runner_output']) && !runner_output.empty?
|
||||||
|
runner_output
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def files_list
|
||||||
|
@files_list ||= Jasmine::Headless::FilesList.new(
|
||||||
|
:config => jasmine_config,
|
||||||
|
:only => options[:files],
|
||||||
|
:seed => options[:seed],
|
||||||
|
:reporters => options.reporters
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def wrap_in_server(run_targets)
|
||||||
|
self.class.ensure_server(options)
|
||||||
|
IndexHandler.index = run_targets.last
|
||||||
|
|
||||||
|
Jasmine::Headless.warn "HTTP powered specs! Located at #{run_targets.join(' ')}"
|
||||||
|
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def jasmine_config_data
|
||||||
|
raise JasmineConfigNotFound.new("Jasmine config not found. I tried #{@options[:jasmine_config]}.") if !File.file?(@options[:jasmine_config])
|
||||||
|
|
||||||
|
YAML.load(ERB.new(File.read(@options[:jasmine_config])).result(binding))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user