[英]How can I unit test Knockout.js subscribe functions with Jasmine?
I have a knockout viewmodel which has a few subscribe functions that update some default selections after it picks up a change to a parent selection.我有一个淘汰赛视图模型,它有一些订阅功能,在它获取对父选择的更改后更新一些默认选择。
But I'm not sure how to call the function and fake the dependencies in order to test it.但我不确定如何调用该函数并伪造依赖项以对其进行测试。
This code snippit is similar to the function but not the exact one.此代码片段与函数相似,但不完全相同。 It's subscribed to SelectedParentOption observable and when it changes to checks through what's available and selects a new value.它订阅了 SelectedParentOption observable,当它更改为检查可用内容并选择新值时。
//When selection changes select default for remaining selection
self.ServerModel.ProductModel.SelectedParentOption.subscribe(function () {
// Loop through options returned by function checking for correct key
self.availableOptions().forEach(function (option) {
if (option.Key == 1)
// Assign default selection
self.ServerModel.ProductModel.SelectedChildOption(option);
}
});
This is the Jasmine unit test这是 Jasmine 单元测试
it("Selection set to default after change", function () {
// Spy on available options to dictate what's available
spyOn(testModel, 'availableOptions').and.returnValue(TestOptions);
// Change selection
ServerModel.ProductModel.SelectedParentOption(Option1);
// Call function
ServerModel.ProductModel.SelectedParentOption.subscribe();
// Verify default was selected
expect(ServerModel.ProductModel.SelectedChildOption()).toBe(ExpectedOption);
});
Currently this changes the option but the subscribe code doesn't seem to get hit at all.目前这改变了选项,但订阅代码似乎根本没有受到影响。
I don't really see anything wrong with your code, other that you don't need to call subscribe()
after setting an observable's value;我真的看不出你的代码有什么问题,除了在设置 observable 的值后你不需要调用subscribe()
; knockout does that for you.淘汰赛为您做到这一点。 The subscribe method is used to register a function that handles a new value. subscribe 方法用于注册一个处理新值的函数。
It's important to keep in mind however, that subscriptions won't be triggered if the observable is set to the same value as it already holds.然而,重要的是要记住,如果 observable 设置为与它已经拥有的值相同的值,则不会触发订阅。
So in your case: if SelectedParentOption() === Option1
before your Change selection
comment, no reset will occur.所以在您的情况下:如果SelectedParentOption() === Option1
在您的Change selection
评论之前,则不会发生重置。 If you want to manually trigger it, you use valueHasMutated()
(instead of where you used subscribe()
)如果你想手动触发它,你使用valueHasMutated()
(而不是你使用subscribe()
)
Check out these (quick and dirty) tests.检查这些(快速和肮脏的)测试。
Test 2 and 3 contradict each other;测试 2 和 3 相互矛盾; only 1 of them will pass.只有 1 个会通过。 They describe different behavior:它们描述了不同的行为:
I can imagine test 2 better describes what you're looking for, but if you want test 3 to pass, you can extend your observable to always notify its subscribers .我可以想象测试 2 更好地描述了您正在寻找的内容,但是如果您希望测试 3 通过,您可以扩展您的 observable 以始终通知其订阅者。 Uncomment the comment in the ViewModel to see the difference.取消注释 ViewModel 中的注释以查看差异。
function ViewModel() { this.selectedParent = ko.observable(0)/*.extend({notify: 'always'})*/; this.children = [{ key: 0 }, { key: 1}, { key: 2 }]; this.selectedChild = ko.observable(null); this.selectedParent.subscribe(function() { this.selectedChild(this.children.find(function(child) { return child.key === 1; })); }, this) } describe('Subscription test', function() { var vm; beforeEach(function() { vm = new ViewModel(); }); it("should reset child selection to child 1 when parent changes", function() { expect(vm.selectedChild()).toBe(null); vm.selectedParent(1); expect(vm.selectedChild().key).toBe(1); }); it("should not reset child when re-setting the same parent selection", function() { vm.selectedParent(1); vm.selectedChild(vm.children[2]); expect(vm.selectedChild().key).toBe(2); // Same primitive, won't trigger the subscription vm.selectedParent(1); expect(vm.selectedChild().key).toBe(2); }); // To fix this test, uncomment .extend in selectedParent it("should always reset child when re-setting the same parent selection", function() { vm.selectedParent(1); vm.selectedChild(vm.children[2]); expect(vm.selectedChild().key).toBe(2); vm.selectedParent(1); expect(vm.selectedChild().key).toBe(1); }); it("should initialize without a selection", function() { expect(vm.selectedChild()).toBe(null); }); it("should set selections", function() { vm.selectedChild(vm.children[2]); expect(vm.selectedChild().key).toBe(2); }); });
<script src="http://searls.github.io/jasmine-all/jasmine-all-min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
You should call .subscribe()
before you change the observed value.您应该在更改观察值之前调用.subscribe()
。 It only detects changes after subscription has been set up.它仅在设置订阅后检测更改。 Try this instead:试试这个:
// enable subscription ServerModel.ProductModel.SelectedParentOption.subscribe(); // Change selection ServerModel.ProductModel.SelectedParentOption(Option1); // Verify default was selected expect(ServerModel.ProductModel.SelectedChildOption()).toBe(ExpectedOption);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.