Javascript AngularJS-单元测试时在脚本标记中找不到指令模板

Javascript AngularJS-单元测试时在脚本标记中找不到指令模板,javascript,angularjs,angularjs-directive,jasmine,fine-uploader,Javascript,Angularjs,Angularjs Directive,Jasmine,Fine Uploader,我有一个指令,它包含了一个很好的上传工具。在功能上,它做了我想做的一切,但我现在在为它编写单元测试时遇到了问题 Fine Uploader使用它在id为“qq template”的脚本标记中查找的模板。我已将其放置在一个模板文件中,该模板文件在指令返回的对象的templateUrl属性中引用 我已经将Grunt配置为在此文件上运行html2js预处理器,并将代码存储在$templateCache中。我在每次调用前的单元测试中包括模板文件 当我运行测试时,我得到一个错误: “找不到ID为'qq t

我有一个指令,它包含了一个很好的上传工具。在功能上,它做了我想做的一切,但我现在在为它编写单元测试时遇到了问题

Fine Uploader使用它在id为“qq template”的脚本标记中查找的模板。我已将其放置在一个模板文件中,该模板文件在指令返回的对象的templateUrl属性中引用

我已经将Grunt配置为在此文件上运行html2js预处理器,并将代码存储在$templateCache中。我在每次调用前的单元测试中包括模板文件

当我运行测试时,我得到一个错误:

“找不到ID为'qq template'的模板脚本!”

在应用程序中使用此指令时没有问题。很明显,关于模板是如何使用的,我有一些不明白的地方。有人能帮忙吗

该指令:

