farengeyt451 / ngx-tippy-wrapper

Angular wrapper for Tippy.js
https://farengeyt451.github.io/ngx-tippy-wrapper
MIT License
60 stars 14 forks source link

Error occured with Jest/Nx/Angular: TypeError: (0 , import_tippy.default) is not a function #33

Open collettemathieu opened 2 years ago

collettemathieu commented 2 years ago

Describe the bug In a Nx workspace, for an angular component (angular v14), using the latest version of ngx-tippy-wrapper package and Jest as a test framework, an error occured "TypeError: (0 , import_tippy.default) is not a function" when we try to test this component.

To Reproduce

Create a simple angular component with its spec file as follows:

The component:

import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, Input, NgModule } from '@angular/core';
import { NgxTippyModule } from 'ngx-tippy-wrapper';

@Component({
    selector: 'my-component',
    templateUrl: './index.component.html',
    styleUrls: ['./index.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MyComponentWithTippyComponent {
    //#region    @Input()
    @Input() tippyName = '';
    @Input() tippyProps = {};
    //#endregion @Input()
}

@NgModule({
    imports: [CommonModule, NgxTippyModule],
    declarations: [MyComponentWithTippyComponent],
})
export class MyModule {}

The template of the component:

<button
    [ngxTippy]="contextualMenuTemplate"
    [tippyName]="tippyName ?? ''"
    [tippyProps]="tippyProps ?? {}"
    >My Button
</button>

<ng-template #contextualMenuTemplate>
    <h1>My component</h1>
</ng-template>

... and its spec file:

import { CommonModule } from '@angular/common';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NgxTippyModule } from 'ngx-tippy-wrapper';
import { MyComponentWithTippyComponent } from './index.component';

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

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports: [CommonModule, NgxTippyModule],
            declarations: [MyComponentWithTippyComponent],
        }).compileComponents();
    });

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

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

Expected behavior Test should passed.

Screenshots

image

Desktop

Environment context

"@angular/core": "^14.0.6", "@nrwl/cli": "^14.4.3", "@nrwl/jest": "^14.4.3", "jest": "^28.1.3", "jest-environment-jsdom": "^28.1.3", "jest-preset-angular": "^12.2.0", "ngx-tippy-wrapper": "^5.0.1", "typescript": "~4.7.4",

Additional context Using 4.0.1 version of ngx-tippy-wrapper, there are no errors and the Jest test passes. Using 5.0.0 version of the same package, test does not pass anymore.

Thank you in advance for your help to fix this bug! ❤️

alex-w0 commented 1 year ago

Any news?

alex-w0 commented 1 year ago

In the meantime I found out the following workaround to completely mock away ngx tippy in my tests:

ngx-tippy-module.mock.ts

import { TestBed } from "@angular/core/testing";
import { Directive, Input, NgModule } from "@angular/core";
import { NgxTippyContent, NgxTippyModule, NgxTippyProps } from "ngx-tippy-wrapper";
import { CommonModule } from "@angular/common";
import { ComponentType } from "@angular/cdk/overlay";

@Directive({
  // eslint-disable-next-line @angular-eslint/directive-selector
  selector: '[ngxTippy]',
})
export class NgxTippyMockedDirective {
  @Input() ngxTippy?: NgxTippyContent;
  @Input() tippyProps?: NgxTippyProps;
  @Input() tippyName?: string;
  @Input() tippyClassName?: string;
}

@NgModule({
  imports: [CommonModule],
  declarations: [NgxTippyMockedDirective],
  exports: [NgxTippyMockedDirective],
})
export class NgxTippyMockedModule {}

export function mockNgxTippyModule(component: ComponentType<unknown>) {
  TestBed.overrideComponent(component, {
    remove: { imports: [NgxTippyModule] },
    add: { imports: [NgxTippyMockedModule] }
  })
}

and now in each test case where you use ngx tippy, just call the function. In my case the function was tailored for standalone components but you can also use it for modules with some changes.

 beforeEach(async () => {
    mockNgxTippyModule(CustomComponent)

    await TestBed.configureTestingModule({
      imports: [
        CustomComponent,
        NoopAnimationsModule,
        TranslateModule.forRoot({
          loader: { provide: TranslateLoader, useClass: TranslateFakeLoader },
        }),
      ],
    })
      .compileComponents()

      ....
})
farengeyt451 commented 1 year ago

hi @alex-w0, I have not found solution yet. Attaching same issue in another tippy wrapper lib

pobutp commented 10 months ago

@farengeyt451 any updates?