2013-04-08 77 views
1

当我在浏览器中运行用户界面时,这是行得通的,但我总是在我的validateAsync方法中需要调用done方法以使其恢复保存中的'd'方法。我无法弄清楚如何使用andCallFake(需要间谍独特的名称测试),但也让它返回(jQuery)延期调用完成。 希望这段代码能给你足够的上下文来看看我正在努力完成什么。使用Jasmine测试嵌套承诺

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

您正在将一个布尔值传递给'.done()',它需要一个函数。 – 2013-04-08 20:22:19

+0

@ Beetroot-Beetroot done()应该在保存方法中将.done烧掉。 $ .Deferred()有一个.resolve方法,但我不认为$ .Deferred()。promise()有一个.resolve方法。 – Aligned 2013-04-08 20:32:39

+0

这是正确的,只有一个Deferred具有状态改变方法,而从Deferred派生的Promise是一个“消费者”对象(与Deferred本身一样)可以响应状​​态更改。但请不要挂在这一点上,因为'validateAsync()'和'save()'中的所有内容都在客户端 - 状态的改变在'uiDataService.GetIsLayoutNameUniqueAsync()'方法内部管理。我不打算试图对Jasmine发表评论,除了编写和调试代码来调试其他复杂或简单顺序的代码似乎完全没有意义。 – 2013-04-09 00:14:35

回答

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

现在你要做的就是“加入了点”(即重新插入自己的声明等。)并希望我没有犯任何错误。

+1

这是要走的路。我不明白你可以从那时候回来,并认为我必须解决从fn_that_returns_a_promise方法返回的承诺。感谢您的帮助! – Aligned 2013-04-09 13:06:28

+0

有趣的是,我认为我在'validateAsync()'中说得很对,'.then()'和'.fail()'这两个方法是可交换的 - 换句话说,它们可以以任何一种顺序链接; '.then()。fail()'或'.fail()。then()'。这不是一般性,就在这种情况下。 – 2013-04-09 16:37:36