help-me-mom / ng-mocks

Angular testing library for mocking components, directives, pipes, services and facilitating TestBed setup
https://www.npmjs.com/package/ng-mocks
MIT License
1.06k stars 77 forks source link

Bug: Mocking standalone components may cause warnings #6928

Closed clusterberries closed 11 months ago

clusterberries commented 1 year ago

Description of the bug

In my app, I have started using standalone components and found a bug related to it. Note that this issue does not occur with non-standalone components.

Steps:

  1. There is a SharedModule with some components used across the application.
  2. There is a standalone component StandaloneComponent that uses components from SharedModule.
  3. MyComponent (not standalone) uses StandaloneComponent and also some components from SharedModule.
  4. Create tests for MyComponent and mock the dependencies using MockComponent like the following example:
    TestBed.configureTestingModule({
      imports: [MockComponent(StandaloneComponent)],
      declarations: [MyComponent, MockComponent(SharedComponent2)],
    }).compileComponents();

Result: After running this test there is a warning in the console NG0304: 'app-shared2' is not a known element (used in the 'MyComponent' component template)

Workaround: mock the entire SharedModule instead of mocking separate components. However, this approach may cause performance issues if SharedModule contains a large number of components.

An example of the bug

Link: https://stackblitz.com/edit/github-pyxbdq?devToolsHeight=33&file=src%2Ftest.spec.ts

Expected vs actual behavior

Actual result: a warning in the console NG0304: 'app-shared2' is not a known element (used in the 'MyComponent' component template). Expected result: The warning should not appear, since the SharedComponent2 is properly mocked.

Thank you for checking this out!

satanTime commented 11 months ago

Hi @clusterberries,

thanks for highlighting the issue. Working on its fix.

satanTime commented 11 months ago

The fix is here. However, even without ng-mocks it throws:

Error: Type SharedComponent2 is part of the declarations of 2 modules: DynamicTestModule and SharedModule! Please consider moving SharedComponent2 to a higher module that imports DynamicTestModule and SharedModule. You can also create a new NgModule that exports and includes SharedComponent2 then import that NgModule in DynamicTestModule and SharedModule.

ng-mocks will process declarations in the same way and will throw the same error now:

Error: Type MockOfSharedComponent2 is part of the declarations of 2 modules: DynamicTestModule and MockOfSharedModule! Please consider moving MockOfSharedComponent2 to a higher module that imports DynamicTestModule and MockOfSharedModule. You can also create a new NgModule that exports and includes MockOfSharedComponent2 then import that NgModule in DynamicTestModule and MockOfSharedModule.

satanTime commented 11 months ago

The right way is to import a mock of SharedModule.

satanTime commented 11 months ago

So, I found a way to fix that in a flexible way. In case of ng-mocks, TestBed will receive SharedModule in imports instead of SharedComponent2 in declarations.

satanTime commented 11 months ago

v14.12.0 has been released and contains a fix for the issue. Feel free to reopen the issue or to submit a new one if you meet any problems.

clusterberries commented 11 months ago

Hi @satanTime, thank you! It works excellently now