diff --git a/README.md b/README.md index 8516adcfe..b713eaa33 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,27 @@ +
+ +--- + + + +--- + English | [简体中文](./docs/zh-cn/README.zh-CN.md) | [日本語](./docs/ja/README-ja.md) | [Português Brasileiro](./docs/pt-br/README-pt-br.md) | [한국어](./docs/ko/README-ko.md) | [Español (España)](./docs/es-es/README-es-es.md) | [Русский](./docs/ru/README-ru.md) | [Türkçe](./docs/tr/README-tr.md) | [සිංහල](./docs/si/README-si.md) | [עברית](./docs/he/README-he.md)
-
-
-
## Sponsors
Support this project by becoming a sponsor. Your logo will show up here with a link to your website.
@@ -123,12 +141,8 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
-
-
-
-
-
-
+
+
@@ -139,6 +153,14 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
+
+
+
+
+
+
+
+
diff --git a/docs/es-es/README-es-es.md b/docs/es-es/README-es-es.md
index d9b54c794..e3519168f 100644
--- a/docs/es-es/README-es-es.md
+++ b/docs/es-es/README-es-es.md
@@ -108,12 +108,6 @@ dayjs().format('Q Do k kk X x') // ahora tenemos más formatos disponibles
📚[Lista de complementos](https://day.js.org/docs/en/plugin/plugin)
-### Tendencia de Uso
-
-
-
-
-
## Patrocinadores
Apoya a este proyecto convirtiéndote en un patrocinador. Tu logo aparecerá aquí, enlazado a tu sitio web. [[Conviértete en un patrocinador](https://opencollective.com/dayjs#sponsor)]
diff --git a/docs/he/README-he.md b/docs/he/README-he.md
index f410269ef..00cc6a2cb 100644
--- a/docs/he/README-he.md
+++ b/docs/he/README-he.md
@@ -120,12 +120,6 @@ dayjs().format('Q Do k kk X x') // כעת יותר אפשרויות זמינות
📚[רשימת תוספים](https://day.js.org/docs/en/plugin/plugin)
-### מגמת השימוש
-
-
-
-
-
### ספונסרים
תמכו בפרויקט זה כדי להיות ספונסר. קבלו לוגו עם קישור לאתר שלכם שיופיע כאן.
diff --git a/docs/ja/README-ja.md b/docs/ja/README-ja.md
index 783e86801..17f7fbe1d 100644
--- a/docs/ja/README-ja.md
+++ b/docs/ja/README-ja.md
@@ -108,12 +108,6 @@ dayjs().format('Q Do k kk X x') // 多様なフォーマットが利用可能に
📚[プラグインリスト](https://day.js.org/docs/en/plugin/plugin)
-### 使用トレンド
-
-
-
-
-
## ライセンス
Day.js は [MIT License](../../LICENSE) のもとで利用を許諾します。
diff --git a/docs/ko/README-ko.md b/docs/ko/README-ko.md
index 3b1b985b5..9a66dfcb5 100644
--- a/docs/ko/README-ko.md
+++ b/docs/ko/README-ko.md
@@ -108,12 +108,6 @@ dayjs().format('Q Do k kk X x') // more available formats
📚[플러그인 목록](https://day.js.org/docs/en/plugin/plugin)
-### 사용 트렌드
-
-
-
-
-
## License
Day.js는 [MIT License](./LICENSE)를 사용합니다.
diff --git a/docs/pt-br/README-pt-br.md b/docs/pt-br/README-pt-br.md
index 31d0bdbc4..0721771d2 100644
--- a/docs/pt-br/README-pt-br.md
+++ b/docs/pt-br/README-pt-br.md
@@ -107,12 +107,6 @@ dayjs().format('Q Do k kk X x') // mais formatos disponíveis pelo plugin
📚[Lista de Plugins](https://day.js.org/docs/en/plugin/plugin)
-### Tendência de Uso
-
-
-
-
-
## Patrocinadores
Ajude este projeto se tornando um patrocinador. O seu logo será exibido aqui, com um link para o seu site. [[Tornar-se um Patrocinador](https://opencollective.com/dayjs#sponsor)].
diff --git a/docs/ru/README-ru.md b/docs/ru/README-ru.md
index 065af14ba..2d1079c77 100644
--- a/docs/ru/README-ru.md
+++ b/docs/ru/README-ru.md
@@ -98,12 +98,6 @@ dayjs().format('Q Do k kk X x') // больше доступных формат
📚[Список плагинов](https://day.js.org/docs/ru/plugin/plugin)
-### Тенденция использования
-
-
-
-
-
## Спонсоры
Поддержите этот проект, став спонсором. Ваш логотип будет показан здесь с ссылкой на ваш веб-сайт. [[Стать спонсором](https://opencollective.com/dayjs#sponsor)]
diff --git a/docs/si/README-si.md b/docs/si/README-si.md
index e5f7fb92b..b170a516b 100644
--- a/docs/si/README-si.md
+++ b/docs/si/README-si.md
@@ -98,12 +98,6 @@ dayjs().format('Q Do k kk X x') // more available formats
📚[ දිගු ලේඛනය](https://day.js.org/docs/en/plugin/plugin)
-### භාවිත ප්රමාණයේ ප්රසූතිය
-
-
-
-
-
## අනුග්රාහකයින්
අනුග්රහය දැක්වීමෙන් මෙම ව්යාපෘතියට සහාය වන්න. ඔබගේ අඩවියේ සබැඳියක් සමඟ ඔබගේ ලාංඡනය මෙහි පෙන්වනු ඇත.
diff --git a/docs/tr/README-tr.md b/docs/tr/README-tr.md
index 2b1a63549..e408dd77c 100644
--- a/docs/tr/README-tr.md
+++ b/docs/tr/README-tr.md
@@ -108,12 +108,6 @@ dayjs().format('Q Do k kk X x') // diğer mevcut formatlar
📚[Eklenti Listesi](https://day.js.org/docs/en/plugin/plugin)
-### Kullanım Trendi
-
-
-
-
-
## Sponsorlar
Sponsor olarak bu projeye destek olun. Logonuz, web sayfanızın linki ile birlikte burada görünür. [[Sponsor Ol](https://opencollective.com/dayjs#sponsor)]
diff --git a/docs/zh-cn/README.zh-CN.md b/docs/zh-cn/README.zh-CN.md
index d7bb1ecbc..5abdea0a3 100644
--- a/docs/zh-cn/README.zh-CN.md
+++ b/docs/zh-cn/README.zh-CN.md
@@ -108,12 +108,6 @@ dayjs().format('Q Do k kk X x') // 使用扩展后的API
📚[插件列表](https://day.js.org/docs/zh-CN/plugin/plugin)
-### 使用量趋势
-
-
-
-
-
## 开源协议
Day.js 遵循 [MIT 开源协议](../../LICENSE).
diff --git a/package.json b/package.json
index 2c74cddc7..e2baf268a 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"main": "dayjs.min.js",
"types": "index.d.ts",
"scripts": {
- "test": "TZ=Pacific/Auckland npm run test-tz && TZ=Europe/London npm run test-tz && TZ=America/Whitehorse npm run test-tz && npm run test-tz && jest",
+ "test": "TZ=Pacific/Auckland npm run test-tz && TZ=Europe/London npm run test-tz && TZ=America/Whitehorse npm run test-tz && npm run test-tz && jest --coverage --coverageThreshold='{ \"global\": { \"lines\": 100} }'",
"test-tz": "date && jest test/timezone.test --coverage=false",
"lint": "./node_modules/.bin/eslint src/* test/* build/*",
"prettier": "prettier --write \"docs/**/*.md\"",
diff --git a/src/locale/ar.js b/src/locale/ar.js
index f418379c8..5d28a1d31 100644
--- a/src/locale/ar.js
+++ b/src/locale/ar.js
@@ -29,6 +29,12 @@ const numberMap = {
'٠': '0'
}
+const fromArabNumeralsRegex = /[١٢٣٤٥٦٧٨٩٠]/g
+const fromArabComaRegex = /،/g
+
+const toArabNumeralsRegex = /\d/g
+const toArabComaRegex = /,/g
+
const locale = {
name: 'ar',
weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
@@ -56,15 +62,15 @@ const locale = {
preparse(string) {
return string
.replace(
- /[١٢٣٤٥٦٧٨٩٠]/g,
+ fromArabNumeralsRegex,
match => numberMap[match]
)
- .replace(/،/g, ',')
+ .replace(fromArabComaRegex, ',')
},
postformat(string) {
return string
- .replace(/\d/g, match => symbolMap[match])
- .replace(/,/g, '،')
+ .replace(toArabNumeralsRegex, match => symbolMap[match])
+ .replace(toArabComaRegex, '،')
},
ordinal: n => n,
formats: {
diff --git a/src/locale/be.js b/src/locale/be.js
index 3b4e2d731..c35d56574 100644
--- a/src/locale/be.js
+++ b/src/locale/be.js
@@ -1,15 +1,63 @@
// Belarusian [be]
import dayjs from 'dayjs'
+const monthFormat = 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_')
+const monthStandalone = 'студзень_лютый_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_')
+
+const monthShortFormat = 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж.'.split('_')
+const monthShortStandalone = 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_')
+
+const MONTHS_IN_FORMAT = /D[oD]?(\[[^[\]]*\]|\s)+MMMM?/
+
+function plural(word, num) {
+ const forms = word.split('_')
+ return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]) // eslint-disable-line
+}
+function relativeTimeWithPlural(number, withoutSuffix, key) {
+ const format = {
+ ss: withoutSuffix ? 'секунда_секунды_секунд' : 'секунду_секунды_секунд',
+ mm: withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін',
+ hh: withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін',
+ dd: 'дзень_дні_дзён',
+ MM: 'месяц_месяцы_месяцаў',
+ yy: 'год_гады_гадоў'
+ }
+ if (key === 'm') {
+ return withoutSuffix ? 'хвіліна' : 'хвіліну'
+ } else if (key === 'h') {
+ return withoutSuffix ? 'гадзіна' : 'гадзіну'
+ }
+
+ return `${number} ${plural(format[key], +number)}`
+}
+
+const months = (dayjsInstance, format) => {
+ if (MONTHS_IN_FORMAT.test(format)) {
+ return monthFormat[dayjsInstance.month()]
+ }
+ return monthStandalone[dayjsInstance.month()]
+}
+months.s = monthStandalone
+months.f = monthFormat
+
+const monthsShort = (dayjsInstance, format) => {
+ if (MONTHS_IN_FORMAT.test(format)) {
+ return monthShortFormat[dayjsInstance.month()]
+ }
+ return monthShortStandalone[dayjsInstance.month()]
+}
+monthsShort.s = monthShortStandalone
+monthsShort.f = monthShortFormat
+
const locale = {
name: 'be',
- weekdays: 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_'),
- months: 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_'),
+ weekdays: 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),
+ weekdaysShort: 'няд_пнд_аўт_сер_чцв_пят_суб'.split('_'),
+ weekdaysMin: 'нд_пн_аў_ср_чц_пт_сб'.split('_'),
+ months,
+ monthsShort,
weekStart: 1,
- weekdaysShort: 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
- monthsShort: 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'),
- weekdaysMin: 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
- ordinal: n => n,
+ yearStart: 4,
formats: {
LT: 'HH:mm',
LTS: 'HH:mm:ss',
@@ -17,10 +65,35 @@ const locale = {
LL: 'D MMMM YYYY г.',
LLL: 'D MMMM YYYY г., HH:mm',
LLLL: 'dddd, D MMMM YYYY г., HH:mm'
+ },
+ relativeTime: {
+ future: 'праз %s',
+ past: '%s таму',
+ s: 'некалькі секунд',
+ m: relativeTimeWithPlural,
+ mm: relativeTimeWithPlural,
+ h: relativeTimeWithPlural,
+ hh: relativeTimeWithPlural,
+ d: 'дзень',
+ dd: relativeTimeWithPlural,
+ M: 'месяц',
+ MM: relativeTimeWithPlural,
+ y: 'год',
+ yy: relativeTimeWithPlural
+ },
+ ordinal: n => n,
+ meridiem: (hour) => {
+ if (hour < 4) {
+ return 'ночы'
+ } else if (hour < 12) {
+ return 'раніцы'
+ } else if (hour < 17) {
+ return 'дня'
+ }
+ return 'вечара'
}
}
dayjs.locale(locale, null, true)
export default locale
-
diff --git a/src/locale/it.js b/src/locale/it.js
index 08f660bef..b4bceb00d 100644
--- a/src/locale/it.js
+++ b/src/locale/it.js
@@ -23,7 +23,7 @@ const locale = {
s: 'qualche secondo',
m: 'un minuto',
mm: '%d minuti',
- h: 'un\' ora',
+ h: 'un\'ora',
hh: '%d ore',
d: 'un giorno',
dd: '%d giorni',
diff --git a/src/plugin/devHelper/index.js b/src/plugin/devHelper/index.js
index bdb83caf7..2f163a25f 100644
--- a/src/plugin/devHelper/index.js
+++ b/src/plugin/devHelper/index.js
@@ -26,6 +26,15 @@ export default (o, c, d) => {
}
return oldLocale(preset, object, isLocal)
}
+
+ const oldDiff = proto.diff
+ proto.diff = function (date, unit, float) {
+ const isInvalidDate = !date || !d(date).isValid()
+ if (isInvalidDate) {
+ console.warn('Invalid usage: diff() requires a valid comparison date as the first argument. https://day.js.org/docs/en/display/difference')
+ }
+
+ return oldDiff.call(this, date, unit, float)
+ }
}
}
-
diff --git a/test/locale/be.test.js b/test/locale/be.test.js
new file mode 100644
index 000000000..0c39f224b
--- /dev/null
+++ b/test/locale/be.test.js
@@ -0,0 +1,142 @@
+import MockDate from 'mockdate'
+import moment from 'moment'
+import dayjs from '../../src'
+import '../../src/locale/be'
+import relativeTime from '../../src/plugin/relativeTime'
+
+dayjs.extend(relativeTime)
+
+beforeEach(() => {
+ MockDate.set(new Date())
+})
+
+afterEach(() => {
+ MockDate.reset()
+})
+
+it('Belarusian locale relative time in past and future with suffix', () => {
+ const cases = [
+ [1, 's', 'праз некалькі секунд'],
+ [-1, 's', 'некалькі секунд таму'],
+ [1, 'm', 'праз хвіліну'],
+ [-1, 'm', 'хвіліну таму'],
+ [1, 'h', 'праз гадзіну'],
+ [-1, 'h', 'гадзіну таму'],
+ [1, 'd', 'праз дзень'],
+ [-1, 'd', 'дзень таму'],
+ [1, 'M', 'праз месяц'],
+ [-1, 'M', 'месяц таму'],
+ [2, 'd', 'праз 2 дні'],
+ [-2, 'd', '2 дні таму'],
+ [10, 'd', 'праз 10 дзён'],
+ [-10, 'd', '10 дзён таму'],
+ [6, 'm', 'праз 6 хвілін'],
+ [-6, 'm', '6 хвілін таму'],
+ [5, 'h', 'праз 5 гадзін'],
+ [-5, 'h', '5 гадзін таму'],
+ [3, 'M', 'праз 3 месяцы'],
+ [-3, 'M', '3 месяцы таму'],
+ [4, 'y', 'праз 4 гады'],
+ [-4, 'y', '4 гады таму']
+ ]
+
+ const locales = ['be']
+ locales.forEach((locale) => {
+ cases.forEach((c) => {
+ expect(dayjs()
+ .add(c[0], c[1])
+ .locale(locale)
+ .fromNow()).toBe(c[2])
+ expect(dayjs()
+ .add(c[0], c[1])
+ .locale(locale)
+ .fromNow()).toBe(moment()
+ .add(c[0], c[1])
+ .locale(locale)
+ .fromNow())
+ })
+ })
+})
+
+it('Belarusian locale relative time in past and future without suffix', () => {
+ const cases = [
+ [1, 's', 'некалькі секунд'],
+ [-1, 's', 'некалькі секунд'],
+
+ [1, 'm', 'хвіліна'],
+ [-1, 'm', 'хвіліна'],
+ [1, 'h', 'гадзіна'],
+ [-1, 'h', 'гадзіна'],
+
+ // Test all plural forms for days
+ [1, 'd', 'дзень'],
+ [21, 'd', '21 дзень'],
+ [31, 'd', 'месяц'],
+ // 2-4 form
+ [2, 'd', '2 дні'],
+ [3, 'd', '3 дні'],
+ [4, 'd', '4 дні'],
+ // 5-20 and other cases
+ [5, 'd', '5 дзён'],
+ [6, 'd', '6 дзён'],
+ // 11-14 special case
+ [11, 'd', '11 дзён'],
+ [12, 'd', '12 дзён'],
+ [13, 'd', '13 дзён'],
+ [14, 'd', '14 дзён'],
+ // 22-24
+ [22, 'd', '22 дні'],
+ [23, 'd', '23 дні'],
+ [24, 'd', '24 дні'],
+
+ // Test all plural forms for months
+ [1, 'M', 'месяц'],
+ [2, 'M', '2 месяцы'],
+ [5, 'M', '5 месяцаў'],
+
+ // Test all plural forms for years
+ [1, 'y', 'год'],
+ [2, 'y', '2 гады'],
+ [5, 'y', '5 гадоў'],
+ [11, 'y', '11 гадоў'],
+ [21, 'y', '21 год']
+ ]
+
+ const locales = ['be']
+ locales.forEach((locale) => {
+ cases.forEach((c) => {
+ expect(dayjs()
+ .add(c[0], c[1])
+ .locale(locale)
+ .fromNow(true)).toBe(c[2])
+ expect(dayjs()
+ .add(c[0], c[1])
+ .locale(locale)
+ .fromNow(true)).toBe(moment()
+ .add(c[0], c[1])
+ .locale(locale)
+ .fromNow(true))
+ })
+ })
+})
+
+it('Belarusian locale formats dates with correct month forms', () => {
+ const tests = [
+ // Full month names
+ { date: '2022-01-19', format: 'dd, D MMMM YYYY г.', expected: 'ср, 19 студзеня 2022 г.' },
+ { date: '2022-01-01', format: 'MMMM', expected: 'студзень' },
+
+ // Short month names in format form (with day)
+ { date: '2022-01-15', format: 'D MMM', expected: '15 студ' },
+ { date: '2022-02-15', format: 'D MMM', expected: '15 лют' },
+
+ // Short month names in standalone form
+ { date: '2022-01-01', format: 'MMM', expected: 'студ' },
+ { date: '2022-02-01', format: 'MMM', expected: 'лют' }
+ ]
+
+ tests.forEach(({ date, format, expected }) => {
+ const dayjsWithLocale = dayjs(date).locale('be')
+ expect(dayjsWithLocale.format(format)).toEqual(expected)
+ })
+})
diff --git a/test/locale/it.test.js b/test/locale/it.test.js
new file mode 100644
index 000000000..56043b1de
--- /dev/null
+++ b/test/locale/it.test.js
@@ -0,0 +1,84 @@
+import moment from 'moment'
+import MockDate from 'mockdate'
+import dayjs from '../../src'
+import '../../src/locale/it'
+import relativeTime from '../../src/plugin/relativeTime'
+import localizedFormat from '../../src/plugin/localizedFormat'
+
+dayjs.extend(relativeTime)
+dayjs.extend(localizedFormat)
+
+describe('Italian formats', () => {
+ beforeEach(() => {
+ dayjs.locale('it')
+ moment.locale('it')
+
+ MockDate.set(new Date())
+ })
+
+ afterEach(() => {
+ MockDate.reset()
+ })
+
+
+ it('Format month with locale function', () => {
+ for (let i = 0; i <= 7; i += 1) {
+ const dayjsWithLocale = dayjs().add(i, 'day')
+ const momentWithLocale = moment().add(i, 'day')
+ const testFormat1 = 'DD MMMM YYYY MMM'
+ const testFormat2 = 'dddd, MMMM D YYYY'
+ const testFormat3 = 'MMMM'
+ const testFormat4 = 'MMM'
+ const testFormat5 = 'L'
+ expect(dayjsWithLocale.format(testFormat1)).toEqual(momentWithLocale.format(testFormat1))
+ expect(dayjsWithLocale.format(testFormat2)).toEqual(momentWithLocale.format(testFormat2))
+ expect(dayjsWithLocale.format(testFormat3)).toEqual(momentWithLocale.format(testFormat3))
+ expect(dayjsWithLocale.format(testFormat4)).toEqual(momentWithLocale.format(testFormat4))
+ expect(dayjsWithLocale.format(testFormat5)).toEqual(momentWithLocale.format(testFormat5))
+ }
+ })
+
+ it('RelativeTime: Time from X', () => {
+ const T = [
+ [89.5, 'second'], // a minute
+ [2, 'minute'], // 2 minutes
+ [5, 'minute'], // 5 minutes
+ [43, 'minute'], // 44 minutes
+ [45, 'minute'], // an hour
+ [3, 'hour'], // 3 hours
+ [21, 'hour'], // 21 hours
+ [1, 'day'], // a day
+ [3, 'day'], // 3 day
+ [25, 'day'], // 25 days
+ [1, 'month'], // a month
+ [2, 'month'], // 2 month
+ [10, 'month'], // 10 month
+ [1, 'year'], // a year
+ [2, 'year'], // 2 year
+ [5, 'year'], // 5 year
+ [18, 'month'] // 2 years
+ ]
+
+
+ T.forEach((t) => {
+ expect(dayjs().from(dayjs().add(t[0], t[1])))
+ .toBe(moment().from(moment().add(t[0], t[1])))
+ expect(dayjs().from(dayjs().add(t[0], t[1]), true))
+ .toBe(moment().from(moment().add(t[0], t[1]), true))
+ })
+ })
+
+ // moment.js uses `alcuni secondi` while dayjs uses `qualche secondo`.
+ it('RelativeTime: A few seconds', () => {
+ const T = [
+ [44.4, 'second'] // a few seconds
+ ]
+
+ T.forEach((t) => {
+ expect(dayjs().from(dayjs().add(t[0], t[1])))
+ .toBe('qualche secondo fa')
+ expect(dayjs().from(dayjs().add(t[0], t[1]), true))
+ .toBe('qualche secondo')
+ })
+ })
+})
diff --git a/test/plugin/devHelper.test.js b/test/plugin/devHelper.test.js
index c69190a14..ff63d434d 100644
--- a/test/plugin/devHelper.test.js
+++ b/test/plugin/devHelper.test.js
@@ -1,6 +1,8 @@
import MockDate from 'mockdate'
import dayjs from '../../src'
+import customParseFormat from '../../src/plugin/customParseFormat'
import devHelper from '../../src/plugin/devHelper'
+import localeData from '../../src/plugin/localeData'
dayjs.extend(devHelper)
@@ -38,3 +40,46 @@ it('Warning: Setting locale before loading locale', () => {
dayjs.locale('zh-cn')
expect(consoleSpy).toHaveBeenCalledWith('Guessing you may want to use locale zh-cn, you have to load it before using it. https://day.js.org/docs/en/i18n/loading-into-nodejs')
})
+
+describe('dev-helper: diff() usage warnings', () => {
+ const diffWarningMsg = 'Invalid usage: diff() requires a valid comparison date as the first argument. https://day.js.org/docs/en/display/difference'
+
+ beforeAll(() => {
+ dayjs.extend(customParseFormat)
+ dayjs.extend(localeData)
+ })
+
+ beforeEach(() => {
+ jest.clearAllMocks()
+ })
+
+ it('warns when diff() is called with no comparison date', () => {
+ const consoleSpy = jest.spyOn(console, 'warn')
+ dayjs('2025-01-10').diff()
+ expect(consoleSpy).toHaveBeenCalledWith(diffWarningMsg)
+ })
+
+ it('warns when diff() is called with just the unit', () => {
+ const consoleSpy = jest.spyOn(console, 'warn')
+ dayjs('2025-01-10').diff('days')
+ expect(consoleSpy).toHaveBeenCalledWith(diffWarningMsg)
+ })
+
+ it('warns when diff() is called with an invalid comparison date (unparsable string)', () => {
+ const consoleSpy = jest.spyOn(console, 'warn')
+ dayjs('2025-01-10').diff('invalid-date', 'days')
+ expect(consoleSpy).toHaveBeenCalledWith(diffWarningMsg)
+ })
+
+ it('does NOT warn when diff() is called with a valid string date', () => {
+ const consoleSpy = jest.spyOn(console, 'warn')
+ dayjs('2025-01-10').diff('2025-01-09', 'days')
+ expect(consoleSpy).not.toHaveBeenCalledWith(diffWarningMsg)
+ })
+
+ it('does NOT warn when diff() is called with a valid Day.js instance', () => {
+ const consoleSpy = jest.spyOn(console, 'warn')
+ dayjs('2025-01-10').diff(dayjs(), 'days')
+ expect(consoleSpy).not.toHaveBeenCalledWith(diffWarningMsg)
+ })
+})