merge sprockets code into mainline, please report bugs

This commit is contained in:
John Bintz 2011-11-23 09:50:14 -05:00
commit 3911041866
44 changed files with 986 additions and 490 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ jhw-test
.jhw-cache/
_site/
jhw.*.html
coverage/

View File

@ -15,3 +15,7 @@ gem 'mocha', '0.9.12'
gem 'guard-jasmine-headless-webkit', :git => 'git://github.com/johnbintz/guard-jasmine-headless-webkit.git'
gem 'facter'
gem 'jquery-rails'
gem 'ejs'
gem 'simplecov'

View File

@ -43,3 +43,22 @@ task :build_runner do
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

View File

@ -1,31 +1,11 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'rainbow'
def gem_dir
File.expand_path('../..', __FILE__)
end
$: << File.expand_path('../../lib', __FILE__)
$:.unshift(File.join(gem_dir, 'lib'))
require 'jasmine-headless-webkit'
require 'coffee-script'
begin
options = Jasmine::Headless::Options.from_command_line
runner = Jasmine::Headless::Runner.new(options)
if options[:do_list]
files_list = Jasmine::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
Jasmine::Headless::CommandLine.run!

View File

@ -20,8 +20,9 @@ Gem::Specification.new do |s|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
s.add_dependency 'jasmine-core', '~>1.1.beta'
s.add_dependency 'coffee-script', '>= 2.2'
s.add_dependency 'rainbow'
s.add_dependency 'multi_json'
s.add_runtime_dependency 'jasmine-core', '~> 1.1'
s.add_runtime_dependency 'coffee-script'
s.add_runtime_dependency 'rainbow'
s.add_runtime_dependency 'multi_json'
s.add_runtime_dependency 'sprockets', '~> 2'
end

View File

@ -0,0 +1,20 @@
module Digest
class JasmineTest
def self.file(file)
new
end
def file(file)
self
end
def hexdigest
'test'
end
def update(prefix)
self
end
end
end

View File

@ -1,7 +1,7 @@
module Jasmine
autoload :FilesList, 'jasmine/files_list'
end
require 'jasmine/headless'
require 'jasmine/headless/railtie' if defined?(Rails) && Rails::VERSION::MAJOR >= 3
module Digest
autoload :JasmineTest, 'digest/jasmine_test'
end

View File

@ -1,176 +0,0 @@
require 'jasmine-core'
require 'time'
require 'multi_json'
module Jasmine
class FilesList
attr_reader :files, :spec_files, :filtered_files, :spec_outside_scope
class << self
def find_vendored_asset_paths(*names)
require 'rubygems'
raise StandardError.new("A newer version of Rubygems is required to use vendored assets. Please upgrade.") if !Gem::Specification.respond_to?(:map)
all_spec_files.find_all do |file|
names.any? { |name| file["/#{name}.js"] }
end
end
def all_spec_files
@all_spec_files ||= Gem::Specification.map { |spec| spec.files.find_all { |file|
file["vendor/assets/javascripts"]
}.compact.collect { |file| File.join(spec.gem_dir, file) } }.flatten
end
end
DEFAULT_FILES = [
File.join(Jasmine::Core.path, "jasmine.js"),
File.join(Jasmine::Core.path, "jasmine-html.js"),
File.join(Jasmine::Core.path, "jasmine.css")
] + %w{jasmine-extensions intense headless_reporter_result jasmine.HeadlessConsoleReporter jsDump beautify-html}.collect { |name|
Jasmine::Headless.root.join("vendor/assets/javascripts/#{name}.js").to_s
}
PLEASE_WAIT_IM_WORKING_TIME = 2
def initialize(options = {})
@options = options
@files = DEFAULT_FILES.dup
@filtered_files = @files.dup
@spec_outside_scope = false
@spec_files = []
use_config! if config?
end
def has_spec_outside_scope?
@spec_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 { |file|
if alert_time && alert_time < Time.now
puts "Rebuilding cache, please wait..."
alert_time = nil
end
source = nil
result = case File.extname(file)
when '.coffee'
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.to_s.color(:white) ]
raise ne
rescue StandardError => e
puts "[%s] Error in compiling one of the followng: %s" % [ 'coffeescript'.color(:red), files.join(' ').color(:yellow) ]
raise e
end
when '.js'
%{<script type="text/javascript" src="#{file}"></script>}
when '.css'
%{<link rel="stylesheet" href="#{file}" type="text/css" />}
end
result
}.flatten.compact.reject(&:empty?)
end
def spec_filter
return @spec_filter if @spec_filter
@spec_filter = begin
if @options[:only]
@options[:only].collect { |path| expanded_dir(path) }.flatten
else
[]
end
end
end
def use_config!
@filtered_files = @files.dup
data = @options[:config].dup
[ [ 'src_files', 'src_dir' ], [ 'stylesheets', 'src_dir' ], [ 'vendored_helpers' ], [ 'helpers', 'spec_dir' ], [ 'spec_files', 'spec_dir' ] ].each do |searches, root|
if data[searches]
case searches
when 'vendored_helpers'
data[searches].each do |name|
found_files = self.class.find_vendored_asset_path(name)
@files += found_files
@filtered_files += found_files
end
else
data[searches].flatten.collect do |search|
path = search
path = File.join(data[root], path) if data[root]
found_files = expanded_dir(path) - @files
@files += found_files
if searches == 'spec_files'
@spec_files += spec_filter.empty? ? found_files : (found_files & spec_filter)
end
@filtered_files += begin
if searches == 'spec_files'
@spec_outside_scope = ((spec_filter | found_files).sort != found_files.sort)
spec_filter.empty? ? found_files : (spec_filter || found_files)
else
found_files
end
end
end
end
end
end
end
def config?
@options[:config]
end
def expanded_dir(path)
Dir[path].collect { |file| File.expand_path(file) }
end
end
end

