最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Unit testing a directive whose templates are all one with file with script tags - Stack Overflow

programmeradmin1浏览0评论

I am having a hard time figuring out how to include my directive's templates (that are all in one file in different script tags) in my Karma unit tests.

The error I get:

PhantomJS 1.9 (Linux) ERROR
 SyntaxError: Parse error
 at /var/www/html/tweak/core/global/views/js/modules/datable/templates.html:1
PhantomJS 1.9 (Linux): Executed 0 of 0 ERROR (0.313 secs / 0 secs)

Here are the relevant parts of the code:

My directives meat:

return {
  scope       : {
    columns : '=',
    config  : '='
  },
  templateUrl : 'datable/table.html',
  restrict    : 'E',
  controller  : 'datableCtrl',
  link        : linkingFunction
};

My template file:

<script type="text/ng-template" id="datable/table.html">
  <!-- data rows -->
  <tr
    ng-repeat="row in rows track by $id($index)"
    class="datable-row"
    ng-hide="loading">

    <td
      ng-repeat="column in columns track by $id($index)"
      ng-class="{'edit-on': editMode == 'on'}"
      class="{{column.classes.join(' ') + ' column' + $index}}"
      ng-style="column.style">

      <div ng-include="editMode == 'on' && column.editable
        ? 'datable/editCell.html'
        : 'datable/normalCell.html'">
      </div>
    </td>

    <!-- save button -->
    <td ng-show="editMode == 'on'" style="width:1px;">
      <button class="btn"> Save </button>
    </td>
    <!-- / save button -->

  </tr>
  <!-- / data rows -->
</script>

<script type="text/ng-template" id="datable/editCell.html">
  <div ng-switch="column.inputType">

    <!-- text input -->
    <div ng-switch-when="text">
      <div ng-class="{
        'input-append'  : column.append != '',
        'input-prepend' : column.prepend != ''
      }">

        <span
          class="add-on"
          ng-show="column.prepend"> {{column.prepend}} </span>

        <input
          type="text"
          ng-model="row[column.model]"
          ng-keydown="query()"
          ng-class="inputClass.join(' ')"
          ng-attrs="column.inputAttrs">

        <span
          class="add-on"
          ng-show="column.append"> {{column.append}} </span>
      </div>
    </div>
    <!-- end text input -->

    <!-- select input -->
    <div ng-switch-when="select">
      <select
        ng-model="row[column.model]"
        ng-change="query()"
        ng-options="item.value as item.name for item in column.options"
        ng-class="inputClass.join(' ')"
        ng-attrs="column.inputAttrs">

        <option value=""> -- </option>
      </select>
    </div>
    <!-- end select -->

    <!-- radio / checkbox -->
    <div ng-switch-default>
      <label ng-repeat="(key, value) in column.options track by $id($index)">
        <input
          type="{{column.inputType}}"
          ng-class="inputClass.join(' ')"
          ng-change="query()"
          value="{{key}}"
          ng-checked="row[column.model].indexOf('key') > -1"
          ng-attrs="column.inputAttrs">

        <span> {{value}} </span>
      </label>
    </div>
    <!-- end radio / checkbox -->

  </div>
</script>

<script type="text/ng-template" id="datable/normalCell.html">
  <div class="read-only">
    <span> {{column.prepend}} </span>
    <!-- <span> {{row[column.model] | datableFilter : column.filter}} </span> -->
    <span ng-bind-html-unsafe="(row[column.model] + '') | datableFilter : column.filter"></span>
    <span> {{column.append}} </span>
  </div>
</script>

My unit tests:

'use strict'

describe("datable", function() {

  describe('directive', function () {
    var $rootScope, $pile, element;

    beforeEach(module('datable'));
    beforeEach(module('/var/www/html/tweak/core/global/views/js/modules/datable/templates.html'));

    beforeEach(inject(function (_$rootScope_, _$pile_) {
      $rootScope = _$rootScope_;
      $pile = _$pile_;

      $rootScope.tableConfig = {
        editable     : true
      };
      $rootScope.columns = [];

      element = angular.element('<datable config="tableConfig" columns="columns"></datable>');

        $pile(element)($rootScope);
        $rootScope.$digest();
    }));

    it('should have ng-scope class', function() {
        expect(element.hasClass('ng-scope')).toBe(true);
    });
  });
});

My Karma config:

var branch = 'tweak';
basePath = '/var/www/html/' + branch + '/';

files = [
  // Dependencies
  JASMINE,
  JASMINE_ADAPTER,
  '.0.0/jquery.min.js',
  '.1.5/angular.min.js',
  '.1.5/angular-mocks.js',

  // other requirements
  'core/global/views/js/modules/rest/module.js',

  // the project source
  'core/global/views/js/modules/datable/module.js',
  'core/global/views/js/modules/datable/values.js',
  'core/global/views/js/modules/datable/services.js',
  'core/global/views/js/modules/datable/filters.js',
  'core/global/views/js/modules/datable/directives.js',
  'core/global/views/js/modules/datable/controllers.js',
  'core/global/views/js/modules/datable/*.html',

  // my spec suite
  'core/global/views/js/modules/datable/tests.js'
];

