Search code examples
angulartypescriptunit-testingng-mocks

Mock import of lazy loaded standalone component


I have a component which is a button, that when clicked will lazily import a standalone component and then pass it to a service to be created inside an ng-template placeholder.

The method called on btn click is like so:

  protected async toggleHelpDrawer(): Promise<void> {
    await import('@myorg/shared-feature-help').then(ref => {
      (this._drawerEvents.drawerOpen && this._drawerEvents.drawerType === this.drawerType)
        ? this._drawerEvents.closeDrawer()
        : this._drawerEvents.openDrawer(ref.HelpComponent, this.drawerType);
    });
  }

I am trying to create a unit test for this component which will mock the DrawerEventsService and spy on the openDrawer and closeDrawer methods.

The issue I am having is that the HelpComponent has elements inside it such as @ViewChild and an import of Router. When running my unit test I get errors about these attributes not being defined, etc.

I want to use ng-mocks to simply mock the HelpComponent, however I do not know how to mock the component returned from a dynamic import and I have been unable to find any examples online.

So, is there any way from the TestBed to ensure that the value returned from my async import is of type MockComponent(HelpComponent)?


Solution

  • According to ChatGPT, this was the solution I needed.

    In my test-setup.ts file, I can mock the import statement like so:

    jest.spyOn(MockService(DrawerEventsService), 'openDrawer');
    jest.spyOn(MockService(DrawerEventsService), 'closeDrawer');
    
    jest.mock('@myorg/shared-feature-help', () => {
      return {
        __esModule: true,
        HelpComponent: () => 'MockedHelpComponent'
      };
    });
    

    The goal was to mock the dynamic import statement itself, without introducing any explicit dependencies to the HelpComponent.

    My understanding of this solution is that this mocks the import command so that the value of ref.HelpComponent is of a string rather than the actual component.

    And this works because my openDrawer() method is of type

    openDrawer(component: Type<unknown>, type: DrawerTypes): void {
      this._drawerType$.next(type);
      this._drawerContainer?.createComponent(component);
    }
    

    Thus allowing me to now correcly spy on the openDrawer method and verify it has been called once as expected.