import { BadiDate } from '../src/badiDate'; import { ayyamiHaLengths, UHJListDates } from './testData'; import * as luxon from 'luxon'; import { badiDateSettings } from '../src/localBadiDate'; import { HolyDay } from '../src/types'; describe('Dates for Naw-Rúz and the Twin Holy Days should agree with the UHJ List 172-221', () => { for (let i = 0; i < 50; i++) { it(`should produce the correct dates for ${172 + i} B.E.`, () => { const nawRuz = new BadiDate({ year: i + 172, holyDayNumber: 1 }); const birthOfTheBab = new BadiDate({ year: i + 172, holyDayNumber: 8 }); const birthOfBahaullah = new BadiDate({ year: i + 172, holyDayNumber: 9 }); expect(nawRuz.gregorianDate.toFormat('yyyy-MM-dd')).toEqual(UHJListDates[i][0]); expect([birthOfTheBab.month, birthOfTheBab.day]) .toEqual((UHJListDates[i][2] as number[]).slice(0, 2)); expect([birthOfBahaullah.month, birthOfBahaullah.day]) .toEqual((UHJListDates[i][2] as number[]).slice(2, 4)); }); } }); describe('BadiDate conversions', () => { for (let i = 0; i < 1000; i++) { const dayOfYear = Math.floor((Math.random() * 365) + 1); const year = Math.floor((Math.random() * 506) + 1845); const initDate = luxon.DateTime.fromObject({ year, ordinal: dayOfYear, zone: 'UTC' }); it(`should be stable when re-creating with diff. constructors: ${initDate.toFormat('yyyy-MM-dd')}`, () => { const badiDate1 = new BadiDate(initDate); const badiDate2 = new BadiDate({ year: badiDate1.year, month: badiDate1.month, day: badiDate1.day }); const badiDate3 = new BadiDate(badiDate2.gregorianDate.toJSDate()); const badiDate4 = new BadiDate(badiDate3.gregorianDate); expect(badiDate4.isValid).toEqual(true); expect(badiDate4.gregorianDate.toISO()).toEqual(initDate.toISO()); }); } }); it('the date should bubble up if set to 5 Ayyám-i-Há for year with only 4', () => { const badiDate = new BadiDate({ year: 173, month: 20, day: 5 }); expect(badiDate.month).toEqual(19); expect(badiDate.day).toEqual(1); }); describe('the date component getters', () => { for (let badiYear = 1; badiYear < 508; badiYear++) { const badiMonth = Math.floor((Math.random() * 19) + 1); const badiDay = Math.floor((Math.random() * 19) + 1); const badiDate = new BadiDate({ year: badiYear, month: badiMonth, day: badiDay }); it(`should return the correct day for [${badiYear}, ${badiMonth}, ${badiDay}]`, () => { expect(badiDate.day).toEqual(badiDay); }); it(`should return the correct month for [${badiYear}, ${badiMonth}, ${badiDay}]`, () => { expect(badiDate.month).toEqual(badiMonth); }); it(`should return the correct year for [${badiYear}, ${badiMonth}, ${badiDay}]`, () => { expect(badiDate.year).toEqual(badiYear); }); it(`should return the correct year in Vahid for [${badiYear}, ${badiMonth}, ${badiDay}]`, () => { expect(badiDate.yearInVahid).toEqual(((badiYear - 1) % 19) + 1); }); it(`should return the correct Vahid for [${badiYear}, ${badiMonth}, ${badiDay}]`, () => { expect(badiDate.vahid).toEqual((Math.floor((badiYear - 1) / 19) % 19) + 1); }); it(`should return the correct Kull-i-Shay for [${badiYear}, ${badiMonth}, ${badiDay}]`, () => { expect(badiDate.kullIShay).toEqual((badiYear < 362) ? 1 : 2); }); it(`should return the correct Ayyam-i-Há length for [${badiYear}, ${badiMonth}, ${badiDay}]`, () => { expect(badiDate.ayyamiHaLength).toEqual(ayyamiHaLengths[badiYear]); }); it(`should return the correct weekday for [${badiYear}, ${badiMonth}, ${badiDay}]`, () => { expect(badiDate.weekday).toEqual((badiDate.gregorianDate.weekday + 1) % 7 + 1); }); } }); describe('`equals`', () => { it('should compare dates', () => { const invalidBadiDate1 = new BadiDate('someString' as any); const invalidBadiDate2 = new BadiDate('someString' as any); const validBadiDate1 = new BadiDate({ year: 172, holyDayNumber: 10 }); const validBadiDate2 = new BadiDate({ year: 172, holyDayNumber: 10 }); const validBadiDate3 = new BadiDate({ year: 172, holyDayNumber: 11 }); const validBadiDate4 = new BadiDate({ year: 173, holyDayNumber: 10 }); const validBadiDate5 = new BadiDate({ year: 173, holyDayNumber: 10 }); expect(invalidBadiDate1.equals(invalidBadiDate2)).toEqual(false); expect(validBadiDate1.equals(invalidBadiDate2)).toEqual(false); expect(validBadiDate1.equals(validBadiDate2)).toEqual(true); expect(validBadiDate1.equals(validBadiDate3)).toEqual(false); expect(validBadiDate4.equals(validBadiDate5)).toEqual(true); }); }); describe('Holy Days', () => { afterEach(() => { badiDateSettings({ defaultLanguage: 'en' }); }); const holyDays = [ { date: { year: 172, holyDayNumber: HolyDay.NawRuz }, expectedOutput: 'Naw-Rúz', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.FirstRidvan }, expectedOutput: 'First day of Riḍván', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.NinthRidvan }, expectedOutput: 'Ninth day of Riḍván', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.TwelfthRidvan }, expectedOutput: 'Twelfth day of Riḍván', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.DeclarationOfTheBab }, expectedOutput: 'Declaration of the Báb', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.AscensionOfBahaullah }, expectedOutput: 'Ascension of Bahá’u’lláh', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.MartyrdomOfTheBab }, expectedOutput: 'Martyrdom of the Báb', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.BirthOfTheBab }, expectedOutput: 'Birth of the Báb', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.BirthOfBahaullah }, expectedOutput: 'Birth of Bahá’u’lláh', workSuspended: true, }, { date: { year: 172, holyDayNumber: HolyDay.DayOfTheCovenant }, expectedOutput: 'Day of the Covenant', workSuspended: false, }, { date: { year: 172, holyDayNumber: HolyDay.AscensionOfAbdulBaha }, expectedOutput: 'Ascension of ‘Abdu’l-Bahá', workSuspended: false, }, { date: { year: 172, month: 1, day: 2 }, expectedOutput: '', workSuspended: undefined, }, ]; holyDays.forEach(({ date, expectedOutput }) => { it('should output Holy Days correctly', () => { const badiDate = new BadiDate(date); expect(badiDate.holyDay()).toEqual(expectedOutput); }); }); holyDays.forEach(({ date, workSuspended }) => { it('should get work suspended info for Holy Days or not correctly', () => { const badiDate = new BadiDate(date); expect(badiDate.workSuspended).toEqual(workSuspended); }); }); it('should be shown in the default language', () => { badiDateSettings({ defaultLanguage: 'es' }); const badiDate = new BadiDate({ year: 172, holyDayNumber: 10 }); expect(badiDate.holyDay()).toEqual('Día de la Alianza'); }); it('should be shown in the selected language', () => { const badiDate = new BadiDate({ year: 172, holyDayNumber: 10 }); expect(badiDate.holyDay('fr')).toEqual('Jour de l’Alliance'); }); it('should fall back', () => { const badiDate = new BadiDate({ year: 172, holyDayNumber: 10 }); expect(badiDate.holyDay('xyz')).toEqual('Day of the Covenant'); }); }); describe('Invalid input', () => { const invalidInputDates = [ 'someString', luxon.DateTime.fromISO('2360-01-01', { zone: 'UTC' }), { year: 508, month: 10, day: 10 }, { year: 172, month: 20, day: 6 }, { year: 172, month: 10, day: 25 }, { year: 172, holyDayNumber: 12 }, ]; invalidInputDates.forEach(inputDate => { it('should produce an invalid Badí date', () => { const badiDate = new BadiDate(inputDate as any); expect(badiDate.isValid).toEqual(false); expect(badiDate.year).toBeNaN(); expect(badiDate.month).toBeNaN(); expect(badiDate.day).toBeNaN(); expect(badiDate.ayyamiHaLength).toBeNaN(); expect(badiDate.gregorianDate.isValid).toEqual(false); expect(badiDate.invalidReason).toBeDefined(); expect(badiDate.format()).toEqual('Not a valid Badí‘ date'); }); }); }); describe('the string formatter', () => { afterAll(() => { badiDateSettings({ underlineFormat: 'css' }); }); it('should use a default format if no format string is defined', () => { const badiDate = new BadiDate({ year: 172, month: 1, day: 1 }); expect(badiDate.format()).toEqual('1 Bahá (Splendour) 172 B.E.'); }); it('should parse all tokens in the format string', () => { badiDateSettings({ underlineFormat: 'diacritic' }); const badiDate = new BadiDate({ year: 50, month: 1, day: 16 }); const formatStr = 'd dd D DD DDL DD+ m mm M MM MML MM+ y yy ww W WW WWL yv yyv YV v vv Va k kk KiS BE BC'; const expectedResult = '16 16 S̲h̲a S̲h̲araf Honour S̲h̲araf (Honour) 1 01 Bah Bahá Splendour ' + 'Bahá (Splendour) 50 050 ‘Id ‘Idá ‘Idál Justice 12 12 Javáb 3 03 Váḥid 1 01 Kull-i-S̲h̲ay’ B.E. ' + 'Badí‘ Calendar'; expect(badiDate.format(formatStr)).toEqual(expectedResult); }); it('should include non-tokens as is in the output', () => { const badiDate = new BadiDate({ year: 172, month: 1, day: 1 }); expect(badiDate.format('d XYZMML yy BE')).toEqual('1 XYZSplendour 172 B.E.'); }); it('should include everything in curly braces as is in the output', () => { const badiDate = new BadiDate({ year: 172, month: 1, day: 1 }); expect(badiDate.format('d { MML M}M yy BE')).toEqual('1 MML MBah 172 B.E.'); }); const croppedFormatData = [ { month: 4, croppedCss: '‘Aẓa', croppedUTag: '‘Aẓa', croppedDiacritic: '‘Aẓa' }, { month: 10, croppedCss: '‘Izz', croppedUTag: '‘Izz', croppedDiacritic: '‘Izz' }, { month: 11, croppedCss: 'Mas', croppedUTag: 'Mas', croppedDiacritic: 'Mas̲', }, { month: 12, croppedCss: '‘Ilm', croppedUTag: '‘Ilm', croppedDiacritic: '‘Ilm' }, { month: 16, croppedCss: 'Sha', croppedUTag: 'Sha', croppedDiacritic: 'S̲h̲a', }, { month: 19, croppedCss: '‘Alá’', croppedUTag: '‘Alá’', croppedDiacritic: '‘Alá’' }, ]; croppedFormatData.forEach(({ month, croppedCss }) => { it('should crop the output appropriately with css underlining', () => { badiDateSettings({ underlineFormat: 'css' }); const badiDate = new BadiDate({ year: 172, month, day: 1 }); expect(badiDate.format('M')).toEqual(croppedCss); }); }); croppedFormatData.forEach(({ month, croppedUTag }) => { it('should crop the output appropriately with u-tag underlining', () => { badiDateSettings({ underlineFormat: 'u' }); const badiDate = new BadiDate({ year: 172, month, day: 1 }); expect(badiDate.format('M')).toEqual(croppedUTag); }); }); croppedFormatData.forEach(({ month, croppedDiacritic }) => { it('should crop the output appropriately with diacritic underlining', () => { badiDateSettings({ underlineFormat: 'diacritic' }); const badiDate = new BadiDate({ year: 172, month, day: 1 }); expect(badiDate.format('M')).toEqual(croppedDiacritic); }); }); it('should omit underlining if underlineFormat is "none"', () => { badiDateSettings({ underlineFormat: 'none' }); const badiDate = new BadiDate({ year: 172, month: 16, day: 1 }); expect(badiDate.format('MM')).toEqual('Sharaf'); }); it('should not change the underlineFormat if new setting is invalid', () => { badiDateSettings({ underlineFormat: 'diacritic' }); badiDateSettings({ underlineFormat: 'invalid' } as any); const badiDate = new BadiDate({ year: 172, month: 16, day: 1 }); expect(badiDate.format('MM')).toEqual('S̲h̲araf'); }); it('should output an error if the formatting string has non-matching braces', () => { const badiDate = new BadiDate({ year: 172, month: 16, day: 1 }); expect(badiDate.format('MM {XYZ')).toEqual('Invalid formatting string.'); }); it('should only render one item each for DD+ and MM+ if both items would be identical', () => { const badiDate = new BadiDate({ year: 172, month: 1, day: 2 }); const expectedOutput = 'الجلال البهاء'; expect(badiDate.format('DD+ MM+', 'ar')).toEqual(expectedOutput); }); it('should render the DD+ and MM+ tokens appropriately in rtl languages', () => { const badiDate = new BadiDate({ year: 172, month: 1, day: 2 }); const expectedOutput = 'الجلال (جلال) البهاء (بهاء)'; expect(badiDate.format('DD+ MM+', 'fa')).toEqual(expectedOutput); }); it('should render digits as different unicode characters where appropriate', () => { const badiDate = new BadiDate({ year: 172, month: 17, day: 5 }); expect(badiDate.format('dd mm', 'ar')).toEqual('٠٥ ١٧'); }); }); describe('the language selection', () => { afterEach(() => { badiDateSettings({ defaultLanguage: 'en' }); }); const badiDate = new BadiDate({ year: 172, month: 1, day: 2 }); it('should format the date in the given language if passed as parameter', () => { expect(badiDate.format('MML', 'es')).toEqual('Esplendor'); }); it('should format the date in the given language if set as default', () => { badiDateSettings({ defaultLanguage: 'es' }); expect(badiDate.format('MML')).toEqual('Esplendor'); }); it('should fall back to English if given an invalid language code', () => { expect(badiDate.format('MML', 'invalidLanguage')).toEqual('Splendour'); }); it('should keep the current default language if set to an invalid language', () => { badiDateSettings({ defaultLanguage: 'es' }); badiDateSettings({ defaultLanguage: 'invalidLanguage' }); expect(badiDate.format('MML')).toEqual('Esplendor'); }); it('should fall back to the primary language if an unknown extended language subtag is present', () => { expect(badiDate.format('MML', 'fr-ch')).toEqual('Splendeur'); }); it('should fall back to the primary language on a per-token basis', () => { expect(badiDate.format('MML BE', 'en-us')).toEqual('Splendor B.E.'); }); it('should use a fallback if the given key is not present in the locale file', () => { expect(badiDate.format('MM BE', 'sv')).toEqual('Bahá B.E.'); }); });