Как запустить $ onInit или $ onChanges косвенно в модульном тестировании контроллера угловых компонентов?

Я использую Angular 1.5.5 и Jasmine в качестве тестовой среды. В настоящее время я должен сделать что-то вроде этого, чтобы тест прошел:

function createController(bindings) {
    return $componentController('myController', null, bindings);
}

beforeEach(inject(function (_$componentController_) {
    $componentController = _$componentController_;
}));

describe('on pages updated', function () {

    beforeEach(function () {
        controller = createController({prop1: 0, prop2: 0});
        controller.$onInit(); // you see I have to explitcitly call this $onInit function
    });

    it('should update isSelected and currentPage', function () {
        expect(controller.prop1).toBe(0);
        expect(controller.prop2).toBe(0);

        controller.prop1= 1;
        controller.prop2= 2;
        controller.$onChanges(controller); // and $onChanges here as well

        expect(controller.prop1).toBe(1);
        expect(controller.prop2).toBe(2);
    });

});
 Dan Pantry28 июл. 2016 г., 10:51
Почему вы хотите вызвать это неявно в первую очередь?$onInit является ловушкой жизненного цикла, вызываемой, когда компонент смонтирован. Там нет причин для$componentController когда-либо вызывать эту функцию самостоятельно в модульных тестах. Вы должны определенно вызывать эти вещи явно, если вы не тестируете компонент в целом.

Ответы на вопрос(3)

В github есть проблема, связанная с этим:https://github.com/angular/angular.js/issues/14129

В основном это работает как задумано, не звонит$onInit или же$onChanges автоматически.

бессмысленно (или не имеет смысла) выполнять $ onInit, я объясняю это: $ componentController является для экземпляров контроллеров своего рода заменой $ controller, но вместо создания экземпляров контроллеров, зарегистрированных в controllerProvider, он создает экземпляры контроллеров, зарегистрированных через директивы (те, которые удовлетворяют определению компонента). Итак, когда у вас есть экземпляр контроллера, вы можете вручную вызывать $ onInit и весь жизненный цикл вашего контроллера, идея состоит в том, что вы тестируете контроллер, а не директиву (и ее взаимосвязи).

Вам потребуется взять ссылку на контроллер из скомпилированной версии элемента. Как показано ниже:

describe('Component: Test Method', function () {

        beforeEach(inject(function (_$rootScope_) {
            scope = _$rootScope_.$new();
        }));


        it('should set value of selectedPackage to null after $onChanges event', inject(function ($compile) {
            // Trigger 1st $onChanges
            scope.selectedPackage = 'packageCode';

            var element = angular.element('<select-my-tv selected-package="selectedPackage"></select-my-tv>');
            element = $compile(element)(scope);
            scope.$digest();

            //Extract the Controller reference from compiled element
            var elementController = element.isolateScope().$ctrl;

            // Assert
            expect(elementController.selectedPackage).toBeNull();
        }));
    });
});
 c24w15 мая 2017 г., 13:37
Но почему вы ожидаетеselectedPackage бытьnull? Я это понимаю$onInit не вызывается, когда тыnewконтроллера, но почему он не вызывается при рендеринге реального компонента с$compile? Конечно, это должно вызвать все ловушки жизненного цикла.

Я не знаю, поможет ли это, но для тестирования компонентов я делаю следующее

beforeEach(module('templates'));

var element;        
var scope;

beforeEach(inject(function ($rootScope, $compile) {
    scope = $rootScope.$new();
    scope.draw = new ol.source.Vector({ wrapX: false });
    element = angular.element('<custom-element draw="draw"></custom-element>');
    element = $compile(element)(scope);
}));

var controller;
beforeEach(inject(function ($rootScope, $componentController) {
    scope = $rootScope.$new();
    scope.draw = new ol.source.Vector({ wrapX: false });
    controller = $componentController('customElement', {draw: new ol.source.Vector({ wrapX: false })}, { $scope: scope });
}));

и $ onInit () и $ onChanges () запускаются, когда они должны быть, сами по себе

 elasticrash28 июл. 2016 г., 11:03
@DanPantry почему это так, вы компилируете компонент и запрашиваете контроллер этого компонента
 Dan Pantry28 июл. 2016 г., 10:55
Разве это не даст вам контроллер, который на самом деле не связан с компонентом, который вы компилируете?
 Great Question28 июл. 2016 г., 10:55
Так что мне кажется, что ваш трюк в том, чтобы использовать сервис $ compile для компиляции директивы, верно?
 Dan Pantry28 июл. 2016 г., 11:17
Из того, что я читаю здесь, вы компилируете компонент, а затем запрашиваете экземпляр контроллера этого компонента, но не обязательно экземпляр контроллера, с которым был скомпилирован компонент (если это имеет смысл). IOW,$compile() создает контроллер, а затем вы создаетедругой контроллер с$componentController, Это тот же класс контроллера, но не тот же экземпляр класса, который создан$compile, Я бы предположил, что лучший способ сделать этоangular.element(...).controller(), что даст вам контроллер, связанный с компонентом.

Ваш ответ на вопрос