使用异步HTML管的角度集成测试失败

发布于 2025-01-21 11:41:06 字数 4939 浏览 0 评论 0原文

我在集成测试上会出现以下错误:

typeError:无法读取null的属性(读取'triggereventhandler')

“在此处输入映像说明”

我认为它是因为管道异步,但我没有知道如何管理这个异步问题。 我需要单击按钮并触发函数initiaTereTurns()采取下一个操作。 由于异步管问题,我只是无法获取无效的DOM元素。

谢谢

详细信息,component.html

<div class="w-100 details-container container-fluid" *ngIf="!(isLoadingDetails$ | async)">
    <div class="d-flex justify-content-end p-2 mb-3" *ngIf="enableReturn">
        <button id="initiate-returns" mat-button class="button button-devolution" (click)='initiateReturns()'>
            <ng-container class="itens-container">
                <span>Start Devolution</span>
            </ng-container>
        </button>
    </div>
</div>

lidets.component.html


import { Component, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { DetailsType } from '../../../../enums/details-type.enum';
import { DetailsModel } from '../../../../details.types';
import { DetailsActions } from '../../../../state/details.actions';
import { DetailsState } from '../../../../state/details.state';



@Component({
  selector: 'app-details',
  templateUrl: './details.component.html',
  styleUrls: ['./details.component.scss']
})
export class DetailsComponent implements OnInit {
  @Input() id: number;
  @Input() maxValue: number;
  @Input() enableReturn: boolean;

  @Select(DetailsState.isLoadingDetails) isLoadingDetails$: Observable<boolean>;
  @Select(DetailsState.error) error$: Observable<boolean>;

  @Select(DetailsState.selectedItemToReturn) details$: Observable<DetailsModel>;

  public detailsType = DetailsType;

  constructor(private router: Router, public store: Store,) { }

  ngOnInit(): void {
    this.store.dispatch(new DetailsActions.GetById(this.id));
  }

  initiateReturns() {
    this.store.dispatch(new DetailsActions.AdvanceToInputValuesStep(this.maxValue));
    this.router.navigateByUrl('/returns-flow');
  }


}

lidets.component.test.ts


import { HttpClient } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule, TranslateService, TranslateStore } from '@ngx-translate/core';
import { NgxsModule, Store } from '@ngxs/store';
import { of } from 'rxjs';
import { DetailsModel } from '../../../../details.types';
import { DetailsActions } from '../../../../state/details.actions';
import { DetailsState } from '../../../../state/details.state';
import { DetailsComponent } from './details.component';



