1 | import {fakeAsync, TestBed, tick} from "@angular/core/testing";
|
2 | import {Observable, of, timer, zip, defer} from "rxjs";
|
3 | import {mapTo, take, toArray, first} from 'rxjs/operators';
|
4 | import {LangChangeEvent, TranslateLoader, TranslateModule, TranslateService, TranslationChangeEvent} from '../public-api';
|
5 |
|
6 | let translations: any = {"TEST": "This is a test"};
|
7 |
|
8 | class FakeLoader implements TranslateLoader {
|
9 | getTranslation(lang: string): Observable<any> {
|
10 | return of(translations);
|
11 | }
|
12 | }
|
13 |
|
14 | describe('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 |
|
43 | translate.get('TEST').subscribe((res: string) => {
|
44 | expect(res).toEqual('This is a test');
|
45 | });
|
46 |
|
47 |
|
48 |
|
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 |
|
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 |
|
414 | translate.get('TEST').subscribe((res: string) => {
|
415 | expect(res).toEqual(translations['TEST']);
|
416 |
|
417 |
|
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');
|
424 | done();
|
425 | });
|
426 | });
|
427 | });
|
428 |
|
429 | it('should be able to reload a lang', () => {
|
430 | translations = {};
|
431 | translate.use('en');
|
432 |
|
433 |
|
434 | translate.get('TEST').subscribe((res: string) => {
|
435 | expect(res).toEqual('TEST');
|
436 |
|
437 | translations = {"TEST": "This is a test 2"};
|
438 |
|
439 |
|
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 |
|
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 | });
|