冲突组件 Angular 测试

Conflicting Components Angular Testing

我正在关注这个项目 (https://stackblitz.com/edit/angular-material-expandable-table-rows) 以进行我的功能开发,因为我正在尝试实现类似的功能。

我能够让我的功能正常工作,但是当我 运行 测试时,我收到以下错误 -

Template parse errors:
    More than one component matched on this element.
    Make sure that only one component's selector can match a given element.
    Conflicting components: MockedComponent,MatHeaderRow ("
                      </ng-container>

                      [ERROR ->]<mat-header-row *matHeaderRowDef="displayedColumnsProgramDetails"></mat-header-row>
                    "): ng:///DynamicTestModule/MaterialAudioProgramsComponent.html@107:18
    More than one component matched on this element.
    Make sure that only one component's selector can match a given element.
    Conflicting components: MockedComponent,MatRow ("t-header-row *matHeaderRowDef="displayedColumnsProgramDetails"></mat-header-row>


         [ERROR ->]<mat-row *matRowDef="let row; columns: displayedColumnsProgramDetails;"></mat-row>

我不知道我需要在这里做什么。

这是我的 component.html

<mat-spinner *ngIf="dataLoading" class="loading"></mat-spinner>
<ng-container class="ap-container" *ngIf="materialAudioPrograms$ | async as materialAudioPrograms">
  <div class="container" *ngIf="materialAudioPrograms.length > 0; else dataLoading">
    <mat-table [dataSource]="dataSource$" class="audio-programs  vertical-data">
      <ng-container matColumnDef="Start Channel">
        <mat-header-cell *matHeaderCellDef>
          Start Channel </mat-header-cell>
        <mat-cell *matCellDef="let element">
          <mat-icon *ngIf="element.show== false" aria-hidden="false" aria-label="ad-info-icon">keyboard_arrow_right
          </mat-icon>
          <mat-icon *ngIf="element.show== true" aria-hidden="false" aria-label="ad-info-icon">keyboard_arrow_down
          </mat-icon>
          {{element.startChannelNumber}}
        </mat-cell>
      </ng-container>

      <ng-container matColumnDef="Layout">
        <mat-header-cell *matHeaderCellDef> Layout </mat-header-cell>
        <mat-cell *matCellDef="let element"> {{element.layout}} </mat-cell>
      </ng-container>

      <ng-container matColumnDef="Language">
        <mat-header-cell *matHeaderCellDef> Language </mat-header-cell>
        <mat-cell mat-cell *matCellDef="let element"> {{(element.language != null) ? element.language : 'None'}}
        </mat-cell>
      </ng-container>

      <ng-container matColumnDef="Active">
        <mat-header-cell *matHeaderCellDef> Active </mat-header-cell>
        <mat-cell *matCellDef="let element"> {{(element.active == true)? 'Yes': 'No'}} </mat-cell>
      </ng-container>

      <ng-container matColumnDef="expandedDetail">
        <mat-cell *matCellDef="let detail">
          <mat-tab-group>
            <!-- Program Tab and Table -->

            <mat-tab label="Program">
              <ng-container>
                <mat-table [dataSource]="audioProgramDetailsDataSource$" class="vertical-data">
                  <ng-container matColumnDef="Censored">
                    <mat-header-cell *matHeaderCellDef> Censored </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.censored != null) ? (element.censored ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>
                  <ng-container matColumnDef="Dubbed">
                    <mat-header-cell *matHeaderCellDef> Dubbed </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.dubbed != null) ? (element.dubbed ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="Music">
                    <mat-header-cell *matHeaderCellDef> Music </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.music != null) ? (element.music ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="Effects">
                    <mat-header-cell *matHeaderCellDef> Effects </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.effects != null) ? (element.effects ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>


                  <ng-container matColumnDef="DVS">
                    <mat-header-cell *matHeaderCellDef> DVS </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{(element.dvs != null) ? (element.dvs ? 'Yes' :'No'): 'None'}}
                    </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="MOS">
                    <mat-header-cell *matHeaderCellDef> MOS </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.muteOrSilence != null) ? (element.muteOrSilence ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="Voiceover">
                    <mat-header-cell *matHeaderCellDef> Voiceover </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.voiceOver != null) ? (element.voiceOver ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="Rescore">
                    <mat-header-cell *matHeaderCellDef> Rescore </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.rescore != null) ? (element.rescore ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>


                  <ng-container matColumnDef="Contains Dialog">
                    <mat-header-cell *matHeaderCellDef> Contains Dialog </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.dialog != null) ? (element.dialog ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="CALM Act">
                    <mat-header-cell *matHeaderCellDef> CALM Act Compliance </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.calmACT != null) ? (element.calmAct ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="EBUR128">
                    <mat-header-cell *matHeaderCellDef> EBUR128 Compliance </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.ebuR128 != null) ? (element.ebuR128 ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <mat-header-row *matHeaderRowDef="displayedColumnsProgramDetails"></mat-header-row>
                  <mat-row *matRowDef="let row; columns: displayedColumnsProgramDetails;"></mat-row>
                </mat-table>

              </ng-container>
            </mat-tab>

            <!-- 
            Attributes Tab and Table -->
            <mat-tab label="Attributes">
              <ng-container>
                <mat-table [dataSource]="audioProgramDetailsDataSource$" class="vertical-data">
                  <ng-container matColumnDef="Loudness Level">
                    <mat-header-cell *matHeaderCellDef> Loudness Level </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.loudnessLevel != null) ? (element.loudnessLevel ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>
                  <ng-container matColumnDef="Loudness Range">
                    <mat-header-cell *matHeaderCellDef> Loudness Range </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.loudness_Range != null) ? (element.loudness_Range ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="True Peak Level (Max)">
                    <mat-header-cell *matHeaderCellDef> True Peak Level (Max) </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.truePeakLevel != null) ? (element.truePeakLevel ? 'Yes' :'No'): 'None'}} </mat-cell>
                  </ng-container>

                  <ng-container matColumnDef="True Peak Channel-L">
                    <mat-header-cell *matHeaderCellDef> True Peak Level Channel-L </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.truePeakLevelChannel_L != null) ? (element.truePeakLevelChannel_L ? 'Yes' :'No'): 'None'}}
                    </mat-cell>
                  </ng-container>


                  <ng-container matColumnDef="True Peak Channel-R">
                    <mat-header-cell *matHeaderCellDef> True Peak Level Channel-R </mat-header-cell>
                    <mat-cell *matCellDef="let element">
                      {{(element.truePeakLevelChannel_R != null) ? (element.truePeakLevelChannel_R ? 'Yes' :'No'): 'None'}}
                    </mat-cell>
                  </ng-container>

                  <mat-header-row *matHeaderRowDef="displayedColumnsAttributeDetails"></mat-header-row>
                  <mat-row *matRowDef="let row; columns: displayedColumnsAttributeDetails;"></mat-row>
                </mat-table>

              </ng-container>
            </mat-tab>
          </mat-tab-group>
        </mat-cell>
      </ng-container>


      <mat-header-row *matHeaderRowDef="displayedColumnsAudioPrograms"></mat-header-row>
      <mat-row *matRowDef="let row; columns: displayedColumnsAudioPrograms;" class="element-row" matRipple
        (click)="toggleRow(row)"></mat-row>
      <mat-row *matRowDef="let row; columns: ['expandedDetail']; when: isExpansionDetailRow"
        [@detailExpand]="row.element.show ? 'expanded' : 'collapsed'" style="overflow: hidden"> </mat-row>
    </mat-table>
    <div class="container" *ngIf="materialAudioPrograms.length === 0 && (dataLoading === false | async)">
      <p class="no-data-msg">No Audio Programs Available</p>
    </div>
  </div>
