Force Knockout computed 在更换可观察内部后重新评估
Force Knockout computed to re-evaluate after replacement of observable inside
一位同事 运行 遇到了一个问题,即他想测试的计算机没有返回预期的输出。发生这种情况是因为我们想要存根其他计算(这又依赖于其他计算)。存根后,计算中剩下 0 个可观察对象,并且计算不断返回缓存的结果。
我们如何强制计算器重新评估其内部不再具有原始可观测值?
const ViewModel = function() {
this.otherComputed = ko.computed(() => true);
this.computedUnderTest = ko.computed(() => this.otherComputed());
};
const vm = new ViewModel();
function expect(expected) {
console.log(vm.computedUnderTest() === expected);
}
// Init
expect(true);
// Stub dependent computed
vm.otherComputed = () => false;
// Computed no longer receives updates :(
expect(false);
// Can we force re-evaluation?
// vm.computedUnderTest.forceReEval()
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
我能想到的唯一 不 涉及更改 ViewModel
代码的解决方案是先存根 ko.computed
...
在下面的示例中,我将 ko.computed
替换为扩展版本。该扩展公开了一个 属性、.stub
,允许您编写自定义函数。设置此函数后,计算将使用提供的逻辑重新计算。
在您的测试文件中,您需要能够在准备代码中替换对 ko.computed
的全局引用,在 实例化 ViewModel 实例之前。
// Extender that allows us to change a computed's main value getter
// method *after* creation
ko.extenders.canBeStubbed = (target, value) => {
if (!value) return target;
const stub = ko.observable(null);
const comp = ko.pureComputed(() => {
const fn = stub();
return fn ? fn() : target();
});
comp.stub = stub;
return comp;
}
// Mess with the default to ensure we always extend
const { computed } = ko;
ko.computed = (...args) =>
computed(...args).extend({ canBeStubbed: true });
// Create the view model with changed computed refs
const ViewModel = function() {
this.otherComputed = ko.computed(() => true);
this.computedUnderTest = ko.computed(() => this.otherComputed());
};
const vm = new ViewModel();
function expect(expected) {
console.log("Test succeeded:", vm.computedUnderTest() === expected);
}
expect(true);
// Replace the `otherComputed`'s code by another function
vm.otherComputed.stub(() => false);
expect(false);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
在我自己的项目中,我倾向于使用一种完全不同的方法来测试我的计算,该方法侧重于将逻辑与依赖项分开。如果上面的示例对您不起作用,请告诉我。 (如果这已经满足您的需求,我不会再写另一个答案)
一位同事 运行 遇到了一个问题,即他想测试的计算机没有返回预期的输出。发生这种情况是因为我们想要存根其他计算(这又依赖于其他计算)。存根后,计算中剩下 0 个可观察对象,并且计算不断返回缓存的结果。
我们如何强制计算器重新评估其内部不再具有原始可观测值?
const ViewModel = function() {
this.otherComputed = ko.computed(() => true);
this.computedUnderTest = ko.computed(() => this.otherComputed());
};
const vm = new ViewModel();
function expect(expected) {
console.log(vm.computedUnderTest() === expected);
}
// Init
expect(true);
// Stub dependent computed
vm.otherComputed = () => false;
// Computed no longer receives updates :(
expect(false);
// Can we force re-evaluation?
// vm.computedUnderTest.forceReEval()
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
我能想到的唯一 不 涉及更改 ViewModel
代码的解决方案是先存根 ko.computed
...
在下面的示例中,我将 ko.computed
替换为扩展版本。该扩展公开了一个 属性、.stub
,允许您编写自定义函数。设置此函数后,计算将使用提供的逻辑重新计算。
在您的测试文件中,您需要能够在准备代码中替换对 ko.computed
的全局引用,在 实例化 ViewModel 实例之前。
// Extender that allows us to change a computed's main value getter
// method *after* creation
ko.extenders.canBeStubbed = (target, value) => {
if (!value) return target;
const stub = ko.observable(null);
const comp = ko.pureComputed(() => {
const fn = stub();
return fn ? fn() : target();
});
comp.stub = stub;
return comp;
}
// Mess with the default to ensure we always extend
const { computed } = ko;
ko.computed = (...args) =>
computed(...args).extend({ canBeStubbed: true });
// Create the view model with changed computed refs
const ViewModel = function() {
this.otherComputed = ko.computed(() => true);
this.computedUnderTest = ko.computed(() => this.otherComputed());
};
const vm = new ViewModel();
function expect(expected) {
console.log("Test succeeded:", vm.computedUnderTest() === expected);
}
expect(true);
// Replace the `otherComputed`'s code by another function
vm.otherComputed.stub(() => false);
expect(false);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
在我自己的项目中,我倾向于使用一种完全不同的方法来测试我的计算,该方法侧重于将逻辑与依赖项分开。如果上面的示例对您不起作用,请告诉我。 (如果这已经满足您的需求,我不会再写另一个答案)