【问题标题】:console.error ERROR TypeError: Cannot read properties of undefined (reading 'zoomIn')console.error 错误类型错误:无法读取未定义的属性(读取 \'zoomIn\')
【发布时间】:2022-08-13 21:51:12
【问题描述】:

我正在尝试测试一个具有 3 个按钮(ZoomIn、ZoomOut 和 ResetImage)和一个图像的组件。测试工作正常,但我从 component.ts 文件的这一行得到一个控制台错误:

this.panzoom.zoomIn({ animated: true });

我正在使用@panzoom/panzoom,但我不知道如何在我的测试规范文件中实现它。

这是我的测试:

describe(\'FigureGraphicComponent\', () => {
  let component: TestHostComponent;
  let fixture: ComponentFixture<TestHostComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [FigureGraphicComponent, TestHostComponent],
      imports:[CommonModule, BrowserAnimationsModule, RouterTestingModule, MatIconModule],
      providers:[Renderer2]
    }).compileComponents();
    
    fixture = TestBed.createComponent(TestHostComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
      
  });


  it(\'should create\', () => {
    expect(component.figureGraphicComponent).toBeDefined();
    const compiledHost: HTMLElement = fixture.debugElement.nativeElement; // Create reference to compiled component code
    const compiled = compiledHost.querySelector(\'.component\');
    expect(compiled).toBeDefined();
  });

  it(\'Should ZoomIn on Button click\', () => {
    const test = jest.spyOn(component.figureGraphicComponent, \'onZoomIn\' );
    test.mock.calls;
    const compiledHost: HTMLElement = fixture.debugElement.nativeElement; // Create reference to compiled component code
    const compiled = compiledHost.querySelector(\'.component\') || new Element();
    //console.log(compiled.innerHTML)
    const button = compiled.querySelector(\'header .zoomIn\');
    //console.log(button?.outerHTML)
    expect(button).toBeTruthy();
    button?.dispatchEvent(new Event(\'click\'));
    
    fixture.detectChanges(); // Update component data
    //component.figureGraphicComponent.panzoom.zoomIn;
    //expect(component.figureGraphicComponent.panzoom.zoomIn).toBeTruthy()

    expect(component.figureGraphicComponent.onZoomIn).toHaveBeenCalled();
  });
  
});

@Component({
  template: `
    <pwc-techpubs-ietp-reader-figure-graphic class=\"component\"
      [graphic]=\"graphic\"
    ></pwc-techpubs-ietp-reader-figure-graphic>`
})
export class TestHostComponent{
  @Input() graphic?: Graphic = {
  id: \"1\",
  graphicId: \"gr\",
  href:\"image.url\"
}
  @ViewChild(FigureGraphicComponent, { static: true })
  figureGraphicComponent!: FigureGraphicComponent;
}

这是我的 component.ts :

import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, Renderer2, ViewChild } from \'@angular/core\';
import Panzoom, { PanzoomObject, PanzoomOptions } from \'@panzoom/panzoom\';
import { Graphic } from \'@pwc/techpubs/ietp-reader/domain\';


@Component({
  selector: \'pwc-techpubs-ietp-reader-figure-graphic\',
  templateUrl: \'./figure-graphic.component.html\',
  styleUrls: [\'./figure-graphic.component.scss\'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FigureGraphicComponent implements AfterViewInit{

  @ViewChild(\'scene\', { static: false }) scene!: ElementRef;

  @Input() graphic!: Graphic;
  @Input() index!: number;

  panzoom!: PanzoomObject;
  overlay = false;

  constructor(public r2: Renderer2, private readonly ref: ChangeDetectorRef) {
    // no-op
  }

  ngAfterViewInit() {

    console.log(\"afterinit\");

    const opts: PanzoomOptions = {
      minScale: 1,
      panOnlyWhenZoomed: true,
      startScale: 0,
      contain: \'outside\'
    }
    
      setTimeout(() => {
        this.panzoom = Panzoom(this.scene.nativeElement, opts);
      }, 500);
  
  } 

  onWheel(event: WheelEvent) {
    if (event.ctrlKey) {
      this.overlay = false;
      this.ref.markForCheck();
      this.panzoom.zoomWithWheel(event);
      event.preventDefault();
    } else if (!this.overlay) {
      this.overlay = true;
      this.ref.markForCheck();
      setTimeout(() => {
          this.overlay = false;
          this.ref.markForCheck();
      }, 2000);
    }
  }

  onZoomIn() {
    this.overlay = false;
    this.ref.markForCheck();
    this.panzoom.zoomIn({ animated: true });
  }

  onZoomOut() {
    this.overlay = false;
    this.ref.markForCheck();
    this.panzoom.zoomOut({ animated: true });
  }

  onReset() {
    this.overlay = false;
    this.ref.markForCheck();
    this.panzoom.reset({ animated: true });
  }
}

这是它的模板:

<ng-container>
  <header>
    <button mat-icon-button
      class=\"zoomIn\"
      type=\"button\"
      aria-label=\"zoom in\"
      (click)=\"onZoomIn()\">
      <mat-icon>zoom_in</mat-icon>
    </button>

    <button
      mat-icon-button
      type=\"button\"
      aria-label=\"zoom out\"
      (click)=\"onZoomOut()\">
      <mat-icon>zoom_out</mat-icon>
    </button>

    <button
      mat-icon-button
      type=\"button\"
      aria-label=\"reset\"
      (click)=\"onReset()\">
      <mat-icon>center_focus_weak</mat-icon>
    </button>
  </header>

  <main>
    <img #scene mat-card-image src=\"{{graphic.href}}\" alt=\"{{graphic.icn}}\" (wheel)=\"onWheel($event)\">

    <div [ngClass]=\"{overlay: overlay, nooverlay: !overlay}\" (wheel)=\"onWheel($event)\">
      <p>Use CTRL + scroll to zoom</p>
    </div>
  </main>
</ng-container>

谢谢大家的时间!

    标签: angular unit-testing testing jestjs panzoom


    【解决方案1】:

    您可以通过提供其模拟实现来模拟Panzoom 对象,而不是使用其原始对象。更喜欢在 beforeEach 中使用对象模拟 zoomIn、zoomOut、reset 等方法来执行此操作。

    import Panzoom from '@panzoom/panzoom';
    ...
    
    describe('FigureGraphicComponent', () => {
      let component: TestHostComponent;
      let fixture: ComponentFixture<TestHostComponent>;
    
      beforeEach(async () => {
    
        jest.mock('@panzoom/panzoom', () => {
          return {
            zoomIn: jest.fn(),
            zoomWithWheel: jest.fn(),
            reset: jest.fn(),
            zoomOut: jest.fn(),
          };
        });
    
        await TestBed.configureTestingModule({
          ...
        }).compileComponents();
        ...
      });
    });
    

    【讨论】:

    • 我不能在 Panzoom 上使用 mockImplementation 它给了我这个错误:Property 'mockImplementation' does not exist on type 'typeof Panzoom'
    • @3at3out 你能试试更新的吗?
    猜你喜欢
    • 2018-04-29
    • 2021-12-03
    • 2021-11-22
    • 1970-01-01
    • 2021-11-05
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多