exclude = [

];

reporters = ['progress'];
port = 9876;
runnerPort = 9100;
colors = true;
logLevel = LOG_INFO;
autoWatch = true;
browsers = ['PhantomJS'];
captureTimeout = 60000;

I am having a hard time figuring out how to include my directive's templates (that are all in one file in different script tags) in my Karma unit tests.

The error I get:

PhantomJS 1.9 (Linux) ERROR
 SyntaxError: Parse error
 at /var/www/html/tweak/core/global/views/js/modules/datable/templates.html:1
PhantomJS 1.9 (Linux): Executed 0 of 0 ERROR (0.313 secs / 0 secs)

Here are the relevant parts of the code:

My directives meat:

return {
  scope       : {
    columns : '=',
    config  : '='
  },
  templateUrl : 'datable/table.html',
  restrict    : 'E',
  controller  : 'datableCtrl',
  link        : linkingFunction
};

My template file:

<script type="text/ng-template" id="datable/table.html">
  <!-- data rows -->
  <tr
    ng-repeat="row in rows track by $id($index)"
    class="datable-row"
    ng-hide="loading">

    <td
      ng-repeat="column in columns track by $id($index)"
      ng-class="{'edit-on': editMode == 'on'}"
      class="{{column.classes.join(' ') + ' column' + $index}}"
      ng-style="column.style">

      <div ng-include="editMode == 'on' && column.editable
        ? 'datable/editCell.html'
        : 'datable/normalCell.html'">
      </div>
    </td>

    <!-- save button -->
    <td ng-show="editMode == 'on'" style="width:1px;">
      <button class="btn"> Save </button>
    </td>
    <!-- / save button -->

  </tr>
  <!-- / data rows -->
</script>

<script type="text/ng-template" id="datable/editCell.html">
  <div ng-switch="column.inputType">

    <!-- text input -->
    <div ng-switch-when="text">
      <div ng-class="{
        'input-append'  : column.append != '',
        'input-prepend' : column.prepend != ''
      }">

        <span
          class="add-on"
          ng-show="column.prepend"> {{column.prepend}} </span>

        <input
          type="text"
          ng-model="row[column.model]"
          ng-keydown="query()"
          ng-class="inputClass.join(' ')"
          ng-attrs="column.inputAttrs">

        <span
          class="add-on"
          ng-show="column.append"> {{column.append}} </span>
      </div>
    </div>
    <!-- end text input -->

    <!-- select input -->
    <div ng-switch-when="select">
      <select
        ng-model="row[column.model]"
        ng-change="query()"
        ng-options="item.value as item.name for item in column.options"
        ng-class="inputClass.join(' ')"
        ng-attrs="column.inputAttrs">

        <option value=""> -- </option>
      </select>
    </div>
    <!-- end select -->

    <!-- radio / checkbox -->
    <div ng-switch-default>
      <label ng-repeat="(key, value) in column.options track by $id($index)">
        <input
          type="{{column.inputType}}"
          ng-class="inputClass.join(' ')"
          ng-change="query()"
          value="{{key}}"
          ng-checked="row[column.model].indexOf('key') > -1"
          ng-attrs="column.inputAttrs">

        <span> {{value}} </span>
      </label>
    </div>
    <!-- end radio / checkbox -->

  </div>
</script>

<script type="text/ng-template" id="datable/normalCell.html">
  <div class="read-only">
    <span> {{column.prepend}} </span>
    <!-- <span> {{row[column.model] | datableFilter : column.filter}} </span> -->
    <span ng-bind-html-unsafe="(row[column.model] + '') | datableFilter : column.filter"></span>
    <span> {{column.append}} </span>
  </div>
</script>

My unit tests:

'use strict'

describe("datable", function() {

  describe('directive', function () {
    var $rootScope, $pile, element;

    beforeEach(module('datable'));
    beforeEach(module('/var/www/html/tweak/core/global/views/js/modules/datable/templates.html'));

    beforeEach(inject(function (_$rootScope_, _$pile_) {
      $rootScope = _$rootScope_;
      $pile = _$pile_;

      $rootScope.tableConfig = {
        editable     : true
      };
      $rootScope.columns = [];

      element = angular.element('<datable config="tableConfig" columns="columns"></datable>');

        $pile(element)($rootScope);
        $rootScope.$digest();
    }));

    it('should have ng-scope class', function() {
        expect(element.hasClass('ng-scope')).toBe(true);
    });
  });
});

