tip
total
diff --git a/src/tips-math.ts b/src/tips-math.ts index 72aea36..880e324 100644 --- a/src/tips-math.ts +++ b/src/tips-math.ts @@ -31,6 +31,14 @@ export function perPersonCents(total: number, people: number): number { return Math.ceil(total / people); } +/** + * One person's share of a total rounded up to the next whole dollar (in cents). + * Whole-dollar shares are kept as-is (no extra cent/dollar added). + */ +export function perPersonRoundedUpCents(total: number, people: number): number { + return Math.ceil(total / (people * 100)) * 100; +} + export function clampPeople(n: number): number { if (!Number.isFinite(n) || n < 1) return 1; return Math.min(MAX_PEOPLE, Math.round(n)); diff --git a/test/tips-math.test.ts b/test/tips-math.test.ts index 252af16..abb9201 100644 --- a/test/tips-math.test.ts +++ b/test/tips-math.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { clampPeople, parseAmount, parsePercent, perPersonCents, tipCents } from "../src/tips-math.ts"; +import { clampPeople, parseAmount, parsePercent, perPersonCents, perPersonRoundedUpCents, tipCents } from "../src/tips-math.ts"; describe("parseAmount", () => { it("parses plain decimals into cents", () => { @@ -49,6 +49,16 @@ describe("perPersonCents", () => { }); }); +describe("perPersonRoundedUpCents", () => { + it("rounds the per-person share up to the next whole dollar", () => { + expect(perPersonRoundedUpCents(11500, 3)).toBe(3900); // 38.33 -> $39.00 + expect(perPersonRoundedUpCents(12000, 3)).toBe(4000); // exact, no extra + expect(perPersonRoundedUpCents(1205, 3)).toBe(500); // $4.02 -> $5.00 + expect(perPersonRoundedUpCents(1000, 1)).toBe(1000); + expect(perPersonRoundedUpCents(99, 3)).toBe(100); // tiny share -> $1.00 + }); +}); + describe("clampPeople", () => { it("keeps the count between 1 and 99", () => { expect(clampPeople(0)).toBe(1); From 1dd5870cfc7dfbb1216105cb047ed5769b92201e Mon Sep 17 00:00:00 2001 From: Michael Gutensohn <19628643+michaelthatsit@users.noreply.github.com> Date: Sun, 25 Oct 2026 15:00:53 -0700 Subject: [PATCH 2/2] Add round-up per person toggle Adds an optional 'Round up per person to a whole dollar' toggle. When on, each person's share is rounded up to the next whole dollar and the tip absorbs the difference (total = per-person x people). Off by default, keeping existing behavior. Adds unit + e2e coverage. --- .vitest/json/output.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vitest/json/output.json b/.vitest/json/output.json index f716e54..641a78e 100644 --- a/.vitest/json/output.json +++ b/.vitest/json/output.json @@ -1 +1 @@ -{"numTotalTestSuites":1,"numPassedTestSuites":0,"numFailedTestSuites":1,"numPendingTestSuites":0,"numTotalTests":0,"numPassedTests":0,"numFailedTests":0,"numPendingTests":0,"numTodoTests":0,"snapshot":{"added":0,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0,"didUpdate":false},"startTime":1792963337027,"success":false,"testResults":[{"assertionResults":[],"startTime":1792963337027,"endTime":1792963337027,"status":"failed","message":"Currency code is required with currency style.","name":"/home/michael/workspace/apps/tips/test/tips-math.test.ts"}]} \ No newline at end of file +{"numTotalTestSuites":7,"numPassedTestSuites":7,"numFailedTestSuites":0,"numPendingTestSuites":0,"numTotalTests":8,"numPassedTests":8,"numFailedTests":0,"numPendingTests":0,"numTodoTests":0,"snapshot":{"added":0,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0,"didUpdate":false},"startTime":1792965203049,"success":true,"testResults":[{"assertionResults":[{"ancestorTitles":["parseAmount"],"fullName":"parseAmount parses plain decimals into cents","status":"passed","title":"parses plain decimals into cents","duration":1.1074950000000001,"failureMessages":[],"meta":{},"tags":[],"benchmarks":[]},{"ancestorTitles":["parseAmount"],"fullName":"parseAmount rejects empty and invalid input","status":"passed","title":"rejects empty and invalid input","duration":0.16899399999999787,"failureMessages":[],"meta":{},"tags":[],"benchmarks":[]},{"ancestorTitles":["parsePercent"],"fullName":"parsePercent parses percentages","status":"passed","title":"parses percentages","duration":0.11859300000000417,"failureMessages":[],"meta":{},"tags":[],"benchmarks":[]},{"ancestorTitles":["parsePercent"],"fullName":"parsePercent rejects empty, invalid and out-of-range input","status":"passed","title":"rejects empty, invalid and out-of-range input","duration":0.0785449999999912,"failureMessages":[],"meta":{},"tags":[],"benchmarks":[]},{"ancestorTitles":["tipCents"],"fullName":"tipCents rounds to the nearest cent","status":"passed","title":"rounds to the nearest cent","duration":0.1635209999999887,"failureMessages":[],"meta":{},"tags":[],"benchmarks":[]},{"ancestorTitles":["perPersonCents"],"fullName":"perPersonCents rounds up so the total is covered","status":"passed","title":"rounds up so the total is covered","duration":0.11150500000000818,"failureMessages":[],"meta":{},"tags":[],"benchmarks":[]},{"ancestorTitles":["perPersonRoundedUpCents"],"fullName":"perPersonRoundedUpCents rounds the per-person share up to the next whole dollar","status":"passed","title":"rounds the per-person share up to the next whole dollar","duration":0.11932899999999336,"failureMessages":[],"meta":{},"tags":[],"benchmarks":[]},{"ancestorTitles":["clampPeople"],"fullName":"clampPeople keeps the count between 1 and 99","status":"passed","title":"keeps the count between 1 and 99","duration":0.14684900000000312,"failureMessages":[],"meta":{},"tags":[],"benchmarks":[]}],"startTime":1792965203159,"endTime":1792965203161.1467,"status":"passed","message":"","name":"/home/michael/workspace/apps/tips/test/tips-math.test.ts"}]} \ No newline at end of file