У меня возникли проблемы с тестированием двух пользовательских реализаций абстрактных классов TranslateLoader и MissingTranslationHandler ngx-translate. Дело в том, что если я расширю абстрактные классы без декораторов, я не смогу внедрить их как службы в конструкторе Testbed, а если я расширю их с помощью декораторов, они не могут быть использованы в качестве намерения для реализации библиотеки ngx-translate.
Ошибка, возникающая при тестировании, связана с тестируемыми классами, не имеющими декоратора. Прилагаю сообщение об ошибке ниже. Есть ли способ каким-либо образом обеспечить тестирование этих двух классов?
Error: Can't resolve all parameters for SvmTranslateLoader: (?).
at getUndecoratedInjectableFactory (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:17131:1)
at injectableDefOrInjectorDefFactory (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:17115:1)
at providerToFactory (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:17183:1)
at providerToRecord (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:17165:1)
at R3Injector.processProvider (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:16981:1)
at http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:16960:1
at http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:1400:1
at <Jasmine>
at deepForEach (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:1400:1)
at R3Injector.processInjectorType (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:16956:1)
Я прилагаю код обоих пользовательских классов, SvmTranslateLoader и SvmMissingTranslationHandler, а также мой файл spe c. Первые два работают нормально для всех остальных тестов в моем наборе.
svm-translate.loader.spe c .ts:
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';
import { SvmMissingTranslationHandler, SvmTranslateLoader } from './svm-translate.loader';
import { TranslateTestingModule } from '../../../mocks/translate-testing.module';
describe('SvmTranslate', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, TranslateTestingModule],
providers: [SvmMissingTranslationHandler, SvmTranslateLoader, { provide: String, useValue: 'dummy' }]
});
});
it('translateLoader should be created', inject([SvmTranslateLoader], (service: SvmTranslateLoader) => {
expect(service).toBeTruthy();
}));
it('missingTranslationHandler should be created', inject([SvmMissingTranslationHandler], (service: SvmMissingTranslationHandler) => {
expect(service).toBeTruthy();
}));
});
SvmTranslateLoader:
export class SvmTranslateLoader implements TranslateLoader {
constructor(private http: HttpClient, private prefix: string = 'i18n', private module: string, private suffix: string = '.json') {}
/**
* Gets the translations from the server
*/
public getTranslation(lang: string): Observable<any> {
const common = this.prefix + '/common_' + lang + this.suffix;
const file = this.prefix + '/' + this.module + '_' + lang + this.suffix;
const mergedObs = forkJoin(this.http.get(common), this.http.get(file));
return mergedObs.pipe(
map(d => {
const merged = {};
Object.assign(merged, d[0], d[1]);
return merged;
})
);
}
}
SvmMissingTranslationHandler:
export class SvmMissingTranslationHandler implements MissingTranslationHandler {
private failNumber: number = 0;
private originalValue: MissingTranslationHandlerParams = null;
constructor() {}
/**
* Tries various methods to adjust case and retry the translations.
* using this.failNumber because its recursive call as they fail
* I think there is a possible problem if two observbles are using
* handler at the same time.
* @param params
*/
handle(params: MissingTranslationHandlerParams): any {
if (this.failNumber === 0) {
this.originalValue = _.clone(params); //clone and save original value
this.failNumber = this.failNumber + 1;
return params.translateService.instant(params.key.toLowerCase());
} else if (this.failNumber === 1) {
this.failNumber = this.failNumber + 1;
return params.translateService.instant(params.key.toUpperCase());
return params.translateService.instant(params.key.toUpperCase());
} else if (this.failNumber === 2) {
this.failNumber = this.failNumber + 1;
return params.translateService.instant(this.titleCase(params.key));
} else if (this.failNumber === 3) {
this.failNumber = this.failNumber + 1;
return params.translateService.instant(this.sentanceCase(params.key));
} else if (this.failNumber === 4) {
this.failNumber = this.failNumber + 1;
return params.translateService.instant(params.key + ' ');
} else if (this.failNumber === 5) {
this.failNumber = this.failNumber + 1;
return params.translateService.instant(params.key.trimRight());
} else {
// clone again original value and set to null to reuse before returning - RO-19/9/2019
const returnValue = _.clone(this.originalValue);
this.originalValue = null;
// reset the fail number so the next word gets tried correctly
this.failNumber = 0;
// just returns english key if string is not in translation
return returnValue.key;
}
}
private titleCase(str: string): string {
const splitStr = str.toLowerCase().split(' ');
for (let i = 0; i < splitStr.length; i++) {
// You do not need to check if i is larger than splitStr length, as your for does that for you
// Assign it back to the array
splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);
}
// Directly return the joined string
return splitStr.join(' ');
}
private sentanceCase(str: string): string {
const splitStr = str.toLowerCase().split(' ');
for (let i = 0; i < splitStr.length; i++) {
// You do not need to check if i is larger than splitStr length, as your for does that for you
// Assign it back to the array
if (i === 0) {
splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);
}
if (i > 0) {
splitStr[i] = splitStr[i].charAt(0).toLowerCase() + splitStr[i].substring(1);
}
}
// Directly return the joined string
return splitStr.join(' ');
}
}