Spaces:
Sleeping
Sleeping
| /** | |
| * Unit tests for src/utils/helpers.js | |
| */ | |
| import { describe, it, expect, vi } from "vitest"; | |
| import { | |
| formatDate, | |
| formatDateTime, | |
| timeAgo, | |
| formatPrice, | |
| formatPricePerQuintal, | |
| formatTemperature, | |
| formatPercentage, | |
| capitalize, | |
| titleCase, | |
| truncate, | |
| generateId, | |
| debounce, | |
| clamp, | |
| deepClone, | |
| } from "../../src/utils/helpers"; | |
| // --------------------------------------------------------------------------- | |
| // formatDate | |
| // --------------------------------------------------------------------------- | |
| describe("formatDate", () => { | |
| it("returns 'N/A' for falsy input", () => { | |
| expect(formatDate(null)).toBe("N/A"); | |
| expect(formatDate("")).toBe("N/A"); | |
| expect(formatDate(undefined)).toBe("N/A"); | |
| }); | |
| it("returns 'Invalid date' for bad input", () => { | |
| expect(formatDate("not-a-date")).toBe("Invalid date"); | |
| }); | |
| it("formats a valid ISO string", () => { | |
| const result = formatDate("2026-02-07T10:30:00Z"); | |
| expect(result).toBeTruthy(); | |
| expect(result).not.toBe("N/A"); | |
| expect(result).not.toBe("Invalid date"); | |
| }); | |
| it("accepts a Date object", () => { | |
| const d = new Date("2026-01-15"); | |
| const result = formatDate(d); | |
| expect(result).toBeTruthy(); | |
| expect(result).not.toBe("N/A"); | |
| }); | |
| }); | |
| // --------------------------------------------------------------------------- | |
| // formatDateTime | |
| // --------------------------------------------------------------------------- | |
| describe("formatDateTime", () => { | |
| it("returns 'N/A' for falsy input", () => { | |
| expect(formatDateTime(null)).toBe("N/A"); | |
| }); | |
| it("returns 'Invalid date' for bad input", () => { | |
| expect(formatDateTime("xyz")).toBe("Invalid date"); | |
| }); | |
| it("formats a valid date with time", () => { | |
| const result = formatDateTime("2026-02-07T10:30:00Z"); | |
| expect(result).toBeTruthy(); | |
| expect(result).not.toBe("N/A"); | |
| }); | |
| }); | |
| // --------------------------------------------------------------------------- | |
| // timeAgo | |
| // --------------------------------------------------------------------------- | |
| describe("timeAgo", () => { | |
| it("returns 'N/A' for falsy input", () => { | |
| expect(timeAgo(null)).toBe("N/A"); | |
| expect(timeAgo("")).toBe("N/A"); | |
| }); | |
| it("returns 'Invalid date' for bad input", () => { | |
| expect(timeAgo("invalid")).toBe("Invalid date"); | |
| }); | |
| it("returns 'Just now' for very recent timestamps", () => { | |
| const now = new Date(); | |
| expect(timeAgo(now)).toBe("Just now"); | |
| }); | |
| it("returns minutes ago", () => { | |
| const fiveMinAgo = new Date(Date.now() - 5 * 60 * 1000); | |
| expect(timeAgo(fiveMinAgo)).toBe("5 minutes ago"); | |
| }); | |
| it("returns hours ago", () => { | |
| const twoHoursAgo = new Date(Date.now() - 2 * 3600 * 1000); | |
| expect(timeAgo(twoHoursAgo)).toBe("2 hours ago"); | |
| }); | |
| it("returns days ago", () => { | |
| const threeDaysAgo = new Date(Date.now() - 3 * 86400 * 1000); | |
| expect(timeAgo(threeDaysAgo)).toBe("3 days ago"); | |
| }); | |
| }); | |
| // --------------------------------------------------------------------------- | |
| // formatPrice | |
| // --------------------------------------------------------------------------- | |
| describe("formatPrice", () => { | |
| it("returns 'N/A' for null/undefined/NaN", () => { | |
| expect(formatPrice(null)).toBe("N/A"); | |
| expect(formatPrice(undefined)).toBe("N/A"); | |
| expect(formatPrice("abc")).toBe("N/A"); | |
| }); | |
| it("formats a number as Indian Rupee", () => { | |
| const result = formatPrice(2250.5); | |
| expect(result).toContain("Rs"); | |
| expect(result).toContain("2,250"); | |
| }); | |
| it("respects fraction digits parameter", () => { | |
| const result = formatPrice(1000, 0); | |
| expect(result).toBe("Rs 1,000"); | |
| }); | |
| }); | |
| // --------------------------------------------------------------------------- | |
| // formatPricePerQuintal | |
| // --------------------------------------------------------------------------- | |
| describe("formatPricePerQuintal", () => { | |
| it("returns 'N/A' for null", () => { | |
| expect(formatPricePerQuintal(null)).toBe("N/A"); | |
| }); | |
| it("appends /qtl suffix", () => { | |
| const result = formatPricePerQuintal(2250); | |
| expect(result).toContain("/qtl"); | |
| expect(result).toContain("Rs"); | |
| }); | |
| }); | |
| // --------------------------------------------------------------------------- | |
| // formatTemperature | |
| // --------------------------------------------------------------------------- | |
| describe("formatTemperature", () => { | |
| it("returns 'N/A' for null", () => { | |
| expect(formatTemperature(null)).toBe("N/A"); | |
| }); | |
| it("formats temperature with C suffix", () => { | |
| expect(formatTemperature(28.5)).toBe("28.5 C"); | |
| expect(formatTemperature(28.5, 0)).toBe("29 C"); | |
| }); | |
| }); | |
| // --------------------------------------------------------------------------- | |
| // formatPercentage | |
| // --------------------------------------------------------------------------- | |
| describe("formatPercentage", () => { | |
| it("returns 'N/A' for null", () => { | |
| expect(formatPercentage(null)).toBe("N/A"); | |
| }); | |
| it("formats percentage without decimal conversion", () => { | |
| expect(formatPercentage(85)).toBe("85.0%"); | |
| }); | |
| it("converts decimal to percentage when flag is true", () => { | |
| expect(formatPercentage(0.852, true)).toBe("85.2%"); | |
| }); | |
| }); | |
| // --------------------------------------------------------------------------- | |
| // String Utilities | |
| // --------------------------------------------------------------------------- | |
| describe("capitalize", () => { | |
| it("returns empty string for falsy input", () => { | |
| expect(capitalize("")).toBe(""); | |
| expect(capitalize(null)).toBe(""); | |
| }); | |
| it("capitalizes first letter", () => { | |
| expect(capitalize("hello")).toBe("Hello"); | |
| expect(capitalize("WORLD")).toBe("World"); | |
| }); | |
| }); | |
| describe("titleCase", () => { | |
| it("returns empty string for falsy input", () => { | |
| expect(titleCase("")).toBe(""); | |
| }); | |
| it("converts to title case", () => { | |
| expect(titleCase("hello world")).toBe("Hello World"); | |
| }); | |
| }); | |
| describe("truncate", () => { | |
| it("returns empty string for falsy input", () => { | |
| expect(truncate("")).toBe(""); | |
| }); | |
| it("returns original string if within limit", () => { | |
| expect(truncate("short", 10)).toBe("short"); | |
| }); | |
| it("truncates with ellipsis", () => { | |
| const result = truncate("a very long string that exceeds the limit", 10); | |
| expect(result).toHaveLength(13); // 10 chars + "..." | |
| expect(result).toMatch(/\.\.\.$/); | |
| }); | |
| }); | |
| // --------------------------------------------------------------------------- | |
| // Miscellaneous | |
| // --------------------------------------------------------------------------- | |
| describe("generateId", () => { | |
| it("generates unique IDs", () => { | |
| const id1 = generateId(); | |
| const id2 = generateId(); | |
| expect(id1).not.toBe(id2); | |
| }); | |
| it("uses prefix", () => { | |
| const id = generateId("test"); | |
| expect(id).toMatch(/^test_/); | |
| }); | |
| }); | |
| describe("debounce", () => { | |
| it("delays function execution", async () => { | |
| vi.useFakeTimers(); | |
| const fn = vi.fn(); | |
| const debounced = debounce(fn, 100); | |
| debounced(); | |
| debounced(); | |
| debounced(); | |
| expect(fn).not.toHaveBeenCalled(); | |
| vi.advanceTimersByTime(100); | |
| expect(fn).toHaveBeenCalledTimes(1); | |
| vi.useRealTimers(); | |
| }); | |
| }); | |
| describe("clamp", () => { | |
| it("clamps value within range", () => { | |
| expect(clamp(5, 0, 10)).toBe(5); | |
| expect(clamp(-1, 0, 10)).toBe(0); | |
| expect(clamp(15, 0, 10)).toBe(10); | |
| }); | |
| }); | |
| describe("deepClone", () => { | |
| it("returns primitives as-is", () => { | |
| expect(deepClone(42)).toBe(42); | |
| expect(deepClone("hello")).toBe("hello"); | |
| expect(deepClone(null)).toBe(null); | |
| }); | |
| it("deep clones objects", () => { | |
| const obj = { a: 1, b: { c: 2 } }; | |
| const cloned = deepClone(obj); | |
| expect(cloned).toEqual(obj); | |
| expect(cloned).not.toBe(obj); | |
| expect(cloned.b).not.toBe(obj.b); | |
| }); | |
| it("deep clones arrays", () => { | |
| const arr = [1, [2, 3], { a: 4 }]; | |
| const cloned = deepClone(arr); | |
| expect(cloned).toEqual(arr); | |
| expect(cloned).not.toBe(arr); | |
| }); | |
| }); | |