122

AngularJS の使用。

指令を出してください。

ディレクティブは を定義しますtemplateUrl

ディレクティブには単体テストが必要です。

現在、ジャスミンで単体テスト中。

これは次のようなコードを推奨します:

describe('module: my.module', function () {
    beforeEach(module('my.module'));

    describe('my-directive directive', function () {
        var scope, $compile;
        beforeEach(inject(function (_$rootScope_, _$compile_, $injector) {
            scope = _$rootScope_;
            $compile = _$compile_;
            $httpBackend = $injector.get('$httpBackend');
            $httpBackend.whenGET('path/to/template.html').passThrough();
        }));

        describe('test', function () {
            var element;
            beforeEach(function () {
                element = $compile(
                    '<my-directive></my-directive>')(scope);
                angular.element(document.body).append(element);
            });

            afterEach(function () {
                element.remove();
            });

            it('test', function () {
                expect(element.html()).toBe('asdf');
            });

        });
    });
});

Jasmine でコードを実行します。

取得エラー:

TypeError: Object #<Object> has no method 'passThrough'

templateUrl はそのままロードする必要があります

使えないrespond

ngMockE2E の使用ではなく、ngMock の使用関連している可能性があります。

4

12 に答える 12

186

ngMock に関連していることは間違いありません。ngMock モジュールは、すべての Angular テストに対して自動的にロードされ、モックを初期化して、テンプレートのフェッチを含むサービス$httpBackendの使用を処理します。$httpテンプレート システムがテンプレートを読み込もうとする$httpと、モックに対する「予期しない要求」になります。

テンプレートを にプリロードして$templateCache、Angular がテンプレートを要求したときにテンプレートを使用せずに使用できるようにする方法が必要です$http

推奨される解決策: カルマ

Karmaを使用してテストを実行している場合(そうすべきです)、 ng-html2jsプリプロセッサを使用してテンプレートをロードするように構成できます。Ng-html2js は、指定した HTML ファイルを読み取り、$templateCache.

ステップ 1: でプリプロセッサを有効にして構成するkarma.conf.js

// karma.conf.js

preprocessors: {
    "path/to/templates/**/*.html": ["ng-html2js"]
},

ngHtml2JsPreprocessor: {
    // If your build process changes the path to your templates,
    // use stripPrefix and prependPrefix to adjust it.
    stripPrefix: "source/path/to/templates/.*/",
    prependPrefix: "web/path/to/templates/",

    // the name of the Angular module to create
    moduleName: "my.templates"
},

アプリのスキャフォールディングにYeomanを使用している場合、この構成は機能します

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

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

ngHtml2JsPreprocessor: { 
  stripPrefix: 'app/', 
  moduleName: 'my.templates' 
},

ステップ 2: テストでモジュールを使用する

// my-test.js

beforeEach(module("my.templates"));    // load new module containing templates

完全な例については、Angular テストの第一人者 Vojta Jina によるこの正規の例を参照してください。カルマ構成、テンプレート、テストなど、セットアップ全体が含まれています。

非カルマ ソリューション

なんらかの理由で Karma を使用せず (私はレガシー アプリのビルド プロセスに柔軟性がありませんでした)、ブラウザーでテストしているだけの$httpBackend場合、生の XHR を使用して実際のテンプレートをフェッチすることで、ngMock によるテイクオーバーを回避できることがわかりました。に挿入し$templateCacheます。このソリューションは柔軟性がはるかに劣りますが、今のところ作業は完了しています。

// my-test.js

// Make template available to unit tests without Karma
//
// Disclaimer: Not using Karma may result in bad karma.
beforeEach(inject(function($templateCache) {
    var directiveTemplate = null;
    var req = new XMLHttpRequest();
    req.onload = function() {
        directiveTemplate = this.responseText;
    };
    // Note that the relative path may be different from your unit test HTML file.
    // Using `false` as the third parameter to open() makes the operation synchronous.
    // Gentle reminder that boolean parameters are not the best API choice.
    req.open("get", "../../partials/directiveTemplate.html", false);
    req.send();
    $templateCache.put("partials/directiveTemplate.html", directiveTemplate);
}));

しかし、真剣に。カルマを使用します。セットアップには少し手間がかかりますが、コマンド ラインから一度に複数のブラウザーですべてのテストを実行できます。そのため、継続的インテグレーション システムの一部として使用したり、エディターからのショートカット キーにしたりできます。alt-tab-refresh-ad-infinitum よりもはるかに優れています。

于 2013-08-21T21:48:17.420 に答える
37

私がやったことは、テンプレートキャッシュを取得してそこにビューを入れることでした。ngMock を使用しないことを制御することはできません。

beforeEach(inject(function(_$rootScope_, _$compile_, $templateCache) {
    $scope = _$rootScope_;
    $compile = _$compile_;
    $templateCache.put('path/to/template.html', '<div>Here goes the template</div>');
}));
于 2013-03-05T18:32:23.237 に答える
13

この最初の問題は、これを追加することで解決できます。

beforeEach(angular.mock.module('ngMockE2E'));

これは、デフォルトでngMockモジュールで$httpBackendを見つけようとしていて、いっぱいではないためです。

于 2013-05-22T09:46:12.550 に答える
8

私が到達したソリューションには、jasmine-jquery.js とプロキシ サーバーが必要です。

私は次の手順に従いました:

  1. karma.conf で:

jasmine-jquery.js をファイルに追加します

files = [
    JASMINE,
    JASMINE_ADAPTER,
    ...,
    jasmine-jquery-1.3.1,
    ...
]

フィクスチャをサーバーするプロキシ サーバーを追加します。

