I am running npm run test
and getting the follow error on my terminal:
1. If 'app-general-screen' is an Angular component, then verify that it is a part of an @NgModule where this component
is declared.
2. If 'app-general-screen' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.'
Chrome Headless 103.0.5060.114 (Windows 10): Executed 30 of 32 SUCCESS (0 secs / 0.385 secs)
ERROR: 'NG0304: 'app-general-screen' is not a known element (used in the 'MenuScreen' component template):
1. If 'app-general-screen' is an Angular component, then verify that it is a part of an @NgModule where this component
is declared.
2. If 'app-general-screen' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this compERROR: 'NG0303: Can't bind to 'generalConfig' since it isn't a known property of 'app-general-screen' (used in the 'MenuScreen' component template).
1. If 'app-general-screen' is an Angular component and it has the 'generalConfig' input, then verify that it is a part
of an @NgModule where this component is declared.
2. If 'app-general-screen' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.'
Chrome Headless 103.0.5060.114 (Windows 10): Executed 30 of 32 SUCCESS (0 secs / 0.385 secs)
ERROR: 'NG0303: Can't bind to 'generalConfig' since it isn't a known property of 'app-general-screen' (used in the 'MenuScreen' component template).
1. If 'app-general-screen' is an Angular component and it has the 'generalConfig' input, then verify that it is a part
of an @NgModule where this component is declared.
2. If 'app-general-screen' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
Most of the post on SO suggest that you declare the required component in both app.module.ts
and the component.spec.ts
files (which I have)
Below the relevant code extracts:
menu.screen.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { GeneralScreen } from '../general/general.screen';
import { MenuScreen } from './menu.screen';
describe('MenuScreen', () => {
let component: MenuScreen;
let fixture: ComponentFixture<MenuScreen>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [MenuScreen, GeneralScreen],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(MenuScreen);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
menu.screen.ts
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Router } from '@angular/router';
import {
MenuPageConfig,
PageConfig,
} from 'src/app/interfaces/common-page-configs.interface';
@Component({
selector: 'app-menu-screen',
templateUrl: './menu.screen.html',
styleUrls: ['./menu.screen.scss'],
})
export class MenuScreen implements OnInit {
@Input() config = {} as MenuPageConfig;
@Output() viewStateSelected = new EventEmitter<any>();
generalConfig = {} as PageConfig;
constructor(public router: Router) {}
ngOnInit() {
this.setPageConfig();
}
setPageConfig() {
this.generalConfig = {
header: this.config.header,
subHeader: this.config.subHeader,
};
}
onMenuOptionClicked(path: string | undefined, viewState: any | undefined) {
path
? this.router.navigate([path])
: this.viewStateSelected.emit(viewState);
}
}
menu.screen.html
<div >
<app-general-screen [generalConfig]="generalConfig"></app-general-screen>
<div >
<button
mat-button
*ngFor="let option of config.menu"
(click)="onMenuOptionClicked(option.path, option.viewState)"
>
{{ option.display }}
</button>
</div>
</div>
general.screen.ts
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { PageConfig } from 'src/app/interfaces/common-page-configs.interface';
@Component({
selector: 'app-general-screen',
templateUrl: './general.screen.html',
styleUrls: ['./general.screen.scss'],
})
export class GeneralScreen {
@Input() generalConfig = {} as PageConfig;
@Output() viewStateSelected = new EventEmitter<any>();
}
general.screen.html
<div *ngIf="generalConfig.header" >
{{ generalConfig.header }}
</div>
<div *ngIf="generalConfig.subHeader" >
{{ generalConfig.subHeader }}
</div>
app.module.ts (extracts)
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { MenuScreen } from './screens/menu/menu.screen';
import { GeneralScreen } from './screens/general/general.screen';
@NgModule({
declarations: [
AppComponent,
MenuScreen,
GeneralScreen,
],
imports: [
BrowserModule,
AppRoutingModule,
],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
I have been racking my brain on this for hours now and would love some insights as to what I am doing wrong here - I just can't see it...
The thing that is really stumping me is that I have the GeneralScreen
component used in other component with no issue - and I am serving the project with no issues...
EDIT
Adding:
schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA]
or
schemas: [NO_ERRORS_SCHEMA]
or
schemas: [CUSTOM_ELEMENTS_SCHEMA]
to the test have not impact in the result
ALTHOUGH removing <app-general-screen [generalConfig]="generalConfig"></app-general-screen>
from menu.screen.html does seem to stop the error presenting, but removing that line is not an option
CodePudding user response:
You're right, it should work, I am not sure why it is not working.
For a quick unblock, you can try adding schemas: [NO_ERRORS_SCHEMA]
to the unit test. This will treat all components that cannot be rendered into dead HTML and you can also do some research on this. This is how I do all of my unit testing because I am usually not concerned about the painting of child components.
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [RouterTestingModule],
// !! Remove GeneralScreen from here !!
declarations: [MenuScreen],
// !! add below line !!
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
});
CodePudding user response:
Sorted after many hours - the common component GeneralScreen
needed to be incorporated not only in MenuScreen
BUT also in the test of the parents of MenuScreen