Angular Тестирование: ¿Как проверить собственную реализацию TranslateLoader и MissingTranslationHandler? - PullRequest
0 голосов
/ 26 мая 2020

У меня возникли проблемы с тестированием двух пользовательских реализаций абстрактных классов 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(' ');
    }
}
...