【问题标题】:ngx-translate instant function is not a function thrown: Unit testingngx-translate 即时函数不是抛出的函数:单元测试
【发布时间】:2019-11-28 10:10:42
【问题描述】:

我是单元测试和 Angular 的新手,我正在尝试为我的项目编写一些单元测试。

我得到的错误是;

Uncaught TypeError: _this.translate.instant is not a function thrown
Expected null to be truthy.

component.spec 文件的导入包括

beforeEach(async(() => {
TestBed.configureTestingModule({
  imports:[
    ClarityModule,
    RouterTestingModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: (http: HttpClient) => new TranslateHttpLoader(http, 'assets/i18n/', '.json'),
        deps: [HttpClient]
      }
    }),
    HttpClientModule
  ],
  declarations: [
    HeaderComponent,
    LanguageSelectorComponent
  ],
  providers: [
    { provide: Store, useClass: TestStore },
    { provide: TranslateService, useClass: TranslateServiceStub },
    { provide: NGXLogger, useClass: NGXLoggerMock }
  ]
})
.compileComponents();
}));

我了解TranslateServiceStub 不包含“即时”功能。这是导致此错误的原因吗?如果是这样,我如何模拟 translate.instant 函数?

或者有什么方法可以在调用即时方法之前将翻译文件加载到规范文件中?

任何建议都会很有帮助。非常感谢!

【问题讨论】:

    标签: angular typescript unit-testing karma-jasmine ngx-translate


    【解决方案1】:

    根据documentation linkinstant 的返回类型是stringObject

    instant(key: string|Array<string>, interpolateParams?: Object): string|Object
    
    export class TranslateServiceStub {
        instant(): string{
          // or put some logic to return Mock data as per the passed value from component
          //  (if being used at multiple places in the component)
          return "some_string";
        }
    }
    

    同样,如果需要,您可以返回 Object

    更新:

    我使用instant()尝试了以下组件:

    import { Component } from '@angular/core';
    import { TranslateService } from '@ngx-translate/core';
    import { Observable } from 'rxjs';
    
    @Component({
        selector: 'app-root',
        template: `
            <div>
                <h2>{{ 'HOME.TITLE' | translate }}</h2>
                <label>
                    {{ 'HOME.SELECT' | translate }}
                    <select #langSelect (change)="translate.use(langSelect.value)">
                        <option *ngFor="let lang of translate.getLangs()" [value]="lang" [selected]="lang === translate.currentLang">{{
                            lang
                        }}</option>
                    </select>
                </label>
                <br>
                {{name}}
            </div>
        `,
    })
    export class AppComponent {
        public name: string;
    
        constructor(public translate: TranslateService) {
            translate.addLangs(['en', 'fr']);
            translate.setDefaultLang('en');
    
            const browserLang = translate.getBrowserLang();
            translate.use(browserLang.match(/en|fr/) ? browserLang : 'en');
        }
        public ngOnInit(): void {
            this.translate.onLangChange.subscribe(() => {
                this.name = this.translate.instant('HOME.TITLE'); // <---- instant() used here
            });
        }
    }
    

    因此,我创建了一个spec 文件:

    import {HttpClient} from "@angular/common/http";
    import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
    import {async, TestBed, ComponentFixture} from '@angular/core/testing';
    import {TranslateLoader, TranslateModule, TranslateService} from "@ngx-translate/core";
    import {AppComponent} from './app.component';
    import {HttpLoaderFactory} from "./app.module";
    
    const TRANSLATIONS_EN = require('../assets/i18n/en.json');
    const TRANSLATIONS_FR = require('../assets/i18n/fr.json');
    
    describe('AppComponent', () => {
      let translate: TranslateService;
      let http: HttpTestingController;
      let fixture: ComponentFixture<AppComponent>;
      let app: AppComponent;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [
            AppComponent
          ],
          imports: [
            HttpClientTestingModule,
            TranslateModule.forRoot({
              loader: {
                provide: TranslateLoader,
                useFactory: HttpLoaderFactory,
                deps: [HttpClient]
              }
            })
          ],
          providers: [TranslateService]
        }).compileComponents();
        translate = TestBed.get(TranslateService);
        http = TestBed.get(HttpTestingController);
        fixture = TestBed.createComponent(AppComponent);
        app = fixture.componentInstance;
      }));
    
      it('should create the app', async(() => {
        expect(app).toBeTruthy();
      }));
    
      it('should load translations', async(() => {
        spyOn(translate, 'getBrowserLang').and.returnValue('en');
        const compiled = fixture.debugElement.nativeElement;
    
        // the DOM should be empty for now since the translations haven't been rendered yet
        expect(compiled.querySelector('h2').textContent).toEqual('');
    
        http.expectOne('/assets/i18n/en.json').flush(TRANSLATIONS_EN);
        http.expectNone('/assets/i18n/fr.json');
    
        // Finally, assert that there are no outstanding requests.
        http.verify();
    
        fixture.detectChanges();
        // the content should be translated to english now
        expect(compiled.querySelector('h2').textContent).toEqual(TRANSLATIONS_EN.HOME.TITLE);
    
        translate.use('fr');
        http.expectOne('/assets/i18n/fr.json').flush(TRANSLATIONS_FR);
    
        // Finally, assert that there are no outstanding requests.
        http.verify();
    
        // the content has not changed yet
        expect(compiled.querySelector('h2').textContent).toEqual(TRANSLATIONS_EN.HOME.TITLE);
    
        fixture.detectChanges();
        // the content should be translated to french now
        expect(compiled.querySelector('h2').textContent).toEqual(TRANSLATIONS_FR.HOME.TITLE);
        expect(app.name).toEqual('Bonjour Angular avec ngx-translate !');
      }));
    
    
    });
    
    

    希望这能帮助您更好地测试ng-translate

    【讨论】:

    • 谢谢,我尝试了类似的解决方案,但遗憾的是,当我运行单元测试时,Karma 崩溃了。所以,我认为模拟即时功能失败了,想知道是否有任何具体的方法。
    • @NivedithaKarmegam:当它崩溃时,你能帮我解决具体的错误吗?另外,您可以尝试几次添加和删除我的代码,看看问题是否仍然存在。我们基本上是用TranslateServiceStub 替换整个类,因此可能需要添加更多依赖项。
    • 我确实有一个 TranslateServiceStub 类,用于模拟“use”和“getTranslation”函数。但是当模拟“即时”功能时,它会在 chrome 中给出错误提示“无法在框架中显示 iframe,因为它将“X-Frame-Options”设置为“拒绝”。
    • @NivedithaKarmegam:嗯……这很奇怪。我会检查并在几个小时内回来。你可以分享tshtml 吗?不过,我不确定它会是多少:(
    • 非常感谢,非常感谢。如果我也找到解决方法,我会及时通知您!
    猜你喜欢
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 2019-10-21
    相关资源
    最近更新 更多