@kelviq/js-promotions-ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,137 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { pdFormatCurrency, sanitizeFractionDigits } from "../src/utils";
3
+
4
+ describe("sanitizeFractionDigits", () => {
5
+ it("should return min 2 max 2 for a standard currency", () => {
6
+ expect(sanitizeFractionDigits("USD", 2, 2)).toEqual({
7
+ minimumFractionDigits: 2,
8
+ maximumFractionDigits: 2,
9
+ });
10
+ });
11
+
12
+ it("should clamp min to 0 when below range", () => {
13
+ expect(sanitizeFractionDigits("USD", -1, 2)).toEqual({
14
+ minimumFractionDigits: 0,
15
+ maximumFractionDigits: 2,
16
+ });
17
+ });
18
+
19
+ it("should clamp max to 2 when above range", () => {
20
+ expect(sanitizeFractionDigits("USD", 0, 5)).toEqual({
21
+ minimumFractionDigits: 0,
22
+ maximumFractionDigits: 2,
23
+ });
24
+ });
25
+
26
+ it("should ensure max is at least as large as min", () => {
27
+ expect(sanitizeFractionDigits("USD", 2, 0)).toEqual({
28
+ minimumFractionDigits: 2,
29
+ maximumFractionDigits: 2,
30
+ });
31
+ });
32
+
33
+ it("should return 0 for both when currency is a Stripe zero-decimal currency", () => {
34
+ expect(sanitizeFractionDigits("JPY", 2, 2)).toEqual({
35
+ minimumFractionDigits: 0,
36
+ maximumFractionDigits: 0,
37
+ });
38
+ });
39
+
40
+ it("should be case-insensitive for zero-decimal currencies", () => {
41
+ expect(sanitizeFractionDigits("jpy", 2, 2)).toEqual({
42
+ minimumFractionDigits: 0,
43
+ maximumFractionDigits: 0,
44
+ });
45
+ });
46
+ });
47
+
48
+ describe("pdFormatCurrency", () => {
49
+ it("should format USD with symbol display", () => {
50
+ const result = pdFormatCurrency({
51
+ amount: 99.99,
52
+ currency: "USD",
53
+ locale: "en-US",
54
+ currencyDisplay: "symbol",
55
+ minimumFractionDigits: 2,
56
+ maximumFractionDigits: 2,
57
+ });
58
+ expect(result.formatted).toBe("$99.99");
59
+ expect(result.integer).toBe("99");
60
+ expect(result.decimal).toBe("99");
61
+ expect(result.decimalSeparator).toBe(".");
62
+ });
63
+
64
+ it("should format USD with code display", () => {
65
+ const result = pdFormatCurrency({
66
+ amount: 50,
67
+ currency: "USD",
68
+ locale: "en-US",
69
+ currencyDisplay: "code",
70
+ minimumFractionDigits: 2,
71
+ maximumFractionDigits: 2,
72
+ });
73
+ expect(result.formatted).toContain("USD");
74
+ expect(result.formatted).toContain("50");
75
+ });
76
+
77
+ it("should format USD with name display", () => {
78
+ const result = pdFormatCurrency({
79
+ amount: 50,
80
+ currency: "USD",
81
+ locale: "en-US",
82
+ currencyDisplay: "name",
83
+ minimumFractionDigits: 2,
84
+ maximumFractionDigits: 2,
85
+ });
86
+ expect(result.formatted).toContain("dollar");
87
+ });
88
+
89
+ it("should format with zero decimal places when min/max are 0", () => {
90
+ const result = pdFormatCurrency({
91
+ amount: 99.99,
92
+ currency: "USD",
93
+ locale: "en-US",
94
+ minimumFractionDigits: 0,
95
+ maximumFractionDigits: 0,
96
+ });
97
+ expect(result.decimal).toBe("");
98
+ expect(result.decimalSeparator).toBe("");
99
+ expect(result.formatted).toBe("$100");
100
+ });
101
+
102
+ it("should handle zero-decimal currency JPY without fractions", () => {
103
+ const result = pdFormatCurrency({
104
+ amount: 1000,
105
+ currency: "JPY",
106
+ locale: "en-US",
107
+ minimumFractionDigits: 2,
108
+ maximumFractionDigits: 2,
109
+ });
110
+ expect(result.decimal).toBe("");
111
+ expect(result.decimalSeparator).toBe("");
112
+ });
113
+
114
+ it("should include thousandsSeparator for large amounts", () => {
115
+ const result = pdFormatCurrency({
116
+ amount: 1000,
117
+ currency: "USD",
118
+ locale: "en-US",
119
+ minimumFractionDigits: 0,
120
+ maximumFractionDigits: 0,
121
+ });
122
+ expect(result.thousandsSeparator).toBe(",");
123
+ expect(result.integer).toBe("1,000");
124
+ });
125
+
126
+ it("should return empty decimal and separator for whole-number amount with 0 fractions", () => {
127
+ const result = pdFormatCurrency({
128
+ amount: 50,
129
+ currency: "USD",
130
+ locale: "en-US",
131
+ minimumFractionDigits: 0,
132
+ maximumFractionDigits: 0,
133
+ });
134
+ expect(result.decimal).toBe("");
135
+ expect(result.decimalSeparator).toBe("");
136
+ });
137
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": ".",
4
+ "paths": {
5
+ "@/*": ["./src/*"],
6
+ "@@/*": ["./*"]
7
+ },
8
+ "target": "ESNext",
9
+ "useDefineForClassFields": true,
10
+ "module": "ESNext",
11
+ "lib": ["ESNext", "dom"],
12
+ "moduleResolution": "Node",
13
+ "strict": false,
14
+ "sourceMap": true,
15
+ "resolveJsonModule": true,
16
+ "esModuleInterop": true,
17
+ "noEmit": true,
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "noImplicitReturns": true,
21
+ "forceConsistentCasingInFileNames": true,
22
+ "types": ["vite/client", "node"]
23
+ },
24
+ "include": ["src"],
25
+ "exclude": ["**/*.test.ts", "node_modules", "test/**", ".history/**"]
26
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,57 @@
1
+ /// <reference types="vitest" />
2
+ import path from "path";
3
+ import { defineConfig } from "vite";
4
+ import packageJson from "./package.json";
5
+
6
+ const getPackageName = () => {
7
+ return packageJson.name;
8
+ };
9
+
10
+ const getPackageNameWithVersion = () => {
11
+ return getPackageName();
12
+ };
13
+
14
+ const getPackageNameCamelCase = () => {
15
+ try {
16
+ return getPackageName()
17
+ .replace(/^@.*\//, "")
18
+ .replace(/-./g, char => char[1].toUpperCase());
19
+ } catch (err) {
20
+ throw new Error("Name property in package.json is missing.");
21
+ }
22
+ };
23
+
24
+ const fileName = {
25
+ es: `${getPackageNameWithVersion()}.js`,
26
+ iife: `${getPackageNameWithVersion()}.iife.js`,
27
+ umd: `${getPackageNameWithVersion()}.umd.js`,
28
+ };
29
+
30
+ const formats = Object.keys(fileName) as Array<keyof typeof fileName>;
31
+
32
+ export default defineConfig({
33
+ base: "./",
34
+ server: {
35
+ port: 3000,
36
+ },
37
+ build: {
38
+ outDir: "./build/dist",
39
+ lib: {
40
+ entry: path.resolve(__dirname, "src/index.ts"),
41
+ name: getPackageNameCamelCase(),
42
+ formats,
43
+ fileName: format => fileName[format],
44
+ },
45
+ },
46
+ test: {
47
+ watch: false,
48
+ environment: "jsdom",
49
+ setupFiles: ["./test/setup.ts"],
50
+ },
51
+ resolve: {
52
+ alias: [
53
+ { find: "@", replacement: path.resolve(__dirname, "src") },
54
+ { find: "@@", replacement: path.resolve(__dirname) },
55
+ ],
56
+ },
57
+ });