Mock a library directive from angular

Viewed 288

I want to unit test a component which uses a directive of a library. My code looks like this:

// component.spec.ts
@Directive({
    selector: 'mwlFlatpickr',
})
class mwlFlatpickr implements OnDestroy{
  @Input('mwlFlatpickr') public x: any;
  @Input('convertModelValue') public y: boolean;
  @Input('dateFormat') public z: string;
  public ngOnDestroy(): void {}
}

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        mwlFlatpickr
      ],
      imports: [
         // other modules
      ],
      providers: [
        // my services
      ]
    })
      .compileComponents();
  }));
  beforeEach(() => {
      fixture = TestBed.createComponent(CreateTaskComponent);
      component = fixture.componentInstance;
  });

html:

// component.html
 <input type="text" class="floating-label-field" mwlFlatpickr [convertModelValue]="true" dateFormat="d.m.Y" formControlName="dueDate">

My Problem is: the component uses the real mwlFlatpickr, which throws an error in it's onDestroy (the component instance is not defined, but that is out of the scope of my tests)

 TypeError: Cannot read property 'destroy' of undefined
    at FlatpickrDirective.ngOnDestroy (angularx-flatpickr.js:330)
    at executeOnDestroys (core.js:14123)
    at cleanUpView (core.js:14030)
    at destroyViewTree (core.js:13799)
    at destroyLView (core.js:13981)
    at RootViewRef.destroy (core.js:14836)
    at ComponentRef$1.destroy (core.js:33986)
    at ComponentFixture.destroy (testing.js:423)
    at UserContext.<anonymous> (component.spec.ts:160)
    at ZoneDelegate.invoke (zone-evergreen.js:364)

the error occurs in the clean up, so the test doesn't matter. Imagine the itto just be:

 it('should not throw an error', () => {
    expect(component).toBeDefined();
 });

I'm a little dumbfounded. All tutorials and topics I found solved a mocked directive in that way (and it works with pipes just fine) The directive class is declared as:

export declare class FlatpickrDirective implements AfterViewInit, OnChanges, OnDestroy, ControlValueAccessor

natrually, I tried to change the name to that and implemented the other implements as well - same error, the component does not use my mockDirective

1 Answers

It uses the real mwlFlatpickr because I bet you have FlatpickrModule in your imports array in TestBed.configureTestingModule or a SharedModule that imports FlatpickerModule and it uses the actual implementation instead of the mock you are providing. Try removing FlatpickrModule or the suspected SharedModule from imports.

If you don't want to remove the SharedModule from imports, you will have to override the directive by using overrideDirective. https://angular-2-training-book.rangle.io/testing/components/injecting-dependencies/overriding

Related