Index: lib/rspec_on_rails.rb =================================================================== --- lib/rspec_on_rails.rb (revision 789) +++ lib/rspec_on_rails.rb (working copy) @@ -114,6 +114,10 @@ rendered = expected ? rendered_file(!expected.include?('/')) : rendered_file expected.should_equal rendered end + + def rjs + RjsResponseBody.new(self.body) + end end end Index: lib/arts.rb =================================================================== --- lib/arts.rb (revision 0) +++ lib/arts.rb (revision 0) @@ -0,0 +1,119 @@ +class RjsResponseBody < String + def should(action, *args, &block) + respond_to?("assert_rjs_#{action}") ? + send("assert_rjs_#{action}", *args) : + lined_response.should_include(create_generator.send(action, *args, &block)) + end + + def should_not(action, *args, &block) + lambda {should(action, *args, &block)}.should_raise Spec::Api::ExpectationNotMetError + end + + include ActionView::Helpers::PrototypeHelper + include ActionView::Helpers::ScriptaculousHelper + include ActionView::Helpers::JavaScriptHelper + + include ActionView::Helpers::UrlHelper + include ActionView::Helpers::TagHelper + + def assert_rjs_insert_html(*args) + position = args.shift + item_id = args.shift + + content = extract_matchable_content(args) + + unless content.blank? + case content + when Regexp + self.to_s.should_match Regexp.new("new Insertion\.#{position.to_s.camelize}(.*#{item_id}.*,.*#{content.source}.*);") + when String + lined_response.should_include("new Insertion.#{position.to_s.camelize}(\"#{item_id}\", #{content});") + else + raise "Invalid content type" + end + else + self.to_s.should_match Regexp.new("new Insertion\.#{position.to_s.camelize}(.*#{item_id}.*,.*?);") + end + end + + def assert_rjs_replace_html(*args) + div = args.shift + content = extract_matchable_content(args) + + unless content.blank? + case content + when Regexp + self.to_s.should_match Regexp.new("Element.update(.*#{div}.*,.*#{content.source}.*);") + when String + lined_response.should_include("Element.update(\"#{div}\", #{content});") + else + raise "Invalid content type" + end + else + self.to_s.should_match Regexp.new("Element.update(.*#{div}.*,.*?);") + end + end + + def assert_rjs_replace(*args) + div = args.shift + content = extract_matchable_content(args) + + unless content.blank? + case content + when Regexp + self.to_s.should_match Regexp.new("Element.replace(.*#{div}.*,.*#{content.source}.*);") + when String + lined_response.include?("Element.replace(\"#{div}\", #{content});") + else + raise "Invalid content type" + end + else + self.to_s.should_match Regexp.new("Element.replace(.*#{div}.*,.*?);") + end + end + + # To deal with [] syntax. I hate JavaScriptProxy so.. SO very much + def assert_rjs_page(*args) + content = build_method_chain!(args) + self.to_s.should_match Regexp.new(Regexp.escape(content)) + end + + protected + + def build_method_chain!(args) + content = create_generator.send(:[], args.shift) # start $('some_id').... + + while !args.empty? + if (method = args.shift.to_s) =~ /(.*)=$/ + content = content.__send__(method, args.shift) + break + else + content = content.__send__(method) + content = content.__send__(:function_chain).first if args.empty? + end + end + + content + end + + def lined_response + self.to_s.split("\n") + end + + def create_generator + block = Proc.new { |*args| yield *args if block_given? } + JavaScriptGenerator.new self, &block + end + + def generic_error(action, args) + "#{action} with args [#{args.join(" ")}] does not show up in response:\n#{lined_response}" + end + + def extract_matchable_content(args) + if args.size == 1 and args.first.is_a? Regexp + return args.first + else + return create_generator.send(:arguments_for_call, args) + end + end +end \ No newline at end of file