单元测试错误:'X'不是已知元素



我正在运行npm run test,并在我的终端上得到以下错误:

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.

大多数关于SO的帖子建议您在app.module.tscomponent.spec.ts文件(我有)中声明所需的组件

相关代码摘录下面:

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 class="page-container">
<app-general-screen [generalConfig]="generalConfig"></app-general-screen>
<div class="button-container">
<button
mat-button
*ngFor="let option of config.menu"
class="navbar-button"
(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" class="page-header">
{{ generalConfig.header }}
</div>
<div *ngIf="generalConfig.subHeader" class="page-sub-header">
{{ generalConfig.subHeader }}
</div>

app.module。ts(提取)

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 {}

我已经为此绞尽脑汁好几个小时了,我很想知道我在这里做错了什么——我就是看不出来……

真正让我难倒的是,我在其他组件中使用了GeneralScreen组件,没有问题-我正在为项目服务,没有问题……

编辑添加:schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA]schemas: [NO_ERRORS_SCHEMA]schemas: [CUSTOM_ELEMENTS_SCHEMA]对测试结果没有影响

尽管从menu.screen.html中删除<app-general-screen [generalConfig]="generalConfig"></app-general-screen>似乎可以阻止错误显示,但删除该行不是一个选项

你是对的,它应该工作,我不知道为什么它不工作。

要快速解除阻塞,您可以尝试将schemas: [NO_ERRORS_SCHEMA]添加到单元测试中。这将处理所有不能呈现为死HTML的组件,您也可以对此进行一些研究。这就是我做单元测试的方式,因为我通常不关心子组件的绘制。

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [RouterTestingModule],
// !! Remove GeneralScreen from here !!
declarations: [MenuScreen],
// !! add below line !!
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
});

经过几个小时的排序-共同组件GeneralScreen不仅需要在MenuScreen中纳入,而且需要在MenuScreen的父级测试中纳入