-->

Testing backbone views with jasmine

2019-07-31 02:24发布

问题:

I am trying to test my backbone views with jasmine. I use underscore library to generate templates for the backbone views.

For testing purposes I use jasmine jasmine-jquery

I am unable to load the fixtures in the jasmine tests as the views have embeded ruby. Here is my code

Backbone view

AlbumView = Backbone.View.extend({
    template: _.template($('#album-template').html()),
    render: function() {
        $('#albums').append(this.template(this.model.attributes));
    }
});

This view uses the following template

Album template album_template.html.erb

<script type="text/html" id="album-template">
  <a href="<%%= url %>" class="album <%%= is_owner %>">
        <%% if (viewable) { %>
            <span class="album-cover">
                <span class="photo" style="background-image:url('<%%= small_thumbnail_url %>'); width: 160px; height: 160px;">
                    <span class="glossy-overlay"></span>
                </span>
            </span>
            <%% } %>
            <h3><%%= name %></h3>
            <p>
                <%%= number_of_photos %>
            </p>
    </a>
</script>

Backbone model

var Album = Backbone.Model.extend({
    initialize: function() {
        this.view = new AlbumView({model: this});
    },
    render: function() {
        this.view.render();
    }
});

Jasmine test - album_spec.js

describe('Album view', function(){

    beforeEach(function() {

        var album = new Album({
            "name": "Photo Stream",
             "url": "/albums/1",
            "id": "2",
            "number_of_photos": "172 Photos",
            "small_thumbnail_url": "/assets/sections/albums/covers/auto.png",
            "viewable": true,
            "is_owner": "owner"
        });

        loadFixtures('albums_fixture.html');

        this.view = new AlbumView();
        this.view.model = album;
        // loadFixtures('albums_fixture.html');

    });

    describe("Rendering", function() {

        it ("produces the correct HTML", function() {

            this.view.render();

            expect($("#albums")).toExist();
            expect(this.view.template).toBeDefined();

        });

    });

});

This spec loads the following fixture - album_fixture.html

<div id="albums"> </div>

<script type="text/html" id="album-template">
  <a href="<%%= url %>" class="album <%%= is_owner %>">
        <%% if (viewable) { %>
            <span class="album-cover">
                <span class="photo" style="background-image:url('<%%= small_thumbnail_url %>'); width: 160px; height: 160px;">
                    <span class="glossy-overlay"></span>
                </span>
            </span>
            <%% } %>
            <h3><%%= name %></h3>
            <p>
                <%%= number_of_photos %>
            </p>
    </a>
</script>

This test is failing at

expect(this.view.template).toBeDefined();

The fixtures is loading as this test passes expect($("#albums")).toExist();

My question is how can I load fixtures that have views with embedded ruby? I was able to successfully test the models and collections but I am having trouble testing the views.

回答1:

This line:

template: _.template($('#album-template').html())

in your AlbumView is going to be executed when that script file is loaded into the page. Since the fixture doesn't get added to the page until the spec starts to execute, the album-template script tag hasn't been added to the DOM yet.

If you rewrote your template attribute to be a method that returned the result of calling _.template then it wouldn't look for the script tag until you actually tried to invoke the template. This could look something like:

AlbumView = Backbone.View.extend({
    template: function() {
        return _.template($('#album-template').html());
    },
    render: function() {
        $('#albums').append(this.template()(this.model.attributes));
    }
});

Granted, this is kinda gross. The other option would be to set up the underscore template as an asset served by the asset pipeline and have jasmine-gem include it into the page before you load your views.