【发布时间】:2017-02-15 04:37:17
【问题描述】:
上下文
我正在测试一个组件,该组件使用基于 observable 的服务来获取一些数据并将其显示用于 i18n 目的。
i18n 服务是根据特定需求定制的。
组件在开发模式下工作(在某些模板中使用,工作正常)但测试失败。
来源
组件
@Component({
selector : "i18n",
template : '<span [innerHTML]="text"></span><span #wrapper hidden="true"><ng-content></ng-content><span>',
encapsulation: ViewEncapsulation.None
})
export class I18nComponent implements OnChanges {
constructor(private i18n:I18n) {
}
@ViewChild('wrapper')
content:ElementRef;
@Input('key')
key:string;
@Input('domain')
domain:string;
@Input('variables')
variables:Variables = [];
@Input("plural")
plural:number;
text:string;
ngOnChanges():any {
this.i18n.get(this.key, this.content.nativeElement.innerHTML, this.variables, this.domain).subscribe((res) => {
this.text = res;
});
}
}
I18n.get
public get(key:string,
defaultValue?:string,
variables:Variables = {},
domain?:string):Observable<string>{
const catalog = {
"StackOverflowDomain":
{
"my-key":"my-value"
}
};
return Observable.of(catalog[domain][key]).delay(300);
}
Variables:
export interface Variables {
[key:string]:any;
}
测试
describe("I18n component", () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers : [
I18n,
{
provide : I18N_CONFIG,
useValue: {
defaultLocale : "fr_FR",
variable_start: '~',
variable_end : '~'
}
},
{
provide : I18N_LOADERS,
useClass: MockLocaleLoader,
multi : true
}
],
declarations: [
I18nComponent
]
});
fixture = TestBed.createComponent<I18nComponent>(I18nComponent);
comp = fixture.componentInstance;
});
fit("can call I18n.get.", fakeAsync(() => {
comp.content.nativeElement.innerHTML = "nope";
comp.key = "test";
comp.domain = "test domain";
comp.ngOnChanges();
tick();
fixture.detectChanges();
expect(comp.text).toBe("test value");
}));
});
问题
测试失败并显示消息:
预期未定义为“测试值”。
错误:1 个周期性计时器仍在队列中。
因为i18n.get在断言被检查之前没有完成它的工作,所以comp.text仍然是undefined。
已经尝试过
- 在
tick方法调用中添加一个非常高的值,没有任何改变(尝试使用 5000)。 - 使
ngOnChanges返回一个在this.text = res;之后立即解析的Promise<void>并更改fakeAsync区域以使用done方法在then中调用comp.ngOnChanges进行简单测试。它有效,但ngOnChanges不应返回Promise,我想要一个干净的解决方案。
【问题讨论】:
-
您能否提供足够多的
get方法的示例实现来重现该问题。我不确定如何实现它以获取错误 -
我编辑了问题,为
i18n.get添加了一个模型实现 -
你的真实代码真的使用
delay吗?我问的原因是因为我试图从使用fakeAsync切换到async看看是否有什么不同,但似乎delay使用setInterval,不能在async内部使用。 -
我的代码没有使用延迟,我只是添加它来模拟异步行为。但由于 Obervable 的异步特性,它应该以相同的方式工作,不会有任何延迟。
-
就是这样。只要返回
Observable.of,我就可以正常工作。我没有问题。这就是为什么我要求一个重现问题的例子:/
标签: angular typescript jasmine karma-jasmine