|
1 | 1 | import {expect, describe, test} from "@jest/globals"; |
2 | 2 |
|
3 | | -import {cn as cnWithMerge, cx as cxFull} from "../index"; |
| 3 | +import {cn, cnMerge, cx as cxFull} from "../index"; |
4 | 4 | import {cn as cnLite, cx as cxLite} from "../lite"; |
5 | 5 | import {cx as cxUtils} from "../utils"; |
6 | 6 |
|
@@ -85,127 +85,183 @@ describe("cn function from lite (simple concatenation)", () => { |
85 | 85 | }); |
86 | 86 |
|
87 | 87 | describe("cn function with tailwind-merge (main index)", () => { |
88 | | - test("should merge conflicting tailwind classes when twMerge is true", () => { |
89 | | - const result = cnWithMerge("px-2", "px-4", "py-2")({twMerge: true}); |
| 88 | + test("should merge conflicting tailwind classes by default", () => { |
| 89 | + const result = cn("px-2", "px-4", "py-2"); |
90 | 90 |
|
91 | 91 | expect(result).toBe("px-4 py-2"); |
92 | 92 | }); |
93 | 93 |
|
94 | | - test("should not merge classes when twMerge is false", () => { |
95 | | - const result = cnWithMerge("px-2", "px-4", "py-2")({twMerge: false}); |
96 | | - |
97 | | - expect(result).toBe("px-2 px-4 py-2"); |
98 | | - }); |
99 | | - |
100 | | - test("should merge text color classes", () => { |
101 | | - const result = cnWithMerge("text-red-500", "text-blue-500")({twMerge: true}); |
| 94 | + test("should merge text color classes by default", () => { |
| 95 | + const result = cn("text-red-500", "text-blue-500"); |
102 | 96 |
|
103 | 97 | expect(result).toBe("text-blue-500"); |
104 | 98 | }); |
105 | 99 |
|
106 | | - test("should merge background color classes", () => { |
107 | | - const result = cnWithMerge("bg-red-500", "bg-blue-500")({twMerge: true}); |
| 100 | + test("should merge background color classes by default", () => { |
| 101 | + const result = cn("bg-red-500", "bg-blue-500"); |
108 | 102 |
|
109 | 103 | expect(result).toBe("bg-blue-500"); |
110 | 104 | }); |
111 | 105 |
|
112 | 106 | test("should merge multiple conflicting classes", () => { |
113 | | - const result = cnWithMerge("px-2 py-1 text-sm", "px-4 py-2 text-lg")({twMerge: true}); |
| 107 | + const result = cn("px-2 py-1 text-sm", "px-4 py-2 text-lg"); |
114 | 108 |
|
115 | 109 | expect(result).toBe("px-4 py-2 text-lg"); |
116 | 110 | }); |
117 | 111 |
|
118 | 112 | test("should handle non-conflicting classes", () => { |
119 | | - const result = cnWithMerge("px-2", "py-2", "text-sm")({twMerge: true}); |
| 113 | + const result = cn("px-2", "py-2", "text-sm"); |
120 | 114 |
|
121 | 115 | expect(result).toBe("px-2 py-2 text-sm"); |
122 | 116 | }); |
123 | 117 |
|
124 | 118 | test("should return undefined when no classes provided", () => { |
125 | | - const result = cnWithMerge()({twMerge: true}); |
| 119 | + const result = cn(); |
126 | 120 |
|
127 | 121 | expect(result).toBeUndefined(); |
128 | 122 | }); |
129 | 123 |
|
130 | 124 | test("should handle arrays with tailwind-merge", () => { |
131 | | - const result = cnWithMerge(["px-2", "px-4"], "py-2")({twMerge: true}); |
| 125 | + const result = cn(["px-2", "px-4"], "py-2"); |
132 | 126 |
|
133 | 127 | expect(result).toBe("px-4 py-2"); |
134 | 128 | }); |
135 | 129 |
|
136 | 130 | test("should handle objects with tailwind-merge", () => { |
137 | | - const result = cnWithMerge({"px-2": true, "px-4": true, "py-2": true})({twMerge: true}); |
| 131 | + const result = cn({"px-2": true, "px-4": true, "py-2": true}); |
138 | 132 |
|
139 | 133 | expect(result).toBe("px-4 py-2"); |
140 | 134 | }); |
141 | 135 |
|
142 | | - test("should merge when config is undefined (default behavior)", () => { |
143 | | - const result = cnWithMerge("px-2", "px-4")({twMerge: true}); |
| 136 | + test("should handle complex className with conditional object classes", () => { |
| 137 | + const selectedZoom: string = "a"; |
| 138 | + const key: string = "b"; |
144 | 139 |
|
145 | | - expect(result).toBe("px-4"); |
| 140 | + const result = cn( |
| 141 | + "text-foreground ease-in-out-quad absolute left-1/2 top-1/2 origin-center -translate-x-1/2 -translate-y-1/2 scale-75 text-[21px] font-medium opacity-0 transition-[scale,opacity] duration-[300ms] ease-[cubic-bezier(0.33,1,0.68,1)] data-[selected=true]:scale-100 data-[selected=true]:opacity-100 data-[selected=true]:delay-200", |
| 142 | + { |
| 143 | + "sr-only": selectedZoom !== key, |
| 144 | + }, |
| 145 | + ); |
| 146 | + |
| 147 | + expect(result).toContain("text-foreground"); |
| 148 | + expect(result).toContain("sr-only"); |
| 149 | + expect(typeof result).toBe("string"); |
146 | 150 | }); |
147 | 151 |
|
148 | | - test("should merge classes by default when called directly without ()", () => { |
149 | | - const result = cnWithMerge("px-2", "px-4", "py-2"); |
| 152 | + test("should handle conditional object classes when condition is false", () => { |
| 153 | + const selectedZoom: string = "a"; |
| 154 | + const key: string = "a"; |
150 | 155 |
|
151 | | - // Should work as a string in template literals and string coercion |
152 | | - expect(String(result)).toBe("px-4 py-2"); |
153 | | - expect(`${result}`).toBe("px-4 py-2"); |
| 156 | + const result = cn("text-xl font-bold", { |
| 157 | + "sr-only": selectedZoom !== key, |
| 158 | + }); |
| 159 | + |
| 160 | + expect(result).toBe("text-xl font-bold"); |
| 161 | + expect(result).not.toContain("sr-only"); |
154 | 162 | }); |
| 163 | +}); |
155 | 164 |
|
156 | | - test("should merge classes by default when no config is provided", () => { |
157 | | - const result = cnWithMerge("px-2", "px-4", "py-2")(); |
| 165 | +describe("cnMerge function with tailwind-merge config", () => { |
| 166 | + test("should merge conflicting tailwind classes when twMerge is true", () => { |
| 167 | + const result = cnMerge("px-2", "px-4", "py-2")({twMerge: true}); |
158 | 168 |
|
159 | 169 | expect(result).toBe("px-4 py-2"); |
160 | 170 | }); |
161 | 171 |
|
162 | | - test("should merge text color classes by default when called directly", () => { |
163 | | - const result = cnWithMerge("text-red-500", "text-blue-500"); |
| 172 | + test("should not merge classes when twMerge is false", () => { |
| 173 | + const result = cnMerge("px-2", "px-4", "py-2")({twMerge: false}); |
164 | 174 |
|
165 | | - expect(String(result)).toBe("text-blue-500"); |
| 175 | + expect(result).toBe("px-2 px-4 py-2"); |
166 | 176 | }); |
167 | 177 |
|
168 | | - test("should merge text color classes by default when no config is provided", () => { |
169 | | - const result = cnWithMerge("text-red-500", "text-blue-500")(); |
| 178 | + test("should merge text color classes", () => { |
| 179 | + const result = cnMerge("text-red-500", "text-blue-500")({twMerge: true}); |
170 | 180 |
|
171 | 181 | expect(result).toBe("text-blue-500"); |
172 | 182 | }); |
173 | 183 |
|
174 | | - test("should merge background color classes by default when called directly", () => { |
175 | | - const result = cnWithMerge("bg-red-500", "bg-blue-500"); |
| 184 | + test("should merge background color classes", () => { |
| 185 | + const result = cnMerge("bg-red-500", "bg-blue-500")({twMerge: true}); |
176 | 186 |
|
177 | | - expect(String(result)).toBe("bg-blue-500"); |
| 187 | + expect(result).toBe("bg-blue-500"); |
178 | 188 | }); |
179 | 189 |
|
180 | | - test("should merge background color classes by default when no config is provided", () => { |
181 | | - const result = cnWithMerge("bg-red-500", "bg-blue-500")(); |
| 190 | + test("should merge multiple conflicting classes", () => { |
| 191 | + const result = cnMerge("px-2 py-1 text-sm", "px-4 py-2 text-lg")({twMerge: true}); |
182 | 192 |
|
183 | | - expect(result).toBe("bg-blue-500"); |
| 193 | + expect(result).toBe("px-4 py-2 text-lg"); |
184 | 194 | }); |
185 | 195 |
|
186 | | - test("should not merge classes when twMerge is explicitly false", () => { |
187 | | - const result = cnWithMerge("px-2", "px-4", "py-2")({twMerge: false}); |
| 196 | + test("should handle non-conflicting classes", () => { |
| 197 | + const result = cnMerge("px-2", "py-2", "text-sm")({twMerge: true}); |
188 | 198 |
|
189 | | - expect(result).toBe("px-2 px-4 py-2"); |
| 199 | + expect(result).toBe("px-2 py-2 text-sm"); |
190 | 200 | }); |
191 | 201 |
|
192 | | - test("should merge classes when twMerge is explicitly true (backward compatibility)", () => { |
193 | | - const result = cnWithMerge("px-2", "px-4", "py-2")({twMerge: true}); |
| 202 | + test("should return undefined when no classes provided", () => { |
| 203 | + const result = cnMerge()({twMerge: true}); |
| 204 | + |
| 205 | + expect(result).toBeUndefined(); |
| 206 | + }); |
| 207 | + |
| 208 | + test("should handle arrays with tailwind-merge", () => { |
| 209 | + const result = cnMerge(["px-2", "px-4"], "py-2")({twMerge: true}); |
194 | 210 |
|
195 | 211 | expect(result).toBe("px-4 py-2"); |
196 | 212 | }); |
197 | 213 |
|
198 | | - test("should merge classes when config is empty object (defaults to true)", () => { |
199 | | - const result = cnWithMerge("px-2", "px-4", "py-2")({}); |
| 214 | + test("should handle objects with tailwind-merge", () => { |
| 215 | + const result = cnMerge({"px-2": true, "px-4": true, "py-2": true})({twMerge: true}); |
| 216 | + |
| 217 | + expect(result).toBe("px-4 py-2"); |
| 218 | + }); |
| 219 | + |
| 220 | + test("should merge classes by default when no config is provided", () => { |
| 221 | + const result = cnMerge("px-2", "px-4", "py-2")(); |
200 | 222 |
|
201 | 223 | expect(result).toBe("px-4 py-2"); |
202 | 224 | }); |
203 | 225 |
|
204 | 226 | test("should merge classes when config is undefined", () => { |
205 | | - const result = cnWithMerge("px-2", "px-4", "py-2")(undefined); |
| 227 | + const result = cnMerge("px-2", "px-4", "py-2")(undefined); |
| 228 | + |
| 229 | + expect(result).toBe("px-4 py-2"); |
| 230 | + }); |
| 231 | + |
| 232 | + test("should merge classes when config is empty object (defaults to true)", () => { |
| 233 | + const result = cnMerge("px-2", "px-4", "py-2")({}); |
| 234 | + |
| 235 | + expect(result).toBe("px-4 py-2"); |
| 236 | + }); |
| 237 | + |
| 238 | + test("should not merge classes when twMerge is explicitly false", () => { |
| 239 | + const result = cnMerge("px-2", "px-4", "py-2")({twMerge: false}); |
| 240 | + |
| 241 | + expect(result).toBe("px-2 px-4 py-2"); |
| 242 | + }); |
| 243 | + |
| 244 | + test("should merge classes when twMerge is explicitly true", () => { |
| 245 | + const result = cnMerge("px-2", "px-4", "py-2")({twMerge: true}); |
206 | 246 |
|
207 | 247 | expect(result).toBe("px-4 py-2"); |
208 | 248 | }); |
| 249 | + |
| 250 | + test("should handle complex className with conditional object classes", () => { |
| 251 | + const selectedZoom: string = "a"; |
| 252 | + const key: string = "b"; |
| 253 | + |
| 254 | + const result = cnMerge( |
| 255 | + "text-foreground ease-in-out-quad absolute left-1/2 top-1/2 origin-center -translate-x-1/2 -translate-y-1/2 scale-75 text-[21px] font-medium opacity-0 transition-[scale,opacity] duration-[300ms] ease-[cubic-bezier(0.33,1,0.68,1)] data-[selected=true]:scale-100 data-[selected=true]:opacity-100 data-[selected=true]:delay-200", |
| 256 | + { |
| 257 | + "sr-only": selectedZoom !== key, |
| 258 | + }, |
| 259 | + )(); |
| 260 | + |
| 261 | + expect(result).toContain("text-foreground"); |
| 262 | + expect(result).toContain("sr-only"); |
| 263 | + expect(typeof result).toBe("string"); |
| 264 | + }); |
209 | 265 | }); |
210 | 266 |
|
211 | 267 | describe.each(cxVariants)("cx function - $name", ({cx}) => { |
|
0 commit comments