My Karma config:

var branch = 'tweak';
basePath = '/var/www/html/' + branch + '/';

files = [
  // Dependencies
  JASMINE,
  JASMINE_ADAPTER,
  'https://ajax.googleapis./ajax/libs/jquery/2.0.0/jquery.min.js',
  'https://ajax.googleapis./ajax/libs/angularjs/1.1.5/angular.min.js',
  'http://code.angularjs/1.1.5/angular-mocks.js',

  // other requirements
  'core/global/views/js/modules/rest/module.js',

  // the project source
  'core/global/views/js/modules/datable/module.js',
  'core/global/views/js/modules/datable/values.js',
  'core/global/views/js/modules/datable/services.js',
  'core/global/views/js/modules/datable/filters.js',
  'core/global/views/js/modules/datable/directives.js',
  'core/global/views/js/modules/datable/controllers.js',
  'core/global/views/js/modules/datable/*.html',

  // my spec suite
  'core/global/views/js/modules/datable/tests.js'
];

exclude = [

];

reporters = ['progress'];
port = 9876;
runnerPort = 9100;
colors = true;
logLevel = LOG_INFO;
autoWatch = true;
browsers = ['PhantomJS'];
captureTimeout = 60000;
Share Improve this question edited Oct 19, 2013 at 0:48 Adi Inbar 12.3k13 gold badges59 silver badges70 bronze badges asked Oct 17, 2013 at 19:10 RonSperRonSper 6931 gold badge7 silver badges20 bronze badges 2
  • I do my templating this way also and have yet to find a testing solution. I only test services because of this problem, but would like to know more. – Kevin Beal Commented Oct 17, 2013 at 23:54
  • Has anyone tried this? I would imagine that this is something that would be supported? – RonSper Commented Oct 18, 2013 at 21:53
Add a ment  | 

1 Answer 1

Reset to default 7

I think your error is because you are trying to load your HTML file into a file list that normally accepts javascript. I do have a solution for you though.

Before I begin, I have karma 0.10.2 and it looks like you are on 0.8.x or under? I have this working in 0.10.2 but I can't install 0.8.x. I'll try to translate for 0.8.x but won't be able to test what I'm doing, so I'll describe mainly in terms of 0.10.x. It may be easier to move to latest karma anyway if you are able.

Config

0.10.x

External HTML partials can be loaded by karma-ng-html2js-preprocessor. This is normally used for loading directly in directives via templateUrl and similar methods. In 0.10.2 you need to make sure this package is installed (using npm) and then include the following in your karma config:

preprocessors: {
    '**/*.html' : ['ng-html2js']
},

ngHtml2JsPreprocessor: {
    cacheIdFromPath: function(filepath) {
        // If you had more than one html file you would want to do something more clever here.
        return 'inlinetemplates';
    },
    moduleName: 'inlinetemplates'
},

plugins: [
    ...,
    'karma-ng-html2js-preprocessor'
],

files: [
    ...,
    'app/alltemplates.html', // your main template html
    // Don't include paths for individual files that are inlined in the file above
]

This will allow you to load a module with module('inlinetemplates') that will insert the contents of your main template file (not the individual templates) into $templateCache.

0.8.x

So, translating for 0.8.x... I think you need to use html2js which is not so powerful but is included in karma in this version. You won't need to install or include it in plugins, and you can't configure how it's used, so you just need

preprocessors = { '**/*.html': ['html2js'] }

The module created, and the item it inserts into $templateCache will be named using the path that you use to refer to your main template html.

Javascript

0.10.x

Now you should be able to load the relevant module and get access to the contents of your main template file using

var templates = $templateCache.get('inlinetemplates')

All that is left to do is pushing your inlined templates from the main template file contents to $templateCache. This is done using the angular script directive, so we just need to pile/link the file we have loaded with angular. You can do this very simply with

$pile(templates)(scope);

So putting this together, you can include the following in any describe block that needs to load your templates.

beforeEach(module('inlinetemplates'));
beforeEach(inject(function($pile, $templateCache, $rootScope) {
    var templatesHTML = $templateCache.get('inlinetemplates');
    $pile(templatesHTML)($rootScope);
}));

0.8.x

var mainTemplateLocation = 'path/used/to/refer/to/main/templates/in/karma/conf.html';
beforeEach(module(mainTemplateLocation));
beforeEach(inject(function($pile, $templateCache, $rootScope) {
    var templatesHTML = $templateCache.get(mainTemplateLocation);
    $pile(templatesHTML)($rootScope);
}));

Summing Up

Again, I can't guarantee that the 0.8.x instructions will work, especially not without tweaking, but this certainly works in 0.10.x.

Karma already has the facilities for pushing external HTML partials into your tests, all that was missing was being able to interpret your main template properly.

发布评论

评论列表(0)

  1. 暂无评论