133 lines
		
	
	
	
		
			5 KiB
			
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			133 lines
		
	
	
	
		
			5 KiB
			
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|   | // Copyright 2021 Signal Messenger, LLC
 | ||
|  | // SPDX-License-Identifier: AGPL-3.0-only
 | ||
|  | 
 | ||
|  | import { assert } from 'chai'; | ||
|  | import * as moment from 'moment'; | ||
|  | import { setup as setupI18n } from '../../../js/modules/i18n'; | ||
|  | import enMessages from '../../../_locales/en/messages.json'; | ||
|  | import esMessages from '../../../_locales/es/messages.json'; | ||
|  | import nbMessages from '../../../_locales/nb/messages.json'; | ||
|  | import nnMessages from '../../../_locales/nn/messages.json'; | ||
|  | import ptBrMessages from '../../../_locales/pt_BR/messages.json'; | ||
|  | import zhCnMessages from '../../../_locales/zh_CN/messages.json'; | ||
|  | 
 | ||
|  | import * as expirationTimer from '../../util/expirationTimer'; | ||
|  | 
 | ||
|  | describe('expiration timer utilities', () => { | ||
|  |   const i18n = setupI18n('en', enMessages); | ||
|  | 
 | ||
|  |   describe('DEFAULT_DURATIONS_IN_SECONDS', () => { | ||
|  |     const { DEFAULT_DURATIONS_IN_SECONDS } = expirationTimer; | ||
|  | 
 | ||
|  |     it('includes at least 3 durations', () => { | ||
|  |       assert.isAtLeast(DEFAULT_DURATIONS_IN_SECONDS.length, 3); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('includes 1 hour as seconds', () => { | ||
|  |       const oneHour = moment.duration(1, 'hour').asSeconds(); | ||
|  |       assert.include(DEFAULT_DURATIONS_IN_SECONDS, oneHour); | ||
|  |     }); | ||
|  |   }); | ||
|  | 
 | ||
|  |   describe('format', () => { | ||
|  |     const { format } = expirationTimer; | ||
|  | 
 | ||
|  |     it('handles an undefined duration', () => { | ||
|  |       assert.strictEqual(format(i18n, undefined), 'off'); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('handles no duration', () => { | ||
|  |       assert.strictEqual(format(i18n, 0), 'off'); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('formats durations', () => { | ||
|  |       new Map<number, string>([ | ||
|  |         [1, '1 second'], | ||
|  |         [2, '2 seconds'], | ||
|  |         [30, '30 seconds'], | ||
|  |         [59, '59 seconds'], | ||
|  |         [moment.duration(1, 'm').asSeconds(), '1 minute'], | ||
|  |         [moment.duration(5, 'm').asSeconds(), '5 minutes'], | ||
|  |         [moment.duration(1, 'h').asSeconds(), '1 hour'], | ||
|  |         [moment.duration(8, 'h').asSeconds(), '8 hours'], | ||
|  |         [moment.duration(1, 'd').asSeconds(), '1 day'], | ||
|  |         [moment.duration(6, 'd').asSeconds(), '6 days'], | ||
|  |         [moment.duration(8, 'd').asSeconds(), '8 days'], | ||
|  |         [moment.duration(30, 'd').asSeconds(), '30 days'], | ||
|  |         [moment.duration(365, 'd').asSeconds(), '365 days'], | ||
|  |         [moment.duration(1, 'w').asSeconds(), '1 week'], | ||
|  |         [moment.duration(3, 'w').asSeconds(), '3 weeks'], | ||
|  |         [moment.duration(52, 'w').asSeconds(), '52 weeks'], | ||
|  |       ]).forEach((expected, input) => { | ||
|  |         assert.strictEqual(format(i18n, input), expected); | ||
|  |       }); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('formats other languages successfully', () => { | ||
|  |       const esI18n = setupI18n('es', esMessages); | ||
|  |       assert.strictEqual(format(esI18n, 120), '2 minutos'); | ||
|  | 
 | ||
|  |       const zhCnI18n = setupI18n('zh_CN', zhCnMessages); | ||
|  |       assert.strictEqual(format(zhCnI18n, 60), '1 分钟'); | ||
|  | 
 | ||
|  |       // The underlying library supports the "pt" locale, not the "pt_BR" locale. That's
 | ||
|  |       //   what we're testing here.
 | ||
|  |       const ptBrI18n = setupI18n('pt_BR', ptBrMessages); | ||
|  |       assert.strictEqual( | ||
|  |         format(ptBrI18n, moment.duration(5, 'days').asSeconds()), | ||
|  |         '5 dias' | ||
|  |       ); | ||
|  | 
 | ||
|  |       // The underlying library supports the Norwegian language, which is a macrolanguage
 | ||
|  |       //   for Bokmål and Nynorsk.
 | ||
|  |       [setupI18n('nb', nbMessages), setupI18n('nn', nnMessages)].forEach( | ||
|  |         norwegianI18n => { | ||
|  |           assert.strictEqual( | ||
|  |             format(norwegianI18n, moment.duration(6, 'hours').asSeconds()), | ||
|  |             '6 timer' | ||
|  |           ); | ||
|  |         } | ||
|  |       ); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('falls back to English if the locale is not supported', () => { | ||
|  |       const badI18n = setupI18n('bogus', {}); | ||
|  |       assert.strictEqual(format(badI18n, 120), '2 minutes'); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('handles a "mix" of units gracefully', () => { | ||
|  |       // We don't expect there to be a "mix" of units, but we shouldn't choke if a bad
 | ||
|  |       //   client gives us an unexpected timestamp.
 | ||
|  |       const mix = moment | ||
|  |         .duration(6, 'days') | ||
|  |         .add(moment.duration(2, 'hours')) | ||
|  |         .asSeconds(); | ||
|  |       assert.strictEqual(format(i18n, mix), '6 days, 2 hours'); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('handles negative numbers gracefully', () => { | ||
|  |       // The proto helps enforce non-negative numbers by specifying a u32, but because
 | ||
|  |       //   JavaScript lacks such a type, we test it here.
 | ||
|  |       assert.strictEqual(format(i18n, -1), '1 second'); | ||
|  |       assert.strictEqual(format(i18n, -120), '2 minutes'); | ||
|  |       assert.strictEqual(format(i18n, -0), 'off'); | ||
|  |     }); | ||
|  | 
 | ||
|  |     it('handles fractional seconds gracefully', () => { | ||
|  |       // The proto helps enforce integer numbers by specifying a u32, but this function
 | ||
|  |       //   shouldn't choke if bad data is passed somehow.
 | ||
|  |       assert.strictEqual(format(i18n, 4.2), '4 seconds'); | ||
|  |       assert.strictEqual(format(i18n, 4.8), '4 seconds'); | ||
|  |       assert.strictEqual(format(i18n, 0.2), '1 second'); | ||
|  |       assert.strictEqual(format(i18n, 0.8), '1 second'); | ||
|  | 
 | ||
|  |       // If multiple things go wrong and we pass a fractional negative number, we still
 | ||
|  |       //   shouldn't explode.
 | ||
|  |       assert.strictEqual(format(i18n, -4.2), '4 seconds'); | ||
|  |       assert.strictEqual(format(i18n, -4.8), '4 seconds'); | ||
|  |       assert.strictEqual(format(i18n, -0.2), '1 second'); | ||
|  |       assert.strictEqual(format(i18n, -0.8), '1 second'); | ||
|  |     }); | ||
|  |   }); | ||
|  | }); |