TypeError: 'undefined' is not an object (evaluating 'text.replace') - when testing backbone view

4k views Asked by At

I am trying to write the tests for a Backbone app which uses twig and symphony to render the underscore templates, using mocha, chai and sinon, with blanket for code-coverage and phantomjs for browser simulation. I have managed to load the template markup into test.html by doing the following in the body tag:

<!-- fixtures -->
<script>
    $(function(){
        $("#fixtures").load("fixtures/comment-fixture.html");
    });
</script>

I have created a html fixture, or at least that is what I was aiming for, however I still get the following error when running my tests: TypeError: 'undefined' is not an object (evaluating 'text.replace')

I understand that it refers to basically underscore evaluating _template(undefined), but I don't understand why it is doing that. Has anyone come across the a similar issue before or know why it is triggering this error?

This is my set-up:

Backbone view I want to test:

var CommentView = Backbone.View.extend({

    //... is a list tag.
    tagName:  "li",

    model: null,

    // Cache the template function for a single item.
    template: _.template($('#comment-template').html()),

    // This is the timeout used to re-render the times
    refreshTimer: null,

    initialize: function(options) {

        this.model = options.model;
        this.listenTo(this.model, 'change', this.render);
        this.listenTo(Backbone, 'stopCommentRefresh', this.stopRefreshTimer);
    },

    render: function() {
        this.$el.html(this.template(this.model.renderAttributes()));

        this.refreshTimer = setTimeout(_.bind(this.render, this), 60000);
        return this;
    },

    // If you hit `enter`, we're through editing the item.
    updateOnEnter: function(e) {
        if (e.keyCode == 13) this.close();
    },

    stopRefreshTimer: function () {
        clearTimeout(this.refreshTimer);
        this.remove();
    }

});

My fixture file for it :

<script type="text/template" id="comment-template">
    <article class="comment">
        <h4><%- user.username %></h4>
        <p><%- comment %></p>
        <time><%- time %></time>
    </article>
</script>

My test file for it (so far nothing special):

describe("Comment View", function () {

    before(function () {

        // create test fixture
        this.$fixture = $('<li id="comment-view-fixture"></li>');
    });

    beforeEach(function () {

        // empty out and rebind the fixture for each run
        this.$fixture.empty().appendTo($("#fixtures"));

        // new default model and view for each test
        this.view = new CommentView ({
            el: this.$fixture,
            model: new Comment({
                comment: "Hello world!",
                created: new Date(),
                modified: new Date(),
                user: {
                    username: "Mario"
                }
            })
        });
    });

    afterEach(function () {
        this.view.model.destroy();
    });

    after(function () {
        $("#fixtures").empty();
    });
});

And my test.html file:

<html>
<head>
    <title>Backbone.js Tests</title>
    <meta http-equiv="Content-Type"
          content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <link rel="stylesheet" href="js/lib/mocha.css" />

</head>

<body>

    <div id="blanket-main" class="hidden" style="display: none;"></div>

    <div id="mocha"></div>


    <!-- Utility libraries -->
    <script src="js/lib/mocha.js"></script>
    <script src="js/lib/chai.js"></script >
    <script src="js/lib/sinon-chai.js"></script >
    <script src="js/lib/sinon.js"></script >
    <script src="js/lib/chai-datetime.js"></script>



    <!-- JavaScript Coverage Libraries. -->
    <script src="js/lib/blanket.js"></script>

    <!-- jquery library -->
    <script src="../../../../ApiBundle/Resources/public/js/thirdParty/jquery-1.11.js"></script>


    <!-- fixtures -->
    <script>
        $(function(){
            $("#fixtures").load("fixtures/comment-fixture.html");
        });
    </script>



    <!-- JavaScript Core Libraries -->
    <script src="../../../../ApiBundle/Resources/public/js/thirdParty/underscore.js"></script>
    <script src="../../../../ApiBundle/Resources/public/js/thirdParty/jquery.dataTables.js"></script>
    <script src="../../../../ApiBundle/Resources/public/js/thirdParty/backbone.js"></script>

    <!-- Javascript Application Libraries - Views -->

    <script src="../../../../ApiBundle/Resources/public/js/comment.js" data-cover></script>




    <script>

        var expect = chai.expect;

        mocha.setup({
            ui: "bdd",
            globals: ['stats', 'failures', 'runner'], // Blanket leaks.
            bail: false
        });

        // Set up Mocha with custom Blanket.js reporter.
        mocha.reporter(function (_reporter) {
            // Updated for Mocha 1.15.1 integration.
            // See: https://github.com/alex-seville/blanket/pull/356
            var blanketReporter = function (runner) {
                // Listeners.
                runner.on("start",  function () { blanket.setupCoverage(); });
                runner.on("suite",  function () { blanket.onModuleStart(); });
                runner.on("test",   function () { blanket.onTestStart(); });
                runner.on("test end", function (test) {
                    blanket.onTestDone(test.parent.tests.length,
                            test.state === 'passed');
                });
                runner.on("end",    function () {
                    blanket.onTestsDone();
                    $("#blanket-main").removeClass("hidden").show("fast");
                    $("html, body").animate({ scrollTop: 0 });
                });
                _reporter.call(this, runner);
            };

            blanketReporter.prototype = _reporter.prototype;
            return blanketReporter;
        }(mocha._reporter));

        blanket.beforeStartTestRunner({
            callback: function () {
                (window.mochaPhantomJS || mocha).run();
            }
        });

    </script>

    <script src="js/spec/views/view_CommentView.spec.js"></script>


    <!-- Coverage style helpers -->
    <style type="text/css">
        #blanket-main {
            margin-top: 65px;
            margin-right: 20px;
            margin-left: 20px;
            border-radius: 5px;
            border: 1px solid #666;
        }
    </style>

    <!-- Test Fixtures. -->
    <div id="fixtures" style="display: none; visibility: hidden;"></div>

</body>

</html>
1

There are 1 answers

0
hyprstack On

It turns out its because $("#fixtures").load("fixtures/comment-fixture.html") is asynchronous and isn't actually loaded when I run the tests. By simply copying the contents of fixture.html into test.html body tag, the error stops happening!