// Prayer time math tests — reference: AlAdhan API method 21 (Morocco, Fajr 19, Isha 17, school STANDARD) // Casablanca (33.5731, -7.5898) 2026-09-09 reference times: // Fajr 05:40, Sunrise 07:10, Dhuhr 13:33, Asr 17:02, Maghrib 19:50, Isha 21:05 'use strict' const assert = require('assert/strict') const prayer = require('../src/common/prayer.js') // Casablanca is UTC+1 in September 2026; emulate the watch by passing tz offset explicitly. const TZ = 1 const CASA = { lat: 33.5731, lon: -7.5898 } function timesFor(y, m, d) { return prayer.times(new Date(Date.UTC(y, m - 1, d, 12, 0, 0)), CASA.lat, CASA.lon, TZ) } function assertClose(actualMin, refHM, label, tol = 2) { const [rh, rm] = refHM.split(':').map(Number) const ref = rh * 60 + rm const diff = Math.abs(actualMin - ref) assert.ok(diff <= tol, `${label}: got ${prayer.format(actualMin)} (${actualMin}), expected ${refHM} — off by ${diff.toFixed(1)} min`) } let passed = 0 function test(name, fn) { try { fn(); passed++; console.log(' ok -', name) } catch (e) { console.error(' FAIL -', name, '\n ', e.message); process.exitCode = 1 } } console.log('prayer.js tests') test('times match AlAdhan Morocco method for Casablanca 2026-09-09', () => { const t = timesFor(2026, 9, 9) assertClose(t.fajr, '05:40', 'Fajr') assertClose(t.sunrise, '07:10', 'Sunrise') assertClose(t.dhuhr, '13:33', 'Dhuhr') assertClose(t.asr, '17:02', 'Asr') assertClose(t.maghrib, '19:50', 'Maghrib') assertClose(t.isha, '21:05', 'Isha') }) test('times match for a midwinter date 2026-01-15 (AlAdhan cross-check)', () => { // AlAdhan method 21, Casablanca, 15-01-2026: Fajr 07:02, Sunrise 08:35, Dhuhr 13:45, Asr 16:26, Maghrib 18:50, Isha 20:08 const t = timesFor(2026, 1, 15) assertClose(t.fajr, '07:02', 'Fajr') assertClose(t.sunrise, '08:35', 'Sunrise') assertClose(t.dhuhr, '13:45', 'Dhuhr') assertClose(t.asr, '16:26', 'Asr') assertClose(t.maghrib, '18:50', 'Maghrib') assertClose(t.isha, '20:08', 'Isha') }) test('times match for a summer date 2026-07-01 (AlAdhan cross-check)', () => { // AlAdhan method 21, Casablanca, 01-07-2026: Fajr 04:34, Sunrise 06:24, Dhuhr 13:39, Asr 17:19, Maghrib 20:50, Isha 22:21 const t = timesFor(2026, 7, 1) assertClose(t.fajr, '04:34', 'Fajr') assertClose(t.sunrise, '06:24', 'Sunrise') assertClose(t.dhuhr, '13:39', 'Dhuhr') assertClose(t.asr, '17:19', 'Asr') assertClose(t.maghrib, '20:50', 'Maghrib') assertClose(t.isha, '22:21', 'Isha') }) test('format pads minutes', () => { assert.equal(prayer.format(9 * 60 + 5), '09:05') assert.equal(prayer.format(13 * 60 + 33), '13:33') }) test('format wraps past midnight (next-day fajr)', () => { // 25h15 -> 01:15 next day assert.equal(prayer.format(25 * 60 + 15), '01:15') }) test('nextPrayer: before fajr -> next is fajr', () => { const t = timesFor(2026, 9, 9) const n = prayer.nextPrayer(t, 4 * 60) assert.equal(n.key, 'fajr') assert.ok(n.minutesLeft > 0 && n.minutesLeft < 1440, 'minutesLeft ' + n.minutesLeft) // 04:00 -> fajr 05:40 ≈ 100 min assert.ok(Math.abs(n.minutesLeft - 100) <= 2, 'minutesLeft ' + n.minutesLeft) }) test('nextPrayer: between dhuhr and asr -> next is asr', () => { const t = timesFor(2026, 9, 9) const n = prayer.nextPrayer(t, 14 * 60) assert.equal(n.key, 'asr') assert.ok(n.current === 'dhuhr') }) test('nextPrayer: after isha -> wraps to fajr (+1d) and minutesLeft crosses midnight', () => { const t = timesFor(2026, 9, 9) const n = prayer.nextPrayer(t, 23 * 60) assert.equal(n.key, 'fajr') assert.ok(n.nextDay === true, 'nextDay flag') // 23:00 -> fajr 05:40 next day = 6h40 = 400 min assert.ok(Math.abs(n.minutesLeft - 400) <= 2, 'minutesLeft ' + n.minutesLeft) }) test('nextPrayer: exactly at dhuhr time -> next is asr (current dhuhr)', () => { const t = timesFor(2026, 9, 9) const n = prayer.nextPrayer(t, Math.round(t.dhuhr)) assert.equal(n.key, 'asr') }) test('minutesLeft is exact', () => { const t = timesFor(2026, 9, 9) const n = prayer.nextPrayer(t, 17 * 60) // 17:00 -> asr 17:02 = 2 min assert.ok(Math.abs(n.minutesLeft - 2) <= 1, 'minutesLeft ' + n.minutesLeft) }) console.log(process.exitCode ? 'FAILED' : 'ALL PASSED (' + passed + ')')