为什么会出现 NG0303 或 NG0300 错误?(角度测试,Karma Jasmine)

Don*_*o87 4 karma-jasmine ionic-framework angular-test

我有几个组件(关于、服务、仪表板等),其中添加了标头组件。该应用程序运行良好。但是,我在测试时遇到错误。

\n
import { Component } from \'@angular/core\';\nimport { ComponentFixture, TestBed, waitForAsync } from \'@angular/core/testing\';\nimport { IonicModule } from \'@ionic/angular\';\nimport { SettingsPage } from \'./settings.page\';\n\ndescribe(\'SettingsPage\', () => {\n  let component: SettingsPage;\n  let fixture: ComponentFixture<SettingsPage>;\n\n  beforeEach(waitForAsync(() => {\n    TestBed.configureTestingModule({\n      declarations: [ SettingsPage,MockHeaderComponent ],\n      imports: [IonicModule.forRoot()]\n    }).compileComponents();\n\n    fixture = TestBed.createComponent(SettingsPage);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  }));\n\n  it(\'should create\', () => {\n    expect(component).toBeTruthy();\n  });\n});\n@Component({\n  selector: \'app-header\',\n  template: \'\'\n})\nclass MockHeaderComponent {\n}\n
Run Code Online (Sandbox Code Playgroud)\n

第一个错误

\n
Chrome 93.0.4577.82 (Windows 10): Executed 22 of 26 (1 FAILED) (0 secs / 5.88 secs)\nERROR: \'NG0303: Can\'t bind to \'headline\' since it isn\'t a known property of \'app-header\'.\'\n
Run Code Online (Sandbox Code Playgroud)\n

header 是我在标头组件中声明的变量,并在我的组件中使用它来为我提供正确的标题。

\n

当然,我已经在互联网上寻找解决方案,并遇到了以下 Stack Overflow 帖子:Unit test Angular with Jasmine and Karma, Error:Can't bind to 'xxx'because it isn't aknown property of 'xxxxxx' 。\n因此,我导入并声明了我的 HeaderComponent。

\n
import { Component } from \'@angular/core\';\nimport { ComponentFixture, TestBed, waitForAsync } from \'@angular/core/testing\';\nimport { IonicModule } from \'@ionic/angular\';\nimport { HeaderComponent } from \'../header/header.component\';\n\nimport { SettingsPage } from \'./settings.page\';\n\ndescribe(\'SettingsPage\', () => {\n  let component: SettingsPage;\n  let fixture: ComponentFixture<SettingsPage>;\n\n  beforeEach(waitForAsync(() => {\n    TestBed.configureTestingModule({\n      declarations: [ SettingsPage,HeaderComponent,MockHeaderComponent ],\n      imports: [IonicModule.forRoot()]\n    }).compileComponents();\n\n    fixture = TestBed.createComponent(SettingsPage);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  }));\n\n  it(\'should create\', () => {\n    expect(component).toBeTruthy();\n  });\n});\n@Component({\n  selector: \'app-header\',\n  template: \'\'\n})\nclass MockHeaderComponent {\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

不幸的是,发生了以下错误。

\n
Chrome 93.0.4577.82 (Windows 10) SettingsPage should create FAILED\n        Failed: NG0300: Multiple components match node with tagname app-header. Find more at https://angular.io/errors/NG0300\n        error properties: Object({ code: \'300\' })\n        Error: NG0300: Multiple components match node with tagname app-header. Find more at https://angular.io/errors/NG0300\n            at throwMultipleComponentError (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:6779:1)\n            at findDirectiveDefMatches (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10344:1)\n            at resolveDirectives (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10158:1)\n            at elementStartFirstCreatePass (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:14772:1)\n            at \xc9\xb5\xc9\xb5elementStart (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:14809:1)\n            at \xc9\xb5\xc9\xb5element (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:14888:1)\n            at SettingsPage_Template (ng:///SettingsPage.js:8:9)\n            at executeTemplate (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9600:1)\n            at renderView (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:9404:1)\n            at renderComponent (node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:10684:1)\n        Error: Expected undefined to be truthy.\n            at <Jasmine>\n            at UserContext.<anonymous> (src/app/components/settings/settings.page.spec.ts:24:23)\n            at ZoneDelegate.invoke (node_modules/zone.js/dist/zone-evergreen.js:364:1)\n            at ProxyZoneSpec.push.QpwO.ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/zone-testing.js:292:1)\nChrome 93.0.4577.82 (Windows 10): Executed 26 of 26 (7 FAILED) (1.712 secs / 1.658 secs)\n
Run Code Online (Sandbox Code Playgroud)\n

