diff --git a/lib/jasmine/headless/files_list.rb b/lib/jasmine/headless/files_list.rb index 5c8f8be..ed37c43 100644 --- a/lib/jasmine/headless/files_list.rb +++ b/lib/jasmine/headless/files_list.rb @@ -1,44 +1,42 @@ require 'jasmine-core' require 'time' require 'multi_json' -require 'set' -require 'sprockets/directive_processor' module Jasmine::Headless class FilesList - attr_reader :spec_outside_scope - class << self - def find_vendored_asset_paths(*names) + 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) - 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 + @vendor_asset_paths = [] + + Gem::Specification.map { |spec| + path = File.join(spec.gem_dir, 'vendor/assets/javascripts') + + File.directory?(path) ? path : nil + }.compact end end - DEFAULT_FILES = - %w{jasmine.js jasmine-html.js jasmine.css}.collect { |name| File.join(Jasmine::Core.path, name) } + - %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 - } + DEFAULT_FILES = %w{jasmine.js jasmine-html jasmine.css jasmine-extensions intense headless_reporter_result jasmine.HeadlessConsoleReporter jsDump beautify-html} PLEASE_WAIT_IM_WORKING_TIME = 2 def initialize(options = {}) @options = options - @files = Set.new(DEFAULT_FILES.dup) - @filtered_files = @files.dup + + @files = [] + @filtered_files = [] + + DEFAULT_FILES.each { |file| add_dependency('require', file) } + @spec_outside_scope = false - @spec_files = Set.new + @spec_files = [] + use_config! if config? end @@ -54,6 +52,10 @@ module Jasmine::Headless @spec_files.to_a end + def search_paths + @search_paths ||= [ Jasmine::Core.path, src_dir, spec_dir ] + self.class.vendor_asset_paths + end + def has_spec_outside_scope? @spec_outside_scope end @@ -82,16 +84,35 @@ module Jasmine::Headless }.compact] end - def add_dependencies(file) - if File.file?(file) - processor = Sprockets::DirectiveProcessor.new(file) - processor.directives.each do |line, type, name| - case type - when 'require' - find_vendored(name) + def add_dependencies(file, source_root) + TestFile.new(file, source_root).dependencies.each { |type, name| add_dependency(type, name) } + end + + def add_dependency(type, file) + if result = find_dependency(file) + path, source_root = result + + case type + when 'require' + add_file(path, source_root) + end + end + end + + def find_dependency(file) + search_paths.each do |dir| + if file[%r{\.(js|css|coffee)$}] + if File.file?(path = File.join(dir, file)) + return [ File.expand_path(path), dir ] + end + else + if path = Dir[File.join(dir, "#{file}.*")].first + return [ File.expand_path(path), dir ] end end end + + false end private @@ -132,33 +153,23 @@ module Jasmine::Headless @config = @options[:config].dup - %w{src_files stylesheets vendored_helpers helpers spec_files}.each do |searches| + %w{src_files stylesheets helpers spec_files}.each do |searches| if data = @config[searches] - if self.respond_to?("add_#{searches}_files", true) - send("add_#{searches}_files", data.flatten) - else - add_files(data.flatten, searches) - end - end - end - end - - def add_vendored_helpers_files(searches) - searches.each do |name| - self.class.find_vendored_asset_path(name).each do |file| - add_file(file) + add_files(data.flatten, searches) end end end def add_files(searches, type) searches.each do |search| - path = search - path = File.join(@config[SEARCH_ROOTS[type]], path) if @config[SEARCH_ROOTS[type]] + dir = @config[SEARCH_ROOTS[type]] || Dir.pwd + + path = File.expand_path(File.join(dir, search)) + found_files = expanded_dir(path) - files found_files.each do |file| - type == 'spec_files' ? add_spec_file(file) : add_file(file) + type == 'spec_files' ? add_spec_file(file) : add_file(file, dir) end end @@ -177,22 +188,22 @@ module Jasmine::Headless Dir[path].collect { |file| File.expand_path(file) } end - def add_file(file) - add_dependencies(file) + def add_file(file, source_root) + add_dependencies(file, source_root) - @files << file - @filtered_files << file + @files << file if !@files.include?(file) + @filtered_files << file if !@filtered_files.include?(file) end def add_spec_file(file) - add_dependencies(file) + add_dependencies(file, spec_dir) if !@files.include?(file) - @files << file + @files << file if !@files.include?(file) if include_spec_file?(file) - @filtered_files << file - @spec_files << file if spec_filter.empty? || spec_filter.include?(file) + @filtered_files << file if !@filtered_files.include?(file) + @spec_files << file if !@spec_files.include?(file) && spec_filter.empty? || spec_filter.include?(file) end true @@ -203,6 +214,23 @@ module Jasmine::Headless spec_filter.empty? || spec_filter.include?(file) end + def src_dir + config_dir_or_pwd('src_dir') + end + + def spec_dir + config_dir_or_pwd('spec_dir') + end + + def config_dir_or_pwd(dir) + found_dir = Dir.pwd + + if @options[:config] + found_dir = @options[:config][dir] || found_dir + end + + found_dir + end end end diff --git a/lib/jasmine/headless/test_file.rb b/lib/jasmine/headless/test_file.rb index cf12667..9605d2b 100644 --- a/lib/jasmine/headless/test_file.rb +++ b/lib/jasmine/headless/test_file.rb @@ -1,11 +1,12 @@ require 'rainbow' +require 'sprockets/directive_processor' module Jasmine::Headless class TestFile - attr_reader :path + attr_reader :path, :source_root - def initialize(path) - @path = path + def initialize(path, source_root = nil) + @path, @source_root = path, source_root end def ==(other) @@ -27,7 +28,7 @@ module Jasmine::Headless %{} end rescue CoffeeScript::CompilationError => ne - puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), path.color(:yellow), ne.message.to_s.color(:white) ] + puts "[%s] %s: %s" % [ 'coffeescript'.color(:red), path.color(:yellow), ne.message.dup.to_s.color(:white) ] raise ne rescue StandardError => e puts "[%s] Error in compiling file: %s" % [ 'coffeescript'.color(:red), path.color(:yellow) ] @@ -39,5 +40,19 @@ module Jasmine::Headless %{} end end + + def dependencies + return @dependencies if @dependencies + + processor = Sprockets::DirectiveProcessor.new(path) + @dependencies = processor.directives.collect do |_, type, name| + if name[%r{^./}] + name = File.expand_path(File.join(File.dirname(path), name)).gsub(%r{^#{source_root}/}, '') + end + + [ type, name ] + end + end end end + diff --git a/spec/bin/jasmine-headless-webkit_spec.rb b/spec/bin/jasmine-headless-webkit_spec.rb index 9105391..e8fcbf9 100644 --- a/spec/bin/jasmine-headless-webkit_spec.rb +++ b/spec/bin/jasmine-headless-webkit_spec.rb @@ -144,14 +144,14 @@ describe "jasmine-headless-webkit" do files = %x{bin/jasmine-headless-webkit -l -j spec/jasmine/with_sprockets_includes/with_sprockets_includes.yml} $?.exitstatus.should == 0 - puts files - - files.lines.to_a.should include('vendor/assets/javascripts/jquery.js') - files.lines.to_a.should include('assets/code.js') - files.lines.to_a.should include('assets/required.js') - files.lines.to_a.should include('assets/subcode/more_code.js') - files.lines.to_a.should include('spec/spec_helper.js') - files.lines.to_a.should include('spec/code_spec.js') + files.lines.to_a.should contain_in_order_in_file_list( + 'vendor/assets/javascripts/jquery.js', + '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 diff --git a/spec/jasmine/with_sprockets_includes/assets/code.js b/spec/jasmine/with_sprockets_includes/assets/code.js deleted file mode 100644 index bd8cb0d..0000000 --- a/spec/jasmine/with_sprockets_includes/assets/code.js +++ /dev/null @@ -1,2 +0,0 @@ -window.a = '1'; - diff --git a/spec/jasmine/with_sprockets_includes/assets/required.js b/spec/jasmine/with_sprockets_includes/assets/required.js deleted file mode 100644 index e69de29..0000000 diff --git a/spec/jasmine/with_sprockets_includes/assets/things/code.js b/spec/jasmine/with_sprockets_includes/assets/things/code.js new file mode 100644 index 0000000..bb2e8ae --- /dev/null +++ b/spec/jasmine/with_sprockets_includes/assets/things/code.js @@ -0,0 +1,4 @@ +//= require 'things/required' + +window.a = '1'; + diff --git a/spec/jasmine/with_sprockets_includes/assets/things/required.js b/spec/jasmine/with_sprockets_includes/assets/things/required.js new file mode 100644 index 0000000..18241c9 --- /dev/null +++ b/spec/jasmine/with_sprockets_includes/assets/things/required.js @@ -0,0 +1,2 @@ +//= require 'jquery' + diff --git a/spec/jasmine/with_sprockets_includes/assets/subcode/more_code.js b/spec/jasmine/with_sprockets_includes/assets/things/subcode/more_code.js similarity index 100% rename from spec/jasmine/with_sprockets_includes/assets/subcode/more_code.js rename to spec/jasmine/with_sprockets_includes/assets/things/subcode/more_code.js diff --git a/spec/jasmine/with_sprockets_includes/spec/code_spec.js b/spec/jasmine/with_sprockets_includes/spec/things/code_spec.js similarity index 100% rename from spec/jasmine/with_sprockets_includes/spec/code_spec.js rename to spec/jasmine/with_sprockets_includes/spec/things/code_spec.js diff --git a/spec/jasmine/with_sprockets_includes/with_sprockets_includes.yml b/spec/jasmine/with_sprockets_includes/with_sprockets_includes.yml index 3b859d0..f5943f8 100644 --- a/spec/jasmine/with_sprockets_includes/with_sprockets_includes.yml +++ b/spec/jasmine/with_sprockets_includes/with_sprockets_includes.yml @@ -2,10 +2,10 @@ src_dir: spec/jasmine/with_sprockets_includes/assets spec_dir: spec/jasmine/with_sprockets_includes/spec spec_files: - - "*_spec.js" + - "**/*_spec.js" src_files: - - "*.js" + - "things/**/*.js" helpers: - "spec_helper.js" diff --git a/spec/lib/jasmine/headless/files_list_spec.rb b/spec/lib/jasmine/headless/files_list_spec.rb index 2bf78ea..ec53257 100644 --- a/spec/lib/jasmine/headless/files_list_spec.rb +++ b/spec/lib/jasmine/headless/files_list_spec.rb @@ -46,7 +46,7 @@ describe Jasmine::Headless::FilesList do shared_examples_for :reading_data do let(:expected_files) do - Jasmine::Headless::FilesList::DEFAULT_FILES + [ + [ File.expand_path(first_file), File.expand_path(src_file), File.expand_path(stylesheet_file), @@ -87,33 +87,6 @@ describe Jasmine::Headless::FilesList do 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 @@ -248,46 +221,120 @@ describe Jasmine::Headless::FilesList do end end - describe '#add_dependencies' do - include FakeFS::SpecHelpers - - let(:file) { 'file.js' } + describe '#add_dependency' do + let(:file) { 'file' } + let(:other_file) { 'other' } + let(:path) { 'path' } before do - File.open(file, 'wb') { |fh| fh.print data } + files_list.stubs(:find_dependency).with(file).returns(path) + files_list.stubs(:find_dependency).with(other_file).returns(false) end - subject { files_list.add_dependencies(file) } - - context 'no requires' do - let(:data) { 'javascript' } - + context 'not found' do before do files_list.expects(:add_file).never end - it 'should succeed' do - subject + it 'should do nothing' do + files_list.add_dependency('', other_file) end end context 'require' do - let(:data) { %{//= require 'other'\njavascript} } - before do - File.open(other, 'wb') + files_list.expects(:add_file).with(path, nil) end - context 'with js' do - let(:other) { 'other.js' } + it 'should add the file to the front' do + files_list.add_dependency('require', file) + end + end + end - before do - files_list.expects(:add_file).with(other) - end + describe '#search_paths' do + let(:files_list) { described_class.new(:config => config) } - it 'should succeed' do - subject - end + let(:config) { { + 'src_dir' => src_dir, + 'spec_dir' => spec_dir + } } + + let(:src_dir) { 'src dir' } + let(:spec_dir) { 'spec dir' } + let(:path) { 'path' } + + context 'no vendored gem paths' do + before do + Jasmine::Headless::FilesList.stubs(:vendor_asset_paths).returns([]) + end + + it 'should take the src dir and spec dirs' do + files_list.search_paths.should == [ Jasmine::Core.path, src_dir, 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, src_dir, spec_dir, path ] + 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 '#find_dependency' do + include FakeFS::SpecHelpers + + let(:dir) { File.expand_path('dir') } + let(:filename) { 'file' } + let(:file) { "#{filename}.js" } + + before do + files_list.stubs(:search_paths).returns([ dir ]) + + FileUtils.mkdir_p dir + end + + context 'does not exist' do + it 'should not be found' do + files_list.find_dependency(file).should be_false + end + end + + context 'exists' do + let(:path) { File.join(dir, file) } + + before do + File.open(path, 'wb') + end + + it 'should be found' do + files_list.find_dependency(filename).should == [ File.expand_path(path), dir ] end end end diff --git a/spec/lib/jasmine/headless/test_file_spec.rb b/spec/lib/jasmine/headless/test_file_spec.rb index f916d9a..8758ba0 100644 --- a/spec/lib/jasmine/headless/test_file_spec.rb +++ b/spec/lib/jasmine/headless/test_file_spec.rb @@ -1,8 +1,10 @@ require 'spec_helper' describe Jasmine::Headless::TestFile do - let(:file) { described_class.new(path) } - let(:path) { 'path' } + let(:source_root) { File.expand_path('source_root') } + let(:path) { File.join(source_root, 'path.js') } + + let(:file) { described_class.new(path, source_root) } subject { file } @@ -36,7 +38,7 @@ describe Jasmine::Headless::TestFile do end it 'should pass along the error' do - expect { subject }.to raise_error(error) + expect { subject }.to raise_error(CoffeeScript::CompilationError) end end @@ -71,4 +73,31 @@ describe Jasmine::Headless::TestFile do end end end + + describe '#dependencies' do + include FakeFS::SpecHelpers + + before do + FileUtils.mkdir_p File.dirname(path) + File.open(path, 'wb') { |fh| fh.print "//= require '#{req}'\njavascript" } + end + + context 'absolute' do + let(:req) { 'test' } + + subject { file.dependencies } + + it { should == [ [ 'require', req ] ] } + end + + context 'relative' do + let(:path) { File.join(source_root, 'subdir/subsubdir/path.js') } + + let(:req) { './test' } + + subject { file.dependencies } + + it { should == [ [ 'require', 'subdir/subsubdir/test' ] ] } + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2348573..0066121 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,6 +6,7 @@ RSpec.configure do |c| c.before(:each) do Jasmine::Headless::CacheableAction.enabled = false + Jasmine::Headless::FilesList.instance_variable_set(:@vendor_asset_paths, nil) end end @@ -51,4 +52,21 @@ 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 + end end +