UNPKG

18 kBPlain TextView Raw
1import {fakeAsync, TestBed, tick} from "@angular/core/testing";
2import {Observable, of, timer, zip, defer} from "rxjs";
3import {mapTo, take, toArray, first} from 'rxjs/operators';
4import {LangChangeEvent, TranslateLoader, TranslateModule, TranslateService, TranslationChangeEvent} from '../public-api';
5
6let translations: any = {"TEST": "This is a test"};
7
8class FakeLoader implements TranslateLoader {
9 getTranslation(lang: string): Observable<any> {
10 return of(translations);
11 }
12}
13
14describe('TranslateService', () => {
15 let translate: TranslateService;
16
17 beforeEach(() => {
18 TestBed.configureTestingModule({
19 imports: [
20 TranslateModule.forRoot({
21 loader: {provide: TranslateLoader, useClass: FakeLoader}
22 })
23 ]
24 });
25 translate = TestBed.inject(TranslateService);
26 });
27
28 afterEach(() => {
29 translations = {"TEST": "This is a test"};
30 });
31
32 it('is defined', () => {
33 expect(TranslateService).toBeDefined();
34 expect(translate).toBeDefined();
35 expect(translate instanceof TranslateService).toBeTruthy();
36 });
37
38 it('should be able to get translations', () => {
39 translations = {"TEST": "This is a test", "TEST2": "This is another test"};
40 translate.use('en');
41
42 // this will request the translation from the backend because we use a static files loader for TranslateService
43 translate.get('TEST').subscribe((res: string) => {
44 expect(res).toEqual('This is a test');
45 });
46
47
48 // this will request the translation from downloaded translations without making a request to the backend
49 translate.get('TEST2').subscribe((res: string) => {
50 expect(res).toEqual('This is another test');
51 });
52 });
53
54 it('should be able to get an array translations', () => {
55 translations = {"TEST": "This is a test", "TEST2": "This is another test2"};
56 translate.use('en');
57
58 // this will request the translation from the backend because we use a static files loader for TranslateService
59 translate.get(['TEST', 'TEST2']).subscribe((res: string) => {
60 expect(res).toEqual(translations);
61 });
62 });
63
64 it("should fallback to the default language", () => {
65 translations = {};
66 translate.use('fr');
67
68 translate.get('TEST').subscribe((res: string) => {
69 expect(res).toEqual('TEST');
70
71 translate.setDefaultLang('nl');
72 translate.setTranslation('nl', {"TEST": "Dit is een test"});
73
74 translate.get('TEST').subscribe((res2: string) => {
75 expect(res2).toEqual('Dit is een test');
76 expect(translate.getDefaultLang()).toEqual('nl');
77 });
78 });
79 });
80
81 it("should use the default language by default", () => {
82 translate.setDefaultLang('nl');
83 translate.setTranslation('nl', {"TEST": "Dit is een test"});
84
85 translate.get('TEST').subscribe((res: string) => {
86 expect(res).toEqual('Dit is een test');
87 });
88 });
89
90 it("should return the key when it doesn't find a translation", () => {
91 translate.use('en');
92
93 translate.get('TEST2').subscribe((res: string) => {
94 expect(res).toEqual('TEST2');
95 });
96 });
97
98 it("should return the key when you haven't defined any translation", () => {
99 translate.get('TEST').subscribe((res: string) => {
100 expect(res).toEqual('TEST');
101 });
102 });
103
104 it('should return an empty value', () => {
105 translate.setDefaultLang('en');
106 translate.setTranslation('en', {"TEST": ""});
107
108 translate.get('TEST').subscribe((res: string) => {
109 expect(res).toEqual('');
110 });
111 });
112
113 it('should be able to get translations with params', () => {
114 translations = {"TEST": "This is a test {{param}}"};
115 translate.use('en');
116
117 translate.get('TEST', {param: 'with param'}).subscribe((res: string) => {
118 expect(res).toEqual('This is a test with param');
119 });
120
121 });
122
123 it('should be able to get translations with nested params', () => {
124 translations = {"TEST": "This is a test {{param.value}}"};
125 translate.use('en');
126
127 translate.get('TEST', {param: {value: 'with param'}}).subscribe((res: string) => {
128 expect(res).toEqual('This is a test with param');
129 });
130
131 });
132
133 it('should throw if you forget the key', () => {
134 translate.use('en');
135
136 expect(() => {
137 translate.get(undefined as any);
138 }).toThrowError('Parameter "key" required');
139
140 expect(() => {
141 translate.get('');
142 }).toThrowError('Parameter "key" required');
143
144 expect(() => {
145 translate.get(null as any);
146 }).toThrowError('Parameter "key" required');
147
148 expect(() => {
149 translate.instant(undefined as any);
150 }).toThrowError('Parameter "key" required');
151 });
152
153 it('should be able to get translations with nested keys', () => {
154 translations = {"TEST": {"TEST": "This is a test"}, "TEST2": {"TEST2": {"TEST2": "This is another test"}}};
155 translate.use('en');
156
157 translate.get('TEST.TEST').subscribe((res: string) => {
158 expect(res).toEqual('This is a test');
159 });
160
161
162 translate.get('TEST2.TEST2.TEST2').subscribe((res: string) => {
163 expect(res).toEqual('This is another test');
164 });
165 });
166
167 it("should merge translations if option shouldMerge is true", (done: Function) => {
168 translations = {};
169 translate.setTranslation('en', {"TEST": {"sub1": "value1"}}, true);
170 translate.setTranslation('en', {"TEST": {"sub2": "value2"}}, true);
171 translate.use('en');
172
173 translate.get('TEST').subscribe((res: any) => {
174 expect(res).toEqual({"sub1": "value1", "sub2": "value2"});
175 expect(translations).toEqual({});
176 done();
177 });
178 });
179
180 it("should merge non-valid JSON translations if option shouldMerge is true", () => {
181 translations = {};
182 translate.setTranslation('en', {"TEST": {"sub1": () => "value1"}}, true);
183 translate.setTranslation('en', {"TEST": {"sub2": () => "value2"}}, true);
184 translate.use('en');
185
186 translate.get('TEST.sub1').subscribe((res: string) => {
187 expect(res).toEqual('value1');
188 });
189 translate.get('TEST.sub2').subscribe((res: string) => {
190 expect(res).toEqual('value2');
191 });
192 });
193
194 it("shouldn't call the current loader if you set the translation yourself", (done: Function) => {
195 translations = {};
196 translate.setTranslation('en', {"TEST": "This is a test"});
197 translate.use('en');
198
199 translate.get('TEST').subscribe((res: string) => {
200 expect(res).toEqual('This is a test');
201 expect(translations).toEqual({});
202 done();
203 });
204 });
205
206 it('should be able to get a stream array', (done: Function) => {
207 let tr = {"TEST": "This is a test", "TEST2": "This is a test2"};
208 translate.setTranslation('en', tr);
209 translate.use('en');
210
211 translate.getStreamOnTranslationChange(['TEST', 'TEST2']).subscribe((res: any) => {
212 expect(res).toEqual(tr);
213 done();
214 });
215 });
216
217 it('should initially return the same value for getStreamOnTranslationChange and non-streaming get', (done: Function) => {
218 translations = {"TEST": "This is a test"};
219 translate.use('en');
220
221 zip(translate.getStreamOnTranslationChange('TEST'), translate.get('TEST')).subscribe((value: [string, string]) => {
222 const [streamed, nonStreamed] = value;
223 expect(streamed).toEqual('This is a test');
224 expect(streamed).toEqual(nonStreamed);
225 done();
226 });
227 });
228
229 it('should be able to stream a translation on translation change', (done: Function) => {
230 translations = {"TEST": "This is a test"};
231 translate.use('en');
232
233 translate.getStreamOnTranslationChange('TEST').pipe(take(3), toArray()).subscribe((res: string[]) => {
234 const expected = ['This is a test', 'I changed the test value!', 'I changed it again!'];
235 expect(res).toEqual(expected);
236 done();
237 });
238 translate.setTranslation('en', {"TEST": "I changed the test value!"});
239 translate.setTranslation('en', {"TEST": "I changed it again!"});
240 });
241
242 it('should interpolate the same param into each streamed value when get strean on translation change', (done: Function) => {
243 translations = {"TEST": "This is a test {{param}}"};
244 translate.use('en');
245
246 translate.getStreamOnTranslationChange('TEST', {param: 'with param'}).subscribe((res: string[]) => {
247 const expected = 'This is a test with param';
248 expect(res).toEqual(expected);
249 done();
250 });
251 });
252
253 it('should be able to stream a translation for the current language', (done: Function) => {
254 translations = {"TEST": "This is a test"};
255 translate.use('en');
256
257 translate.stream('TEST').subscribe((res: string) => {
258 expect(res).toEqual('This is a test');
259 done();
260 });
261 });
262
263 it('should be able to stream a translation of an array for the current language', (done: Function) => {
264 let tr = {"TEST": "This is a test", "TEST2": "This is a test2"};
265 translate.setTranslation('en', tr);
266 translate.use('en');
267
268 translate.stream(['TEST', 'TEST2']).subscribe((res: any) => {
269 expect(res).toEqual(tr);
270 done();
271 });
272 });
273
274 it('should initially return the same value for streaming and non-streaming get', (done: Function) => {
275 translations = {"TEST": "This is a test"};
276 translate.use('en');
277
278 zip(translate.stream('TEST'), translate.get('TEST')).subscribe((value: [string, string]) => {
279 const [streamed, nonStreamed] = value;
280 expect(streamed).toEqual('This is a test');
281 expect(streamed).toEqual(nonStreamed);
282 done();
283 });
284 });
285
286 it('should update streaming translations on language change', (done: Function) => {
287 translations = {"TEST": "This is a test"};
288 translate.use('en');
289
290 translate.stream('TEST').pipe(take(3), toArray()).subscribe((res: string[]) => {
291 const expected = ['This is a test', 'Dit is een test', 'This is a test'];
292 expect(res).toEqual(expected);
293 done();
294 });
295
296 translate.setTranslation('nl', {"TEST": "Dit is een test"});
297 translate.use('nl');
298 translate.use('en');
299 });
300
301 it('should update lazy streaming translations on translation change', (done: Function) => {
302 translations = {"TEST": "This is a test"};
303 translate.use('en');
304
305 const translation$ = translate.getStreamOnTranslationChange('TEST');
306
307 translate.setTranslation('en', {"TEST": "This is a test2"});
308
309 translation$.pipe(first()).subscribe((res: string[]) => {
310 const expected = "This is a test2";
311 expect(res).toEqual(expected);
312 done();
313 });
314 });
315
316 it('should update lazy streaming translations on language change', (done: Function) => {
317 translations = {"TEST": "This is a test"};
318 translate.use('en');
319
320 const translation$ = translate.stream('TEST');
321
322 translate.setTranslation('nl', {"TEST": "Dit is een test"});
323 translate.use('nl');
324
325 translation$.pipe(first()).subscribe((res: string[]) => {
326 const expected = 'Dit is een test';
327 expect(res).toEqual(expected);
328 done();
329 });
330 });
331
332 it('should update streaming translations of an array on language change', (done: Function) => {
333 const en = {"TEST": "This is a test", "TEST2": "This is a test2"};
334 const nl = {"TEST": "Dit is een test", "TEST2": "Dit is een test2"};
335 translate.setTranslation('en', en);
336 translate.use('en');
337
338 translate.stream(['TEST', 'TEST2']).pipe(take(3), toArray()).subscribe((res: any[]) => {
339 const expected = [en, nl, en];
340 expect(res).toEqual(expected);
341 done();
342 });
343
344 translate.setTranslation('nl', nl);
345 translate.use('nl');
346 translate.use('en');
347 });
348
349 it('should interpolate the same param into each streamed value', (done: Function) => {
350 translations = {"TEST": "This is a test {{param}}"};
351 translate.use('en');
352
353 translate.stream('TEST', {param: 'with param'}).pipe(take(3), toArray()).subscribe((res: string[]) => {
354 const expected = [
355 'This is a test with param',
356 'Dit is een test with param',
357 'This is a test with param'
358 ];
359 expect(res).toEqual(expected);
360 done();
361 });
362
363 translate.setTranslation('nl', {"TEST": "Dit is een test {{param}}"});
364 translate.use('nl');
365 translate.use('en');
366 });
367
368 it('should be able to get instant translations', () => {
369 translate.setTranslation('en', {"TEST": "This is a test"});
370 translate.use('en');
371
372 expect(translate.instant('TEST')).toEqual('This is a test');
373 });
374
375 it('should be able to get instant translations of an array', () => {
376 let tr = {"TEST": "This is a test", "TEST2": "This is a test2"};
377 translate.setTranslation('en', tr);
378 translate.use('en');
379
380 expect(translate.instant(['TEST', 'TEST2'])).toEqual(tr);
381 });
382
383 it('should return the key if instant translations are not available', () => {
384 translate.setTranslation('en', {"TEST": "This is a test"});
385 translate.use('en');
386
387 expect(translate.instant('TEST2')).toEqual('TEST2');
388 });
389
390 it('should trigger an event when the translation value changes', () => {
391 translate.setTranslation('en', {});
392 translate.onTranslationChange.subscribe((event: TranslationChangeEvent) => {
393 expect(event.translations).toBeDefined();
394 expect(event.translations["TEST"]).toEqual("This is a test");
395 expect(event.lang).toBe('en');
396 });
397 translate.set("TEST", "This is a test", 'en');
398 });
399
400 it('should trigger an event when the lang changes', () => {
401 let tr = {"TEST": "This is a test"};
402 translate.setTranslation('en', tr);
403 translate.onLangChange.subscribe((event: LangChangeEvent) => {
404 expect(event.lang).toBe('en');
405 expect(event.translations).toEqual(tr);
406 });
407 translate.use('en');
408 });
409
410 it('should be able to reset a lang', (done: Function) => {
411 translate.use('en');
412
413 // this will request the translation from the backend because we use a static files loader for TranslateService
414 translate.get('TEST').subscribe((res: string) => {
415 expect(res).toEqual(translations['TEST']);
416
417 // reset the lang as if it was never initiated
418 translate.resetLang('en');
419
420 expect(translate.instant('TEST')).toEqual('TEST');
421
422 translate.get('TEST').subscribe((res2: string) => {
423 expect(res2).toEqual('TEST'); // because the loader is "pristine" as if it was never called
424 done();
425 });
426 });
427 });
428
429 it('should be able to reload a lang', () => {
430 translations = {};
431 translate.use('en');
432
433 // this will request the translation from the loader
434 translate.get('TEST').subscribe((res: string) => {
435 expect(res).toEqual('TEST');
436
437 translations = {"TEST": "This is a test 2"};
438
439 // reset the lang as if it was never initiated
440 translate.reloadLang('en').subscribe((res2: string) => {
441 expect(translate.instant('TEST')).toEqual(translations['TEST']);
442 });
443 });
444 });
445
446 it('should be able to add new langs', () => {
447 translate.addLangs(['pl', 'es']);
448 expect(translate.getLangs()).toEqual(['pl', 'es']);
449 translate.addLangs(['fr']);
450 translate.addLangs(['pl', 'fr']);
451 expect(translate.getLangs()).toEqual(['pl', 'es', 'fr']);
452
453 // this will request the translation from the backend because we use a static files loader for TranslateService
454 translate.use('en').subscribe((res: string) => {
455 expect(translate.getLangs()).toEqual(['pl', 'es', 'fr', 'en']);
456 translate.addLangs(['de']);
457 expect(translate.getLangs()).toEqual(['pl', 'es', 'fr', 'en', 'de']);
458 });
459 });
460
461 it('should be able to get the browserLang', () => {
462 let browserLang = translate.getBrowserLang();
463 expect(browserLang).toBeDefined();
464 expect(typeof browserLang === 'string').toBeTruthy();
465 });
466
467 it('should be able to get the browserCultureLang', () => {
468 let browserCultureLand = translate.getBrowserCultureLang();
469 expect(browserCultureLand).toBeDefined();
470 expect(typeof browserCultureLand === 'string').toBeTruthy();
471 });
472
473 it('should not make duplicate getTranslation calls', fakeAsync(() => {
474 let getTranslationCalls = 0;
475 jest.spyOn(translate.currentLoader, 'getTranslation').mockImplementation(() => {
476 getTranslationCalls += 1;
477 return timer(1000).pipe(mapTo(of(translations)));
478 });
479 translate.use('en');
480 translate.use('en');
481
482 tick(1001);
483
484 expect(getTranslationCalls).toEqual(1);
485 }));
486
487 it('should subscribe to the loader just once', () => {
488 let subscriptions = 0;
489 jest.spyOn(translate.currentLoader, 'getTranslation').mockImplementation(() => {
490 return defer(() => {
491 subscriptions++;
492 return of(translations);
493 });
494 });
495 translate.use('en');
496 translate.use('en');
497 translate.use('en').subscribe();
498 translate.use('en').subscribe();
499
500 expect(subscriptions).toEqual(1);
501 });
502
503 it('should compile translations only once, even when subscribing to translations while translations are loading', fakeAsync(() => {
504 jest.spyOn(translate.currentLoader, 'getTranslation').mockImplementation(() => {
505 return timer(1000).pipe(mapTo(of(translations)));
506 });
507
508 let translateCompilerCallCount = 0;
509 jest.spyOn(translate.compiler, 'compile').mockImplementation((value) => {
510 ++translateCompilerCallCount;
511 return value;
512 });
513 jest.spyOn(translate.compiler, 'compileTranslations').mockImplementation((value) => {
514 ++translateCompilerCallCount;
515 return value;
516 });
517
518 translate.setDefaultLang('en-US');
519 translate.get('TEST1').subscribe();
520 translate.get('TEST2').subscribe();
521 translate.get('TEST3').subscribe();
522 translate.get('TEST4').subscribe();
523
524 tick(1001);
525
526 expect(translateCompilerCallCount).toBe(1);
527 }));
528});