Core: ng2-translate problem in unit test Jasmine

Created on 18 Mar 2017  路  19Comments  路  Source: ngx-translate/core

Reproduction of the problem
I am using karma with Jasmine for unit testing my component of Angular 2 but when I open karma server in testing and open pages tested ng2-translate don't charging attributes references in json.
I find this problem just in unit test but when I start my project in dev mode all attributes have good charging from json.

My code in the pictures :
capture d ecran 2017-03-18 a 17 15 18

My environment:

  • ng2-translate version: 5.0.0

  • Angular version: 2.4.8

  • Angular/cli version: 1.0.0-rc.0
  • karma version: 1.5.0
  • jasmine version: 2.5.38
  • Browser: Chrome

Without Testing :
capture d ecran 2017-03-18 a 17 21 18
With Testing in Karma :
capture d ecran 2017-03-18 a 17 19 45

questiosupport

Most helpful comment

Hello guys. Perhaps it is too late and not what you really want, but I had a similar problem. I needed to test a component that uses translation, but the TranslateService is used in a parent component. To test my component I had to substitute TranslateHttpLoader by my own like the following:

  1. Inside TestBed.configureTestingModule:
imports: [
        TranslateModule.forRoot({
          loader: {
            provide: TranslateLoader,
            useClass: TranslateCustomLoader
          }
        })
      ]
  1. TranslateCustomLoader itself:
import {TranslateLoader} from "@ngx-translate/core";
import {Observable} from "rxjs";

declare let readJSON: any;

export class TranslateCustomLoader implements TranslateLoader {
  getTranslation(lang: string): Observable<any> {
    if (lang=="ru"){
      let ru = readJSON('assets/i18n/ru.json');
      return Observable.of(ru);
    }
    let en = readJSON('assets/i18n/en.json');
    return Observable.of(en);
  }
}
  1. readJSON function (file read-json.js):
var readJSON = function (url) {
  url = readJSON.base + url;

  var xhr = new XMLHttpRequest();
  var json = null;

  xhr.open("GET", url, false);

  xhr.onload = function (e) {
    if (xhr.status === 200) {
      json = JSON.parse(xhr.responseText);
    }

    else {
      console.error('readJSON', url, xhr.statusText);
    }
  };

  xhr.onerror = function (e) {
    console.error('readJSON', url, xhr.statusText);
  };

  xhr.send(null);
  return json;
};

readJSON.base = '';

try {
  if (exports) {
    exports.readJSON = readJSON;
  }
}

catch (error) {
  //exports not available so not loaded by require
}
  1. Make appropriate changes in karma.conf.js (include file with readJSON function and *.json files with translations):
files: [
      './src/assets/scripts/read-json.js',
      {pattern: './src/test.ts', watched: false},
      {pattern: './src/assets/i18n/*.json', included: false}
    ]
  1. Inside of descibe declare a service:

let translateService: TranslateService;

and inject it before each test:

beforeEach(inject([TranslateService], (service) => {
    translateService = service;
    translateService.use('en');
  }));

this forces TranslateService to load translations and also you can change language in your test.

I hope it will be useful for someone. Good luck!

All 19 comments

Did you call .use() somewhere in your testing app? (like in a component that's you're testing)
if not then that's why it's not loading the json

@ocombe Yes, I do this in the first component but not in the same component testing because it will be redundance code when I call other component use ng2-translate , also I think if user change language in the first page and change the route to another page (component) the language will be changed or it's not logical... I search for another solution when the testing component work with here own ng2-translate just for testing...I hope you interstrand me.

were you able to resolve the issue ? if so, please explain.

@mmarimuthu sorry but problem not resolved 馃槩 ... If you have any other solution tell me 馃槂

Please let me know if anyone able to resolve the problem.

Hello guys. Perhaps it is too late and not what you really want, but I had a similar problem. I needed to test a component that uses translation, but the TranslateService is used in a parent component. To test my component I had to substitute TranslateHttpLoader by my own like the following:

  1. Inside TestBed.configureTestingModule:
imports: [
        TranslateModule.forRoot({
          loader: {
            provide: TranslateLoader,
            useClass: TranslateCustomLoader
          }
        })
      ]
  1. TranslateCustomLoader itself:
import {TranslateLoader} from "@ngx-translate/core";
import {Observable} from "rxjs";

declare let readJSON: any;

export class TranslateCustomLoader implements TranslateLoader {
  getTranslation(lang: string): Observable<any> {
    if (lang=="ru"){
      let ru = readJSON('assets/i18n/ru.json');
      return Observable.of(ru);
    }
    let en = readJSON('assets/i18n/en.json');
    return Observable.of(en);
  }
}
  1. readJSON function (file read-json.js):
