| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- import {
- dayKeyOf,
- fmtDate,
- fmtDateTime,
- fmtDayLabel,
- fmtDuration,
- fmtRelTime,
- fmtTime,
- tsOf,
- } from './time';
- /**
- * 时间格式化 —— 全项目唯一实现。
- *
- * 重点回归:
- * ① Parse 的 Date 形态 `{__type:'Date', iso}` 不能被 String() 成 `[object Object]`
- * ② 相对时间的边界(刚刚 / 分钟前 / 昨天)
- * ③ 无法解析时不能返回 NaN 或 Invalid Date
- */
- describe('time', () => {
- describe('tsOf 归一(所有格式化都依赖它)', () => {
- it('毫秒数字原样返回', () => {
- expect(tsOf(1700000000000)).toBe(1700000000000);
- });
- it('Date 对象', () => {
- const d = new Date('2026-10-27T10:00:00Z');
- expect(tsOf(d)).toBe(d.getTime());
- });
- it('ISO 字符串', () => {
- expect(tsOf('2026-10-27T10:00:00Z')).toBe(Date.parse('2026-10-27T10:00:00Z'));
- });
- it('🔴 Parse 的 {__type,iso} 形态(不能变成 [object Object])', () => {
- const t = tsOf({ __type: 'Date', iso: '2026-10-27T10:00:00.000Z' });
- expect(t).toBe(Date.parse('2026-10-27T10:00:00.000Z'));
- expect(Number.isFinite(t)).toBeTrue();
- });
- it('{__type, value} 形态', () => {
- expect(tsOf({ __type: 'Date', value: '2026-10-27T10:00:00.000Z' })).toBe(
- Date.parse('2026-10-27T10:00:00.000Z'),
- );
- });
- it('无法解析 → NaN(而不是 0 —— 0 会被当成 1970 年)', () => {
- expect(Number.isNaN(tsOf(null))).toBeTrue();
- expect(Number.isNaN(tsOf('not-a-date'))).toBeTrue();
- expect(Number.isNaN(tsOf({}))).toBeTrue();
- });
- });
- describe('格式化输出', () => {
- const ISO = '2026-10-27T14:35:00+08:00';
- it('fmtTime / fmtDate / fmtDateTime 都能输出非空字符串', () => {
- expect(fmtTime(ISO)).toMatch(/\d{1,2}:\d{2}/);
- expect(fmtDate(ISO)).toMatch(/\d/);
- expect(fmtDateTime(ISO)).toMatch(/\d/);
- });
- it('🔴 无法解析时不返回 Invalid Date 之类的脏字符串', () => {
- for (const fn of [fmtTime, fmtDate, fmtDateTime, fmtDayLabel]) {
- const out = fn('garbage');
- expect(out).not.toContain('Invalid');
- expect(out).not.toContain('NaN');
- }
- });
- });
- describe('fmtRelTime(会话里的时间显示)', () => {
- // 实际语义:今天 → 时刻;昨天 → 「昨天 HH:MM」;更早 → 日期
- const NOW = new Date('2026-10-27T12:00:00');
- function rel(iso: string): string {
- return fmtRelTime(iso, NOW);
- }
- it('今天 → 只显示时刻', () => {
- const out = rel(new Date('2026-10-27T09:30:00').toISOString());
- expect(out).toMatch(/^\d{1,2}:\d{2}$/);
- });
- it('昨天 → 「昨天 + 时刻」', () => {
- const out = rel(new Date('2026-10-26T16:20:00').toISOString());
- expect(out).toContain('昨天');
- expect(out).toMatch(/\d{1,2}:\d{2}/);
- });
- it('今年更早 → 月-日', () => {
- const out = rel(new Date('2026-03-05T10:00:00').toISOString());
- expect(out).toMatch(/\d{2}-\d{2}/);
- expect(out).not.toContain('昨天');
- });
- it('往年 → 带年份的日期', () => {
- const out = rel(new Date('2025-03-05T10:00:00').toISOString());
- expect(out).toContain('2025');
- });
- it('🔴 无法解析 → 占位符,不返回 Invalid Date', () => {
- const out = rel('garbage');
- expect(out).toBe('—');
- expect(out).not.toContain('Invalid');
- });
- });
- describe('dayKeyOf(事件流分组)', () => {
- // 实际语义:今天 / 昨天 / 更早用日期
- it('同一个自然日 → 同一个 key', () => {
- const a = dayKeyOf('2026-10-20T01:00:00');
- const b = dayKeyOf('2026-10-20T23:00:00');
- expect(a).toBe(b);
- });
- it('跨天 → key 不同', () => {
- expect(dayKeyOf('2026-10-20T10:00:00')).not.toBe(dayKeyOf('2026-10-21T10:00:00'));
- });
- it('今天的 key 是「今天」', () => {
- expect(dayKeyOf(new Date().toISOString())).toBe('今天');
- });
- it('无法解析 → 「未知时间」(不崩)', () => {
- expect(dayKeyOf('garbage')).toBe('未知时间');
- });
- });
- describe('fmtDuration', () => {
- it('小时数 → 可读文案', () => {
- expect(fmtDuration(436)).toBeTruthy();
- });
- it('0 / 未定义时不返回奇怪内容', () => {
- expect(fmtDuration(0)).not.toContain('NaN');
- expect(fmtDuration(undefined)).not.toContain('NaN');
- });
- });
- });
|