谁能告诉我我做错了什么?

\n

更新 1:\n我的 ComponentsModule 类,我在其中集成了所有可重用组件:

\n
import {NgModule} from \'@angular/core\';\nimport {HeaderComponent} from \'./header/header.component\';\nimport { FooterComponent } from \'./footer/footer.component\';\n@NgModule({\n    declarations: [HeaderComponent, FooterComponent],\n    exports: [HeaderComponent, FooterComponent]\n})\nexport class ComponentsModule{}\n
Run Code Online (Sandbox Code Playgroud)\n

我的HTML:

\n
<ion-header>\n  <app-header [headline]="headlines.settings"></app-header>\n</ion-header>\n\n<ion-content>\n\n</ion-content>\n\n
Run Code Online (Sandbox Code Playgroud)\n
import { NgModule } from \'@angular/core\';\nimport { CommonModule } from \'@angular/common\';\nimport { FormsModule } from \'@angular/forms\';\n\nimport { IonicModule } from \'@ionic/angular\';\n\nimport { SettingsPageRoutingModule } from \'./settings-routing.module\';\n\nimport { SettingsPage } from \'./settings.page\';\nimport { ComponentsModule } from \'../components.module\';\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n    IonicModule,\n    ComponentsModule,\n    SettingsPageRoutingModule\n  ],\n  declarations: [SettingsPage]\n})\nexport class SettingsPageModule {}\n
Run Code Online (Sandbox Code Playgroud)\n

设置.page.ts

\n
import { Component, OnInit } from \'@angular/core\';\nimport { lablesHeadlines } from \'src/environments/lables\';\n\n@Component({\n  selector: \'app-settings\',\n  templateUrl: \'./settings.page.html\',\n  styleUrls: [\'./settings.page.scss\'],\n})\nexport class SettingsPage implements OnInit {\n\n  lablesHeadlines = lablesHeadlines;\n  headlines = lablesHeadlines;\n\n  constructor() { }\n\n  ngOnInit() {\n  }\n\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

设置.module.ts

\n
import { NgModule } from \'@angular/core\';\nimport { CommonModule } from \'@angular/common\';\nimport { FormsModule } from \'@angular/forms\';\n\nimport { IonicModule } from \'@ionic/angular\';\n\nimport { SettingsPageRoutingModule } from \'./settings-routing.module\';\n\nimport { SettingsPage } from \'./settings.page\';\nimport { ComponentsModule } from \'../components.module\';\n@NgModule({\n  imports: [\n    CommonModule,\n    FormsModule,\n    IonicModule,\n    ComponentsModule,\n    SettingsPageRoutingModule\n  ],\n  declarations: [SettingsPage]\n})\nexport class SettingsPageModule {}\n\n
Run Code Online (Sandbox Code Playgroud)\n

Don*_*o87 7

问题解决了。 https://testing-angular.com/testing-components-with-children/#testing-components-with-children向我展示了解决方案。我编写单元测试时,可以使用 schemas: [NO_ERRORS_SCHEMA] 来忽略顶级组件中的组件。低级组件已准备好在自己的测试中进行检查。如果您想了解 Angular 测试,我强烈建议您使用上面的链接。

这是我更新的源代码:

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { AboutClientServiceService } from 'src/app/services/about-client-service.service';
import { AppComponent } from 'src/app/app.component';
import { MockAboutClientService } from 'src/app/Mock/MockAboutClientService';
import { AboutPage } from './about.page';
import { Component } from '@angular/core';
import { NO_ERRORS_SCHEMA } from '@angular/core';

describe('AboutPage', () => {
  let component: AboutPage;
  let fixture: ComponentFixture<AboutPage>;

  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      declarations: [ AboutPage, MockHeaderComponent ],
      schemas: [NO_ERRORS_SCHEMA],
      imports: [IonicModule, HttpClientTestingModule],
      providers: [AppComponent, AboutClientServiceService]
    }).compileComponents();

    TestBed.overrideComponent(
      AboutPage,
      {
        set: {
          providers: [
            { provide: AboutClientServiceService, useClass: MockAboutClientService }]
        }
      });

    fixture = TestBed.createComponent(AboutPage);
    component = fixture.componentInstance;
    fixture.detectChanges();

  }));

  it('should create', (done) => {
    expect(component).toBeTruthy();
    expect(component.version).toBeDefined();
    done();
  });
});
@Component({
  selector: 'app-header',
  template: ''
})
class MockHeaderComponent {
}
Run Code Online (Sandbox Code Playgroud)