1

外部テンプレートを使用し、サービスからデータが渡されるカスタム ディレクティブがあります。データを変更する前に約束が解決されていることを確認することにしました。これは実際のコードでは問題ありませんでしたが、単体テストが壊れてしまい、面倒でした。私はいくつかのバリエーションを試しましたが、今は立ち往生しています。「ng-html2js」プリプロセッサを使用しています。

単体テストはこちら

describe('ccAccordion', function () {
var elm, scope, deferred, promise, things;
beforeEach(module('ccAccordion'));
// load the templates
beforeEach(module('components/accordion/accordion.html'));

beforeEach(inject(function ($rootScope, $compile, $q) {
    elm = angular.element(
      '<cc-accordion items="genres"></cc-accordion>'
      );
    scope = $rootScope;
    things = [{
            title: 'Scifi',
            description: 'Scifi description'
        }, {
            title: 'Comedy',
            description: 'Comedy description'
        }];

    deferred = $q.defer();
    promise = deferred.promise;

    promise.then(function (things) {
        scope.items = things;   
    });

    // Simulate resolving of promise
    deferred.resolve(things);

    // Propagate promise resolution to 'then' functions using $apply().
    scope.$apply();

    // compile the template?
    $compile(elm)(scope);
    scope.$digest();
}));

it('should create clickable titles', function () {
    var titles = elm.find('.cc-accord h2');

    expect(titles.length).toBe(2);
    expect(titles.eq(0).text().trim()).toBe('Scifi');
    expect(titles.eq(1).text().trim()).toBe('Comedy');
});

カスタム addMatchers と残りのテストは省略しました。私が得るエラーは

TypeError: 'undefined' is not an object (evaluating 'scope.items.$promise')

ここにディレクティブがあります

var ccAccordion = angular.module("ccAccordion", []);
ccAccordion.directive("ccAccordion", function () {
return {
    restrict: "AE",
    templateUrl: "components/accordion/accordion.html",
    scope: {
        items: "="
    },
    link: function (scope) {
        scope.items.$promise.then(function (items) {
            angular.forEach(scope.items, function (item) {
                item.selected = false;
            });
            items[0].selected = true;
        });

        scope.select = function (desiredItem) {
            (desiredItem.selected === true) ? desiredItem.selected = false : desiredItem.selected = true;
            angular.forEach(scope.items, function (item) {
                if (item !== desiredItem) {
                    item.selected = false;
                }
            });
        };

    }
};

});

これは、ディレクティブが main.html で使用される場所です。

<cc-accordion items="genres"></cc-accordion>

メインコントローラーでは、ジャンルサービスが渡されます

 angular.module('magicApp')
.controller('GenresCtrl', ['$scope', 'BREAKPOINTS', 'Genre', 
function ($scope, BREAKPOINTS, Genre) {
    $scope.bp = BREAKPOINTS;
    $scope.genres = Genre.query();
}]);
4

2 に答える 2

0

わかりました、あなたがリンクに入れたコードをコントローラーに移動します。データ処理はおそらくサービスで行われるはずです。大きなコントローラーは良くないと言われたことは知っていますが、大きなリンク関数は一般的に悪いので、そのようなデータ処理を行うべきではありません。

.controller('GenresCtrl', ['$scope', 'BREAKPOINTS', 'Genre', 
function ($scope, BREAKPOINTS, Genre) {
    $scope.bp = BREAKPOINTS;
    $scope.genres = Genre.query().then(function (items) {
        angular.forEach(scope.items, function (item) {
            item.selected = false;
        });
        items[0].selected = true;
    });

    scope.select = function (desiredItem) {
        (desiredItem.selected === true) ? desiredItem.selected = false : desiredItem.selected = true;
        angular.forEach(scope.items, function (item) {
            if (item !== desiredItem) {
                item.selected = false;
            }
        });
    };
});

リンク関数は空になりました。代わりに rootScope でアイテムを定義します。これにより、isolateScope とディレクティブ インターフェイスが正しく機能することが保証されます。

beforeEach(inject(function ($rootScope, $compile, $q) {
    elm = angular.element(
      '<cc-accordion items="genres"></cc-accordion>'
      );
    scope = $rootScope;
    things = [{
            title: 'Scifi',
            description: 'Scifi description'
        }, {
            title: 'Comedy',
            description: 'Comedy description'
        }];
    scope.items = things; // Tests your directive interface

    // compile the template?
    $compile(elm)(scope);
    scope.$digest();
}));

promise の動作は、サービスの戻り値をモックすることにより、コントローラー テストでテストする必要があります。$promise テストに関する問題は解決されました。

実際の問題は、 $q.defer() が角度のある $http と同じ種類の約束をしたと想定していたことですが、それは代わりに設計によって解決されています。

于 2015-01-23T08:37:00.873 に答える