johnbintz / jasmine-headless-webkit

This project is dead. You should use Karma instead. I do.
http://karma-runner.github.io/
196 stars 99 forks source link

Sprockets not compiling JavaScript templates #102

Open andrewdeandrade opened 12 years ago

andrewdeandrade commented 12 years ago

When sprockets handles template assets it moves from right to left compiling a template and then adding it to the JST array. So if a file is template.jst.hbs, it will first take the template and package it as an hbs object and then it will wrap it as an object in a this.JST array.

Here's one of my Handlebars templates compiled correctly when I run my server normally or run rake jasmine

(function() {
  this.JST || (this.JST = {});
  this.JST["mobile/meeting/story_feed_item"] = (function() {
              this.HandlebarsTemplates || (this.HandlebarsTemplates = {});
              this.HandlebarsTemplates["mobile/meeting/story_feed_item"] = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
    helpers = helpers || Handlebars.helpers;
    var buffer = "", stack1, self=this, functionType="function", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;

    buffer += "<li data-user-id=\"";
    stack1 = helpers.story || depth0.story;
    stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.user_id);
    if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
    else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "story.user_id", { hash: {} }); }
    buffer += escapeExpression(stack1) + "\" class=\"feed_story ";
    stack1 = helpers.story || depth0.story;
    stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.action);
    if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
    else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "story.action", { hash: {} }); }
    buffer += escapeExpression(stack1) + " ";
    stack1 = helpers.self || depth0.self;
    if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
    else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "self", { hash: {} }); }
    buffer += escapeExpression(stack1) + "\">\n  <div class=\"story_content\">\n    <span class=\"user_name\">";
    stack1 = helpers.story || depth0.story;
    stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.invitee_name);
    if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
    else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "story.invitee_name", { hash: {} }); }
    buffer += escapeExpression(stack1) + "</span>\n    <span class=\"content\">";
    stack1 = helpers.story || depth0.story;
    stack1 = (stack1 === null || stack1 === undefined || stack1 === false ? stack1 : stack1.content);
    if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }
    else if(stack1=== undef) { stack1 = helperMissing.call(depth0, "story.content", { hash: {} }); }
    buffer += escapeExpression(stack1) + "</span>\n  </div>\n</li>\n";
    return buffer;});
              return HandlebarsTemplates["mobile/meeting/story_feed_item"];
            }).call(this);;
}).call(this);

It looks like Sprockets isn't being called so that it handles template precompiling correctly. Here is the jasmine-headless-webkit output for the same file:

<script type="text/javascript">(function() {
  this.JST || (this.JST = {});
  this.JST["mobile/meeting/story_feed_item"] = <li data-user-id="{{story.user_id}}" class="feed_story {{story.action}} {{self}}">
    <div class="story_content">
      <span class="user_name">{{story.invitee_name}}</span>
      <span class="content">{{story.content}}</span>
    </div>
  </li>;
}).call(this);
</script>

In this script, the template string is being compiled straight to an object in the this.JST array, without being processed by Handlebars (or any other templating system) first. I observed this same issue with EJS files.

Any clue why this my not be working with JHW, but work via rake jasmine? Thanks!

johnbintz commented 12 years ago

What gem are you using to perform Handlebars compilation in your application?

andrewdeandrade commented 12 years ago

Les Hill's handlebars_assets github.com/leshill/handlebars_assets

I'm looking through the jasmine-gem source now to see exactly how they call and compile templates via sprockets. Oddly I can't find any reference to Sprockets::JstProcessor, nor do I see any reference to either Sprockets or JST.

andrewdeandrade commented 12 years ago

I figured out the cause. Trying to find a solution.

Basically, the code right now is calling JstProcessor directly. It needs to call the sprockets function that takes a file and analyzes it and processes via the appropriate engine based on the file extension.

andrewdeandrade commented 12 years ago

Looks like the code should instead call the Sprockets::Environment.find_assets method. http://rubydoc.info/gems/sprockets/2.0.0/Sprockets/Environment:find_asset

AFAICT the find_assets method take a path to a file, finds the file, processes/builds the file and returns the result

johnbintz commented 12 years ago

I am using find_asset to process files:

https://github.com/johnbintz/jasmine-headless-webkit/blob/master/lib/jasmine/headless/files_list.rb#L88 https://github.com/johnbintz/jasmine-headless-webkit/blob/master/lib/jasmine/headless/files_list.rb#L182