View File

@ -1,6 +1,8 @@
require 'pathname'
module Jasmine::Headless
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'
@ -8,9 +10,15 @@ module Jasmine::Headless
autoload :Runner, 'jasmine/headless/runner'
autoload :Options, 'jasmine/headless/options'
autoload :Task, 'jasmine/headless/task'
autoload :FilesList, 'jasmine/headless/files_list'
autoload :TemplateWriter, 'jasmine/headless/template_writer'
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 :Report, 'jasmine/headless/report'
autoload :ReportMessage, 'jasmine/headless/report_message'

View File

@ -0,0 +1,30 @@
require 'tilt/template'
require 'rainbow'
module Jasmine::Headless
class CoffeeTemplate < Tilt::Template
self.default_mime_type = 'application/javascript'
def prepare ; end
def evaluate(scope, locals, &block)
begin
cache = Jasmine::Headless::CoffeeScriptCache.new(file)
source = cache.handle
if cache.cached?
%{<script from="jhw" type="text/javascript" src="#{cache.cache_file}"></script>
<script type="text/javascript">window.CSTF['#{File.split(cache.cache_file).last}'] = '#{file}';</script>}
else
%{<script from="jhw" 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

View 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

View File

@ -0,0 +1,14 @@
require 'tilt/template'
module Jasmine::Headless
class CSSTemplate < Tilt::Template
self.default_mime_type = 'text/css'
def prepare ; end
def evaluate(scope, locals, &block)
file ? %{<link rel="stylesheet" href="#{file}" type="text/css" />} : data
end
end
end

View File

@ -0,0 +1,275 @@
require 'jasmine-core'
require 'time'
require 'multi_json'
require 'set'
require 'sprockets'
require 'sprockets/engines'
module Jasmine::Headless
class FilesList
class << self
def vendor_asset_paths
return @vendor_asset_paths if @vendor_asset_paths
require 'rubygems'
raise StandardError.new("A newer version of Rubygems is required to use vendored assets. Please upgrade.") if !Gem::Specification.respond_to?(:map)
@vendor_asset_paths = []
Gem::Specification.map { |spec|
path = File.join(spec.gem_dir, 'vendor/assets/javascripts')
File.directory?(path) ? path : nil
}.compact
end
def reset!
@vendor_asset_paths = nil
# register haml-sprockets if it's available...
%w{haml-sprockets}.each do |library|
begin
require library
rescue LoadError
end
end
# ...and unregister ones we don't want/need
Sprockets.instance_eval do
%w{less sass scss erb str}.each do |extension|
@engines.delete(".#{extension}")
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
end
def default_files
%w{jasmine.js jasmine-html jasmine.css jasmine-extensions intense headless_reporter_result jasmine.HeadlessConsoleReporter jsDump beautify-html}
end
end
PLEASE_WAIT_IM_WORKING_TIME = 2
attr_reader :required_files, :potential_files_to_filter
def initialize(options = {})
@options = options
@required_files = []
@potential_files_to_filter = []
self.class.default_files.each do |file|
@required_files << sprockets_environment.find_asset(file, :bundle => false)
end
use_config! if config?
end
def files
required_files.collect { |file| file.to_a.collect { |asset| asset.pathname.to_s } }.flatten.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 ]
@search_paths += src_dir.collect { |dir| File.expand_path(dir) }
@search_paths += spec_dir.collect { |dir| File.expand_path(dir) }
@search_paths += self.class.vendor_asset_paths
@search_paths
end
def sprockets_environment
return @sprockets_environment if @sprockets_environment
@sprockets_environment = Sprockets::Environment.new
search_paths.each do |path|
@sprockets_environment.append_path(path)
end
@sprockets_environment.unregister_postprocessor('application/javascript', Sprockets::SafetyColons)
@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? { |file|
File.fnmatch?(File.join(dir, search), file)
}
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.flatten.compact.reject(&:empty?)
end
def spec_filter
return @spec_filter if @spec_filter
@spec_filter = begin
if @options[:only]
@options[:only].collect { |path| expanded_dir(path) }.flatten
else
[]
end
end
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]
dirs = send(SEARCH_ROOTS[type])
add_files(@searches[type] = data.flatten, type, dirs)
end
end
filtered_required_files = []
@required_files.each do |file|
if !filtered_required_files.any? { |other_file| other_file.logical_path == file.logical_path }
filtered_required_files << file
end
end
@required_files = filtered_required_files
end
def add_files(patterns, type, dirs)
dirs.each do |dir|
patterns.each do |search|
search = File.expand_path(File.join(dir, search))
Dir[search].find_all { |file| file[extension_filter] }.each do |path|
add_path(path, type) if File.file?(path)
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)
Dir[path].collect { |file| File.expand_path(file) }.find_all { |path| File.file?(path) && path[extension_filter] }
end
def extension_filter
%r{(#{(%w{.js .css} + Sprockets.engine_extensions).join('|')})$}
end
def add_path(path, type)
asset = sprockets_environment.find_asset(path)
@required_files << asset
if type == 'spec_files'
@potential_files_to_filter << path
end
end
def src_dir
config_dir_or_pwd('src_dir')
end
def spec_dir
config_dir_or_pwd('spec_dir')
end
def spec_file_searches
@searches['spec_files']
end
def config_dir_or_pwd(dir)
found_dir = Dir.pwd
if @options[:config]
found_dir = @options[:config][dir] || found_dir
end
[ found_dir ].flatten.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
end
end

View File

@ -0,0 +1,18 @@
require 'tilt/template'
module Jasmine::Headless
class JSTemplate < Tilt::Template
self.default_mime_type = 'application/javascript'
def prepare ; end
def evaluate(scope, locals, &block)
if data['from="jhw"']
data
else
file ? %{<script type="text/javascript" src="#{file}"></script>} : data
end
end
end
end

View File

@ -0,0 +1,10 @@
require 'sprockets/jst_processor'
module Jasmine::Headless
class JSTTemplate < Sprockets::JstProcessor
def evaluate(*args)
%{<script type="text/javascript">#{super}</script>}
end
end
end

View File

@ -4,6 +4,8 @@ require 'coffee-script'
require 'rainbow'
require 'yaml'
require 'sprockets'
module Jasmine
module Headless
@ -23,10 +25,12 @@ module Jasmine
attr_reader :options
def self.run(options = {})
class << self
def run(options = {})
options = Options.new(options) if !options.kind_of?(Options)
new(options).run
end
end
def initialize(options)
if !File.file?(RUNNER)
@ -65,8 +69,9 @@ module Jasmine
def run
Jasmine::Headless::CacheableAction.enabled = @options[:enable_cache]
FilesList.reset!
files_list = Jasmine::FilesList.new(
files_list = Jasmine::Headless::FilesList.new(
:config => jasmine_config,
:only => @options[:files]
)

View File

@ -1,23 +1,3 @@
module Digest
class JasmineTest
def self.file(file)
new
end
def file(file)
self
end
def hexdigest
'test'
end
def update(prefix)
self
end
end
end
module Jasmine
module Headless
class Task
@ -41,8 +21,9 @@ module Jasmine
private
def create_rails_compliant_task
if Rails.respond_to?(:version) && Rails.version >= "3.1.0"
desc 'Force generate static assets without an MD5 hash, all assets end with -test.<ext>'
task 'assets:precompile:for_testing' => :environment do
$stderr.puts "This task is deprecated and will be removed after 2012-01-01"
Rails.application.assets.digest_class = Digest::JasmineTest
Rake::Task['assets:precompile'].invoke

View File

@ -23,7 +23,15 @@
if (window.JHW) {
jasmine.getEnv().addReporter(new jasmine.HeadlessConsoleReporter());
} else {
jasmine.getEnv().addReporter(new jasmine.HtmlReporter());
types = [ 'HtmlReporter', 'TrivialReporter' ];
for (var i = 0, j = types.length; i < j; ++i) {
var type = jasmine[types[i]]
if (type) {
jasmine.getEnv().addReporter(new type());
break;
}
}
}
jasmine.getEnv().execute();

View File

@ -138,5 +138,23 @@ describe "jasmine-headless-webkit" do
File.size(runner_path.path).should_not == 0
end
end
describe 'sprockets' do
it 'should pull in the code via sprockets' do
files = %x{bin/jasmine-headless-webkit -l -j spec/jasmine/with_sprockets_includes/with_sprockets_includes.yml}
$?.exitstatus.should == 0
files.lines.to_a.should contain_in_order_in_file_list(
'vendor/assets/javascripts/jquery.js',
'templates/that.jst.ejs',
'templates/this.jst',
'assets/things/required.js',
'assets/things/code.js',
'assets/things/subcode/more_code.js',
'spec_helper.js',
'spec/things/code_spec.js'
)
end
end
end

View File

@ -0,0 +1,2 @@
//= require 'jquery'
//= require_tree '.'

View File

@ -0,0 +1,6 @@
//= require 'jquery'
//= require_tree './templates'
//= require 'things/required'
window.a = '1';

View File

@ -0,0 +1,2 @@
//= require 'jquery'

View File

@ -0,0 +1,2 @@
//= require 'things/required'

View File

@ -0,0 +1,2 @@
'hello'

View File

@ -0,0 +1 @@
//= require 'jquery'

View File

@ -0,0 +1,9 @@
//= require 'things/code'
describe('code', function() {
it('should equal 1', function() {
expect(window.a).toEqual(1)
expect(jQuery).not.toBeUndefined()
});
});

View File

@ -0,0 +1,12 @@
src_dir: spec/jasmine/with_sprockets_includes/assets
spec_dir: spec/jasmine/with_sprockets_includes/spec
spec_files:
- "**/*_spec.js"
src_files:
- "things/**/*"
helpers:
- "spec_helper.js"

View File

@ -1,248 +0,0 @@
# encoding: UTF-8
require 'spec_helper'
require 'jasmine/files_list'
require 'fakefs/spec_helpers'
require 'coffee-script'
describe Jasmine::FilesList do
let(:files_list) { described_class.new }
describe '#initialize' do
it "should have default files" do
files_list.files.should == [
File.join(Jasmine::Core.path, "jasmine.js"),
File.join(Jasmine::Core.path, "jasmine-html.js"),
File.join(Jasmine::Core.path, "jasmine.css"),
File.expand_path('vendor/assets/javascripts/jasmine-extensions.js'),
File.expand_path('vendor/assets/javascripts/intense.js'),
File.expand_path('vendor/assets/javascripts/headless_reporter_result.js'),
File.expand_path('vendor/assets/javascripts/jasmine.HeadlessConsoleReporter.js'),
File.expand_path('vendor/assets/javascripts/jsDump.js'),
File.expand_path('vendor/assets/javascripts/beautify-html.js'),
]
end
end
describe '#use_config' do
let(:files_list) { described_class.new(:config => config) }
include FakeFS::SpecHelpers
let(:src_dir) { 'src' }
let(:spec_dir) { 'spec' }
let(:first_file) { File.join(src_dir, 'js/first_file.js') }
let(:src_file) { File.join(src_dir, 'js/src_file.js') }
let(:spec_file) { File.join(spec_dir, 'spec_file_spec.js') }
let(:helper_file) { File.join(spec_dir, 'helper/helper_file.js') }
let(:stylesheet_file) { File.join(src_dir, 'stylesheet/blah.css') }
before do
[ first_file, src_file, spec_file, helper_file, stylesheet_file ].each do |file|
FileUtils.mkdir_p File.split(file).first
File.open(file, 'w')
end
end
shared_examples_for :reading_data do
it 'should read the data from the jasmine.yml file and add the files' do
files_list.files.should == Jasmine::FilesList::DEFAULT_FILES + [
File.expand_path(first_file),
File.expand_path(src_file),
File.expand_path(stylesheet_file),
File.expand_path(helper_file),
File.expand_path(spec_file)
]
files_list.spec_files.should == [ File.expand_path(spec_file) ]
end
end
context 'with normal list' do
let(:config) { {
'src_dir' => src_dir,
'spec_dir' => spec_dir,
'src_files' => [ 'js/first_file.js', 'js/*.js' ],
'spec_files' => [ '*_spec.js' ],
'helpers' => [ 'helper/*.js' ],
'stylesheets' => [ 'stylesheet/*.css' ]
} }
it_should_behave_like :reading_data
end
context 'with multidimensional list' do
let(:config) { {
'src_dir' => src_dir,
'spec_dir' => spec_dir,
'src_files' => [ [ 'js/first_file.js', 'js/*.js' ] ],
'spec_files' => [ '*_spec.js' ],
'helpers' => [ 'helper/*.js' ],
'stylesheets' => [ 'stylesheet/*.css' ]
} }
it_should_behave_like :reading_data
end
context 'with vendored helpers' do
let(:config) { {
'src_dir' => src_dir,
'spec_dir' => spec_dir,
'src_files' => [ 'js/first_file.js', 'js/*.js' ],
'spec_files' => [ '*_spec.js' ],
'helpers' => [],
'stylesheets' => [ 'stylesheet/*.css' ],
'vendored_helpers' => [ 'one', 'two' ]
} }
let(:helper_file) { "path/one.js" }
let(:other_helper_file) { "path/two.js" }
before do
described_class.expects(:find_vendored_asset_path).with('one').returns([ helper_file ])
described_class.expects(:find_vendored_asset_path).with('two').returns([ other_helper_file ])
end
it 'should find the vendored file' do
files_list.files.should include(helper_file)
files_list.files.should include(other_helper_file)
files_list.files.index(helper_file).should be < files_list.files.index(other_helper_file)
end
end
end
context 'with filtered specs' do
let(:files_list) { Jasmine::FilesList.new(:only => filter, :config => config) }
let(:spec_dir) { 'spec' }
include FakeFS::SpecHelpers
let(:config) { {
'spec_files' => [ '*_spec.js' ],
'spec_dir' => spec_dir
} }
let(:spec_files) { %w{one_spec.js two_spec.js whatever.js} }
before do
spec_files.each do |file|
FileUtils.mkdir_p spec_dir
File.open(File.join(spec_dir, file), 'w')
end
end
context 'empty filter' do
let(:filter) { [] }
it 'should return all files for filtered and all files' do
files_list.files.any? { |file| file['two_spec.js'] }.should be_true
files_list.filtered?.should be_false
files_list.should_not have_spec_outside_scope
files_list.spec_files.sort.should == %w{one_spec.js two_spec.js}.sort.collect { |file| File.expand_path(File.join(spec_dir, file)) }
end
end
context 'filter with a file that is matchable' do
let(:filter) { [ File.expand_path('spec/one_spec.js') ] }
it 'should return all files for files' do
files_list.files.any? { |file| file['two_spec.js'] }.should be_true
files_list.filtered?.should be_true
files_list.should_not have_spec_outside_scope
files_list.spec_files.should == filter
end
it 'should return only filtered files for filtered_files' do
files_list.filtered_files.any? { |file| file['two_spec.js'] }.should be_false
files_list.should_not have_spec_outside_scope
end
end
context 'filter with a glob' do
let(:filter) { [ File.expand_path('spec/one*') ] }
it 'should return all files for files' do
files_list.files.any? { |file| file['two_spec.js'] }.should be_true
files_list.filtered?.should be_true
files_list.should_not have_spec_outside_scope
end
it 'should return only filtered files for filtered_files' do
files_list.filtered_files.any? { |file| file['two_spec.js'] }.should be_false
files_list.should_not have_spec_outside_scope
end
end
context 'filter with a file that is not even there' do
let(:filter) { [ File.expand_path('spec/whatever.js') ] }
it 'should use the provided file' do
files_list.filtered_files.any? { |file| file['whatever.js'] }.should be_true
files_list.should have_spec_outside_scope
end
end
end
describe '#.*files_to_html' do
include FakeFS::SpecHelpers
before do
files_list.instance_variable_set(:@files, [
'test.js',
'test.coffee',
'test.whatever',
'test.css'
])
files_list.instance_variable_set(:@filtered_files, [
'test.js',
'test.coffee'
])
File.stubs(:read)
Jasmine::Headless::CoffeeScriptCache.any_instance.stubs(:handle).returns("i compiled")
end
context '#files_to_html' do
it "should create the right HTML" do
files_list.files_to_html.should == [
%{<script type="text/javascript" src="test.js"></script>},
%{<script type="text/javascript">i compiled</script>},
%{<link rel="stylesheet" href="test.css" type="text/css" />}
]
end
end
context '#filtered_files_to_html' do
it "should create the right HTML" do
files_list.filtered_files_to_html.should == [
%{<script type="text/javascript" src="test.js"></script>},
%{<script type="text/javascript">i compiled</script>}
]
end
end
end
describe '#spec_file_line_numbers' do
include FakeFS::SpecHelpers
before do
files_list.instance_variable_set(:@spec_files, [
'test.coffee',
'test2.coffee'
])
File.open('test.coffee', 'w') { |fh| fh.print "describe('cat')\ndescribe('cat')" }
File.open('test2.coffee', 'w') { |fh| fh.print "no matches" }
end
it 'should generate filenames and line number info' do
files_list.spec_file_line_numbers.should == {
'test.coffee' => { 'cat' => [ 1, 2 ] }
}
end
end
end

View File

@ -0,0 +1,55 @@
require 'spec_helper'
describe Jasmine::Headless::CoffeeTemplate do
let(:data) { 'data' }
let(:path) { 'path.coffee' }
let(:template) { described_class.new(path) { data } }
subject { template.render }
let(:handle_expectation) { Jasmine::Headless::CoffeeScriptCache.any_instance.stubs(:handle) }
context 'compilation error' do
let(:error) { CoffeeScript::CompilationError.new("fail") }
before do
handle_expectation.raises(error)
end
it 'should pass along the error' do
expect { subject }.to raise_error(CoffeeScript::CompilationError)
end
end
context 'compiles fine' do
let(:source) { 'source' }
before do
Jasmine::Headless::CoffeeScriptCache.any_instance.stubs(:cached?).returns(cache_return)
handle_expectation.returns(source)
end
context 'cached' do
let(:file_path) { 'dir/file.js' }
let(:cache_return) { true }
before do
Jasmine::Headless::CoffeeScriptCache.any_instance.stubs(:cache_file).returns(file_path)
end
it 'should return the cached file' do
subject.should include(%{<script from="jhw" type="text/javascript" src="#{file_path}"></script>})
end
end
context 'not cached' do
let(:cache_return) { false }
it 'should return the generated js' do
subject.should include(%{<script from="jhw" type="text/javascript">#{source}</script>})
end
end
end
end

View File

@ -0,0 +1,25 @@
require 'spec_helper'
describe Jasmine::Headless::CSSTemplate do
include FakeFS::SpecHelpers
let(:template) { described_class.new(file) { data } }
let(:file) { 'file' }
let(:data) { 'data' }
subject { template.render }
before do
File.open(file, 'wb') if file
end
context "no file'" do
let(:file) { nil }
it { should == data }
end
context 'file' do
it { should == %{<link rel="stylesheet" href="#{file}" type="text/css" />} }
end
end

View File

@ -0,0 +1,179 @@
require 'spec_helper'
require 'fakefs/spec_helpers'
require 'coffee-script'
describe Jasmine::Headless::FilesList do
let(:files_list) { described_class.new }
describe '#initialize' do
it "should have default files" do
files_list.files.should == [
File.join(Jasmine::Core.path, "jasmine.js"),
File.join(Jasmine::Core.path, "jasmine-html.js"),
File.join(Jasmine::Core.path, "jasmine.css"),
File.expand_path('vendor/assets/javascripts/jasmine-extensions.js'),
File.expand_path('vendor/assets/javascripts/intense.js'),
File.expand_path('vendor/assets/javascripts/headless_reporter_result.js'),
File.expand_path('vendor/assets/javascripts/jasmine.HeadlessConsoleReporter.js'),
File.expand_path('vendor/assets/javascripts/jsDump.js'),
File.expand_path('vendor/assets/javascripts/beautify-html.js'),
]
end
end
def self.no_default_files!
before do
described_class.stubs(:default_files).returns([])
end
end
it 'should have tests for #use_config!'
it 'should have tests for #add_files'
describe '#spec_file_line_numbers' do
include FakeFS::SpecHelpers
no_default_files!
before do
files_list.stubs(:spec_files).returns(['test.coffee', 'test2.coffee'])
File.open('test.coffee', 'w') { |fh| fh.print "describe('cat')\ndescribe('cat')" }
File.open('test2.coffee', 'w') { |fh| fh.print "no matches" }
end
it 'should generate filenames and line number info' do
files_list.spec_file_line_numbers.should == {
'test.coffee' => { 'cat' => [ 1, 2 ] }
}
end
end
describe '#search_paths' do
no_default_files!
let(:files_list) { described_class.new(:config => config) }
let(:config) { {
'src_dir' => src_dir,
'spec_dir' => spec_dir
} }
let(:src_dir) { 'src dir' }
let(:spec_dir) { 'spec dir' }
let(:path) { 'path' }
before do
Jasmine::Headless::FilesList.stubs(:vendor_asset_paths).returns([])
end
context 'no vendored gem paths' do
it 'should take the src dir and spec dirs' do
files_list.search_paths.should == [ Jasmine::Core.path, File.expand_path(src_dir), File.expand_path(spec_dir) ]
end
end
context 'vendored gem paths' do
before do
Jasmine::Headless::FilesList.stubs(:vendor_asset_paths).returns([ path ])
end
it 'should add the vendor gem paths to the list' do
files_list.search_paths.should == [ Jasmine::Core.path, File.expand_path(src_dir), File.expand_path(spec_dir), path ]
end
end
context 'src_dir is an array' do
let(:dir_1) { 'dir 1' }
let(:dir_2) { 'dir 2' }
let(:src_dir) { [ dir_1, dir_2 ] }
it 'should take the src dir and spec dirs' do
files_list.search_paths.should == [ Jasmine::Core.path, File.expand_path(dir_1), File.expand_path(dir_2), File.expand_path(spec_dir) ]
end
end
end
describe '.vendor_asset_paths' do
include FakeFS::SpecHelpers
let(:dir_one) { 'dir_one' }
let(:dir_two) { 'dir_two' }
let(:gem_one) { stub(:gem_dir => dir_one) }
let(:gem_two) { stub(:gem_dir => dir_two) }
before do
described_class.instance_variable_set(:@vendor_asset_paths, nil)
FileUtils.mkdir_p File.join(dir_two, 'vendor/assets/javascripts')
Gem::Specification.stubs(:_all).returns([gem_one, gem_two])
end
it 'should return all matching gems with vendor/assets/javascripts directories' do
described_class.vendor_asset_paths.should == [ File.join(dir_two, 'vendor/assets/javascripts') ]
end
end
describe '#files' do
let(:path_one) { 'one' }
let(:path_two) { 'two' }
let(:path_three) { 'three' }
let(:file_one) { stub(:to_a => [ asset_one, asset_two ] ) }
let(:file_two) { stub(:to_a => [ asset_two, asset_three ] ) }
let(:asset_one) { stub(:pathname => Pathname(path_one)) }
let(:asset_two) { stub(:pathname => Pathname(path_two)) }
let(:asset_three) { stub(:pathname => Pathname(path_three)) }
before do
files_list.stubs(:required_files).returns([ file_one, file_two ])
end
subject { files_list.files }
it { should == [ path_one, path_two, path_three ] }
end
describe '#filtered_files' do
let(:spec_dir) { 'spec' }
let(:file_one) { "#{spec_dir}/one" }
let(:file_two) { "#{spec_dir}/two" }
let(:file_three) { "#{spec_dir}/three" }
let(:file_four) { 'other/four' }
before do
files_list.stubs(:files).returns([
file_one,
file_two,
file_three,
file_four
])
files_list.stubs(:potential_files_to_filter).returns([ file_one, file_two, file_three ])
end
subject { files_list.filtered_files }
context 'empty filter' do
before do
files_list.stubs(:spec_filter).returns([])
end
it { should == [ file_one, file_two, file_three, file_four ] }
end
context 'with filter' do
before do
files_list.stubs(:spec_filter).returns([ "#{spec_dir}/one", '**/tw*' ])
end
it { should == [ file_one, file_two, file_four ] }
end
end
end

View File

@ -0,0 +1,31 @@
require 'spec_helper'
describe Jasmine::Headless::JSTemplate do
include FakeFS::SpecHelpers
let(:template) { described_class.new(file) { data } }
let(:file) { 'file' }
let(:data) { 'data' }
subject { template.render }
before do
File.open(file, 'wb') if file
end
context "no file'" do
let(:file) { nil }
it { should == data }
end
context 'file' do
it { should == %{<script type="text/javascript" src="#{file}"></script>} }
end
context 'jhw content' do
let(:data) { 'from="jhw"' }
it { should == data }
end
end

View File

@ -0,0 +1,21 @@
require 'spec_helper'
describe Jasmine::Headless::JSTTemplate do
include FakeFS::SpecHelpers
let(:template) { described_class.new(file) }
let(:file) { 'file' }
let(:data) { 'data' }
let(:context) { stub(:logical_path => 'path') }
before do
File.open(file, 'wb') { |fh| fh.print data }
end
subject { template.render(context) }
it { should include(%{<script type="text/javascript">}) }
it { should include(data) }
end

View File

@ -47,17 +47,21 @@ describe Jasmine::Headless::TemplateWriter do
include FakeFS::SpecHelpers
before do
Jasmine::Headless::FilesList.stubs(:default_files).returns([])
File.stubs(:read).returns(nil)
runner.stubs(:keep_runner).returns(true)
runner.stubs(:runner_filename).returns(false)
Sprockets::Environment.any_instance.stubs(:find_asset).returns(stub(:body => ''))
end
let(:files_list) { Jasmine::FilesList.new }
let(:files_list) { Jasmine::Headless::FilesList.new }
before do
files_list.files << 'file.js'
files_list.filtered_files << 'file.js'
files_list.stubs(:files).returns([ 'file.js' ])
files_list.stubs(:filtered_files).returns([ 'file.js' ])
end
context 'no filter' do
@ -70,7 +74,7 @@ describe Jasmine::Headless::TemplateWriter do
context 'filtered files' do
before do
files_list.files << 'file2.js'
files_list.stubs(:files).returns([ 'file.js', 'file2.js' ])
end
it 'should write two files' do

View File

@ -1,11 +1,18 @@
if ENV['COVERAGE']
require 'simplecov'
SimpleCov.start
end
require 'jasmine-headless-webkit'
require 'fakefs/spec_helpers'
RSpec.configure do |c|
c.mock_with :mocha
#c.backtrace_clean_patterns = []
c.before(:each) do
Jasmine::Headless::CacheableAction.enabled = false
Jasmine::Headless::FilesList.reset!
end
end
@ -17,6 +24,14 @@ if !File.file?(specrunner)
end
end
class FakeFS::File
class << self
def fnmatch?(pattern, file)
RealFile.fnmatch?(pattern, file)
end
end
end
module RSpec::Matchers
define :be_a_report_containing do |total, failed, used_console|
match do |filename|
@ -51,4 +66,25 @@ module RSpec::Matchers
File.file?(file)
end
end
define :contain_in_order_in_file_list do |*files|
match do |lines|
file_list = files.dup
lines.each do |line|
next if !file_list.first
if line[file_list.first]
file_list.shift
end
end
file_list.length == 0
end
failure_message_for_should do |lines|
%{expected\n#{lines.join("\n")}\nto contain the following files, in order:\n#{files.join("\n")}}
end
end
end

View File

@ -11,7 +11,7 @@ class window.HeadlessReporterResult
bestChoice = HeadlessReporterResult.findSpecLine(@splitName)
output += " (#{bestChoice.file}:#{bestChoice.lineNumber})".foreground('blue') if bestChoice.file
JHW.stdout.puts "\n\n#{output}"
JHW.stdout.puts "\n#{output}"
for result in @results
output = result.message.foreground('red')
if result.lineNumber

View File

@ -20,6 +20,7 @@ window.Intense = {
else
this
useColors: true
moveBack: (count = 1) -> "\033[#{count}D"
}
for method, code of Intense.methods

View File

@ -73,7 +73,10 @@ if window.JHW
pauseAndRun = (onComplete) ->
JHW.timerPause()
jasmine.getEnv().reporter.reportSpecWaiting()
this._execute ->
jasmine.getEnv().reporter.reportSpecRunning()
JHW.timerDone()
onComplete()
@ -88,3 +91,13 @@ if window.JHW
result.expectations = jasmine.NestedResults.parseAndStore(arguments.callee.caller.caller.caller.toString())
this.addResult_(result)
for method in [ "reportSpecWaiting", "reportSpecRunning" ]
generator = (method) ->
(args...) ->
for reporter in @subReporters_
if reporter[method]?
reporter[method](args...)
jasmine.MultiReporter.prototype[method] = generator(method)

View File

@ -6,6 +6,9 @@ class jasmine.HeadlessConsoleReporter
@results = []
@failedCount = 0
@length = 0
@timer = null
@position = 0
@positions = "|/-\\"
reportRunnerResults: (runner) ->
return if this.hasError()
@ -34,7 +37,7 @@ class jasmine.HeadlessConsoleReporter
reportRunnerStarting: (runner) ->
@startTime = new Date()
JHW.stdout.puts("\nRunning Jasmine specs...".bright())
JHW.stdout.puts("\nRunning Jasmine specs...".bright()) if !this.hasError()
reportSpecResults: (spec) ->
return if this.hasError()
@ -67,6 +70,33 @@ class jasmine.HeadlessConsoleReporter
spec.finish()
spec.suite.finish()
reportSpecWaiting: ->
runner = null
if !@timer
@timer = true
first = true
runner = =>
@timer = setTimeout(
=>
if @timer
JHW.stdout.print(Intense.moveBack()) if !first
JHW.stdout.print(@positions.substr(@position, 1).foreground('yellow'))
@position += 1
@position %= @positions.length
first = false
runner()
, 750
)
runner()
reportSpecRunning: ->
if @timer
clearTimeout(@timer)
@timer = null
JHW.stdout.print(Intense.moveBack())
reportSuiteResults: (suite) ->
hasError: ->
JHW._hasErrors

View File

@ -18,7 +18,7 @@
if (bestChoice.file) {
output += (" (" + bestChoice.file + ":" + bestChoice.lineNumber + ")").foreground('blue');
}
JHW.stdout.puts("\n\n" + output);
JHW.stdout.puts("\n" + output);
_ref = this.results;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {

View File

@ -28,7 +28,11 @@
}
}
},
useColors: true
useColors: true,
moveBack: function(count) {
if (count == null) count = 1;
return "\033[" + count + "D";
}
};
_ref = Intense.methods;

View File

@ -1,5 +1,6 @@
(function() {
var getSplitName, pauseAndRun;
var generator, getSplitName, method, pauseAndRun, _i, _len, _ref;
var __slice = Array.prototype.slice;
if (!(typeof jasmine !== "undefined" && jasmine !== null)) {
throw new Error("jasmine not laoded!");
@ -85,7 +86,9 @@
jasmine.WaitsForBlock.prototype._execute = jasmine.WaitsForBlock.prototype.execute;
pauseAndRun = function(onComplete) {
JHW.timerPause();
jasmine.getEnv().reporter.reportSpecWaiting();
return this._execute(function() {
jasmine.getEnv().reporter.reportSpecRunning();
JHW.timerDone();
return onComplete();
});
@ -98,6 +101,28 @@
result.expectations = jasmine.NestedResults.parseAndStore(arguments.callee.caller.caller.caller.toString());
return this.addResult_(result);
};
_ref = ["reportSpecWaiting", "reportSpecRunning"];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
method = _ref[_i];
generator = function(method) {
return function() {
var args, reporter, _j, _len2, _ref2, _results;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
_ref2 = this.subReporters_;
_results = [];
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
reporter = _ref2[_j];
if (reporter[method] != null) {
_results.push(reporter[method].apply(reporter, args));
} else {
_results.push(void 0);
}
}
return _results;
};
};
jasmine.MultiReporter.prototype[method] = generator(method);
}
}
}

View File

@ -10,6 +10,9 @@
this.results = [];
this.failedCount = 0;
this.length = 0;
this.timer = null;
this.position = 0;
this.positions = "|/-\\";
}
HeadlessConsoleReporter.prototype.reportRunnerResults = function(runner) {
@ -37,7 +40,9 @@
HeadlessConsoleReporter.prototype.reportRunnerStarting = function(runner) {
this.startTime = new Date();
if (!this.hasError()) {
return JHW.stdout.puts("\nRunning Jasmine specs...".bright());
}
};
HeadlessConsoleReporter.prototype.reportSpecResults = function(spec) {
@ -77,6 +82,37 @@
}
};
HeadlessConsoleReporter.prototype.reportSpecWaiting = function() {
var first, runner;
var _this = this;
runner = null;
if (!this.timer) {
this.timer = true;
first = true;
runner = function() {
return _this.timer = setTimeout(function() {
if (_this.timer) {
if (!first) JHW.stdout.print(Intense.moveBack());
JHW.stdout.print(_this.positions.substr(_this.position, 1).foreground('yellow'));
_this.position += 1;
_this.position %= _this.positions.length;
first = false;
return runner();
}
}, 750);
};
return runner();
}
};
HeadlessConsoleReporter.prototype.reportSpecRunning = function() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
return JHW.stdout.print(Intense.moveBack());
}
};
HeadlessConsoleReporter.prototype.reportSuiteResults = function(suite) {};
HeadlessConsoleReporter.prototype.hasError = function() {