proxies = {
    '/' : 'http://localhost:3502/'
};
  1. あなたの仕様では

    describe('MySpec', function() { var $scope, template; jasmine.getFixtures().fixturesPath = 'public/partials/'; //アプリで使用する実際のテンプレートを提供できるようにするためのカスタム パス beforeEach(function () { テンプレート = angular.element('');

        module('project');
        inject(function($injector, $controller, $rootScope, $compile, $templateCache) {
            $templateCache.put('partials/resources-list.html', jasmine.getFixtures().getFixtureHtml_('resources-list.html')); //loadFixture function doesn't return a string
            $scope = $rootScope.$new();
            $compile(template)($scope);
            $scope.$apply();
        })
    });
    

    });

  2. アプリのルート ディレクトリでサーバーを実行する

    python -m SimpleHTTPServer 3502

  3. カルマを実行します。

多くの投稿を検索する必要があり、これを理解するのにしばらく時間がかかりました。これは非常に重要な問題であるため、これに関するドキュメントをより明確にする必要があると思います。

于 2013-05-13T18:46:04.560 に答える
7

私の解決策:

test/karma-utils.js:

function httpGetSync(filePath) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/base/app/" + filePath, false);
  xhr.send();
  return xhr.responseText;
}

function preloadTemplate(path) {
  return inject(function ($templateCache) {
    var response = httpGetSync(path);
    $templateCache.put(path, response);
  });
}

karma.config.js:

files: [
  //(...)
  'test/karma-utils.js',
  'test/mock/**/*.js',
  'test/spec/**/*.js'
],

テスト:

'use strict';
describe('Directive: gowiliEvent', function () {
  // load the directive's module
  beforeEach(module('frontendSrcApp'));
  var element,
    scope;
  beforeEach(preloadTemplate('views/directives/event.html'));
  beforeEach(inject(function ($rootScope) {
    scope = $rootScope.$new();
  }));
  it('should exist', inject(function ($compile) {
    element = angular.element('<event></-event>');
    element = $compile(element)(scope);
    scope.$digest();
    expect(element.html()).toContain('div');
  }));
});
于 2014-09-04T11:06:02.367 に答える
6

Grunt を使用している場合は、grunt-angular-templates を使用できます。テンプレートを templateCache にロードし、スペック構成に対して透過的です。

私のサンプル設定:

module.exports = function(grunt) {

  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    ngtemplates: {
        myapp: {
          options: {
            base:       'public/partials',
            prepend:    'partials/',
            module:     'project'
          },
          src:          'public/partials/*.html',
          dest:         'spec/javascripts/angular/helpers/templates.js'
        }
    },

    watch: {
        templates: {
            files: ['public/partials/*.html'],
            tasks: ['ngtemplates']
        }
    }

  });

  grunt.loadNpmTasks('grunt-angular-templates');
  grunt.loadNpmTasks('grunt-contrib-watch');

};
于 2013-06-12T19:26:26.793 に答える
2

jasmine-maven-pluginを RequireJS と一緒に使用している場合は、テキスト プラグインを使用してテンプレートコンテンツを変数にロードし、それをテンプレート キャッシュに入れることができます。


define(['angular', 'text!path/to/template.html', 'angular-route', 'angular-mocks'], function(ng, directiveTemplate) {
    "use strict";

    describe('Directive TestSuite', function () {

        beforeEach(inject(function( $templateCache) {
            $templateCache.put("path/to/template.html", directiveTemplate);
        }));

    });
});
于 2014-05-15T11:11:04.837 に答える
2

Karma を使用している場合は、karma-ng-html2js-preprocessorを使用して外部 HTML テンプレートをプリコンパイルし、Angular がテスト実行中に HTTP GET を試みないようにすることを検討してください。私の場合、templateUrl の部分パスは通常のアプリの実行中に解決されましたが、テスト中には解決されませんでした。これは、アプリとテストのディレクトリ構造の違いによるものです。

于 2014-01-29T18:09:33.667 に答える
2

テストで requirejs を使用する場合、'text' プラグインを使用して html テンプレートを取り込み、$templateCache に入れることができます。

require(["text!template.html", "module-file"], function (templateHtml){
  describe("Thing", function () {

    var element, scope;

    beforeEach(module('module'));

    beforeEach(inject(function($templateCache, $rootScope, $compile){

      // VOILA!
      $templateCache.put('/path/to/the/template.html', templateHtml);  

      element = angular.element('<my-thing></my-thing>');
      scope = $rootScope;
      $compile(element)(scope);   

      scope.$digest();
    }));
  });
});
于 2015-04-03T18:09:35.367 に答える
0

この問題は、すべてのテンプレートをテンプレート キャッシュにコンパイルすることで解決します。私はgulpを使用しています.gruntについても同様の解決策を見つけることができます. ディレクティブの私のtemplateUrls、モーダルは次のようになります

`templateUrl: '/templates/directives/sidebar/tree.html'`
  1. package.json に新しい npm パッケージを追加する

    "gulp-angular-templatecache": "1.*"

  2. gulp ファイルに templatecache と新しいタスクを追加します。

    var templateCache = require('gulp-angular-templatecache'); ... ... gulp.task('compileTemplates', function () { gulp.src([ './app/templates/**/*.html' ]).pipe(templateCache('templates.js', { transformUrl: function (url) { return '/templates/' + url; } })) .pipe(gulp.dest('wwwroot/assets/js')); });

  3. すべての js ファイルを index.html に追加します

    <script src="/assets/js/lib.js"></script> <script src="/assets/js/app.js"></script> <script src="/assets/js/templates.js"></script>

  4. 楽しみ!

于 2015-08-26T08:28:17.940 に答える