Как протестировать компонент Angular 1.6 с внедренным сервисом?

Я хочу протестировать свой компонент Angular, который синтаксически основан на руководстве по стилю Джона Папы:

'use strict';

 angular.module('MyModule')
    .component('MyCmpnt', MyCmpnt())
    .controller('MyCtrl', MyCtrl);

function MyCmpnt() {

    return {
        restrict: 'E',
        templateUrl: 'myPath/myTemplate.html',
        bindings: {
            foo: '=',
            bar: '<'
        },
        controller: 'MyCtrl',
        controllerAs: 'vm'
    };
}

MyCtrl.$inject = ['MyService'];

function MyCtrl (MyService) {
    // controller logic
}

Как видите, я хочу внедрить MyService в контроллер и подсмотреть в функции этого самого сервиса.

Мой тестовый код:

'use strict';

describe('component: MyCmpnt', function () {

    var $componentController,
        MyService;

    beforeEach(module('MyModule'));

    beforeEach(module(function ($provide) {
        $provide.value('MyService', MyService);

        spyOn(MyService, 'serviceFunc').and.callThrough();
    }));

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


    it('should initiate the component and define bindings', function () {

        var bindings = {
            foo: 'baz',
            bar: []
        };

        var ctrl = $componentController('MyCmpnt', null, bindings);

        expect(ctrl.foo).toBeDefined();
    });
});

Однако эта настройка позволяет мне столкнуться со следующей ошибкой:

TypeError: undefined не является конструктором (оценка '$componentController('MyModule', null, bindings)')


person DonJuwe    schedule 01.02.2017    source источник
comment
Нет компонента MyModule...   -  person Estus Flask    schedule 01.02.2017
comment
@estus: MyModule — это модуль, состоящий из компонента MyCmpnt и соответствующего контроллера MyCtrl. Что вы имеете в виду?   -  person DonJuwe    schedule 02.02.2017
comment
Вы делаете $componentController('MyModule'..., а компонента MyModule нет. Это именно то, что говорит сообщение об ошибке. Это MyCmpnt. Не МойМодуль.   -  person Estus Flask    schedule 02.02.2017
comment
Вы правы, спасибо, это была опечатка, но вышеуказанная ошибка остается, поскольку $componentController не определено. Это означает, что инъекция даже не была выполнена.   -  person DonJuwe    schedule 02.02.2017
comment
Это не сходится. is not a constructor означает, что не просто что-то стало неопределенным, но конструктор стал неопределенным. Angular использует конструкторы только для контроллеров и service сервисов. Я предлагаю дважды проверить, исправили ли вы это в спецификации, которую вы используете, потому что я не вижу другого разумного объяснения этой ошибки из приведенного выше кода. Если проблема не устранена, рассмотрите возможность предоставления plunk/fiddle, который может воспроизвести эту ошибку. Кстати, у вас есть переменная MyService, не определенная в приведенном выше коде (spyOn(MyService... выкинет), это означает, что опубликованный код отличается от реального кода.   -  person Estus Flask    schedule 02.02.2017
comment
По-видимому, spyOn(MyService, 'serviceFunc').and.callThrough(); выдает ошибку при запуске в той же функции beforeEach(), что и $provide. Более того, эта ошибка, кажется, проглатывается репортером PhantomJS. Перемещение шпиона в функцию beforeEach(inject(function (_$componentController_) {})); работает. Спасибо за ваши усилия @estus, вы можете опубликовать это как ответ, и я приму его.   -  person DonJuwe    schedule 02.02.2017
comment
Конечно. Проглатывание ошибок - самая распространенная проблема с тестами Karma, с которыми я встречался, но не похоже, что это было так, потому что, если есть ошибка начальной загрузки, это приведет к тому, что $componentController будет неопределенным (а ошибка undefined is not a constructor означает, что это было определено), В любом случае, я бы посоветовал переключиться на Chrome, если у вас есть подозрения, что ошибки подавляются.   -  person Estus Flask    schedule 02.02.2017


Ответы (1)


В приведенном выше коде есть компонент $componentController('MyModule'..., но нет компонента MyModule.

Переменная MyService не определена при вызове spyOn(MyService.... Это вызовет ошибку, препятствующую правильной загрузке приложения.

Если тестовая установка использует PhantomJS, это может привести к подавлению ошибок в блоках beforeEach, для правильного сообщения об ошибках рекомендуется использовать лаунчер Chrome Karma.

Если проблема в том, что MyService не определено в точке, где определена фиктивная служба, ее можно определить на месте как заглушку:

beforeEach(module(function ($provide) {
    $provide.value('MyService', {
      serviceFunc: jasmine.createSpy().and.callThrough()
    });
}));
person Estus Flask    schedule 02.02.2017