angular.module('ai.upload').directive('fineUploader', function($compile) {
    return {
        replace: false,
        restrict: 'A',
        scope: {
            validation: '@',
            uploadServer:'@'
        },
        templateUrl: 'source/shared/upload/partials/fine-uploader-template.html',
        link: function(scope, element, attrs) { ... }
}
模板文件:

<script type="text/template" id="qq-template">
<div class="qq-uploader-selector qq-uploader">
    <div id="totalProgress" class="progress progress-striped active hide">
        <div class="progress-bar" role="progressbar"></div>
    </div>
    <div class="qq-upload-drop-area-selector uploader-drop-zone">
        <span class="drop-zone-text" ng-bind="dropZoneText"></span>
        <ul class="qq-upload-list-selector qq-upload-list">
            <li class="file-container hide">
                <div class="qq-progress-bar-container-selector progress">
                    <div class="qq-progress-bar-selector progress-bar"></div>
                </div>
                <div class="file-info">
                    <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                    <img class="qq-thumbnail-selector" qq-max-size="50" qq-server-scale>
                    <span class="qq-upload-file-selector qq-upload-file"></span>
                    <span class="qq-upload-size-selector qq-upload-size"></span>
                </div>
                <button class="qq-upload-cancel-selector btn btn-small btn-warning hide" href="#">Cancel</button>
                <button class="qq-upload-retry-selector qq-upload-retry btn btn-small hide" href="#">Retry</button>
                <button class="qq-upload-delete-selector btn btn-small btn-danger hide" href="#">Delete</button>
                <span class="qq-upload-status-text-selector qq-upload-status-text"></span>
            </li>
        </ul>
        <div class="qq-upload-button-selector ai-button-default button-separator select-button">
            <div ng-bind="uploadButtonText"></div>
        </div>
    </div>
    <span class="qq-drop-processing-selector qq-drop-processing">
        <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
    </span>
</div>

  • 取消 重试 删除

单元测试:

describe('aiFineUploader', function() {
var element;
var scope;

beforeEach(module('ai.upload'));
beforeEach(module('source/shared/upload/partials/fine-uploader-template.html'));

beforeEach(inject(function($compile, $rootScope) {
    scope = $rootScope;

    scope.validation = {
        fileExtensions: 'xml',
        sizeLimit : '100000000',
        acceptFiles: ['text/xml']
    };

    var html =
        ' <div fine-uploader' +
        ' validation = "{{validation}}"' +
        ' upload-server="mockServer"';

    element = angular.element(html);
    $compile(element)(scope);
    $rootScope.$digest();
}));
description('aiFineUploader',function(){
var元素;
var范围;
每个模块之前(模块('ai.upload');
每个模块之前(模块('source/shared/upload/partials/fine uploader template.html');
beforeach(注入函数($compile,$rootScope){
scope=$rootScope;
scope.validation={
文件扩展名:“xml”,
sizeLimit:'100000000',
接受文件:['text/xml']
};
变量html=

“如果可以,请在chrome中调试您的站点,并检查源代码。查看html文件是否有不同大小写的文件夹路径

我遇到了一个疯狂的问题,我的grunt/karma设置会将html加载到这样的路径(app/src/Templates/my.html) 但是我的$templateCache正在寻找(app/src/templates/my.html)

问题是套管问题/模板与/模板

同样在您的测试中,即使加载了html,您也可能需要手动填充模板缓存,这是由于路径问题我不得不做的

编辑:尝试使用moduleName

确保您正在使用ngHtml2js预处理器

在karma配置文件中,您可以尝试使用moduleName选项

ngHtml2JsPreprocessor: {
    moduleName: 'myModule'
}
如果您使用的是require.js

我在我的项目中使用require时遇到了一个问题,它没有填充我的$templateCache 围绕名称和html包装对象的步骤

TEMPLATE = '(function() {\n' +
'  define([], function(){\n' +
'      return { name: \'%s\', html: \'%s\' };    \n' +
'  });\n' +
'}());\n';
在我的测试中,我刚刚添加了myHtml.html.js文件作为测试中的依赖项

define(['myHtml.html'], function (myHtml) {

    describe('Test', function () {

        it('should...', inject(function ($injector, $rootScope, $controller, $compile, $templateCache) {

            var $httpBackend = $injector.get('$httpBackend');
            $httpBackend.whenGET('/' + myHtml.name).respond(myHtml.html);
            var $scope = $rootScope.$new(); 
            var element = $compile('<div my-directive></div>')($scope);
            $scope.$digest();
            $httpBackend.flush();

            expect(element
        }

    }));
}
define(['myHtml.html'],函数(myHtml){
描述(‘测试’、功能(){
它('should…',inject(函数($injector,$rootScope,$controller,$compile,$templateCache){
var$httpBackend=$injector.get(“$httpBackend”);
$httpBackend.whenGET('/'+myHtml.name).response(myHtml.html);
var$scope=$rootScope.$new();
var元素=$compile(“”)($scope);
$scope.$digest();
$httpBackend.flush();
期望(元素)
}
}));
}

只是一些想法

我解决这个问题的方法是使用angular.element()将元素手动附加到beforeEach块中的文档正文。现在,当FineUploader查找它时,它就可用了。该块现在看起来像:

beforeEach(inject(function($compile, $rootScope, $templateCache) {
    scope = $rootScope;

    scope.validation = {
        fileExtensions: 'xml',
        sizeLimit : '100000000',
        acceptFiles: ['text/xml']
    };

    scope.onUploadComplete = function(){
        return 'onUploadComplete called';
    }

    scope.updateFileStatus = function(){
        return 'updateFileStatus called';
    }

    var html =
        ' <div fine-uploader' +
        ' validation = "{{validation}}"' +
        ' upload-server="mockServer"'+
        ' authentication-token="123"'+
        ' on-submit-file="onSubmitFile(file)"'+
        ' update-file-status="updateFileStatus(file)"'+
        ' on-upload-complete="onUploadComplete(response, file)">'+
        '</div>';

    element = angular.element(html);
    $compile(element)(scope);
    angular.element(document.body).append(element);
    scope.$digest();
}));
beforeach(注入函数($compile、$rootScope、$templateCache){
scope=$rootScope;
scope.validation={
文件扩展名:“xml”,
sizeLimit:'100000000',
接受文件:['text/xml']
};
scope.onUploadComplete=函数(){
返回'onUploadComplete called';
}
scope.updateFileStatus=函数(){
返回'updateFileStatus called';
}
变量html=
' '+
'';
element=angular.element(html);
$compile(元素)(范围);
元素(document.body).append(element);
范围。$digest();
}));

我遇到了同样的问题,cormacb的回答提供了我需要的提示(非常感谢cormacb

在我的工作方法中,在每个
之前的
中,我在一个html变量文本字符串中定义
,然后首先将该html附加到
文档.body
中。然后,我创建一个精细的上传程序
,编译并消化它——此时
qq模板
可用

var html =
        '<script type="text/template" id="qq-template">' +
        '    <div class="qq-uploader-selector qq-uploader qq-gallery" ng-attr-qq-drop-area-text="{{ dropZoneText }}">' +
        '        <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">' +
// ...
        '        </div>' +
        '    </div>' +
        '</script>';

angular.element(document.body).append(html);

var element = angular.element('<div fine-uploader></div>');
var compiledElement = _compile(element)(_scope);
_scope.$digest();
var-html=
'' +
'    ' +
'        ' +
// ...
'        ' +
'    ' +
'';
元素(document.body).append(html);
变量元素=角度元素(“”);
var compiledElement=_compile(element)(_scope);
_范围。$digest();
这种方法为
qq模板使用了一个简单的html/文本定义
,并且不需要像这里的其他答案那样使用任何html2js预处理器


希望这对其他人有所帮助。感谢SO社区提供了所有精彩的答案!

包含模板的
qq模板
脚本标记必须在DOM中可用/可供选择,直到您的测试/代码创建了一个优秀的上传器实例。错误消息表明事件顺序不符合此要求。您知道吗运气好吗?我正试图做完全相同的事情,但无法让测试正常进行……我的头撞在墙上已经有一段时间了。@mylescc你看到了OP中包含的答案吗?@RayNicholus抱歉,OP是什么意思?@mylescc原始海报,提问者。t