Adding Jasmine-Parser gem to generate JS stack trace in Rspec #140

Closed
wants to merge 3 commits into
from
View
@@ -71,4 +71,5 @@ Gem::Specification.new do |s|
s.add_dependency 'rack', '~> 1.0'
s.add_dependency 'rspec', '>= 1.3.1'
s.add_dependency 'selenium-webdriver', '>= 0.1.3'
+ s.add_dependency 'jasmine-parser', '>= 0.0.1'
end
@@ -1,8 +1,8 @@
module Jasmine
class Configuration
attr_writer :jasmine_css_files, :css_files
- attr_writer :jasmine_files, :boot_files, :src_files, :spec_files
- attr_accessor :jasmine_path, :spec_path, :boot_path, :src_path
+ attr_writer :jasmine_files, :boot_files, :src_files
+ attr_accessor :jasmine_path, :spec_path, :boot_path, :src_path, :spec_files
attr_accessor :jasmine_dir, :spec_dir, :boot_dir, :src_dir
#TODO: these are largely client concerns, move them.
attr_accessor :port, :browser, :host, :result_batch_size
@@ -10,28 +10,22 @@ def process(results_hash, suites_hash)
end
def example_locations
- # example_locations = {}
- # example_name_parts = []
- # previous_indent_level = 0
- # @config.spec_files_full_paths.each do |filename|
- # line_number = 1
- # File.open(filename, "r") do |file|
- # file.readlines.each do |line|
- # match = /^(\s*)(describe|it)\s*\(\s*["'](.*)["']\s*,\s*function/.match(line)
- # if (match)
- # indent_level = match[1].length / 2
- # example_name = match[3]
- # example_name_parts[indent_level] = example_name
-
- # full_example_name = example_name_parts.slice(0, indent_level + 1).join(" ")
- # example_locations[full_example_name] = "#{filename}:#{line_number}: in `it'"
- # end
- # line_number += 1
- # end
- # end
- # end
- # example_locations
- {}
+ @suite_parser ||= parse_suite
+ end
+
+ private
+
+ def parse_suite
+ require 'jasmine-parser'
+ JasmineParser::Config.logging=[:info, :error]
+
+ suite = JasmineParser::JasmineSuite.new
+ parser = JasmineParser::FileParser.new(suite)
+
+
+ parser.parse @config.spec_files.call
+
+ suite
end
end
@@ -0,0 +1,36 @@
+require "spec/example/example_methods"
+module Spec
+ module Example
+ module ExampleMethods
+ def execute(run_options, instance_variables) # :nodoc:
+ run_options.reporter.example_started(@_proxy)
+ set_instance_variables_from_hash(instance_variables)
+
+ execution_error = nil
+ Timeout.timeout(run_options.timeout) do
+ begin
+ before_each_example
+ instance_eval(&@_implementation)
+ rescue Interrupt
+ exit 1
+ rescue Exception => e
+ e.backtrace.unshift @_proxy.location #Adding these 2 lines here to pre-pend the JS stack on top of the
+ e.backtrace.flatten!
+ e.backtrace.compact! #ruby stack trace
+ execution_error ||= e
+ end
+ begin
+ after_each_example
+ rescue Interrupt
+ exit 1
+ rescue Exception => e
+ execution_error ||= e
+ end
+ end
+
+ run_options.reporter.example_finished(@_proxy.update(description), execution_error)
+ success = execution_error.nil? || ExamplePendingError === execution_error
+ end
+ end
+ end
+end
@@ -0,0 +1,54 @@
+require "rspec/core/example"
+module RSpec
+ module Core
+
+ class Example
+ def run(example_group_instance, reporter)
+ @example_group_instance = example_group_instance
+ @example_group_instance.example = self
+
+ start(reporter)
+
+ begin
+ unless pending
+ with_around_each_hooks do
+ begin
+ run_before_each
+ @example_group_instance.instance_eval(&@example_block)
+ rescue Pending::PendingDeclaredInExample => e
+ @pending_declared_in_example = e.message
+ rescue Exception => e
+
+ #Insert the backtrace from jasmine on top of the the regular ruby backtrace
+ #Note: options is depricated method, and should use metadata instead.
+ if options[:jasmine_backtrace]
+ e.backtrace.unshift options[:jasmine_backtrace]
+ e.backtrace.flatten!
+ e.backtrace.compact!
+ end
+ set_exception(e)
+ ensure
+ run_after_each
+ end
+ end
+ end
+ rescue Exception => e
+ set_exception(e)
+ ensure
+ @example_group_instance.instance_variables.each do |ivar|
+ @example_group_instance.instance_variable_set(ivar, nil)
+ end
+ @example_group_instance = nil
+
+ begin
+ assign_generated_description
+ rescue Exception => e
+ set_exception(e, "while assigning the example description")
+ end
+ end
+
+ finish(reporter)
+ end
+ end
+ end
+end
@@ -20,7 +20,8 @@ def process_children(parent, children)
children.each do |suite_or_spec|
type = suite_or_spec["type"]
if type == "suite"
- process_children(parent.describe(suite_or_spec["name"]), suite_or_spec["children"])
+ grand_parent_and_parent = example_group(parent.description + " " + suite_or_spec["name"]) {}
+ process_children(grand_parent_and_parent, suite_or_spec["children"])
elsif type == "spec"
declare_spec(parent, suite_or_spec)
else
@@ -34,7 +35,7 @@ def declare_spec(parent, spec)
example_name = spec["name"]
backtrace = @results.example_location_for(parent.description + " " + example_name)
if Jasmine::Dependencies.rspec2?
- parent.it example_name, {} do
+ parent.it example_name, {:jasmine_backtrace => backtrace} do
me.report_spec(spec["id"])
end
else
View
@@ -2,10 +2,13 @@
require 'rubygems'
require 'jasmine'
+
if Jasmine::Dependencies.rspec2?
require 'rspec'
+ require 'jasmine/rspec_2_backtrace'
else
require 'spec'
+ require 'jasmine/rspec_1_backtrace'
end
jasmine_yml = File.join(Dir.pwd, 'spec', 'javascripts', 'support', 'jasmine.yml')
@@ -52,7 +52,8 @@ def spec_ids
end
def wait_for_suites_to_finish_running
- puts "Waiting for suite to finish in browser ..."
+ puts "Waiting for suite to finish in browser and parsing SPEC files ..."
+ @results_processor.example_locations
while !eval_js('return jsApiReporter.finished') do
sleep 0.1
end
View
@@ -16,8 +16,8 @@
end
it "should return an example location for a particular string" do
- example_location1 = {:some => 'spec location'}
- example_location2 = {:some => 'other spec location'}
+ example_location1 = ["file1", "file2", "file3"]
+ example_location2 = ["file4", "file5"]
example_locations = {'foo bar' => example_location1, 'baz quux' => example_location2 }
results = Jasmine::Results.new({}, {}, example_locations)
results.example_location_for('foo bar').should == example_location1