e3e7d2f60b
Run Tests on Branches / Detect Changes (push) Successful in 17s
Run Tests on Branches / Backend Tests (push) Successful in 2m44s
Run Tests on Branches / Frontend Tests (push) Successful in 1m59s
Run Tests on Branches / Frontend Mobile Tests (push) Has been skipped
Run Tests on Branches / Parapharmacy API Tests (push) Has been skipped
Run Tests on Branches / PIP Platform Tests (push) Has been skipped
- Add is_open_now and is_always_open helpers in backend - Add backend endpoint enrichment with is_open and is_24h fields - Add client-side getOpenStatus with 24h, opens-at, opens-tomorrow support - Add open-now filter toggle in PublicView and SearchView - Add pharmacy no-hours fallback display - Add sticky pharmacy controls on scroll - Add admin hours editor with 24h toggle - Add translations (es/ca) for all hour-related strings - Add backend tests for hours logic and pharmacy endpoint - Remove unused backup test files
159 lines
5.5 KiB
JavaScript
159 lines
5.5 KiB
JavaScript
import { isOpenNow, isAlwaysOpen } from '../src/hours.js';
|
|
|
|
const HOURS_24_7 = {
|
|
mon: ['00:00', '24:00'],
|
|
tue: ['00:00', '24:00'],
|
|
wed: ['00:00', '24:00'],
|
|
thu: ['00:00', '24:00'],
|
|
fri: ['00:00', '24:00'],
|
|
sat: ['00:00', '24:00'],
|
|
sun: ['00:00', '24:00'],
|
|
};
|
|
|
|
const HOURS_NORMAL_WEEK = {
|
|
mon: ['09:00', '21:00'],
|
|
tue: ['09:00', '21:00'],
|
|
wed: ['09:00', '21:00'],
|
|
thu: ['09:00', '21:00'],
|
|
fri: ['09:00', '21:00'],
|
|
sat: ['09:00', '14:00'],
|
|
sun: null,
|
|
};
|
|
|
|
const HOURS_ALL_CLOSED = {
|
|
mon: null, tue: null, wed: null, thu: null, fri: null, sat: null, sun: null,
|
|
};
|
|
|
|
const HOURS_MIDNIGHT_CROSS = {
|
|
mon: ['22:00', '02:00'],
|
|
tue: ['09:00', '21:00'],
|
|
wed: null, thu: null, fri: null, sat: null, sun: null,
|
|
};
|
|
|
|
const at = (iso) => new Date(iso);
|
|
|
|
describe('isAlwaysOpen', () => {
|
|
test('all 7 days 00:00-24:00 → true', () => {
|
|
expect(isAlwaysOpen(HOURS_24_7)).toBe(true);
|
|
});
|
|
|
|
test('accepts JSON string', () => {
|
|
expect(isAlwaysOpen(JSON.stringify(HOURS_24_7))).toBe(true);
|
|
});
|
|
|
|
test('one day different → false', () => {
|
|
expect(isAlwaysOpen({ ...HOURS_24_7, sun: ['00:00', '23:59'] })).toBe(false);
|
|
});
|
|
|
|
test('one day null → false', () => {
|
|
expect(isAlwaysOpen({ ...HOURS_24_7, sun: null })).toBe(false);
|
|
});
|
|
|
|
test('null input → false', () => {
|
|
expect(isAlwaysOpen(null)).toBe(false);
|
|
expect(isAlwaysOpen('')).toBe(false);
|
|
expect(isAlwaysOpen(undefined)).toBe(false);
|
|
});
|
|
|
|
test('malformed JSON → false', () => {
|
|
expect(isAlwaysOpen('{not-json')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('isOpenNow', () => {
|
|
test('null/empty input → null', () => {
|
|
expect(isOpenNow(null)).toBeNull();
|
|
expect(isOpenNow('')).toBeNull();
|
|
expect(isOpenNow(undefined)).toBeNull();
|
|
});
|
|
|
|
test('malformed JSON → null', () => {
|
|
expect(isOpenNow('{garbage')).toBeNull();
|
|
});
|
|
|
|
test('24/7 → { isOpen: true, kind: "24h" }', () => {
|
|
const s = isOpenNow(HOURS_24_7, at('2026-07-27T10:00:00'));
|
|
expect(s).toEqual({ isOpen: true, kind: '24h' });
|
|
});
|
|
|
|
test('24/7 at midnight → still 24h', () => {
|
|
const s = isOpenNow(HOURS_24_7, at('2026-07-27T00:00:00'));
|
|
expect(s).toEqual({ isOpen: true, kind: '24h' });
|
|
});
|
|
|
|
test('24/7 (JSON string) → kind 24h', () => {
|
|
const s = isOpenNow(JSON.stringify(HOURS_24_7), at('2026-07-27T15:00:00'));
|
|
expect(s).toEqual({ isOpen: true, kind: '24h' });
|
|
});
|
|
|
|
test('normal weekday at 10:00 (monday) → open, closesAt 21:00', () => {
|
|
// 2026-07-27 is a Monday (verify with date -d)
|
|
const s = isOpenNow(HOURS_NORMAL_WEEK, at('2026-07-27T10:30:00'));
|
|
expect(s).toEqual({ isOpen: true, kind: 'open', closesAt: '21:00' });
|
|
});
|
|
|
|
test('normal weekday at 21:30 (monday) → closed, nextOpen tuesday 09:00', () => {
|
|
const s = isOpenNow(HOURS_NORMAL_WEEK, at('2026-07-27T21:30:00'));
|
|
expect(s.isOpen).toBe(false);
|
|
expect(s.kind).toBe('after-close');
|
|
expect(s.nextOpen).toEqual({ day: 'tue', time: '09:00' });
|
|
});
|
|
|
|
test('normal weekday at 08:30 (monday) → closed before-open, opensAt 09:00', () => {
|
|
const s = isOpenNow(HOURS_NORMAL_WEEK, at('2026-07-27T08:30:00'));
|
|
expect(s).toEqual({ isOpen: false, kind: 'before-open', opensAt: '09:00', nextOpen: null });
|
|
});
|
|
|
|
test('sunday with no hours → closed, nextOpen monday 09:00', () => {
|
|
// 2026-07-26 is a Sunday
|
|
const s = isOpenNow(HOURS_NORMAL_WEEK, at('2026-07-26T10:00:00'));
|
|
expect(s.isOpen).toBe(false);
|
|
expect(s.kind).toBe('closed');
|
|
expect(s.nextOpen).toEqual({ day: 'mon', time: '09:00' });
|
|
});
|
|
|
|
test('all week closed → closed, no nextOpen', () => {
|
|
const s = isOpenNow(HOURS_ALL_CLOSED, at('2026-07-27T10:00:00'));
|
|
expect(s).toEqual({ isOpen: false, kind: 'closed', nextOpen: null });
|
|
});
|
|
|
|
test('midnight-crossing: monday 22:00-02:00, at 23:00 → open', () => {
|
|
const s = isOpenNow(HOURS_MIDNIGHT_CROSS, at('2026-07-27T23:00:00'));
|
|
expect(s.isOpen).toBe(true);
|
|
expect(s.kind).toBe('open');
|
|
expect(s.closesAt).toBe('02:00');
|
|
});
|
|
|
|
test('midnight-crossing: monday 22:00-02:00, at 01:00 → open (yesterday range still active)', () => {
|
|
// Tuesday 01:00 → it's inside monday's 22:00-02:00 range (extended past midnight)
|
|
const s = isOpenNow(HOURS_MIDNIGHT_CROSS, at('2026-07-28T01:00:00'));
|
|
expect(s.isOpen).toBe(true);
|
|
expect(s.kind).toBe('open');
|
|
});
|
|
|
|
test('midnight-crossing: at tuesday 03:00, today opens at 09:00 → before-open', () => {
|
|
// Tuesday 03:00 with monday 22:00-02:00 already finished; today's tue is 09:00-21:00.
|
|
const s = isOpenNow(HOURS_MIDNIGHT_CROSS, at('2026-07-28T03:00:00'));
|
|
expect(s).toEqual({ isOpen: false, kind: 'before-open', opensAt: '09:00', nextOpen: null });
|
|
});
|
|
|
|
test('midnight-crossing: same day before today opens → before-open with today time', () => {
|
|
// HOURS_MIDNIGHT_CROSS: mon 22:00-02:00 (crossing). At monday 10:00, before today's 22:00.
|
|
const s = isOpenNow(HOURS_MIDNIGHT_CROSS, at('2026-07-27T10:00:00'));
|
|
expect(s).toEqual({ isOpen: false, kind: 'before-open', opensAt: '22:00', nextOpen: null });
|
|
});
|
|
|
|
test('saturday morning at 10:00 (with 09:00-14:00) → open, closesAt 14:00', () => {
|
|
// 2026-07-25 is a Saturday
|
|
const s = isOpenNow(HOURS_NORMAL_WEEK, at('2026-07-25T10:00:00'));
|
|
expect(s).toEqual({ isOpen: true, kind: 'open', closesAt: '14:00' });
|
|
});
|
|
|
|
test('saturday at 15:00 → closed, nextOpen monday 09:00', () => {
|
|
const s = isOpenNow(HOURS_NORMAL_WEEK, at('2026-07-25T15:00:00'));
|
|
expect(s.isOpen).toBe(false);
|
|
expect(s.kind).toBe('after-close');
|
|
expect(s.nextOpen).toEqual({ day: 'mon', time: '09:00' });
|
|
});
|
|
});
|