Skip to content

Commit ddce357

Browse files
dario-piotrowiczalxhub
authored andcommitted
fix(core): improve TestBed declarations standalone error message (#45999)
improve the error message developers get when adding a standalone component in the TestBed.configureTestingModule's declarations array, by making more clear the fact that this error originated from the TestBed call resolves #45923 PR Close #45999
1 parent ce66cfc commit ddce357

File tree

3 files changed

+44
-7
lines changed

3 files changed

+44
-7
lines changed

packages/core/src/render3/jit/module.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,13 @@ export function isStandalone<T>(type: Type<T>) {
202202
return def !== null ? def.standalone : false;
203203
}
204204

205+
export function generateStandaloneInDeclarationsError(type: Type<any>, location: string) {
206+
const prefix = `Unexpected "${stringifyForError(type)}" found in the "declarations" array of the`;
207+
const suffix = `"${stringifyForError(type)}" is marked as standalone and can't be declared ` +
208+
'in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?';
209+
return `${prefix} ${location}, ${suffix}`;
210+
}
211+
205212
function verifySemanticsOfNgModuleDef(
206213
moduleType: NgModuleType, allowDuplicateDeclarationsInRoot: boolean,
207214
importingModule?: NgModuleType): void {
@@ -280,10 +287,8 @@ function verifySemanticsOfNgModuleDef(
280287
type = resolveForwardRef(type);
281288
const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef(type);
282289
if (def?.standalone) {
283-
errors.push(`Unexpected "${stringifyForError(type)}" declaration in "${
284-
stringifyForError(moduleType)}" NgModule. "${
285-
stringifyForError(
286-
type)}" is marked as standalone and can't be declared in any NgModule - did you intend to import it?`);
290+
const location = `"${stringifyForError(moduleType)}" NgModule`;
291+
errors.push(generateStandaloneInDeclarationsError(type, location));
287292
}
288293
}
289294

packages/core/test/acceptance/ng_module_spec.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ describe('NgModule', () => {
124124
TestBed.createComponent(MyComp);
125125
})
126126
.toThrowError(
127-
`Unexpected "MyComp" declaration in "MyModule" NgModule. "MyComp" is marked as standalone and can't be declared in any NgModule - did you intend to import it?`);
127+
`Unexpected "MyComp" found in the "declarations" array of the "MyModule" NgModule, "MyComp" 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)?`);
128128
});
129129

130130
it('should throw when a standalone directive is added to NgModule declarations', () => {
@@ -154,7 +154,7 @@ describe('NgModule', () => {
154154
TestBed.createComponent(MyComp);
155155
})
156156
.toThrowError(
157-
`Unexpected "MyDir" declaration in "MyModule" NgModule. "MyDir" is marked as standalone and can't be declared in any NgModule - did you intend to import it?`);
157+
`Unexpected "MyDir" found in the "declarations" array of the "MyModule" NgModule, "MyDir" 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)?`);
158158
});
159159

160160
it('should throw when a standalone pipe is added to NgModule declarations', () => {
@@ -184,8 +184,25 @@ describe('NgModule', () => {
184184
TestBed.createComponent(MyComp);
185185
})
186186
.toThrowError(
187-
`Unexpected "MyPipe" declaration in "MyModule" NgModule. "MyPipe" is marked as standalone and can't be declared in any NgModule - did you intend to import it?`);
187+
`Unexpected "MyPipe" found in the "declarations" array of the "MyModule" NgModule, "MyPipe" 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)?`);
188188
});
189+
190+
it('should throw a testing specific error when a standalone component is added to the configureTestingModule declarations',
191+
() => {
192+
@Component({
193+
selector: 'my-comp',
194+
template: '',
195+
standalone: true,
196+
})
197+
class MyComp {
198+
}
199+
200+
expect(() => {
201+
TestBed.configureTestingModule({declarations: [MyComp]});
202+
})
203+
.toThrowError(
204+
`Unexpected "MyComp" found in the "declarations" array of the "TestBed.configureTestingModule" call, "MyComp" 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)?`);
205+
});
189206
});
190207

191208
describe('destroy', () => {

packages/core/testing/src/r3_test_bed_compiler.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {ApplicationInitStatus, Compiler, COMPILER_OPTIONS, Component, Directive,
1111

1212
import {clearResolutionOfComponentResourcesQueue, isComponentDefPendingResolution, resolveComponentResources, restoreComponentResolutionQueue} from '../../src/metadata/resource_loading';
1313
import {ComponentDef, ComponentType} from '../../src/render3';
14+
import {generateStandaloneInDeclarationsError} from '../../src/render3/jit/module';
1415

1516
import {MetadataOverride} from './metadata_override';
1617
import {ComponentResolver, DirectiveResolver, NgModuleResolver, PipeResolver, Resolver} from './resolvers';
@@ -26,6 +27,16 @@ function isTestingModuleOverride(value: unknown): value is TestingModuleOverride
2627
value === TestingModuleOverride.OVERRIDE_TEMPLATE;
2728
}
2829

30+
function assertNoStandaloneComponents(
31+
types: Type<any>[], resolver: Resolver<any>, location: string) {
32+
types.forEach(type => {
33+
const component = resolver.resolve(type);
34+
if (component && component.standalone) {
35+
throw new Error(generateStandaloneInDeclarationsError(type, location));
36+
}
37+
});
38+
}
39+
2940
// Resolvers for Angular decorators
3041
type Resolvers = {
3142
module: Resolver<NgModule>,
@@ -107,6 +118,10 @@ export class R3TestBedCompiler {
107118
configureTestingModule(moduleDef: TestModuleMetadata): void {
108119
// Enqueue any compilation tasks for the directly declared component.
109120
if (moduleDef.declarations !== undefined) {
121+
// Verify that there are no standalone components
122+
assertNoStandaloneComponents(
123+
moduleDef.declarations, this.resolvers.component,
124+
'"TestBed.configureTestingModule" call');
110125
this.queueTypeArray(moduleDef.declarations, TestingModuleOverride.DECLARATION);
111126
this.declarations.push(...moduleDef.declarations);
112127
}

0 commit comments

Comments
 (0)