Skip to content

Instantly share code, notes, and snippets.

@leonid-shevtsov
Created November 27, 2025 20:18
Show Gist options
  • Select an option

  • Save leonid-shevtsov/45d1e21de77ccdd5a2fdbc50a45c056e to your computer and use it in GitHub Desktop.

Select an option

Save leonid-shevtsov/45d1e21de77ccdd5a2fdbc50a45c056e to your computer and use it in GitHub Desktop.
import { expect } from 'chai';
import dayjs from 'dayjs';
import 'dayjs/locale/en';
import 'dayjs/locale/uk';
import DayjsDate from 'dayjs-date';
import i18next from 'i18next';
import { dateRangeTitle } from './dateRanges';
import en from '../i18n/locales/en';
import uk from '../i18n/locales/uk';
describe('dateRangeTitle', () => {
// Use a fixed "today" date for consistent testing
// We'll use 2024-03-15 as our reference "today"
const TODAY_YEAR = 2024;
const TODAY_MONTH = 3;
const TODAY_DAY = 15;
// Store original today method
let originalToday: typeof DayjsDate.today;
beforeEach(() => {
// Mock DayjsDate.today() to return a fixed date
originalToday = DayjsDate.today;
DayjsDate.today = () => DayjsDate.build(TODAY_YEAR, TODAY_MONTH, TODAY_DAY);
});
afterEach(() => {
// Restore original today method
DayjsDate.today = originalToday;
});
type TestCase = {
name: string;
startDate: DayjsDate;
endDate: DayjsDate;
options?: { fullMonthNames?: boolean; showYear?: boolean };
expected: string;
};
type LocaleConfig = {
locale: string;
resources: { [key: string]: { translation: typeof en | typeof uk } };
testCases: TestCase[];
};
const testMatrix: LocaleConfig[] = [
{
locale: 'en',
resources: { en: { translation: en } },
testCases: [
// Same month and year
{
name: 'same month/year - default options',
startDate: DayjsDate.build(2024, 3, 1),
endDate: DayjsDate.build(2024, 3, 31),
expected: 'Mar 1–31',
},
{
name: 'same month/year - fullMonthNames: true',
startDate: DayjsDate.build(2024, 3, 1),
endDate: DayjsDate.build(2024, 3, 31),
options: { fullMonthNames: true },
expected: 'March 1–31',
},
{
name: 'same month/year - showYear: true (current year)',
startDate: DayjsDate.build(2024, 3, 1),
endDate: DayjsDate.build(2024, 3, 31),
options: { showYear: true },
expected: 'March 1–31',
},
{
name: 'same month/year - showYear: true and fullMonthNames: true (current year)',
startDate: DayjsDate.build(2024, 3, 1),
endDate: DayjsDate.build(2024, 3, 31),
options: { showYear: true, fullMonthNames: true },
expected: 'March 1–31',
},
{
name: 'same month/year - showYear: true (different year)',
startDate: DayjsDate.build(2023, 3, 1),
endDate: DayjsDate.build(2023, 3, 31),
options: { showYear: true },
expected: 'Mar 1–31',
},
// Different months, same year
{
name: 'different months same year - default options',
startDate: DayjsDate.build(2024, 2, 1),
endDate: DayjsDate.build(2024, 3, 15),
expected: 'Feb 1 — Mar 15',
},
{
name: 'different months same year - fullMonthNames: true',
startDate: DayjsDate.build(2024, 2, 1),
endDate: DayjsDate.build(2024, 3, 15),
options: { fullMonthNames: true },
expected: 'February 1 — March 15',
},
{
name: 'different months same year - showYear: true (current year)',
startDate: DayjsDate.build(2024, 2, 1),
endDate: DayjsDate.build(2024, 3, 15),
options: { showYear: true },
expected: 'February 1 — March 15',
},
{
name: 'different months same year - showYear: true and fullMonthNames: true (current year)',
startDate: DayjsDate.build(2024, 2, 1),
endDate: DayjsDate.build(2024, 3, 15),
options: { showYear: true, fullMonthNames: true },
expected: 'February 1 — March 15',
},
// Different months, different year (past)
{
name: 'different months different year (past) - default options',
startDate: DayjsDate.build(2023, 11, 1),
endDate: DayjsDate.build(2024, 1, 31),
expected: 'Nov 1 — Jan 31',
},
{
name: 'different months different year (past) - fullMonthNames: true',
startDate: DayjsDate.build(2023, 11, 1),
endDate: DayjsDate.build(2024, 1, 31),
options: { fullMonthNames: true },
expected: 'November 1 — January 31',
},
{
name: 'different months different year (past) - showYear: true',
startDate: DayjsDate.build(2023, 11, 1),
endDate: DayjsDate.build(2024, 1, 31),
options: { showYear: true },
expected: 'November 1 — January 31',
},
{
name: 'different months different year (past) - showYear: true and fullMonthNames: true',
startDate: DayjsDate.build(2023, 11, 1),
endDate: DayjsDate.build(2024, 1, 31),
options: { showYear: true, fullMonthNames: true },
expected: 'November 1 — January 31',
},
// Different months, different year (future)
{
name: 'different months different year (future) - default options',
startDate: DayjsDate.build(2024, 12, 1),
endDate: DayjsDate.build(2025, 2, 28),
expected: 'Dec 1 — Feb 28',
},
{
name: 'different months different year (future) - fullMonthNames: true',
startDate: DayjsDate.build(2024, 12, 1),
endDate: DayjsDate.build(2025, 2, 28),
options: { fullMonthNames: true },
expected: 'December 1 — February 28',
},
{
name: 'different months different year (future) - showYear: true',
startDate: DayjsDate.build(2024, 12, 1),
endDate: DayjsDate.build(2025, 2, 28),
options: { showYear: true },
expected: 'Dec 1 — Feb 28, 2025',
},
{
name: 'different months different year (future) - showYear: true and fullMonthNames: true',
startDate: DayjsDate.build(2024, 12, 1),
endDate: DayjsDate.build(2025, 2, 28),
options: { showYear: true, fullMonthNames: true },
expected: 'December 1 — February 28, 2025',
},
// Edge cases
{
name: 'single day budget (same start and end date)',
startDate: DayjsDate.build(2024, 3, 15),
endDate: DayjsDate.build(2024, 3, 15),
expected: 'Mar 15',
},
{
name: 'cross-year budget spanning multiple months',
startDate: DayjsDate.build(2023, 12, 1),
endDate: DayjsDate.build(2024, 2, 29),
options: { showYear: true },
expected: 'December 1 — February 29',
},
{
name: 'past year budget with showYear',
startDate: DayjsDate.build(2022, 6, 1),
endDate: DayjsDate.build(2022, 6, 30),
options: { showYear: true },
expected: 'Jun 1–30',
},
],
},
{
locale: 'uk',
resources: { uk: { translation: uk } },
testCases: [
// Same month and year
{
name: 'same month/year - default options',
startDate: DayjsDate.build(2024, 3, 1),
endDate: DayjsDate.build(2024, 3, 31),
expected: '1–31 бер',
},
{
name: 'same month/year - fullMonthNames: true',
startDate: DayjsDate.build(2024, 3, 1),
endDate: DayjsDate.build(2024, 3, 31),
options: { fullMonthNames: true },
expected: '1–31 березня',
},
{
name: 'same month/year - showYear: true (current year)',
startDate: DayjsDate.build(2024, 3, 1),
endDate: DayjsDate.build(2024, 3, 31),
options: { showYear: true },
expected: '1–31 березня',
},
{
name: 'same month/year - showYear: true and fullMonthNames: true (current year)',
startDate: DayjsDate.build(2024, 3, 1),
endDate: DayjsDate.build(2024, 3, 31),
options: { showYear: true, fullMonthNames: true },
expected: '1–31 березня',
},
{
name: 'same month/year - showYear: true (different year)',
startDate: DayjsDate.build(2023, 3, 1),
endDate: DayjsDate.build(2023, 3, 31),
options: { showYear: true },
expected: '1–31 бер',
},
// Different months, same year
{
name: 'different months same year - default options',
startDate: DayjsDate.build(2024, 2, 1),
endDate: DayjsDate.build(2024, 3, 15),
expected: '1 лют — 15 бер',
},
{
name: 'different months same year - fullMonthNames: true',
startDate: DayjsDate.build(2024, 2, 1),
endDate: DayjsDate.build(2024, 3, 15),
options: { fullMonthNames: true },
expected: '1 лютого — 15 березня',
},
{
name: 'different months same year - showYear: true (current year)',
startDate: DayjsDate.build(2024, 2, 1),
endDate: DayjsDate.build(2024, 3, 15),
options: { showYear: true },
expected: '1 лютого — 15 березня',
},
{
name: 'different months same year - showYear: true and fullMonthNames: true (current year)',
startDate: DayjsDate.build(2024, 2, 1),
endDate: DayjsDate.build(2024, 3, 15),
options: { showYear: true, fullMonthNames: true },
expected: '1 лютого — 15 березня',
},
// Different months, different year (future)
{
name: 'different months different year (future) - default options',
startDate: DayjsDate.build(2024, 12, 1),
endDate: DayjsDate.build(2025, 2, 28),
expected: '1 груд — 28 лют',
},
{
name: 'different months different year (future) - fullMonthNames: true',
startDate: DayjsDate.build(2024, 12, 1),
endDate: DayjsDate.build(2025, 2, 28),
options: { fullMonthNames: true },
expected: '1 грудня — 28 лютого',
},
{
name: 'different months different year (future) - showYear: true',
startDate: DayjsDate.build(2024, 12, 1),
endDate: DayjsDate.build(2025, 2, 28),
options: { showYear: true },
expected: '1 груд — 28 лют 2025 р.',
},
{
name: 'different months different year (future) - showYear: true and fullMonthNames: true',
startDate: DayjsDate.build(2024, 12, 1),
endDate: DayjsDate.build(2025, 2, 28),
options: { showYear: true, fullMonthNames: true },
expected: '1 грудня — 28 лютого 2025 р.',
},
// Edge cases
{
name: 'single day budget (same start and end date)',
startDate: DayjsDate.build(2024, 3, 15),
endDate: DayjsDate.build(2024, 3, 15),
expected: '15 бер',
},
{
name: 'cross-year budget spanning multiple months',
startDate: DayjsDate.build(2023, 12, 1),
endDate: DayjsDate.build(2024, 2, 29),
options: { showYear: true },
expected: '1 грудня — 29 лютого',
},
{
name: 'past year budget with showYear',
startDate: DayjsDate.build(2022, 6, 1),
endDate: DayjsDate.build(2022, 6, 30),
options: { showYear: true },
expected: '1–30 черв',
},
],
},
];
testMatrix.forEach(({ locale, resources, testCases }) => {
describe(`${locale === 'en' ? 'English' : 'Ukrainian'} locale`, () => {
beforeEach(() => {
// Set dayjs locale to ensure month names are in the correct language
// This must be set before creating any DayjsDate instances
dayjs.locale(locale);
i18next.init({
lng: locale,
resources,
});
});
testCases.forEach(({ name, startDate, endDate, options, expected }) => {
it(name, () => {
const t = i18next.getFixedT(locale);
const result = dateRangeTitle(t, startDate, endDate, options);
expect(result).to.equal(expected);
});
});
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment