Подтвердить что ты не робот

Модуль тестирует вывод $sce.trustAsHtml в Angular

Я пишу приложение REST в Angular, и я хочу написать для него единичные тесты (конечно!). У меня есть контроллер, который получает список сообщений в блоге из службы REST в json и помещает резюме в область $, поэтому я могу отображать их в представлении.

Сначала сообщения в блоге просто отображались как текст, т.е. <p>Blog body</p>, а не отображались как обработанные HTML, пока я не обнаружил, что вы можете использовать ng-bind -html в сочетании с сервисом $sce. Теперь это прекрасно работает с точки зрения корректного отображения сообщений в блоге.

Проблема возникает при модульном тестировании. Я пытаюсь издеваться над json-ответом с некоторым HTML-кодом, а затем проверяю, что мой контроллер правильно работает с 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;
    });
})

unit test

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 : '<p>Post body.</p>
    ', summary : '<p>Summary.</p>
    ' }, created : '1388415860000', previewText : { $$unwrapTrustedValue : Function } }          ] to equal [ { body
: { value : '<p>Post body.</p>
    ', summary : '<p>Summary.</p>
    ' }, created : '1388415860000', previewText : { $$unwrapTrustedValue : Function } }     ].

Я подозреваю, что проблема связана с тем, что $sce.trustAsHtml возвращает объект, содержащий функцию, а не строку.

Мой вопрос, во-первых, Я правильно подошел к этой проблеме?

Во-вторых, если это так, , как мне следует тестировать вывод $sce.trustAsHtml?

4b9b3361

Ответ 1

Поскольку ответ, заданный 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>.'); 
}));

UPDATE:

Как @gugol любезно отметил, что не рекомендуется использовать Angular внутренние методы, такие как $$ unwrapTrustedValue. Лучшим подходом является использование общедоступного метода getTrustedHtml в службе $sce. Например:

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>.');
}));

Ответ 2

Вы должны отключить $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
});

Ответ 3

Я обнаружил, что вы можете использовать $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>');
});

Ответ 4

Другой вариант - использовать функцию getTrustedHtml(), чтобы получить значение строки html из $$ unwrapTrustedValue.

vm.user.bio = $sce.getTrustedHtml(vm.user.bio);