【问题标题】:Why tick() doesn't work int this unit test为什么 tick() 在此单元测试中不起作用
【发布时间】:2021-08-04 06:57:35
【问题描述】:

我有一个指令可以记住某些 div 的滚动位置。

指令

   constructor(
        private elementRef: ElementRef,
        private restoreValueService: KeyValueMapService
    ) {}

    ngOnInit(): void {
      const debounceTimeValue = 200;
      console.log(this.elementRef.nativeElement);
      fromEvent(this.elementRef.nativeElement, 'scroll').pipe(
        takeUntil(this.destroyed$),
        debounceTime(debounceTimeValue)
      ).subscribe((event: Event) => this.onScroll());
    }

    ngOnDestroy(): void {
      this.destroyed$.next(true);
      this.destroyed$.complete();
    }

    onScroll(): void {
      console.log('on Scroll');
      this.scrollValue = this.elementRef.nativeElement.scrollTop;
      this.restoreValueService.values.set('scroll', this.scrollValue);
    }

我也有 Map 的小服务,应该接收滚动值:

export class KeyValueMapService {
    values: Map<string, any> = new Map();
}

我正在尝试使用fakeAsync()tick() 对其进行测试,但是当我运行此测试时,期望在回调方法onScroll() 之前运行并且测试失败,因为地图还没有滚动值。

规格

fdescribe('RestoreScrollDirective', () => {
    let fixture: ComponentFixture<TestComponent>;
    let component: TestComponent;
    let debugElement: DebugElement;
    let innerDiv: DebugElement;
    let keyValueService: KeyValueMapService;

    beforeEach(() => {
        keyValueService = new KeyValueMapService();

        TestBed.configureTestingModule({
            declarations: [ TestComponent, RestoreScrollDirective ],
            providers: [ {provide: KeyValueMapService, useValue: keyValueService}]
        }).compileComponents();

        fixture = TestBed.createComponent(TestComponent);
        component = fixture.componentInstance;
        debugElement = fixture.debugElement;
        innerDiv = debugElement.query(By.css('.outer-div'));
    });

    it('Should save in service its last scroll position',  fakeAsync(() => {
        fixture.detectChanges();

        // I scroll div element which holds directive

        const scrollPosition = 250;
        const element = innerDiv.nativeElement as HTMLDivElement;
        element.scrollTo(0, scrollPosition);
        fixture.detectChanges();

        // I simulate time passage needed to my callback run, due to the debounce time

        tick(201);
        fixture.detectChanges();

        console.log('Exceptations begin'); // this logs earlier than 'on Scroll'
        const map = keyValueService.values;
        expect(map.has('scroll')).toBe(true);
        expect(map.get('scroll')).toBe(scrollPosition);
    }));
});

任何人都可以向我解释为什么我的期望在onScroll() 方法之前执行? 'Exceptionations begin' 的记录早于 on Scroll,即使我使用的 tick 的值高于去抖动时间。

【问题讨论】:

    标签: angular unit-testing testing rxjs


    【解决方案1】:

    如果我们调用 HTMLElement API 的滚动方法,显然 Angular 不会触发事件。我们需要使用其他方法触发:

    innerDiv.dispatchEvent(new Event('scroll'));
    // or 
    innerDiv.triggerEventHandler('scroll', null); 
    

    【讨论】:

    • 感谢您的回答!不幸的是,它没有帮助,即使将函数更改为 asyncawait fixture.whenStable(); 我仍然得到相同的行为 - 期望在 onScroll() 回调之前运行
    • 遗憾(:我在评论中添加了另一个更改。可能是 div 没有呈现并且那里没有滚动。
    • 感谢您的建议,仍然没有成功。滚动发生是因为我可以从 div 控制台记录 scrollTop 并且它显示 250 所以我的滚动被执行了
    • 对不起,我更新了答案
    • 抱歉没有反馈,我试过手动触发事件,它有效!我使用了dispatchEvent,因为我的事件处理程序是通过 rxjs fromEvent 注册的。目前我的处理程序被执行了两次——首先是手动触发,然后是异常,然后是第二次处理程序。仍然不知道为什么第二个不受tick() 影响,但第一个被延迟了,因为它应该是我的测试工作:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    • 1970-01-01
    • 2018-07-12
    相关资源
    最近更新 更多