templateUrl
が定義されているAngularJSディレクティブがあります。私はジャスミンでそれを単体テストしようとしています。
this の推奨に従って、私のJasmine JavaScriptは次のようになります。
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 を使用して関連していると思われます。これが原因である場合、前者の代わりに後者を使用するにはどうすればよいですか?
前もって感謝します!
私がやったことは、テンプレートキャッシュを取得してそこにビューを置くことでした。 ngMockを使用しないように制御することはできません。
beforeEach(inject(function(_$rootScope_, _$compile_, $templateCache) {
$scope = _$rootScope_;
$compile = _$compile_;
$templateCache.put('path/to/template.html', '<div>Here goes the template</div>');
}));
NgMockに関連していることは正しいです。 ngMockモジュールはAngularテストごとに自動的にロードされ、テンプレートフェッチを含む$httpBackend
サービスの使用を処理するためにモック$http
を初期化します。テンプレートシステムは、$http
を介してテンプレートをロードしようとし、モックに対する「予期しない要求」になります。
Angularが$templateCache
を使用せずにテンプレートを要求したときに既に利用できるように、テンプレートを$http
にプリロードする方法に必要なもの。
Karma を使用してテストを実行している場合(実行する必要があります)、 ng-html2js プリプロセッサーを使用してテンプレートをロードするように構成できます。 Ng-html2jsは、指定したHTMLファイルを読み取り、$templateCache
をプリロードするAngularモジュールに変換します。
ステップ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 test guru Vojta Jinaの標準的な例 。カルマ構成、テンプレート、およびテストのセットアップ全体が含まれます。
何らかの理由でKarmaを使用せず(レガシーアプリで柔軟性のないビルドプロセスを行っていた)、ブラウザーでテストしているだけであれば、生のXHRを使用して$httpBackend
の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);
}));
しかし、真剣に。 Karma を使用します。設定には少し手間がかかりますが、コマンドラインから複数のブラウザーですべてのテストを一度に実行できます。したがって、継続的インテグレーションシステムの一部として使用したり、エディターからショートカットキーにしたりできます。 alt-tab-refresh-ad-infinitumよりもはるかに優れています。
この最初の問題は、これを追加することで解決できます。
beforeEach(angular.mock.module('ngMockE2E'));
これは、デフォルトでngMockモジュールで$ httpBackendを見つけようとし、満杯ではないためです。
私が到達したソリューションには、jasmine-jquery.jsとプロキシサーバーが必要です。
私は次の手順に従いました。
ファイルにjasmine-jquery.jsを追加します
files = [
JASMINE,
JASMINE_ADAPTER,
...,
jasmine-jquery-1.3.1,
...
]
フィクスチャーを提供するプロキシサーバーを追加します
proxies = {
'/' : 'http://localhost:3502/'
};
あなたのスペックで
describe( 'MySpec'、function(){var $ scope、template; jasmine.getFixtures()。fixturesPath = 'public/partials /'; //カスタムパスなので、アプリで使用する実際のテンプレートをbeforeEach(function (){template = 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();
})
});
});
アプリのルートディレクトリでサーバーを実行する
python -m SimpleHTTPServer 3502
カルマを実行します。
多くの投稿を検索しなければならないので、これを理解するのにしばらく時間がかかりました。これに関する重要な問題であるため、これに関するドキュメントはより明確になるはずです。
私の解決策:
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');
}));
});
選択したソリューションとは少し異なる方法で同じ問題を解決しました。
まず、karmaの ng-html2js プラグインをインストールして構成しました。 karma.conf.jsファイルで:
preprocessors: {
'path/to/templates/**/*.html': 'ng-html2js'
},
ngHtml2JsPreprocessor: {
// you might need to strip the main directory prefix in the URL request
stripPrefix: 'path/'
}
次に、beforeEachで作成されたモジュールをロードしました。 Spec.jsファイルで:
beforeEach(module('myApp', 'to/templates/myTemplate.html'));
次に、$ templateCache.getを使用して変数に保存しました。 Spec.jsファイルで:
var element,
$scope,
template;
beforeEach(inject(function($rootScope, $compile, $templateCache) {
$scope = $rootScope.$new();
element = $compile('<div my-directive></div>')($scope);
template = $templateCache.get('to/templates/myTemplate.html');
$scope.$digest();
}));
最後に、この方法でテストしました。 Spec.jsファイルで:
describe('element', function() {
it('should contain the template', function() {
expect(element.html()).toMatch(template);
});
});
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');
};
テンプレートhtmlを動的に$ templateCacheにロードするには、説明されているように、html2jsカルマプリプロセッサを使用するだけです here
これは、テンプレート「。html」をconf.jsファイル内のファイルに追加するだけでなく、プリプロセッサー= {'。html': 'html2js' };
そして使用
beforeEach(module('..'));
beforeEach(module('...html', '...html'));
あなたのjsテストファイルに
テストで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();
}));
});
});
jasmine-maven-plugin をRequireJSと一緒に使用している場合、 text plugin を使用してテンプレートコンテンツを変数にロードし、テンプレートキャッシュに配置できます。
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);
}));
});
});
karmaを使用している場合は、 karma-ng-html2js-preprocessor を使用して外部HTMLテンプレートをプリコンパイルし、テスト実行中にAngularがHTTP GETしようとすることを避けます。私は、アプリとテストのディレクトリ構造の違いにより、通常のアプリの実行中にtemplateUrlの部分パスが解決されましたが、テスト中には解決されなかったため、これに苦労しました。
すべてのテンプレートをtemplatecacheにコンパイルすることで、この問題を解決します。私はgulpを使用していますが、あなたはうなり声にも同様の解決策を見つけることができます。ディレクティブの私のtemplateUrls、モーダルは次のようになります
`templateUrl: '/templates/directives/sidebar/tree.html'`
Package.jsonに新しいnpmパッケージを追加します
"gulp-angular-templatecache": "1.*"
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')); });
Index.htmlにすべてのjsファイルを追加します
<script src="/assets/js/lib.js"></script> <script src="/assets/js/app.js"></script> <script src="/assets/js/templates.js"></script>
楽しい!