1

これは、ブラウザーで UI を実行すると機能しますが、done メソッドを呼び出して save メソッドに戻す必要がある validateAsync メソッドの 'd' に対して常に null を取得しています。andCallFake (一意の名前テストをスパイするために必要) の使用方法がわかりませんが、(jQuery) 遅延呼び出しを返すようにすることもできません。このコードが、私が達成しようとしていることを理解するのに十分なコンテキストを提供してくれることを願っています。

    validateAsync = function () {
        var d,
            isValid = true,
            isUnique = false;
            // validate that name and description are given
            if (layout.Name() === '') {
                toastr.warning('Layout name is required', 'Layout');
                isValid = false;
            }
             // validate that there are no other layouts of the same type with the same name
            d = uiDataService.GetIsLayoutNameUniqueAsync(layout.LayoutId(), layout.Name(), layout.LayoutTypeId())
                .done(function (isUniqueResult) {
                    isUnique = isUniqueResult.toLowerCase() === "true";
                    if (!isUnique) {
                        toastr.warning('Layout name ' + layout.Name() + ' must be unique. There is already a layout with this name.', 'Layout');
                    }
                    // this is always undefined in my Jasmine tests
                    d.done(isValid && isUnique);
                })
                .fail(function (response) {
                    mstar.AjaxService.CommonFailHandling(response.responseText);
                });
            return d;
    },
    save = function () {
        validateAsync()
            .done(function (isValidResult) {
                var isValid = isValidResult.toLowerCase() === "true";
                if (!isValid) {
                    return;
                }
                 // show a toastr notification on fail or success
                dataContext.SaveChanges(layout, uiDataService)
                    .done(function (layoutIdFromSave) {
                        toastr.success('The layout was saved. Refreshing...');
                    })
                    .fail(function () {
                        toastr.error('There was an error saving the layout.');
                    })
                    .always(function () {
                        // toastr.info('finished');
                    });
            })
            .fail(function () {
                throw new Error('There was an error validating before save');
            });
    };      

    // in uiDataService
     getIsLayoutNameUniqueAsync = function (layoutId, layoutName, layoutTypeId) {
        return ajaxService.AjaxGetJsonAsync(webServiceUrl + "GetIsLayoutNameUnique?layoutId=" + layoutId + "&layoutName=" + escape(layoutName) + "&layoutTypeId=" + layoutTypeId);
    },
    // in ajaxService
 ajaxGetJsonAsync = function (url, cache) {
            return $.ajax({
                type: "GET",
                url: url,
                dataType: "json",
                accepts: {
                    json: "application/json"
                },
                cache: cache === undefined ? false : cache
        });
    },
// in a beforeEach
var getIsLayoutNameUniquePromiseSpy = spyOn(mstar.dataService.UiDataService, "GetIsLayoutNameUniqueAsync")
    .andCallFake(function () {
        spyObj.called = true;
        // http://stackoverflow.com/questions/13148356/how-to-properly-unit-test-jquerys-ajax-promises-using-jasmine-and-or-sinon
        var d = $.Deferred();
        d.resolve('true');
        return d.promise();
    });
// and a test
it("should show a toastr", function () {
    // Act
    vm.GetLayout().Name('Test');
    vm.GetLayout().Description('Test');
    vm.Save();
    // Assert
    expect(toastr.success).toHaveBeenCalledWith('The layout was saved. Refreshing...');
});
4

1 に答える 1

2

整理すると、私はジャスミンについてあまり知りませんが、コードを独自のメリットで取り上げると、必要最小限の骨まで剥ぎ取られた場合に何が起こっているのかを理解するのがはるかに簡単になります.

大幅に簡素化され、validateAsync()現在は次のように構成されています。

validateAsync = function () {
    ...
    var d = fn_that_returns_a_promise().done(function() {
        ...
        d.done(boolean);
    }).fail(function() {
        ...
    });
    return d;
};

ブール値の引数を受け入れないため、正しいと.done()は言えません。また、絶対に間違っているとは言えませんが、ハンドラーd.done()内では実際には適切ではありません(状況が異なる可能性があります)。d.done()

失敗の場合は保持しながら、成功の場合をフィルタリングするために採用することをお勧めします.then()(したがって、ブール値で解決された新しい約束を渡します) 。.fail()次のような構造を与える:

validateAsync = function () {
    ...
    return uiDataService.GetIsLayoutNameUniqueAsync(...).then(function(...) {
        ...
        return isValid && isUnique;
    }).fail(function(...) {
        ...
    });
};

したがって、save()次のようになります。

save = function() {
    validateAsync().done(function(isValid) {
        //validation success
        if(!isValid) return;
        ...
    }.fail(function() {
        //validation failure
        ...
    });
};

あとは、「点をつなげる」(つまり、自分のステートメントを再挿入するなど) だけです。私が間違いを犯していないことを願っています。

于 2013-04-08T21:25:10.050 に答える