</ng-container>

这里是 component.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MaterialAudioProgramsComponent } from './material-audio-programs.component';
import {
  MatTableModule,
  MatTabsModule,
  MatIconModule,
  MatProgressSpinnerModule
} from '@angular/material';

@NgModule({
  declarations: [MaterialAudioProgramsComponent],
  imports: [CommonModule, MatProgressSpinnerModule, MatTableModule, MatTabsModule, MatIconModule],
  entryComponents: [MaterialAudioProgramsComponent]
})
export class MaterialAudioProgramsModule {
  // Define entry property to access entry component in lazy-loader service
  static entry = MaterialAudioProgramsComponent;
}

和component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MaterialMockModule } from '@content-platform/unit-test-helpers';
import { MaterialAudioProgramsComponent } from './material-audio-programs.component';
import { StoreModule } from '@ngrx/store';
import { RouterTestingModule } from '@angular/router/testing';
import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { MatTableModule } from '@angular/material';

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MaterialAudioProgramsComponent],
      imports: [MaterialMockModule, StoreModule.forRoot({}), RouterTestingModule, MatTableModule],
      schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MaterialAudioProgramsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

我无法找到解决方案,非常感谢您的帮助。

谢谢

尝试删除 MaterialMockModule 并保留 MatTableModule。如果我是你,我会利用 NO_ERRORS_SCHEMA 而不是导入任何模块,但在进行集成测试时你可能需要它们(子组件)。