var readJSON = function (url) {
  url = readJSON.base + url;

  var xhr = new XMLHttpRequest();
  var json = null;

  xhr.open("GET", url, false);

  xhr.onload = function (e) {
    if (xhr.status === 200) {
      json = JSON.parse(xhr.responseText);
    }

    else {
      console.error('readJSON', url, xhr.statusText);
    }
  };

  xhr.onerror = function (e) {
    console.error('readJSON', url, xhr.statusText);
  };

  xhr.send(null);
  return json;
};

readJSON.base = '';

try {
  if (exports) {
    exports.readJSON = readJSON;
  }
}

catch (error) {
  //exports not available so not loaded by require
}
  1. Make appropriate changes in karma.conf.js (include file with readJSON function and *.json files with translations):
files: [
      './src/assets/scripts/read-json.js',
      {pattern: './src/test.ts', watched: false},
      {pattern: './src/assets/i18n/*.json', included: false}
    ]
  1. Inside of descibe declare a service:

let translateService: TranslateService;

and inject it before each test:

beforeEach(inject([TranslateService], (service) => {
    translateService = service;
    translateService.use('en');
  }));

this forces TranslateService to load translations and also you can change language in your test.

I hope it will be useful for someone. Good luck!

@IevhenIkonnykov You are a savior. The solution worked for me!!
I am getting one Warning while executing the unit test cases -

WARN [watcher]: All files matched by "F:\WS\poc\src\assets/**" were excluded or matched by prior matchers.

How to supress that?

@linux-nerd It seems like you have different matchers that cover the same files. I am not sure, but perhaps it would be right to check you matchers or make them more precise. To be honest I do not have a real solution for your problem. When you fix it would be great to share your solution. Actually I do not have anything like that in my tests. Good luck.

Just run into testing of the component which uses ngx-translate. I don't think it matters for unit tests to have correct translation displayed in the component, you're usually testing functionality, not translation itself (which makes no sense almost and can lead to broken tests over time when translation changes). So using only bare TranslateModule.forRoot() in TestBed imports is pretty fine imho.

@IevhenIkonnykov thanks for your solution, it works. By the way, just be careful the path of the file.

export class TranslateCustomLoader implements TranslateLoader {
  getTranslation(lang: string): Observable<any> {
    if (lang === 'zh-CN') {
      const zhCN = readJSON('../../assets/i18n/zh-CN.json');
      return Observable.of(zhCN);
    }
    const en = readJSON('../../assets/i18n/EN.json');
    return Observable.of(en);
  }
}

this path should be the relative path to file with the class defined.

Just checked my tests in Angular 5.2.6 and they work as before. Perhaps there is another problem that you experience.

Hello, I'm closing this issue because it's too old.
If you have a similar problem with recent version of the library, please open a new issue.

You can find an example of unit test with this lib here: https://github.com/ngx-translate/example/blob/master/src/app/app.component.spec.ts

I'm accepting PRs to add more complex tests.

@ocombe

While writing unit test case for translate, Even though we are able to test multi-lingual support, still branch completion is not 100%, it lagging on browser language get call negative case.

Please find the screenshot attached.
image

We tried the spec available in the example provided, it too has not covered the branch
https://github.com/ngx-translate/example/blob/master/src/app/app.component.spec.ts

We also tried to send mock data using spyon
spyOn(translate, 'getBrowserLang').and.returnValue('de');

Can anybody help us here!!!!

This case is only happening in some old versions of IE, it should never occur in a normal scenario.
You know that you don't need 100% coverage, right?
But if you really need it, then you could set window.navigator.languages, window.navigator.language, window.navigator.browserLanguage AND window.navigator.userLanguage to null

@ocombe
Currently we are in start of the project, thus we are trying to cover as much as possible from every corner.

We are working with Google Chrome Version 80.0, still facing the issue.

We tried to change the browser language via window.navigator but as languages is read-only it not allowing to reset it.

Please find the attached screenshot for the ref.
image

you need to do (window as any).navigator.languages = null;

@ocombe
Even though we are able to change it, but karma-jasmine is bit smarter. :-;

image

Well too bad then...
But I don't understand why spyOn(translate, 'getBrowserLang').and.returnValue('de'); doesn't work

@ocombe

Got a workaround to make branch cover uptill 100%.

Raised PR for the same: Pull Request

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rbaumi picture rbaumi  路  4Comments

guysan picture guysan  路  4Comments

ryanki1 picture ryanki1  路  4Comments

madoublet picture madoublet  路  3Comments

pndewit picture pndewit  路  3Comments