import { describe, expect, it } from 'vitest' import { uyMerge } from './tailwind-merge' describe('uyMerge', () => { describe('Basic functionality', () => { it('should merge basic class strings', () => { const result = uyMerge('uy:p-4', 'uy:m-2') expect(result).toBe('uy:p-4 uy:m-2') }) it('should handle conflicting classes with last one winning', () => { const result = uyMerge('uy:p-4', 'uy:p-8') expect(result).toBe('uy:p-8') }) it('should merge Unity classes with Tailwind classes', () => { const result = uyMerge('uy:p-4', 'p-500', 'uy:text-100', 'p-600') expect(result).toBe('uy:p-4 p-500 uy:text-100 p-600') }) it('should handle multiple class types without conflicts', () => { const result = uyMerge( 'uy:p-100 uy:bg-red', 'uy:m-200 uy:m-100 uy:p-100', 'uy:rounded-100 uy:m-50', 'uy:bg-primary-500', ) expect(result).toBe('uy:p-100 uy:rounded-100 uy:m-50 uy:bg-primary-500') }) it('should resolve conflicts in complex scenarios', () => { const result = uyMerge( 'uy:p-100 uy:m-50 uy:text-primary-500', 'uy:p-200 uy:bg-secondary-100', 'uy:m-100 uy:bg-primary-500', 'uy:md:p-100', 'uy:md:p-300', ) expect(result).toBe( 'uy:text-primary-500 uy:p-200 uy:m-100 uy:bg-primary-500 uy:md:p-300', ) }) it('should handle conflicting responsive classes', () => { const result = uyMerge('uy:sm:p-100', 'uy:sm:p-200') expect(result).toBe('uy:sm:p-200') }) it('should handle hover and focus variants', () => { const result = uyMerge( 'uy:bg-primary-500', 'uy:hover:bg-primary-600', 'uy:focus:bg-primary-700', ) expect(result).toBe( 'uy:bg-primary-500 uy:hover:bg-primary-600 uy:focus:bg-primary-700', ) }) }) describe('Unity Colors', () => { describe('Primitive colors', () => { it('should merge conflicting primitive background colors', () => { const result = uyMerge('uy:bg-grayscale-l0', 'uy:bg-red-l5') expect(result).toBe('uy:bg-red-l5') }) it('should merge conflicting primitive text colors', () => { const result = uyMerge('uy:text-blue-l10', 'uy:text-green-l3') expect(result).toBe('uy:text-green-l3') }) it('should merge conflicting primitive border colors', () => { const result = uyMerge('uy:border-yellow-l6', 'uy:border-purple-l8') expect(result).toBe('uy:border-purple-l8') }) it('should handle all primitive color utilities', () => { const result = uyMerge( 'uy:bg-red-l1 uy:text-blue-l2 uy:border-green-l3', 'uy:outline-yellow-l4 uy:ring-purple-l5 uy:divide-cyan-l6', 'uy:decoration-plum-l7 uy:from-orange-l8 uy:via-teal-l9 uy:to-grayscale-l10', ) expect(result).toBe( 'uy:bg-red-l1 uy:text-blue-l2 uy:border-green-l3 uy:outline-yellow-l4 uy:ring-purple-l5 uy:divide-cyan-l6 uy:decoration-plum-l7 uy:from-orange-l8 uy:via-teal-l9 uy:to-grayscale-l10', ) }) }) describe('Semantic colors', () => { it('should merge conflicting surface colors', () => { const result = uyMerge( 'uy:bg-surface-primary-default', 'uy:bg-surface-danger-low', ) expect(result).toBe('uy:bg-surface-danger-low') }) it('should merge conflicting content colors', () => { const result = uyMerge( 'uy:text-content-neutral-default-default', 'uy:text-content-primary-high', ) expect(result).toBe('uy:text-content-primary-high') }) it('should merge conflicting border colors', () => { const result = uyMerge( 'uy:border-border-form-enabled', 'uy:border-border-danger-default', ) expect(result).toBe('uy:border-border-danger-default') }) it('should handle complex semantic color names', () => { const result = uyMerge( 'uy:bg-surface-primary-default-default', 'uy:bg-surface-primary-default-hover', 'uy:bg-surface-primary-default-pressed', ) expect(result).toBe('uy:bg-surface-primary-default-pressed') }) it('should handle utility colors', () => { const result = uyMerge( 'uy:ring-utility-focus-ring', 'uy:ring-utility-inverted-focus-ring', ) expect(result).toBe('uy:ring-utility-inverted-focus-ring') }) it('should handle canvas colors', () => { const result = uyMerge( 'uy:bg-canvas-default', 'uy:bg-surface-primary-default', ) expect(result).toBe('uy:bg-surface-primary-default') }) }) describe('Mixed color types', () => { it('should merge primitive and semantic colors', () => { const result = uyMerge( 'uy:bg-grayscale-l0', 'uy:bg-surface-primary-default', ) expect(result).toBe('uy:bg-surface-primary-default') }) it('should handle different color utilities without conflicts', () => { const result = uyMerge( 'uy:bg-surface-primary-default', 'uy:text-content-neutral-low', 'uy:border-border-form-enabled', ) expect(result).toBe( 'uy:bg-surface-primary-default uy:text-content-neutral-low uy:border-border-form-enabled', ) }) }) }) describe('Unity Spacing', () => { it('should merge conflicting padding values', () => { const result = uyMerge('uy:p-100', 'uy:p-200') expect(result).toBe('uy:p-200') }) it('should merge conflicting margin values', () => { const result = uyMerge('uy:m-50', 'uy:m-300') expect(result).toBe('uy:m-300') }) it('should handle directional spacing conflicts', () => { const result = uyMerge('uy:px-100 uy:py-200', 'uy:p-300') expect(result).toBe('uy:p-300') }) it('should handle specific directional spacing', () => { const result = uyMerge('uy:p-100', 'uy:px-200', 'uy:pt-300') expect(result).toBe('uy:p-100 uy:px-200 uy:pt-300') }) it('should merge gap values', () => { const result = uyMerge('uy:gap-100', 'uy:gap-200') expect(result).toBe('uy:gap-200') }) it('should handle gap directional values', () => { const result = uyMerge('uy:gap-100', 'uy:gap-x-200', 'uy:gap-y-300') expect(result).toBe('uy:gap-100 uy:gap-x-200 uy:gap-y-300') }) it('should handle space-between values', () => { const result = uyMerge('uy:space-x-100', 'uy:space-x-200') expect(result).toBe('uy:space-x-200') }) it('should handle scroll spacing', () => { const result = uyMerge('uy:scroll-p-100', 'uy:scroll-p-200') expect(result).toBe('uy:scroll-p-200') }) it('should handle all Unity spacing values', () => { const spacingValues = [ '0', '25', '50', '75', '100', '125', '150', '200', '250', '300', '400', '500', '600', '800', '1000', ] spacingValues.forEach(value => { const result = uyMerge('uy:p-100', `uy:p-${value}`) expect(result).toBe(`uy:p-${value}`) }) }) }) describe('Unity Typography', () => { it('should merge conflicting typography classes', () => { const result = uyMerge('uy:typography-h1', 'uy:typography-body') expect(result).toBe('uy:typography-body') }) it('should handle all typography variants', () => { const typographyClasses = [ 'display-heading', 'h1', 'h2', 'h3', 'h4', 'overline', 'subtitle', 'display-title', 'display-body', 'body', 'body-strong', 'body-small', 'body-small-strong', 'body-large', 'body-large-strong', 'action', 'action-small', 'action-large', ] typographyClasses.forEach(variant => { const result = uyMerge('uy:typography-body', `uy:typography-${variant}`) expect(result).toBe(`uy:typography-${variant}`) }) }) it('should merge font size classes', () => { const result = uyMerge('uy:text-100', 'uy:text-400') expect(result).toBe('uy:text-400') }) it('should handle all Unity font sizes', () => { const fontSizes = [ '50', '75', '100', '200', '300', '400', '500', '600', '800', '1000', '1200', '1400', '1600', ] fontSizes.forEach(size => { const result = uyMerge('uy:text-100', `uy:text-${size}`) expect(result).toBe(`uy:text-${size}`) }) }) }) describe('Unity Border Radius', () => { it('should merge conflicting border radius values', () => { const result = uyMerge('uy:rounded-100', 'uy:rounded-200') expect(result).toBe('uy:rounded-200') }) it('should handle semantic border radius values', () => { const result = uyMerge('uy:rounded-sm', 'uy:rounded-lg') expect(result).toBe('uy:rounded-lg') }) it('should handle special border radius values', () => { const result = uyMerge('uy:rounded-100', 'uy:rounded-circle') expect(result).toBe('uy:rounded-circle') }) it('should handle directional border radius', () => { const result = uyMerge( 'uy:rounded-100', 'uy:rounded-t-200', 'uy:rounded-br-300', ) expect(result).toBe('uy:rounded-100 uy:rounded-t-200 uy:rounded-br-300') }) it('should merge conflicting directional border radius', () => { const result = uyMerge('uy:rounded-t-100', 'uy:rounded-t-200') expect(result).toBe('uy:rounded-t-200') }) it('should handle all Unity border radius values', () => { const radiusValues = [ '0', '25', '50', '75', '100', '125', '150', '200', '300', '400', 'xs', 'sm', 'md', 'lg', 'xl', 'circle', 'pill', ] radiusValues.forEach(value => { const result = uyMerge('uy:rounded-100', `uy:rounded-${value}`) expect(result).toBe(`uy:rounded-${value}`) }) }) }) describe('Unity Shadows', () => { it('should merge conflicting shadow values', () => { const result = uyMerge('uy:shadow-raising', 'uy:shadow-floating') expect(result).toBe('uy:shadow-floating') }) it('should handle all Unity shadow values', () => { const shadowValues = [ 'canvas', 'raising', 'floating', 'flying', 'soaring', ] shadowValues.forEach(value => { const result = uyMerge('uy:shadow-raising', `uy:shadow-${value}`) expect(result).toBe(`uy:shadow-${value}`) }) }) }) describe('Responsive and State Variants', () => { it('should handle responsive variants with Unity classes', () => { const result = uyMerge( 'uy:bg-surface-primary-default', 'uy:md:bg-surface-secondary-default', 'uy:lg:bg-surface-danger-default', ) expect(result).toBe( 'uy:bg-surface-primary-default uy:md:bg-surface-secondary-default uy:lg:bg-surface-danger-default', ) }) it('should merge conflicting responsive variants', () => { const result = uyMerge('uy:md:p-100', 'uy:md:p-200') expect(result).toBe('uy:md:p-200') }) it('should handle state variants with Unity colors', () => { const result = uyMerge( 'uy:bg-surface-primary-default', 'uy:hover:bg-surface-primary-hover', 'uy:focus:bg-surface-primary-focus', ) expect(result).toBe( 'uy:bg-surface-primary-default uy:hover:bg-surface-primary-hover uy:focus:bg-surface-primary-focus', ) }) it('should merge conflicting state variants', () => { const result = uyMerge( 'uy:hover:bg-surface-primary-default', 'uy:hover:bg-surface-danger-default', ) expect(result).toBe('uy:hover:bg-surface-danger-default') }) }) describe('Edge Cases and Complex Scenarios', () => { it('should handle empty strings', () => { const result = uyMerge('', 'uy:p-100', '') expect(result).toBe('uy:p-100') }) it('should handle undefined values', () => { const result = uyMerge('uy:p-100', undefined, 'uy:m-200') expect(result).toBe('uy:p-100 uy:m-200') }) it('should handle complex real-world scenario', () => { const result = uyMerge( // Base styles 'uy:bg-surface-neutral-default-default uy:text-content-neutral-default-default uy:p-200 uy:rounded-100', // Conditional styles 'uy:bg-surface-primary-default uy:text-content-inverted-default', // Responsive styles 'uy:md:p-300 uy:lg:p-400', // State styles 'uy:hover:bg-surface-primary-hover uy:focus:bg-surface-primary-focus', // Override styles 'uy:shadow-floating uy:border-border-primary-default', ) expect(result).toBe( 'uy:p-200 uy:rounded-100 uy:bg-surface-primary-default uy:text-content-inverted-default uy:md:p-300 uy:lg:p-400 uy:hover:bg-surface-primary-hover uy:focus:bg-surface-primary-focus uy:shadow-floating uy:border-border-primary-default', ) }) it('should preserve non-Unity classes', () => { const result = uyMerge( 'flex items-center justify-center', 'uy:bg-surface-primary-default uy:p-200', 'absolute top-0 left-0', ) expect(result).toBe( 'flex items-center justify-center uy:bg-surface-primary-default uy:p-200 absolute top-0 left-0', ) }) it('should handle mixed Unity and Tailwind conflicts correctly', () => { const result = uyMerge( 'p-4 uy:p-100', // Different systems, should not conflict 'bg-red-500 uy:bg-surface-primary-default', // Different systems, should not conflict 'uy:p-200', // Unity conflict, should override Unity ) expect(result).toBe( 'p-4 bg-red-500 uy:bg-surface-primary-default uy:p-200', ) }) }) })