javascript - 无法解析组件的所有参数: (?, [object Object]) 在 jasmine 组件 UT 上
问题描述
我正在定义一个组件的 UT,该组件具有扩展类并同时使用 i8nService (用于翻译目的)和 ChangeDetectionRef 并且由于以下错误而无法实例化它:
Failed: Can't resolve all parameters for BrandingMultiselectComponent: (?, [object Object]).
Error: Can't resolve all parameters for BrandingMultiselectComponent: (?, [object Object]).
at syntaxError node_modules/@angular/compiler/fesm5/compiler.js:2426:1)
at CompileMetadataResolver.push../node_modules/@angular/compiler/fesm5/compiler.js.CompileMetadataResolver._getDependenciesMetadata node_modules/@angular/compiler/fesm5/compiler.js:18979:1)
at CompileMetadataResolver.push../node_modules/@angular/compiler/fesm5/compiler.js.CompileMetadataResolver._getTypeMetadata node_modules/@angular/compiler/fesm5/compiler.js:18872:1)
at CompileMetadataResolver.push../node_modules/@angular/compiler/fesm5/compiler.js.CompileMetadataResolver.getNonNormalizedDirectiveMetadata node_modules/@angular/compiler/fesm5/compiler.js:18491:1)
at CompileMetadataResolver.push../node_modules/@angular/compiler/fesm5/compiler.js.CompileMetadataResolver.loadDirectiveMetadata node_modules/@angular/compiler/fesm5/compiler.js:18353:1)
at http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm5/compiler.js:26011:1
at Array.forEach (<anonymous>)
at http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/compiler/fesm5/compiler.js:26010:1
at Array.forEach (<anonymous>)
at JitCompiler.push../node_modules/@angular/compiler/fesm5/compiler.js.JitCompiler._loadModules node_modules/@angular/compiler/fesm5/compiler.js:26007:1),Expected undefined to be defined.
at UserContext.<anonymous> src/app/wa/components/branding/ddl-multiselect/ddl-multiselect.component.spec.ts:62:23)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:391:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvoke node_modules/zone.js/dist/zone-testing.js:289:1)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:390:1)
这是我目前准备的UT:
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AngularMultiSelectModule } from 'angular2-multiselect-dropdown';
import { I18nService } from '@core/language/i18n.service';
import { BrandingMultiselectComponent } from '@branding/ddl-multiselect/ddl-multiselect.component';
let component: BrandingMultiselectComponent ;
let fixture: ComponentFixture<BrandingMultiselectComponent >;
let ngOnitComponent_Spy: jasmine.Spy;
let I18nServiceStub: Partial<I18nService>;
describe('branding component - BrandingMultiselectComponent - testing initialization', () => {
I18nServiceStub = {
language: 'en-US',
supportedLanguages: ['en-US', 'es-ES']
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BrandingMultiselectComponent ],
imports: [
BrowserModule,
AngularMultiSelectModule,
RouterTestingModule
],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
providers: [ { provide: I18nService, useClass: I18nServiceStub } ]
})
.compileComponents();
fixture = TestBed.createComponent(BrandingMultiselectComponent );
component = fixture.componentInstance;
// Spies for component stuff
ngOnitComponent_Spy = spyOn(component, 'ngOnInit').and.callThrough();
}));
it('should component be defined', () => {
expect(component).toBeDefined();
});
});
这是组件本身(虽然并非所有内容都已设置)
import { Component, Input, Output, EventEmitter,
ViewEncapsulation, OnInit, AfterViewChecked,
ChangeDetectorRef, AfterViewInit, ViewChild } from '@angular/core';
import { ArrayUtil } from '@utils/ArrayUtil/ArrayUtil';
import { ObjectUtil } from '@utils/ObjectUtil/ObjectUtil';
import { I18nService } from '@core/index';
import { BaseTranslation } from '@app/components/base/base.translations';
import { DDLPluginTexts, DDLMultiselectComponent } from '@shared/components/single/ddl-multiselect/ddl-multiselect.component';
@Component({
selector: 'wa-ddl-multiselect',
templateUrl: './ddl-multiselect.component.html',
styleUrls: ['./ddl-multiselect.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class BrandingMultiselectComponent extends BaseTranslation implements OnInit, AfterViewInit, AfterViewChecked {
// Required params
//#region OPTIONS
sOptions: any[];
backupRowOpts: any[];
@Output() optionsChange: EventEmitter<any[]> = new EventEmitter<any[]>();
@Input()
get options() {
return this.sOptions;
}
set options(val: any[]) {
if (!ArrayUtil.AreEqual(this.sOptions, val)) {
if (!this.hasComponentAlreadyBeenInitialized) {
this.backupRowOpts = val;
}
this.sOptions = val;
this.optionsChange.emit(this.sOptions);
}
}
//#endregion
//#region SELECTED OPTIONS
sSelectedOptions: any[];
@Output() selectedOptionsChange: EventEmitter<any[]> = new EventEmitter<any[]>();
@Input()
get selectedOptions() {
return ArrayUtil.IsNotEmptyOrNull(this.sSelectedOptions) ? this.applyOptionsTranslation(false, this.sSelectedOptions)
: this.sSelectedOptions;
}
set selectedOptions(val: any[]) {
if (!ArrayUtil.AreEqual(this.sSelectedOptions, val)) {
this.sSelectedOptions = val;
// We want to overwrite text shown with the one expected
if (this.hasComponentAlreadyBeenInitialized &&
ArrayUtil.IsNotEmptyOrNull(this.sSelectedOptions) &&
this.ddlSettings.singleSelection === false &&
ObjectUtil.IsNotNullOrUndefined(this.translationTexts)) {
this.defineDdlFooter();
}
this.selectedOptionsChange.emit(this.sSelectedOptions);
}
}
//#endregion
hasComponentAlreadyBeenInitialized = false;
hasOptionsAlreadyBeenTranslated = false;
// Optional params
@Input() doesOptionsRequireTranslations = false;
//#region TRANSLATION TEXTS
originalKeyTranslationTexts: DDLPluginTexts = null;
sTranslationTexts: DDLPluginTexts;
@Output() translationTextsChange = new EventEmitter<DDLPluginTexts>();
@Input()
get translationTexts(): DDLPluginTexts {
return this.sTranslationTexts;
}
set translationTexts(val: DDLPluginTexts) {
if (val !== null && val !== undefined) {
if (this.originalKeyTranslationTexts === null) {
this.originalKeyTranslationTexts = val;
}
this.sTranslationTexts = this.applyTranslations();
this.translationTextsChange.emit(this.sTranslationTexts);
}
}
//#endregion
@Input() displayProp: string;
@Input() valueProp: string;
showToggleAll: boolean;
// Plugin optional params
@Input() isEditionMode = false;
@Input() isFilterActive = false;
@Input() selectionLimit: string = null;
// Shared component ref
@ViewChild(DDLMultiselectComponent) ddlBaseMultiSelect: DDLMultiselectComponent;
// Events
@Output() ddlOptionSelectedEvent = new EventEmitter<any>();
//#region COMPONENT LIFE-CYLCE HOOKS
constructor(_i8nService: I18nService, private cdRef: ChangeDetectorRef) { super(_i8nService); }
ngAfterViewInit(): void {
this.cdRef.detectChanges();
if (this.isLocalPreference) {
const currentUserDefaultPrefs = this.ddlBaseMultiSelect.loadDefaultUserPrefs();
if (ObjectUtil.IsNotNullOrUndefined(currentUserDefaultPrefs)) {
this.selectedOptions = currentUserDefaultPrefs;
} else {
this.selectedOptions = this.options;
}
} else {
if (!ArrayUtil.IsNotEmptyOrNull(this.selectedOptions)) {
this.selectedOptions = this.options;
}
}
this.hasComponentAlreadyBeenInitialized = true;
}
//#endregion
//#region COMPONENT FUNCS
applyTranslations(isForLangChange: boolean = false): DDLPluginTexts {
let resultTranslationsTexts: DDLPluginTexts = null;
if (this.originalKeyTranslationTexts !== null &&
this.originalKeyTranslationTexts !== undefined) {
// Apply translations for input PrimeNG labels
resultTranslationsTexts = {
buttonDefaultText: this.i8nService.getInstantTranslation(this.originalKeyTranslationTexts.buttonDefaultText),
dynamicButtonTextSuffix: '{0} ' + this.i8nService.getInstantTranslation(this.originalKeyTranslationTexts.dynamicButtonTextSuffix),
filterPlaceHolder: this.i8nService.getInstantTranslation(this.originalKeyTranslationTexts.filterPlaceHolder),
emptyFilterMessage: this.i8nService.getInstantTranslation(this.originalKeyTranslationTexts.emptyFilterMessage),
checkAll: this.i8nService.getInstantTranslation(this.originalKeyTranslationTexts.checkAll),
uncheckAll: this.i8nService.getInstantTranslation(this.originalKeyTranslationTexts.uncheckAll),
filterSelectAll: this.i8nService.getInstantTranslation(this.originalKeyTranslationTexts.filterSelectAll),
filterUnSelectAll: this.i8nService.getInstantTranslation(this.originalKeyTranslationTexts.filterUnSelectAll)
};
if (isForLangChange) {
this.translationTexts = resultTranslationsTexts;
}
}
// Apply translations for options (if applies)
if (this.doesOptionsRequireTranslations &&
this.doesOptionsRequireTranslations.valueOf() &&
ArrayUtil.IsNotEmptyOrNull(this.backupRowOpts)) {
this.hasOptionsAlreadyBeenTranslated = false;
this.applyOptionsTranslation(true);
}
return resultTranslationsTexts;
}
applyOptionsTranslation(isForLangChange: boolean = false, optionsToTranslate: any[] = null): any[] {
// tslint:disable-next-line:prefer-const
let optionsTranslated = ArrayUtil.Clone(ArrayUtil.IsNotEmptyOrNull(optionsToTranslate) ? optionsToTranslate
: this.backupRowOpts);
optionsTranslated.forEach(option => {
option[this.displayProp] = this.i8nService.getInstantTranslation(option[this.displayProp]);
});
if (isForLangChange) {
this.options = this.backupRowOpts;
}
return optionsTranslated;
}
//#endregion
}
#endregion
}
我在这里想念什么?有什么要定义的吗?据我了解,它应该与 18nService 有关,但我 100% 确定。
欢迎任何建议
解决方案
使用NO_ERRORS_SCHEMA允许未知元素和属性
TestBed.configureTestingModule({
declarations: [ BrandingMultiselectComponent ],
imports: [
BrowserModule,
AngularMultiSelectModule,
RouterTestingModule
],
schemas: [ NO_ERRORS_SCHEMA ], // here
providers: [ { provide: I18nService, useClass: I18nServiceStub } ]
}).compileComponents();
推荐阅读
- pywinauto - 如何在 .net 应用程序的 pywinauto 中访问数据网格?
- wix - Wixtoolset,根据安装程序的位置指定文件的源
- python - Web Scraping 脚本无法正常工作
- python - 运行火花作业:python vs spark.submit
- xcode - 在表格视图中插入来自 REST API 的信息
- php - 如何在 php 中解析出这个对象/数组?
- delphi - 如何使用动态创建的按钮在 onclick 事件上运行过程,并通过变量传递
- eclipse - 无法使用 Spring 初始化导入 Sring Boot 项目,有关属性“snippetsDir”的 gradle uild 错误
- python - 通过电子邮件发送后如何删除文本文件?Python
- php - 为什么我的 Wordpress 管理仪表板没有“评论”菜单项?