11import { expect , describe , test } from "@jest/globals" ;
22
3- import { cnBase as cnFull } from "../index" ;
4- import { cn as cnLite } from "../lite" ;
5- import { cn as cnUtils } from "../utils" ;
6-
7- const variants = [
8- { name : "full - tailwind-merge " , cn : cnFull } ,
9- { name : "lite - without tailwind-merge " , cn : cnLite } ,
10- { name : "utils - without tailwind-merge " , cn : cnUtils } ,
3+ import { cn as cnWithMerge , cx as cxFull } from "../index" ;
4+ import { cn as cnLite , cx as cxLite } from "../lite" ;
5+ import { cx as cxUtils } from "../utils" ;
6+
7+ const cxVariants = [
8+ { name : "main index " , cx : cxFull } ,
9+ { name : "lite" , cx : cxLite } ,
10+ { name : "utils" , cx : cxUtils } ,
1111] ;
1212
13- describe . each ( variants ) ( "cn function - $name" , ( { cn} ) => {
13+ describe ( "cn function from lite (simple concatenation)" , ( ) => {
14+ test ( "should join strings and ignore falsy values" , ( ) => {
15+ expect ( cnLite ( "text-xl" , false && "font-bold" , "text-center" ) ( ) ) . toBe ( "text-xl text-center" ) ;
16+ expect ( cnLite ( "text-xl" , undefined , null , 0 , "" ) ( ) ) . toBe ( "text-xl 0" ) ;
17+ } ) ;
18+
19+ test ( "should join arrays of class names" , ( ) => {
20+ expect ( cnLite ( [ "px-4" , "py-2" ] , "bg-blue-500" ) ( ) ) . toBe ( "px-4 py-2 bg-blue-500" ) ;
21+ expect ( cnLite ( [ "px-4" , false , [ "hover:bg-red-500" , null , "rounded-lg" ] ] ) ( ) ) . toBe (
22+ "px-4 hover:bg-red-500 rounded-lg" ,
23+ ) ;
24+ } ) ;
25+
26+ test ( "should handle nested arrays" , ( ) => {
27+ expect ( cnLite ( [ "px-4" , [ "py-2" , [ "bg-blue-500" , [ "rounded-lg" , false , [ "shadow-md" ] ] ] ] ] ) ( ) ) . toBe (
28+ "px-4 py-2 bg-blue-500 rounded-lg shadow-md" ,
29+ ) ;
30+ } ) ;
31+
32+ test ( "should join objects with truthy values as keys" , ( ) => {
33+ expect ( cnLite ( { "text-sm" : true , "font-bold" : false , "bg-green-200" : 1 , "m-0" : 0 } ) ( ) ) . toBe (
34+ "text-sm bg-green-200" ,
35+ ) ;
36+ } ) ;
37+
38+ test ( "should handle mixed arguments correctly" , ( ) => {
39+ expect (
40+ cnLite (
41+ "text-lg" ,
42+ [ "px-3" , { "hover:bg-yellow-300" : true , "focus:outline-none" : false } ] ,
43+ { "rounded-md" : true , "shadow-md" : null } ,
44+ "leading-tight" ,
45+ ) ( ) ,
46+ ) . toBe ( "text-lg px-3 hover:bg-yellow-300 rounded-md leading-tight" ) ;
47+ } ) ;
48+
49+ test ( "should handle numbers and bigint" , ( ) => {
50+ expect ( cnLite ( 123 , "text-base" , 0n , { border : true } ) ( ) ) . toBe ( "123 text-base 0 border" ) ;
51+ } ) ;
52+
53+ test ( "should return undefined for no input" , ( ) => {
54+ expect ( cnLite ( ) ( ) ) . toBeUndefined ( ) ;
55+ } ) ;
56+
57+ test ( "should return '0' for zero and ignore other falsy" , ( ) => {
58+ expect ( cnLite ( false , null , undefined , "" , 0 ) ( ) ) . toBe ( "0" ) ;
59+ } ) ;
60+
61+ test ( "should normalize template strings with irregular whitespace" , ( ) => {
62+ const input = `
63+ px-4
64+ py-2
65+
66+ bg-blue-500
67+ rounded-lg
68+ ` ;
69+
70+ expect ( cnLite ( input ) ( ) ) . toBe ( "px-4 py-2 bg-blue-500 rounded-lg" ) ;
71+
72+ expect (
73+ cnLite (
74+ ` text-center
75+ font-semibold ` ,
76+ [ "text-sm" , ` uppercase ` ] ,
77+ { "shadow-lg" : true , "opacity-50" : false } ,
78+ ) ( ) ,
79+ ) . toBe ( "text-center font-semibold text-sm uppercase shadow-lg" ) ;
80+ } ) ;
81+
82+ test ( "should handle empty and falsy values correctly" , ( ) => {
83+ expect ( cnLite ( "" , null , undefined , false , NaN , 0 , "0" ) ( ) ) . toBe ( "0 0" ) ;
84+ } ) ;
85+ } ) ;
86+
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 } ) ;
90+
91+ expect ( result ) . toBe ( "px-4 py-2" ) ;
92+ } ) ;
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 } ) ;
102+
103+ expect ( result ) . toBe ( "text-blue-500" ) ;
104+ } ) ;
105+
106+ test ( "should merge background color classes" , ( ) => {
107+ const result = cnWithMerge ( "bg-red-500" , "bg-blue-500" ) ( { twMerge : true } ) ;
108+
109+ expect ( result ) . toBe ( "bg-blue-500" ) ;
110+ } ) ;
111+
112+ test ( "should merge multiple conflicting classes" , ( ) => {
113+ const result = cnWithMerge ( "px-2 py-1 text-sm" , "px-4 py-2 text-lg" ) ( { twMerge : true } ) ;
114+
115+ expect ( result ) . toBe ( "px-4 py-2 text-lg" ) ;
116+ } ) ;
117+
118+ test ( "should handle non-conflicting classes" , ( ) => {
119+ const result = cnWithMerge ( "px-2" , "py-2" , "text-sm" ) ( { twMerge : true } ) ;
120+
121+ expect ( result ) . toBe ( "px-2 py-2 text-sm" ) ;
122+ } ) ;
123+
124+ test ( "should return undefined when no classes provided" , ( ) => {
125+ const result = cnWithMerge ( ) ( { twMerge : true } ) ;
126+
127+ expect ( result ) . toBeUndefined ( ) ;
128+ } ) ;
129+
130+ test ( "should handle arrays with tailwind-merge" , ( ) => {
131+ const result = cnWithMerge ( [ "px-2" , "px-4" ] , "py-2" ) ( { twMerge : true } ) ;
132+
133+ expect ( result ) . toBe ( "px-4 py-2" ) ;
134+ } ) ;
135+
136+ test ( "should handle objects with tailwind-merge" , ( ) => {
137+ const result = cnWithMerge ( { "px-2" : true , "px-4" : true , "py-2" : true } ) ( { twMerge : true } ) ;
138+
139+ expect ( result ) . toBe ( "px-4 py-2" ) ;
140+ } ) ;
141+
142+ test ( "should merge when config is undefined (default behavior)" , ( ) => {
143+ const result = cnWithMerge ( "px-2" , "px-4" ) ( { twMerge : true } ) ;
144+
145+ expect ( result ) . toBe ( "px-4" ) ;
146+ } ) ;
147+ } ) ;
148+
149+ describe . each ( cxVariants ) ( "cx function - $name" , ( { cx} ) => {
14150 test ( "should join strings and ignore falsy values" , ( ) => {
15- expect ( cn ( "text-xl" , false && "font-bold" , "text-center" ) ) . toBe ( "text-xl text-center" ) ;
16- expect ( cn ( "text-xl" , undefined , null , 0 , "" ) ) . toBe ( "text-xl 0" ) ;
151+ expect ( cx ( "text-xl" , false && "font-bold" , "text-center" ) ) . toBe ( "text-xl text-center" ) ;
152+ expect ( cx ( "text-xl" , undefined , null , 0 , "" ) ) . toBe ( "text-xl 0" ) ;
17153 } ) ;
18154
19155 test ( "should join arrays of class names" , ( ) => {
20- expect ( cn ( [ "px-4" , "py-2" ] , "bg-blue-500" ) ) . toBe ( "px-4 py-2 bg-blue-500" ) ;
21- expect ( cn ( [ "px-4" , false , [ "hover:bg-red-500" , null , "rounded-lg" ] ] ) ) . toBe (
156+ expect ( cx ( [ "px-4" , "py-2" ] , "bg-blue-500" ) ) . toBe ( "px-4 py-2 bg-blue-500" ) ;
157+ expect ( cx ( [ "px-4" , false , [ "hover:bg-red-500" , null , "rounded-lg" ] ] ) ) . toBe (
22158 "px-4 hover:bg-red-500 rounded-lg" ,
23159 ) ;
24160 } ) ;
25161
26162 test ( "should handle nested arrays" , ( ) => {
27- expect ( cn ( [ "px-4" , [ "py-2" , [ "bg-blue-500" , [ "rounded-lg" , false , [ "shadow-md" ] ] ] ] ] ) ) . toBe (
163+ expect ( cx ( [ "px-4" , [ "py-2" , [ "bg-blue-500" , [ "rounded-lg" , false , [ "shadow-md" ] ] ] ] ] ) ) . toBe (
28164 "px-4 py-2 bg-blue-500 rounded-lg shadow-md" ,
29165 ) ;
30166 } ) ;
31167
32168 test ( "should join objects with truthy values as keys" , ( ) => {
33- expect ( cn ( { "text-sm" : true , "font-bold" : false , "bg-green-200" : 1 , "m-0" : 0 } ) ) . toBe (
169+ expect ( cx ( { "text-sm" : true , "font-bold" : false , "bg-green-200" : 1 , "m-0" : 0 } ) ) . toBe (
34170 "text-sm bg-green-200" ,
35171 ) ;
36172 } ) ;
37173
38174 test ( "should handle mixed arguments correctly" , ( ) => {
39175 expect (
40- cn (
176+ cx (
41177 "text-lg" ,
42178 [ "px-3" , { "hover:bg-yellow-300" : true , "focus:outline-none" : false } ] ,
43179 { "rounded-md" : true , "shadow-md" : null } ,
@@ -47,15 +183,15 @@ describe.each(variants)("cn function - $name", ({cn}) => {
47183 } ) ;
48184
49185 test ( "should handle numbers and bigint" , ( ) => {
50- expect ( cn ( 123 , "text-base" , 0n , { border : true } ) ) . toBe ( "123 text-base 0 border" ) ;
186+ expect ( cx ( 123 , "text-base" , 0n , { border : true } ) ) . toBe ( "123 text-base 0 border" ) ;
51187 } ) ;
52188
53189 test ( "should return undefined for no input" , ( ) => {
54- expect ( cn ( ) ) . toBeUndefined ( ) ;
190+ expect ( cx ( ) ) . toBeUndefined ( ) ;
55191 } ) ;
56192
57193 test ( "should return '0' for zero and ignore other falsy" , ( ) => {
58- expect ( cn ( false , null , undefined , "" , 0 ) ) . toBe ( "0" ) ;
194+ expect ( cx ( false , null , undefined , "" , 0 ) ) . toBe ( "0" ) ;
59195 } ) ;
60196
61197 test ( "should normalize template strings with irregular whitespace" , ( ) => {
@@ -67,10 +203,10 @@ describe.each(variants)("cn function - $name", ({cn}) => {
67203 rounded-lg
68204 ` ;
69205
70- expect ( cn ( input ) ) . toBe ( "px-4 py-2 bg-blue-500 rounded-lg" ) ;
206+ expect ( cx ( input ) ) . toBe ( "px-4 py-2 bg-blue-500 rounded-lg" ) ;
71207
72208 expect (
73- cn (
209+ cx (
74210 ` text-center
75211 font-semibold ` ,
76212 [ "text-sm" , ` uppercase ` ] ,
@@ -80,6 +216,15 @@ describe.each(variants)("cn function - $name", ({cn}) => {
80216 } ) ;
81217
82218 test ( "should handle empty and falsy values correctly" , ( ) => {
83- expect ( cn ( "" , null , undefined , false , NaN , 0 , "0" ) ) . toBe ( "0 0" ) ;
219+ expect ( cx ( "" , null , undefined , false , NaN , 0 , "0" ) ) . toBe ( "0 0" ) ;
220+ } ) ;
221+
222+ test ( "should NOT merge conflicting classes (simple concatenation)" , ( ) => {
223+ // cx should just concatenate, not merge
224+ expect ( cx ( "px-2" , "px-4" , "py-2" ) ) . toBe ( "px-2 px-4 py-2" ) ;
225+ } ) ;
226+
227+ test ( "should handle conflicting classes without merging" , ( ) => {
228+ expect ( cx ( "text-red-500" , "text-blue-500" ) ) . toBe ( "text-red-500 text-blue-500" ) ;
84229 } ) ;
85230} ) ;
0 commit comments