Angular 2 Karma测试中,“component-name”不是已知元素

166

在AppComponent中,我在HTML代码中使用了导航组件。用户界面看起来很好。执行ng serve时没有错误,当我查看应用程序时控制台也没有错误。

但是,当我为我的项目运行Karma时,出现了一个错误:

Failed: Template parse errors: 
'app-nav' is not a known element:
1. If 'app-nav' is an Angular component, then verify that it is part of this module.
2. If 'app-nav' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.

在我的 app.module.ts 文件中:

有以下代码:

import { NavComponent } from './nav/nav.component';

它也在NgModule的声明部分中。

@NgModule({
  declarations: [
    AppComponent,
    CafeComponent,
    ModalComponent,
    NavComponent,
    NewsFeedComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    JsonpModule,
    ModalModule.forRoot(),
    ModalModule,
    NgbModule.forRoot(),
    BootstrapModalModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})

我在我的 AppComponent 中使用了 NavComponent

app.component.ts

import { Component, ViewContainerRef } from '@angular/core';
import { Overlay } from 'angular2-modal';
import { Modal } from 'angular2-modal/plugins/bootstrap';
import { NavComponent } from './nav/nav.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Angela';
}

app.component.html

<app-nav></app-nav>
<div class="container-fluid">
</div>

我看到过一个类似的问题,但那个问题的答案说我们应该在具有导出的nav组件中添加NgModule,但是当我这样做时,我得到了编译错误。

还有一个app.component.spec.ts文件。

import {NavComponent} from './nav/nav.component';
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';

你可能在规范文件中缺少了一个导入。我假设规范测试在app.spec.ts上进行,所以你需要在spec.ts中import { NavComponent } - Z. Bagley
1
它已导入。我漏了声明部分。 - Angela P
1
在 app.component.spec.ts 中导入和声明自定义组件对我很有用,谢谢大家! - ENDEESA
7个回答

247

因为在单元测试中,你希望主要测试组件与应用程序的其他部分相互隔离。Angular默认不会添加模块的依赖项,例如组件、服务等。因此,你需要在测试中手动添加这些依赖项。基本上,你有两个选择:

A)在测试中声明原始的NavComponent

describe('AppComponent', () => {
  beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [
          AppComponent,
          NavComponent
        ]
      }).compileComponents();
    }));

B) 模拟NavComponent

describe('AppComponent', () => {
  beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [
          AppComponent,
          MockNavComponent
        ]
      }).compileComponents();
    }));

// it(...) test cases 

});

@Component({
  selector: 'app-nav',
  template: ''
})
class MockNavComponent {
}

您可以在官方文档中找到更多信息。


2
谢谢。我遇到了导入多个组件和模块的问题,以至于只导入AppModule在TestBed配置中更有意义。您会反对这样做吗? - mcheah
3
@jonathan也许你声明的组件有自己的依赖关系?在单元测试中,最好使用模拟对象。 - Kim Kern
1
有没有办法配置日志以显示测试名称或任何相关信息,以显示哪个规范导致这些消息? - claudekennilol
文档已移至https://angular.io/guide/testing-components-scenarios#nested-component-tests。 - Big McLargeHuge
1
对于那些仍然存在问题的人,请确保在所有测试文件中进行操作。我花了一整天的时间试图弄清为什么我仍然会出现这个错误,结果发现我在测试中其他地方使用了父组件。 - user1328889
喜欢这种方法 - 尤其是B选项 - Gregor

12

3
这样做会有潜在问题吗?看起来这是一个方便的解决方法,但是是否会导致关键错误被忽略? - mcheah
13
这是测试文档中的内容:“NO_ERRORS_SCHEMA 还可以防止编译器告诉您无意中省略或拼错的缺失组件和属性。您可能会浪费数小时追踪编译器立即捕获的虚假错误。” - Kim Kern
9
在编写单元测试时,一定不要引入多余的隐含行为。使用NO_ERRORS_SCHEMA会鼓励你将依赖项置于“模拟”和“引入”之间的“灰色”区域内。对这些依赖项所做的任何更改都有可能触发似乎无关的单元测试失败,这是不可取的。 - averasko

3
对我来说,在父组件中导入该组件解决了问题。
describe('AppComponent', () => {
  beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [
          AppComponent,
          NavComponent
        ]
      }).compileComponents();
    }));

将此内容添加到使用此组件的父级的spec中。

1

导致此错误的另一个来源是父组件 app-root 的测试中包括该组件 app-nav 的标签。

尽管错误消息是关于子组件 app-nav,但修复应该在父组件 app-root 的测试中添加。

修复可以是模拟:

app.component.spec.ts:

@Component({selector: 'app-nav', template: ''})
    class NavComponentStub {
}

发生的情况是您创建了根组件及其测试,它们通过了。然后您在根组件标记中添加子组件,现在即使您只是在模板中添加了一个标记,也必须更新根组件测试。

此外,该消息并未说明哪个测试失败,从消息中您可能会认为是子组件的测试失败,而实际上是父组件的测试。


0
另一个原因是在您的测试用例中,beforeEach() 可以有多个 .compileComponents()。例如:
beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [TestComponent]
  }).compileComponents();
}));

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [HttpClientModule],
    declarations: [Test1Component],
    providers: [HttpErrorHandlerService]
  }).compileComponents();
});

0
如果您创建了一个存根并仍然遇到相同的错误,可能是因为处于--watch模式。尝试停止它并重新运行。

0

步骤1:在规范文件开头创建存根。

@Component({selector: 'app-nav', template: ''})
class NavComponent{}

步骤2:在组件声明中添加存根。

TestBed.configureTestingModule({
  imports: [
    RouterTestingModule
  ],
  declarations: [
    AppComponent,
    NavComponent
  ],
}).compileComponents();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接