我正在Angular中编写一个REST应用程序,我想为它编写单元测试(当然!).我有一个控制器,它从json中的REST服务获取博客文章列表,并将摘要放入$ scope,因此我可以在视图中显示它们.
起初,博客帖子只是显示为文本 Blog body
,而不是渲染为解析的HTML,直到我发现你可以将ng-bind-html与$ sce服务结合使用.这在正确显示博客文章方面现在可以正常工作.
单元测试时会出现问题.我试图用一些HTML模拟一个json响应,然后测试我的控制器是否正确处理HTML.这是我的代码:
.controller( 'HomeCtrl', function HomeController( $scope, $http, $sce ) { $scope.posts = {}; $http.get('../drupal/node.json').success(function (data) { var posts; posts = data.list; for(var i = 0; i < posts.length; i ++) { posts[i].previewText = $sce.trustAsHtml(posts[i].body.summary); posts[i].created = posts[i].created + '000'; // add milliseconds so it can be properly formatted } $scope.posts = posts; }); })
describe('HomeCtrl', function() { var $httpBackend, $rootScope, $sce, createController; beforeEach(inject(function ($injector) { // Set up the mock http service responses $httpBackend = $injector.get('$httpBackend'); // Get hold of a scope (i.e. the root scope) $rootScope = $injector.get('$rootScope'); // The $controller service is used to create instances of controllers var $controller = $injector.get('$controller'); $sce = $injector.get('$sce'); createController = function() { return $controller('HomeCtrl', { '$scope': $rootScope }); }; })); it('should get a list of blog posts', function() { var rawResponse = { "list": [ { "body": { "value": "\u003Cp\u003EPost body.\u003C\/p\u003E\n", "summary": "\u003Cp\u003ESummary.\u003C\/p\u003E\n" }, "created": "1388415860" } ]}; var processedResponse = [{ "body": { "value": "\u003Cp\u003EPost body.\u003C\/p\u003E\n", "summary": "\u003Cp\u003ESummary.\u003C\/p\u003E\n" }, "created": "1388415860000", previewText: $sce.trustAsHtml("\u003Cp\u003ESummary.\u003C\/p\u003E\n") }]; $httpBackend.when('GET', '../drupal/node.json').respond(rawResponse); $httpBackend.expectGET("../drupal/node.json").respond(rawResponse); var homeCtrl = createController(); expect(homeCtrl).toBeTruthy(); $httpBackend.flush(); expect($rootScope.posts).toEqual(processedResponse); }); });
当我通过Karma测试运行器运行上述内容时,我收到以下响应:
Chrome 31.0.1650 (Windows) home section HomeCtrl should get a list of blog posts FAILED Expected [ { body : { value : 'Post body.
', summary : 'Summary.
' }, created : '1388415860000', previewText : { $$unwrapTrustedValue : Function } } ] to equal [ { body : { value : 'Post body.
', summary : 'Summary.
' }, created : '1388415860000', previewText : { $$unwrapTrustedValue : Function } } ].
我怀疑问题是由于$sce.trustAsHtml
返回包含函数的对象而不是字符串的事实.
我的问题是,首先,我是否以正确的方式处理这个问题?
其次,如果是这样,我该如何测试输出$sce.trustAsHtml
?
我发现你可以使用$sce.getTrusted
哪个将返回最初传递给的值$sce.trustAsHtml
,在这种情况下是一个包含HTML的字符串,然后你可以用通常的方式测试它是否相等.
所以我的测试现在看起来像这样:
it('should create a previewText property using $sce.trustAsHtml', function() { // confirms that it is an object, as should be the case when // it has been through $sce.trustAsHtml expect(typeof result.previewText === 'object').toEqual(true); expect($sce.getTrusted($sce.HTML, result.previewText)) .toEqual('<p>Original HTML content string</p>'); });
在每次测试之前,您必须使用其提供程序禁用$ sce.
当$ sce被禁用时,所有$ sce.trust*方法只返回原始值而不是包装函数.
beforeEach(module(function ($sceProvider) { $sceProvider.enabled(false); })); it('shall pass', inject(function($sce){ expect($sce.trustAsHtml('<span>text</span>')).toBe('<span>text</span>'); }));
在您的特定示例中,只需这样做:
describe('HomeCtrl', function() { var $httpBackend, $rootScope, $sce, createController; beforeEach(module(function ($sceProvider) { $sceProvider.enabled(false); })); // rest of the file });
由于michael-bromley给出的答案对我不起作用,我想指出另一种解决方案.在我的情况下,我使用的是一个过滤器,它将每个字符串的出现包装在另一个字符串中,其字符串的类别为"highlight".换句话说,我希望突出显示单词.这是代码:
angular.module('myModule').filter('highlight', function ($sce) { return function (input, str) { return $sce.trustAsHtml((input || '').replace(new RegExp(str, 'gi'), '<span class=\"highlighted\">$&</span>')); }; });
我使用$ sce服务将结果值信任为HTML.为了测试这个,我需要对结果值使用$$ unwrapTrustedValue函数来使我的测试工作:
it('01: should add a span with class \'highlight\' around each mathing string.', inject(function ($filter) { // Execute var result = $filter('highlight')('this str contains a str that will be a highlighted str.', 'str'); // Test expect(result.$$unwrapTrustedValue()).toEqual('this <span class="highlighted">str</span> contains a <span class="highlighted">str</span> that will be a highlighted <span class="highlighted">str</span>.'); }));
更新:
正如@gugol所指出的那样,最好不要使用像$$ unwrapTrustedValue这样的Angular内部方法.更好的方法是在$ sce服务上使用public getTrustedHtml方法.像这样:
it('01: should add a span with class \'highlight\' around each mathing string.', inject(function ($sce, $filter) { // Execute var result = $filter('highlight')('this str contains a str that will be a highlighted str.', 'str'); // Test expect($sce.getTrustedHtml(result)).toEqual('this <span class="highlighted">str</span> contains a <span class="highlighted">str</span> that will be a highlighted <span class="highlighted">str</span>.'); }));