typescript - 如何测试mobx反应?
问题描述
注意:这不是真正的应用程序,而是问题的提炼版本。
我有一个简单的应用程序假 Todo 用于@computed
获取以下值TodoItemComputed.isSelected
:
import { computed, observable, action } from 'mobx';
export class TodoItemComputed {
readonly id: string;
readonly list: TodoListComputed;
constructor(id: string, list: TodoListComputed) {
this.id = id;
this.list = list;
}
// ** This is the attribute we are interested in and we want to test!
@computed
get isSelected() {
return this.id === this.list.selectedId;
}
}
export class TodoListComputed {
@observable.shallow
private serverData: string[] = [];
@observable
selectedId = '';
@action
setServerData(data: string[]) {
this.serverData = data;
}
@action
setSelected(id: string) {
this.selectedId = id;
}
@computed
get todoItems() {
return this.serverData.map(d => new TodoItemComputed(d, this));
}
}
测试TodoItemComputed.isSelected
我可以做这样的事情:
import { TodoListComputed } from '../TodoExample';
// Using jesthere, but the test framework should not matter...
describe('isSelected', function() {
it('should have no Item selected initially', function() {
const todoList = new TodoListComputed();
todoList.setServerData(['foo', 'bar']);
expect(todoList.todoItems[0].isSelected).toBe(false);
expect(todoList.todoItems[1].isSelected).toBe(false);
});
it('should select the correct item', function() {
const todoList = new TodoListComputed();
todoList.setServerData(['foo', 'bar']);
todoList.setSelected('bar');
expect(todoList.todoItems[0].isSelected).toBe(false);
expect(todoList.todoItems[1].isSelected).toBe(true);
});
});
由于某些原因,我必须重构我的应用程序并使用反应而不是计算(例如,因为我必须显示 10,000 个项目并且选择快速更改并且调用TodoListComputed.setSelected
导致所有计算在所有项目上重新运行)。
因此我将其更改为使用reaction
(似乎当我使用时,autorun
我可以使用与版本相同的测试computed
):
import { autorun, computed, observable, action } from 'mobx';
export class TodoItemReaction {
readonly id: string;
@observable
isSelected = false;
constructor(id: string) {
this.id = id;
}
@action
setSelected(isSelected: boolean) {
this.isSelected = isSelected;
}
}
export class TodoListReaction {
@observable.shallow
private serverData: string[] = [];
@observable
selectedId = '';
constructor() {
reaction(
() => [this.selectedId, this.todoItems],
() => {
this.todoItems.forEach(t => {
t.setSelected(t.id === this.selectedId);
});
}
);
}
@action
setServerData(data: string[]) {
this.serverData = data;
}
@action
setSelected(id: string) {
this.selectedId = id;
}
@computed
get todoItems() {
return this.serverData.map(d => new TodoItemReaction(d));
}
}
问题:如何测试autorun
版本?
奖励问题autorun
:如何测试我使用或无关紧要的代码computed
?
解决方案
无论您如何实现,您都应该能够测试这两种实现。顺便说一句,我认为这应该适用于任何测试,避免“了解”实现,测试需求。
您的实现的问题是列表@computed
上的使用todoItems
,当您isSelected
使用setSelected
. 这将导致@computed
todoItems
重新计算。这是因为您在初始化类时将设置isSelected
为。false
换句话说,@computed
todoItems
就是“倾听”每个项目的变化@observable
isSelected
。
这是一个非常简单快速的实现(没有reaction
):
export class TodoItem {
readonly id: string;
@observable isSelected = false;
constructor(id: string) {
this.id = id;
}
@action
setSelected(isSelected: boolean) {
this.isSelected = isSelected;
}
}
export class TodoList {
@observable.shallow
todoItems: TodoItem[] = [];
@action
setServerData(data: string[]) {
this.todoItems = data.map((d) => new TodoItem(d));
}
@action
setSelected(id: string) {
this.todoItems.forEach((t) => t.setSelected(t.id === id));
}
}
推荐阅读
- javascript - 我应该使用什么来代替 React 中数组的键中的索引?
- reactjs - Error React Redux Toolkit:为什么我不能使用 .findIndex 更改数组对象的键值
- c# - 如何在具有 TaskCompletionSource 的 IO-Bound 中使用异步操作?
- c# - ASP.NET Core 5 中的空 User.Identity.Name
- java - RedirectAttribute 的 addFlashAttribute 功能无法正常工作
- python - 根据每行中的条件插入新列
- c# - 如何使用 Autofac 在 MassTransit 中注册 GenericRequestClient
- reactjs - 我想在我的项目中自定义条纹表单以做出反应
- python - python 如何将输入值转换为数学函数
- html - CSS从右到左排序元素