gpt4 book ai didi

Angular Testing - 如果计时器在组件初始化中,则 Tick 不起作用

转载 作者:行者123 更新时间:2023-12-04 14:11:14 24 4
gpt4 key购买 nike

问题

如何让 tick 工作,或者至少如何让测试提前 10 秒以在我的组件中适本地调用 submit

注意:我不想做 await new Promise(r => setTimeout(r, 10000)) 因为它会让我的测试运行很长时间,而测试应该很短

目标

我希望 submit 仅在组件创建 10 秒后调用 cb

描述

我的组件中有一个计时器,它会在 10 秒后完成。此计时器将主题从 false 更改为 true,并用于确定提交组件中的数据是否被视为有效

在测试中,tick 似乎根本没有让计时器提前,它实际上运行了整整 10 秒。我试图通过在创建组件的 beforeEach 中放置一个 fakeAsync 来解决这个问题,但没有成功。

我尝试过的

  • 在测试组件init中使用fakeAsync,以及测试
  • 仅在测试中使用fakeAsync
  • 使用 setTimeout(() => this.obs.next(true), 10_000) 代替计时器
  • 使用 empty().pipe(delay(10000)).subscribe(() => this.obs.next(true)); 而不是计时器
  • timer 放在 ngOnInit 而不是构造函数中
  • timer 放在构造函数中而不是 ngOnInit

观察

如果你调整这段代码

    timer(10_000).subscribe(() => this.testThis$.next(true));

变成这样

    timer(10_000).subscribe(() => {
debugger;
this.testThis$.next(true)
});

您会发现每次运行测试时,开发工具中的 Javascript 调试器都会在组件创建后 10 秒触发(而不是如果 tick 有效则立即触发)。

代码

这是代码。底部是指向 GitHub 上最小复制的链接。

// component code
import { Component, OnInit, Inject } from '@angular/core';
import { BehaviorSubject, Subject, timer } from 'rxjs';
import { first, filter } from 'rxjs/operators';

@Component({
selector: 'app-tick-test',
templateUrl: './tick-test.component.html',
styleUrls: ['./tick-test.component.scss']
})
export class TickTestComponent implements OnInit {

public testThis$: Subject<boolean>;

constructor(
@Inject('TICK_CALLBACK') private readonly cb: () => void,
) {
this.testThis$ = new BehaviorSubject<boolean>(false);
timer(10_000).subscribe(() => this.testThis$.next(true));
}

public ngOnInit(): void {
}

public submit(): void {
// call the callback after 10s
this.testThis$
.pipe(first(), filter(a => !!a))
.subscribe(() => this.cb());
}

}
// test code
/**
* The problem in this one is that I am expecting `tick` to advance the
* time for the timer that was created in the constructor, but it is not working
*/



import { async, ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';

import { TickTestComponent } from './tick-test.component';

describe('TickTestComponent', () => {
let component: TickTestComponent;
let fixture: ComponentFixture<TickTestComponent>;

let callback: jasmine.Spy;

beforeEach(async(() => {

callback = jasmine.createSpy('TICK_CALLBACK');

TestBed.configureTestingModule({
providers: [
{ provide: 'TICK_CALLBACK', useValue: callback },
],
declarations: [ TickTestComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(TickTestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should be true after 10s', fakeAsync(() => {
tick(10_001);

component.submit();
expect(callback).toHaveBeenCalled();
}));
});

最小复制 repo

Link To Github

最佳答案

解决方案

  1. fixture.detectChanges() 移动到每个测试中,并在那里调用 tick(10_000)
  2. timer(10_000)...移动到组件中的ngOnInit

发生了什么

每当您使用 fakeAsync 时,都会创建一个您的代码可以在其中运行的“区域”。根据我的观察,这个区域“存在”直到它超出范围。通过在 beforeEach 中使用 fakeAsync,您会破坏区域并遇到计时器未完成的问题(尽管计时器未完成是理想的结果)。

您想将 timer 移动到 ngOnInit 中,因为它不会在 .createComponent 调用时立即调用。当您第一次运行 fixture.detectChanges() 时,改为调用它。因此,当您第一次在测试的 fakeAsync 区域内调用 fixture.detectChanges() 时,会为您调用 ngOnInit,计时器是在区域中捕获,您可以按预期控制时间。

代码

describe('TickTestComponent', () => {
let component: TickTestComponent;
let fixture: ComponentFixture<TickTestComponent>;

let callback: jasmine.Spy;

beforeEach(async(() => {

callback = jasmine.createSpy('TICK_CALLBACK');

TestBed.configureTestingModule({
providers: [
{ provide: 'TICK_CALLBACK', useValue: callback },
],
declarations: [ TickTestComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(TickTestComponent);
component = fixture.componentInstance;
// don't run this here
// fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should be true after 10s', fakeAsync(() => {
// this calls ngOnInit if it is the first detectChanges call
fixture.detectChanges();
tick(10_001);

component.submit();
expect(callback).toHaveBeenCalled();
}));
});

关于 Angular Testing - 如果计时器在组件初始化中,则 Tick 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64160751/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com