describe('DetailsComponent', () => {
  let component: DetailsComponent;
  let fixture: ComponentFixture<DetailsComponent>;
  let router: Router;
  let store: Store;
  let httpClient: HttpClient;

  beforeEach((() => {
    TestBed.configureTestingModule({
      declarations: [DetailsComponent],
      schemas:[CUSTOM_ELEMENTS_SCHEMA],
      imports: [
        RouterTestingModule,
        NgxsModule.forRoot([DetailsState]),
        TranslateModule.forChild(),
        HttpClientTestingModule
      ],
      providers: [TranslateService, TranslateStore]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DetailsComponent);
    component = fixture.componentInstance;
    component.id = 1;
    component.maxValue = 50;
    component.enableReturn = true; 
    fixture.detectChanges();
    router = TestBed.inject(Router);
    store = TestBed.inject(Store);
    httpClient = TestBed.inject(HttpClient);
    jest.spyOn(store, 'dispatch');
    store.dispatch(new DetailsActions.GetById(component.id));
  });

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

  it ('should dispatch new id to state', () => {
    expect(store.dispatch).toHaveBeenCalledWith(new DetailsActions.GetById(component.id));
  });


  it ('should call function initiateReturns when button id initiate-returns clicked', async () => {
    
    const isLoadingSpy = await jest.spyOn(DetailsState, 'isLoadingDetails');

    spyOn(component,'initiateReturns');
    fixture.detectChanges();
    const button = fixture.debugElement.query(By.css('#initiate-returns'));
    button.triggerEventHandler('click',{stopPropagation: ()=>{}});
    expect(component.initiateReturns).toHaveBeenCalledWith();

    
  });

  
});

I´m get the following error on integration test:

TypeError: Cannot read properties of null (reading 'triggerEventHandler')

enter image description here

I think its because of the pipe async but I dont know how to manage this async issue.
I need to click the button and trigger a function initiateReturns() to take the next actions.
I just cant´get the dom element that is null because of the async pipe problema.

Thank you

details.component.html

<div class="w-100 details-container container-fluid" *ngIf="!(isLoadingDetails$ | async)">
    <div class="d-flex justify-content-end p-2 mb-3" *ngIf="enableReturn">
        <button id="initiate-returns" mat-button class="button button-devolution" (click)='initiateReturns()'>
            <ng-container class="itens-container">
                <span>Start Devolution</span>
            </ng-container>
        </button>
    </div>
</div>

details.component.html


import { Component, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { DetailsType } from '../../../../enums/details-type.enum';
import { DetailsModel } from '../../../../details.types';
import { DetailsActions } from '../../../../state/details.actions';
import { DetailsState } from '../../../../state/details.state';



@Component({
  selector: 'app-details',
  templateUrl: './details.component.html',
  styleUrls: ['./details.component.scss']
})
export class DetailsComponent implements OnInit {
  @Input() id: number;
  @Input() maxValue: number;
  @Input() enableReturn: boolean;

  @Select(DetailsState.isLoadingDetails) isLoadingDetails$: Observable<boolean>;
  @Select(DetailsState.error) error$: Observable<boolean>;

  @Select(DetailsState.selectedItemToReturn) details$: Observable<DetailsModel>;

  public detailsType = DetailsType;

  constructor(private router: Router, public store: Store,) { }

  ngOnInit(): void {
    this.store.dispatch(new DetailsActions.GetById(this.id));
  }

  initiateReturns() {
    this.store.dispatch(new DetailsActions.AdvanceToInputValuesStep(this.maxValue));
    this.router.navigateByUrl('/returns-flow');
  }


}

details.component.test.ts


import { HttpClient } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule, TranslateService, TranslateStore } from '@ngx-translate/core';
import { NgxsModule, Store } from '@ngxs/store';
import { of } from 'rxjs';
import { DetailsModel } from '../../../../details.types';
import { DetailsActions } from '../../../../state/details.actions';
import { DetailsState } from '../../../../state/details.state';
import { DetailsComponent } from './details.component';



describe('DetailsComponent', () => {
  let component: DetailsComponent;
  let fixture: ComponentFixture<DetailsComponent>;
  let router: Router;
  let store: Store;
  let httpClient: HttpClient;

  beforeEach((() => {
    TestBed.configureTestingModule({
      declarations: [DetailsComponent],
      schemas:[CUSTOM_ELEMENTS_SCHEMA],
      imports: [
        RouterTestingModule,
        NgxsModule.forRoot([DetailsState]),
        TranslateModule.forChild(),
        HttpClientTestingModule
      ],
      providers: [TranslateService, TranslateStore]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DetailsComponent);
    component = fixture.componentInstance;
    component.id = 1;
    component.maxValue = 50;
    component.enableReturn = true; 
    fixture.detectChanges();
    router = TestBed.inject(Router);
    store = TestBed.inject(Store);
    httpClient = TestBed.inject(HttpClient);
    jest.spyOn(store, 'dispatch');
    store.dispatch(new DetailsActions.GetById(component.id));
  });

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

  it ('should dispatch new id to state', () => {
    expect(store.dispatch).toHaveBeenCalledWith(new DetailsActions.GetById(component.id));
  });


  it ('should call function initiateReturns when button id initiate-returns clicked', async () => {
    
    const isLoadingSpy = await jest.spyOn(DetailsState, 'isLoadingDetails');

    spyOn(component,'initiateReturns');
    fixture.detectChanges();
    const button = fixture.debugElement.query(By.css('#initiate-returns'));
    button.triggerEventHandler('click',{stopPropagation: ()=>{}});
    expect(component.initiateReturns).toHaveBeenCalledWith();

    
  });

  
});

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

红玫瑰 2025-01-28 11:41:06

模拟您的条件以立即显示 +使用超时,以防它仍然不起作用。


it('...', () => {
  component.enableReturn = true;
  
  // component.isLoadingDetails = of(true);
  Object.defineProperty(component, 'isLoadingDetails', { value: of(true) });
  
  const button = fixture.debugElement.query(By.css('#initiate-returns'));
  button.triggerEventHandler('click',{stopPropagation: ()=>{}});
  expect(component.initiateReturns).toHaveBeenCalledWith();
});

有超时:

it('...', (done) => {
  component.enableReturn = true;

  // component.isLoadingDetails = of(true);
  Object.defineProperty(component, 'isLoadingDetails', { value: of(true) });

  const button = fixture.debugElement.query(By.css('#initiate-returns'));
  button.triggerEventHandler('click',{stopPropagation: ()=>{}});
  
  setTimeout(() => {
    expect(component.initiateReturns).toHaveBeenCalledWith();
    done();
  });
});

Mock your conditions to display it instantly + use a timeout in case it still does not work.


it('...', () => {
  component.enableReturn = true;
  
  // component.isLoadingDetails = of(true);
  Object.defineProperty(component, 'isLoadingDetails', { value: of(true) });
  
  const button = fixture.debugElement.query(By.css('#initiate-returns'));
  button.triggerEventHandler('click',{stopPropagation: ()=>{}});
  expect(component.initiateReturns).toHaveBeenCalledWith();
});

With a timeout :

it('...', (done) => {
  component.enableReturn = true;

  // component.isLoadingDetails = of(true);
  Object.defineProperty(component, 'isLoadingDetails', { value: of(true) });

  const button = fixture.debugElement.query(By.css('#initiate-returns'));
  button.triggerEventHandler('click',{stopPropagation: ()=>{}});
  
  setTimeout(() => {
    expect(component.initiateReturns).toHaveBeenCalledWith();
    done();
  });
});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文