业力错误 StaticInjectorError -> 如何正确地向组件提供自定义管道

Karma error StaticInjectorError -> how to correctly provide custom pipe to component

我正在尝试为我使用自定义编写的管道的组件编写测试,但我收到因果报应错误,我没有正确提供它。项目 building/working 没有错误(似乎所有内容都正确提供),但对于测试,似乎有些地方不对劲。出了什么问题以及如何解决? :? (一些组件仅在 html 中使用它,其中一些组件在服务等中使用,所以问题似乎不在 providers: [AppTranslatePipe]

Failed: StaticInjectorError(DynamicTestModule)[AppTranslatePipe -> 
TranslateService]: 
  StaticInjectorError(Platform: core)[AppTranslatePipe -> TranslateService]: 
    NullInjectorError: No provider for TranslateService!

.html(我使用这个管道的部分)

<button
  mat-raised-button
  mat-dialog-close
  class="close">
  {{ 'common.cancel' | appTranslate }}
</button>

.module 导入管道的模块,因为我在 html

上使用它
@NgModule({
  declarations: [
    UserSettingsComponent
  ],
  imports: [
    CommonModule,
    MatDialogModule,
    MatFormFieldModule,
    MatInputModule,
    MatButtonModule,
    MatSelectModule,
    AppTranslateModule,
  ],
  exports: [
    UserSettingsComponent,
  ]
})
export class UserSettingsModule { }

.component.ts(因为我也在 showNotificationOnSubmit 函数中使用了这个管道,我需要通过 providers[=32= 设置 AppTranslatePipe ], 这可能是问题所在?:?

@Component({
  selector: 'lib-user-settings',
  templateUrl: './user-settings.component.html',
  styleUrls: ['./user-settings.component.sass'],
  providers: [ AppTranslatePipe ]
})
export class UserSettingsComponent {

  constructor(
    public dialogRef: MatDialogRef<UserSettingsComponent>,
    private translationService: TranslationService,
    private globalNotificationsService: GlobalNotificationsService,
    private appTranslatePipe: AppTranslatePipe,
  ) { }

  showNotificationOnSubmit(
    isNewLangSetted: boolean,
    isNewPasswordSetted: boolean
  ): void {
    this.globalNotificationsService.addTypedNotification(
      this.appTranslatePipe.transform('user-settings.success.update'),
      NotificationTypeEnum.success
    );
  }
}

*spec.ts

fdescribe('UserSettingsComponent', () => {
  let component: UserSettingsComponent;
  let fixture: ComponentFixture<UserSettingsComponent>;

  let translationService: jasmine.SpyObj<TranslationService>;
  let appTranslatePipe: jasmine.SpyObj<AppTranslatePipe>;
  let userService: jasmine.SpyObj<UserService>;
  let globalNotificationsService: jasmine.SpyObj<GlobalNotificationsService>;
  const fb: FormBuilder = new FormBuilder();
  let matDialogRef: jasmine.SpyObj<MatDialogRef<UserSettingsComponent>>;

  const MOCK_TRANSLATIONS: ILocale[] = [
    {
      Id: 0,
      Key: 'key',
      Snapshot: null,
      Title: 'title-1',
      TotalCount: 0
    }
  ];

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        UserSettingsComponent,
      ],
      imports: [
        LoaderModule,
        BrowserAnimationsModule,
        ReactiveFormsModule,
        FormsModule,
        MatDialogModule,
        MatFormFieldModule,
        MatInputModule,
        MatButtonModule,
        MatSelectModule,
        AppTranslateModule,
      ],
      providers: [
        {
          provide: TranslationService,
          useValue: jasmine.createSpyObj('TranslationService', [
            'getTranslationList',
            'updateLanguage',
            'setLanguage'
          ])
        },
        {
          provide: UserService,
          useValue: jasmine.createSpyObj('UserService', [
            'updatePassword',
          ])
        },
        {
          provide: GlobalNotificationsService,
          useValue: jasmine.createSpyObj('GlobalNotificationsService', [
            'addTypedNotification',
          ])
        },
        { provide: FormBuilder, useValue: fb },
        {
          provide: MatDialogRef,
          useValue: jasmine.createSpyObj('MatDialogRef', [
            'close'
          ]),
        },
        {
          provide: AppTranslatePipe,
          useValue: jasmine.createSpyObj('AppTranslatePipe', [
            'transform'
          ]),
        },
      ]
    })
    .compileComponents();

    translationService = TestBed.get(TranslationService);
    appTranslatePipe = TestBed.get(AppTranslatePipe);
    userService = TestBed.get(UserService);
    globalNotificationsService = TestBed.get(GlobalNotificationsService);
    matDialogRef = TestBed.get(MatDialogRef);

    fixture = TestBed.createComponent(UserSettingsComponent);
    component = fixture.componentInstance;
  }));

  fit('should create', () => {
    translationService.getTranslationList.and.returnValue(
      of([])
    );

    fixture.detectChanges();

    expect(component).toBeTruthy();
    expect(translationService.getTranslationList)
      .toHaveBeenCalled();
  });
});

管道本身:

import { PipeTransform, Pipe } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

import { TranslationService } from '../../services/translation/translation.service';
import { ILocale } from '../../models/locale.model';

@Pipe({
  name: 'appTranslate',
  pure: false
})
export class AppTranslatePipe implements PipeTransform {
  constructor(
    private translationService: TranslationService,
    private translate: TranslateService,
  ) { }

  transform(
    fileKey: string,
    dbKey?: string
  ) {
    if (!fileKey) {
      return '';
    }

    const currentLang: ILocale = this.translationService.getLanguage();
    if (currentLang) {
      const dbTranslation: string = this.translationService.getDBTranslation_byKey(dbKey);
      if (dbKey && dbTranslation) {
        return dbTranslation;
      } else {
        return this.translate.instant(fileKey) + '\`';  
      }
    } else {
      return this.translate.instant(fileKey) + '\`';
    }
  }
}

因为您将真实管道作为依赖项添加到您的测试中(如果您在组件级别声明了提供者,则无法避免)您需要确保该管道的所有依赖项在您的测试中可用.

所以你需要为你的 TranslateService 注入一个模拟,它被注入你的 AppTranslatePipe 并在 TestBed providers 数组

中声明它

由于报错,您的 AppTranslatePipe 需要 TranslateService 作为依赖项,您还需要将其提供给 TestBed:

 TestBed.configureTestingModule({
      ....
      providers:[
      ....
      TranslateService
      ]
      ...