ng 19 and default standalone and ng-mocks => `assertNoStandaloneComponents()` fails
Opened this issue · 1 comments
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
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.
@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.