Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"test": "vitest run",
"test:coverage": "vitest run --coverage --coverage.reporter=text-summary --coverage.include='src/**/*.ts' --coverage.exclude='src/**/*.test.ts'"
"test:coverage": "vitest run --coverage --coverage.reporter=text-summary --coverage.include=src/**/*.ts --coverage.exclude=src/**/*.test.ts"
},
"devDependencies": {
"@vitest/coverage-v8": "^2.0.0",
Expand Down
40 changes: 40 additions & 0 deletions src/arrays.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, it } from "vitest";
import { chunk, dedupe, groupBy } from "./arrays";

describe("chunk", () => {
it("splits arrays into fixed-size groups and keeps a shorter tail", () => {
expect(chunk([1, 2, 3, 4, 5], 2)).toEqual([[1, 2], [3, 4], [5]]);
});

it("returns an empty list for non-positive chunk sizes", () => {
expect(chunk([1, 2, 3], 0)).toEqual([]);
expect(chunk([1, 2, 3], -1)).toEqual([]);
});
});

describe("dedupe", () => {
it("preserves first-seen order while removing duplicates", () => {
expect(dedupe(["a", "b", "a", "c", "b"])).toEqual(["a", "b", "c"]);
});
});

describe("groupBy", () => {
it("groups items by string or numeric keys", () => {
const grouped = groupBy(
[
{ kind: "fruit", name: "apple" },
{ kind: "veg", name: "carrot" },
{ kind: "fruit", name: "pear" },
],
(item) => item.kind,
);

expect(grouped).toEqual({
fruit: [
{ kind: "fruit", name: "apple" },
{ kind: "fruit", name: "pear" },
],
veg: [{ kind: "veg", name: "carrot" }],
});
});
});
41 changes: 41 additions & 0 deletions src/dates.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describe, expect, it } from "vitest";
import { addDays, daysBetween, isWeekend, startOfDayUTC } from "./dates";

describe("daysBetween", () => {
it("returns an absolute rounded day count", () => {
const morning = new Date("2026-05-01T06:00:00Z");
const nextEvening = new Date("2026-05-02T20:00:00Z");

expect(daysBetween(morning, nextEvening)).toBe(2);
expect(daysBetween(nextEvening, morning)).toBe(2);
});
});

describe("isWeekend", () => {
it("identifies Saturdays and Sundays as weekends", () => {
expect(isWeekend(new Date("2026-05-23T12:00:00Z"))).toBe(true);
expect(isWeekend(new Date("2026-05-24T12:00:00Z"))).toBe(true);
});

it("treats weekdays as non-weekends", () => {
expect(isWeekend(new Date("2026-05-25T12:00:00Z"))).toBe(false);
});
});

describe("addDays", () => {
it("returns a new date shifted by the requested number of days", () => {
const input = new Date("2026-05-01T10:30:00Z");
const shifted = addDays(input, 5);

expect(shifted.toISOString()).toBe("2026-05-06T10:30:00.000Z");
expect(input.toISOString()).toBe("2026-05-01T10:30:00.000Z");
});
});

describe("startOfDayUTC", () => {
it("normalizes a date to midnight in UTC", () => {
expect(startOfDayUTC(new Date("2026-05-01T23:59:59Z")).toISOString()).toBe(
"2026-05-01T00:00:00.000Z",
);
});
});
43 changes: 43 additions & 0 deletions src/money.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { describe, expect, it } from "vitest";
import { formatCents, netPayoutCents, platformFeeCents, splitEvenly } from "./money";

describe("formatCents", () => {
it("formats USD with a dollar prefix", () => {
expect(formatCents(12345)).toBe("$123.45");
});

it("formats EUR with the library's euro prefix", () => {
expect(formatCents(12345, "EUR")).toBe("€123.45");
});

it("falls back to an ISO-like currency prefix for other currencies", () => {
expect(formatCents(12345, "GBP")).toBe("GBP 123.45");
});
});

describe("platformFeeCents", () => {
it("rounds basis-point fees to whole cents", () => {
expect(platformFeeCents(999, 250)).toBe(25);
});

it("returns zero for non-positive gross amounts or fee rates", () => {
expect(platformFeeCents(0, 250)).toBe(0);
expect(platformFeeCents(1000, 0)).toBe(0);
});
});

describe("netPayoutCents", () => {
it("subtracts the platform fee from the gross amount", () => {
expect(netPayoutCents(1000, 250)).toBe(975);
});
});

describe("splitEvenly", () => {
it("splits cents evenly and distributes the remainder from the front", () => {
expect(splitEvenly(10, 3)).toEqual([4, 3, 3]);
});

it("returns no shares for non-positive recipient counts", () => {
expect(splitEvenly(10, 0)).toEqual([]);
});
});
35 changes: 34 additions & 1 deletion src/strings.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,40 @@
import { describe, it, expect } from "vitest";
import { slugify } from "./strings";
import { escapeHtml, slugify, titleCase, truncate } from "./strings";
describe("slugify", () => {
it("lowercases and dashifies basic input", () => {
expect(slugify("Hello World")).toBe("hello-world");
});

it("removes punctuation and collapses duplicate dashes", () => {
expect(slugify(" Hello, --- Tiny Utils!! ")).toBe("hello-tiny-utils");
});
});

describe("truncate", () => {
it("keeps short strings unchanged", () => {
expect(truncate("short", 10)).toBe("short");
});

it("truncates longer strings with the default suffix", () => {
expect(truncate("abcdef", 5)).toBe("abcd…");
});

it("supports empty results and custom suffixes", () => {
expect(truncate("abcdef", 0)).toBe("");
expect(truncate("abcdef", 4, "..")).toBe("ab..");
});
});

describe("titleCase", () => {
it("capitalizes words and lowercases the remainder", () => {
expect(titleCase("hELLO tiny UTILS")).toBe("Hello Tiny Utils");
});
});

describe("escapeHtml", () => {
it("escapes characters that are significant in HTML", () => {
expect(escapeHtml(`Tom & "Jerry" <cat>'s>`)).toBe(
"Tom &amp; &quot;Jerry&quot; &lt;cat&gt;&#39;s&gt;",
);
});
});