The real issue is including outside libraries like handlebars_assets. One typically uses Sprockets with Rails, and Rails does Bundler.require(:default, ENV['RAILS_ENV'].to_sym) which includes things like handlebars_assets.

However, I want to be able to use JHW without having to load all of Rails, as it's not a Rails-only project. Since this is all still pretty new for me, I was only maybe-requiring haml-sprockets, where the act of requiring it loads it in to the Sprockets environment.

I just pushed to master with two changes:

JHW_ENV=jasmine bundle exec jasmine-headless-webkit

and have this in your Gemfile:

group :jasmine do
  gem 'handlebars_assets'
  gem 'haml-sprockets'
end

Give it a shot.

andrewdeandrade commented 12 years ago

Didn't work.

Weird, I put gem 'jasmine-headless-webkit', :git => 'git://github.com/johnbintz/jasmine-headless-webkit.git', :branch => 'master' in my Gemfile and executed bundle install and it pulled your gem just fine, but when I go to ~/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/jasmine-headless-webkit-0.8.4/ and browse the project, I see no reference to handlebars_assets in the project.

For whatever reason, defining the github repository in my Gemfile didn't work. I had to clone your repository manually and rake build and then install the manually built local gem to get it installed in my project. Then I tried running jasmine-headless-webkit again and got this error:

[ruby-1.9.3-p0@improvisu] [~/code/improvisu] [working]$ jasmine-headless-webkit --runner-out tmp/temp.html 
[jasmine-headless-webkit] uninitialized constant ActionController (NameError)
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/devise_invitable-0.5.7/lib/devise_invitable/controllers/helpers.rb:7:in `<top (required)>'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/devise_invitable-0.5.7/lib/devise_invitable.rb:11:in `<top (required)>'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/bundler-1.0.21/lib/bundler/runtime.rb:68:in `require'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/bundler-1.0.21/lib/bundler/runtime.rb:68:in `block (2 levels) in require'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/bundler-1.0.21/lib/bundler/runtime.rb:66:in `each'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/bundler-1.0.21/lib/bundler/runtime.rb:66:in `block in require'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/bundler-1.0.21/lib/bundler/runtime.rb:55:in `each'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/bundler-1.0.21/lib/bundler/runtime.rb:55:in `require'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/bundler-1.0.21/lib/bundler.rb:122:in `require'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/files_list.rb:58:in `reset!'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/runner.rb:73:in `run'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/command_line.rb:18:in `run!'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/gems/jasmine-headless-webkit-0.8.4/bin/jasmine-headless-webkit:10:in `<top (required)>'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/bin/jasmine-headless-webkit:19:in `load'
  /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0@improvisu/bin/jasmine-headless-webkit:19:in `<main>'

This is all pretty new to me as well. This is my first time delving into someone else's gem and trying to debug it. I'm also pretty new to Ruby as well. I spend most of my time with Javascript.

PS, when I ran rake build I got this deprecation error:

[ruby-1.9.3-p0] [~/code/jasmine-headless-webkit] [working]$ rake build
/Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/rake-0.8.7/lib/rake/alt_system.rb:32: Use RbConfig instead of obsolete and deprecated Config.
(in /Users/andrewdeandrade/code/jasmine-headless-webkit)
jasmine-headless-webkit 0.8.4 built to pkg/jasmine-headless-webkit-0.8.4.gem
andrewdeandrade commented 12 years ago

John,

Here's some more info:

I tried installing your new version of JHW into that backbone-jasmine-examples project and running it there and got the following error:

[ruby-1.9.3-p0] [~/code/backbone-jasmine-examples] [working]$ gem install ../jasmine-headless-webkit/pkg/jasmine-headless-webkit-0.8.4.gem 
Building native extensions.  This could take a while...
Successfully installed jasmine-headless-webkit-0.8.4
1 gem installed
Installing ri documentation for jasmine-headless-webkit-0.8.4...
Installing RDoc documentation for jasmine-headless-webkit-0.8.4...

[ruby-1.9.3-p0] [~/code/backbone-jasmine-examples] [working]$ gem install jasmine-headless-webkit
/Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/files_list.rb:65:in `block (2 levels) in reset!': cannot load such file -- jasmine/headless/nil_template (LoadError)
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/files_list.rb:64:in `each'
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/files_list.rb:64:in `block in reset!'
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/files_list.rb:63:in `instance_eval'
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/files_list.rb:63:in `reset!'
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/runner.rb:73:in `run'
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/jasmine-headless-webkit-0.8.4/lib/jasmine/headless/command_line.rb:18:in `run!'
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/gems/jasmine-headless-webkit-0.8.4/bin/jasmine-headless-webkit:10:in `<top (required)>'
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/bin/jasmine-headless-webkit:19:in `load'
    from /Users/andrewdeandrade/.rvm/gems/ruby-1.9.3-p0/bin/jasmine-headless-webkit:19:in `<main>'
johnbintz commented 12 years ago

In relation to a pull request someone submitted, I'll be taking a look at how other Sprockets gems are integrated more closely once I get reporters cleaned up and Qt 4.8.0 issues resolved. I can do more work on cleaning all this up then. I'll keep this open for now to remind me to look at it later.

andrewdeandrade commented 12 years ago

Cool deal. Let me know if you need any more info on this when you get around to it. Thanks

atroche commented 12 years ago

My JavaScript Template (JST) files aren't being compiled and included in my tests. They work fine with the browser-based /specs/, but when I use jasmine-headless-webkit, the global JST object is just set to {}.

Has anyone else had this problem? Is there anything I can do to help debug it?

johnbintz commented 12 years ago

What are your templates written in?

kevinrobinson commented 12 years ago

I'm having the same problem, using the handlebars_assets gem. If I run my tests through jasmine-headless-webkit and the JST object is empty. I tried putting handlebars_assets in the jasmine group in my Gemfile as suggested above, but no success. Any other ideas on this?

Thanks!

madtrick commented 12 years ago

Another one here with an empty JST object. I'm using .jst.eco templates and the processing gem is the eco one.

Update: Actually I found out that my problem is as this one #issue138. My .jst.eco files are processed but stored on a diferent path

rsachdeva commented 12 years ago

Same issue running bundle exec jasmine-headless-webkit, empty {} for JST. Using .jst.eco. Result: TypeError: Result of expression 'this.template' [undefined] is not a function.

class Some.Views.EntriesIndex extends Backbone.View

template: JST['entries/index']

render: ->

$(@el).html(@template(entries: "Entries goes here"))

console.log(JST)
coll_temp = @template(entries: @collection)
$(@el).html(coll_temp)
this
conzett commented 12 years ago

Any update on this? I am also experiencing this issue using EJS templates. The global JST object is empty, but the jst.ejs files are included when I run jasmine-headless-webkit -l.

kevinrobinson commented 12 years ago

This was my workaround for using jasmine-headless-webkit on a Rails project that used the handlebars_assets gem. It's not a general solution, but maybe will be helpful to others.

Before my 'jhw' alias runs jasmine-headless-webkit, it compiles the project's Handlebars templates into a single JavaScript file using the Handlebars node module. This produces a slightly different output than the handlebars_assets gem does, so I added a file to my Jasmine helpers that translates that output into the format that handlebars_assets would provide in the Rails app itself. Here's that file:

/*
This function takes the output from the Handlebars node.js compiler and translates it into the format
that the handlebars_assets gem would produce through Sprockets.  This lets the Jasmine unit tests have
access to precompiled templates in the HandlebarsTemplates object the way the application code expects.
It also takes the compiled partials and registers them.
*/
(function() {
  HandlebarsTemplates = {};
  _.keys(Handlebars.templates).forEach(function(inputKey) {
    var matches = inputKey.match(new RegExp(/([\w\/]*)\.jst\.hbs/));
    if (!matches || matches.length === 0) throw new Error('could not match Handlebars.templates inputKey: ' + inputKey);
    var outputPath = matches[1];

    //Register partials and put templates into HandlebarsTemplates
    var outputParts = outputPath.split('/');
    if (outputParts[0] === 'partials') {
      Handlebars.registerPartial(outputParts[1].substr(1), Handlebars.templates[inputKey])
    } else {
      HandlebarsTemplates[outputPath] = Handlebars.templates[inputKey];
    }
  });
})();

Not sure if this will be helpful to anyone else, but thought I'd share.

ku1ik commented 12 years ago

Same problem here with handlebars_assets.

buger commented 11 years ago

Working great with this tip: https://github.com/johnbintz/jasmine-headless-webkit/pull/137/files