L1ghtk3ira
L1ghtk3ira

Reputation: 3199

Angular 1.x Testing with Jasmine: Compiling a template not working to verify data output in template

I am trying to unit test an html template that has variables in paragraph, anchor tags, and {{header.title || translate}} however no matter what posts I have tried it does not seem to work. I get the retrieved HTML template and when it is compiled it is still the same. In the template I still see {{user}} for example. It seems none of them are actually being compiled.

Current Template Output:

<h1>{{header.title | translate}}</h1>
<h2>{{homeCtrl.name}}</h2>

Expected Output:

<h1>Cake Blogger</h1>
<h2>Alexandria</h2>

Test Suite:

(function() {
  'use strict';

  describe('home.tpl.html', function() {
    var scope, controller, createController, template, element, rootScope;

    beforeEach(module('Templates'));
    beforeEach(module('mainApp'));

    /**
      @name: home.tpl.html
      @description: Inject and set test related objects
      @param {Service} rootScope - Used to get the language
      @param {Compiler} $templateCache - Holding the compiled template
      @param {Injector} $compile - Compiles an HTML string or DOM
    */
    beforeEach(inject(
      function(_$controller_, _$rootScope_, $templateCache, $compile) {
        scope = _$rootScope_.$new();
        createController = function() {
          return _$controller_('homeCtrl', {
            '$scope': scope
         });
      };

      controller = createController();

      rootScope = _$rootScope_;
      template = $templateCache.get('home.tpl.html');
      element = $compile(template)(rootScope);

      // var ctrl = element.controller('homeCtrl');
      rootScope.$digest();
      console.log("home page", element);
  }));

  /**
    @name: Describe Block - home.tpl.html
    @description: Test cases related to home.tpl.html
  */
  describe('home.tpl.html tests', function() {
    fit('should have "Alexandria"', function() {
      expect(element.html()).toContain("Alexandria");
    });
  });
});
})();

Karma File:

files: ['list of files'],

port: 8080,

browsers: [
  'PhantomJS'
],

plugins: [
  'karma-phantomjs-launcher',
  'karma-jasmine',
  'karma-ng-html2js-preprocessor',
],

preprocessors: {
  'app/**/*.tpl.html': 'html2js'
},

ngHtml2JsPreprocessor: {
  'moduleName': 'Templates',
  'stripPrefix': 'app/'
}

package.json

{
  "name": "",
  "private": true,
  "devDependencies": {
    "autoprefixer-core": "^5.2.1",
    "grunt": "^0.4.5",
    "grunt-angular-templates": "^0.5.7",
    "grunt-concurrent": "^1.0.0",
    "grunt-contrib-clean": "^0.6.0",
    "grunt-contrib-compass": "^1.0.0",
    "grunt-contrib-concat": "^0.5.0",
    "grunt-contrib-connect": "^0.9.0",
    "grunt-contrib-copy": "^0.7.0",
    "grunt-contrib-cssmin": "^0.12.0",
    "grunt-contrib-htmlmin": "^0.4.0",
    "grunt-contrib-imagemin": "^1.0.0",
    "grunt-contrib-jshint": "^0.11.0",
    "grunt-contrib-uglify": "^0.7.0",
    "grunt-contrib-watch": "^0.6.1",
    "grunt-filerev": "^2.1.2",
    "grunt-google-cdn": "^0.4.3",
    "grunt-jscs": "^1.8.0",
    "grunt-karma": "*",
    "grunt-modernizr": "^1.0.2",
    "grunt-newer": "^1.1.0",
    "grunt-ng-annotate": "^0.9.2",
    "grunt-ng-constant": "^2.0.1",
    "grunt-postcss": "^0.5.5",
    "grunt-svgmin": "^2.0.0",
    "grunt-usemin": "^3.0.0",
    "grunt-wiredep": "^2.0.0",
    "jasmine-core": "^2.4.1",
    "jit-grunt": "^0.9.1",
    "jshint-stylish": "^1.0.0",
    "karma": "^0.13.22",
    "karma-coverage": "^0.5.5",
    "karma-fixture": "^0.2.6",
    "karma-jasmine": "*",
    "karma-json-fixtures-preprocessor": "0.0.6",
    "karma-json-preprocessor": "^0.3.3",
    "karma-junit-reporter": "^1.2.0",
    "karma-ng-html2js-preprocessor": "~0.1.0",
    "karma-phantomjs-launcher": "*",
    "phantomjs": "^2.1.7",
    "time-grunt": "^1.0.0"
  },
  "engines": {
    "node": ">=0.10.0"
  },
  "scripts": {
    "test": "grunt test"
  },
  "dependencies": {}
}

According to posts I have read such as this plunker from a post plunker example, this should be working correctly. I am thinking perhaps the controller is not binding to the scope so that when $digest runs the template cannot find the controller maybe.

Helpful Information:

Links viewed:

The template returns but the angular in the template is never compiled. Always seeing {{homeCtrl.name}} instead of Alexandria.

Update 1.1

I am thinking perhaps since the translate {{header.title | translate}} is not working that maybe angular-translate (module: pascalprecht.translate) is not actually working correctly and is then causing the controller to also fail binding. Will continue investigation.

Upvotes: 3

Views: 748

Answers (1)

Linker
Linker

Reputation: 56

After injecting angular-translate the | translate filter just works and yields expected translated value after $compile. See this plunker as an example:

http://plnkr.co/edit/j8rbnMI067YntllwTcGi?p=preview

One possible reason that leads to your issue is timing - suppose you have big translate array / json and it takes a while to load, but Jasmine testing already starts and finishes before they are fully loaded and ready. Then Jasmine will see un-translated string during tests.


Updated 2017-06-30

After a few experiments, I can confirm that any async json loader, whether it's .useStaticFilesLoader or $.getJSON(), will not be executed before jasmine. See http://plnkr.co/edit/nreUd52iqOVvwLPMNtJA?p=preview as an example, the static loader works fine for page view but fails unit test.

One possible way to go is to ditch .useStaticFilesLoader completely. Instead, we can use grunt-replace to inject the translations during the build process. Example grunt task:

// replace string with json
replace: {
  dist: {
    options: {
      patterns: [
        {
          match: /\"JSONEN\"/,
          replacement: '<%= grunt.file.read("app/resources/en.json") %>'
        }
      ]
    },
    files: [
      {expand: true, flatten: true, src: ['app/scripts/app.js'], dest: 'public/'}
    ]
  }
}

Upvotes: 1

Related Questions