Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ng 19 and default standalone and ng-mocks => assertNoStandaloneComponents() fails #685

Open
johncrim opened this issue Dec 7, 2024 · 1 comment

Comments

@johncrim
Copy link
Contributor

johncrim commented Dec 7, 2024

Is this a regression?

Yes

Description

This is a regression, but it's not due to a bug in Spectator - it's caused by a breaking change in ng19 and a bug in ng-mocks that doesn't yet handle that change. This issue was brought up in #682 - it is not related to the fix for #682, but should be documented as a form of pro-active support b/c it's likely that people will report it here.

In short, if a test uses spectator, and ng 19, and ng-mocks, and the test uses a default standalone component (standalone: is not declared but the component is standalone by default), createComponentFactory() fails with an error:

Failed: Unexpected "MyComponent" found in the "declarations" array of the "TestBed.configureTestingModule" call, "MyComponent" is marked as standalone and can't be declared in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?

This error is caused by a bug in ng-mocks: ng-mocks#10632 - I don't believe anything needs to be fixed in spectator, but I can't verify that in tests until there's a fix for the ng-mocks bug.

There is an easy workaround - standalone components used in tests with mocks need to have standalone: true explicitly declared.

Please provide a link to a minimal reproduction of the bug

https://github.com/johncrim/spectator/blob/bug/default-standalone-mocks-failure/projects/spectator/test/standalone/component/container-with-mock.spec.ts

Please provide the exception or error you saw

✔ Browser application bundle generation complete.
Chrome 131.0.0.0 (Windows 10) Standalone component with mock using Spectator should render mocked and un-mocked children FAILED
        Failed: Unexpected "MockOfChildBComponent" found in the "declarations" array of the "TestBed.configureTestingModule" call, "MockOfChildBComponent" is marked as standalone and can't be declared in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?
            at forEach (node_modules/@angular/core/fesm2022/testing.mjs:769:23)
            at Array.forEach (<anonymous>)
            at assertNoStandaloneComponents (node_modules/@angular/core/fesm2022/testing.mjs:765:11)
            at TestBedCompiler.configureTestingModule (node_modules/@angular/core/fesm2022/testing.mjs:844:13)
            at TestBedImpl.call (node_modules/@angular/core/fesm2022/testing.mjs:1974:23)
            at TestBedImpl.configureTestingModule (node_modules/ng-mocks/index.mjs:1:109087)
            at Function.call (node_modules/@angular/core/fesm2022/testing.mjs:1789:37)
            at Function.call (node_modules/ng-mocks/index.mjs:1:128562)
            at Function.configureTestingModule (node_modules/ng-mocks/index.mjs:1:109277)
            at UserContext.<anonymous> (projects/spectator/src/lib/spectator/create-factory.ts:129:13)

Please provide the environment you discovered this bug in

Windows 11
Angular 19.01
"@ngneat/spectator": "^19.1.2",
"ng-mocks": "^14.13.1",

Anything else?

This test case reproduces the error:

import { Component } from '@angular/core';
import { createComponentFactory, Spectator } from '@ngneat/spectator';
import { MockComponent } from 'ng-mocks';

@Component({
  selector: `test-child-a`,
  template: `<h3 id="child-a">child A</h3>`,
  // standalone: true,
})
export class ChildAComponent {}

@Component({
  selector: `test-child-b`,
  template: `<h3 id="child-b">child B</h3>`,
  // standalone: true,
})
export class ChildBComponent {}

@Component({
  selector: `test-container`,
  template: `<test-child-a /><test-child-b />`,
  // standalone: true,
  imports: [ChildAComponent, ChildBComponent],
})
export class ContainerComponent {}

fdescribe('Standalone component with mock', () => {
  describe('using Spectator', () => {
    let spectator: Spectator<ContainerComponent>;

    const createComponent = createComponentFactory({
      component: ContainerComponent,
      imports: [
        ChildAComponent,
        // ChildBComponent // Removing the mock and declaring the component here fixes the create error
        MockComponent(ChildBComponent),
      ],
    });

    beforeEach(() => {
      spectator = createComponent();
    });

    it('should render mocked and un-mocked children', () => {
      expect(spectator.query('#child-a')).toContainText('child A');
      expect(spectator.query(ChildBComponent)).toBeTruthy();
      expect(spectator.query('#child-b')).not.toContainText('child B');
    });
  });
});

If you remove the MockComponent line and declare ChildBComponent as an import, the failure goes away (but the test fails).

If you uncomment all the standalone: true lines, the test succeeds. That's the easy but non-obvious workaround for this.

Do you want to create a pull request?

Sure - I am willing to improve these tests and provide a PR with the tests after the ng-mocks bug is fixed. It would require adding ng-mocks as a devDependency, which is probably not a bad idea IMO.

@johncrim
Copy link
Contributor Author

johncrim commented Dec 7, 2024

@carflynn2009 and @PeterEnevoldsen - this is the issue you brought up in #682. I came across the same issue today, so I investigated it and created a repro case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant