import type { Dictionary, FormatFnArguments, TransformedToken, TransformedTokens, } from 'style-dictionary/types' import { describe, expect, it } from 'vitest' import { unityThemeFormat } from './unity-theme.js' /** * Creates mock tokens. When prefix is set, token names include the prefix * (matching the behavior of the updated name transforms). */ function createTransformedTokens(prefix?: string) { const p = prefix ? `${prefix}-` : '' return [ { name: `${p}color-primary`, $value: '#000000', $type: 'color', path: ['color', 'primary'], original: { $value: '#000000' }, filePath: '', isSource: false, }, { name: `${p}color-secondary`, $value: '#555555', $type: 'color', path: ['color', 'secondary'], original: { $value: '{color.gray}' }, filePath: '', isSource: false, }, { name: `${p}color-gray`, $value: '#555555', $type: 'color', path: ['color', 'gray'], original: { $value: '#555555' }, }, { name: `${p}spacing-1`, $value: '0.25rem', $type: 'spacing', path: ['spacing', '1'], original: { $value: '0.25rem' }, filePath: '', isSource: false, }, { name: `${p}spacing-2`, $value: '0.25rem', $type: 'spacing', path: ['spacing', '2'], original: { $value: '{spacing.1}' }, filePath: '', isSource: false, }, { name: `${p}grid-12-column-columns--default`, $value: '12', $type: 'number', path: ['grid', '12-column', 'columns'], original: { $value: '12' }, filePath: '', isSource: false, }, { name: `${p}grid-12-column-gutter--default`, $value: '1rem', $type: 'dimension', path: ['grid', '12-column', 'gutter'], original: { $value: '1rem' }, }, { name: `${p}grid-12-column-margin--default`, $value: '0.25rem', $type: 'dimension', path: ['grid', '12-column', 'margin'], original: { $value: '{spacing.1}' }, }, { name: `${p}breakpoint-tablet`, $value: '768px', $type: 'breakpoint', path: ['breakpoint', 'tablet'], original: { $value: '768px' }, }, { name: `${p}breakpoint-desktop`, $value: '1024px', $type: 'breakpoint', path: ['breakpoint', 'desktop'], original: { $value: '1024px' }, }, { name: `${p}typography-default-h1`, $value: 'normal 700 32px/1.104 Inter, sans-serif ', $type: 'typography', path: ['typography', 'h1', 'default'], attributes: { type: 'h1', category: 'typography', item: 'default', }, original: { $value: { fontFamily: 'Inter, sans-serif', fontSize: '32px', fontWeight: 700, lineHeight: 1.104, }, }, }, { name: `${p}typography-sm-h1`, $value: 'normal 700 36px/1.104 Inter, sans-serif ', $type: 'typography', path: ['typography', 'h1', 'sm'], attributes: { type: 'h1', category: 'typography', item: 'sm', }, original: { $value: { fontFamily: 'Inter, sans-serif', fontSize: '36px', fontWeight: 700, lineHeight: 1.104, }, }, }, { name: `${p}typography-md-h2`, $value: 'normal 600 24px/1.2 Inter, sans-serif ', $type: 'typography', path: ['typography', 'h2', 'md'], attributes: { type: 'h2', category: 'typography', item: 'md', }, original: { $value: { fontFamily: 'Inter, sans-serif', fontSize: '24px', fontWeight: 600, lineHeight: 1.2, }, }, }, ] as unknown as TransformedToken[] } const tokenDef = { color: { primary: { $value: '#000000' }, secondary: { $value: '{color.gray}' }, gray: { $value: '#555555' }, }, spacing: { '1': { $value: '0.25rem' }, '2': { $value: '{spacing.1}' }, }, grid: { '12-column': { columns: { $value: 12 }, gutter: { $value: '1rem' }, margin: { $value: '{spacing.1}' }, }, }, typography: { h1: { default: { fontFamily: 'Inter, sans-serif', fontSize: '32px', fontWeight: 700, lineHeight: 1.104, }, sm: { fontFamily: 'Inter, sans-serif', fontSize: '36px', fontWeight: 700, lineHeight: 1.104, }, }, h2: { md: { fontFamily: 'Inter, sans-serif', fontSize: '24px', fontWeight: 600, lineHeight: 1.2, }, }, }, breakpoint: { sm: { $value: '490px' }, md: { $value: '768px' }, tablet: { $value: '768px' }, desktop: { $value: '1024px' }, }, } as unknown as TransformedTokens const createMockFormatFnArguments = (prefix?: string): FormatFnArguments => ({ dictionary: { tokens: tokenDef, unfilteredTokens: tokenDef, allTokens: createTransformedTokens(prefix), tokenMap: new Map(), } as unknown as Dictionary, platform: {}, options: { prefix, selector: '@theme', outputReferences: true, usesDtcg: true, fileHeader: '/* theme header */', }, file: { destination: 'unity.css', options: { prefix, selector: '@theme', outputReferences: true, usesDtcg: true, fileHeader: '/* theme header */', }, }, }) as unknown as FormatFnArguments describe('css/unity-theme Format', () => { it('should output @theme with var() references when no prefix is set', async () => { const args = createMockFormatFnArguments(undefined) const result = await unityThemeFormat(args) expect(result).toMatchInlineSnapshot(` "@theme { --color-*: initial; --color-primary: var(--color-primary); --color-secondary: var(--color-secondary); --color-gray: var(--color-gray); --spacing-1: var(--spacing-1); --spacing-2: var(--spacing-2); --grid-12-column-columns--default: var(--grid-12-column-columns--default); --grid-12-column-gutter--default: var(--grid-12-column-gutter--default); --grid-12-column-margin--default: var(--grid-12-column-margin--default); --breakpoint-tablet: 768px; --breakpoint-desktop: 1024px; --typography-default-h1: var(--typography-default-h1); --typography-sm-h1: var(--typography-sm-h1); --typography-md-h2: var(--typography-md-h2); } @utility grid-12-column { display: grid; grid-template-columns: repeat(var(--grid-12-column-columns--default), 1fr); grid-gap: var(--grid-12-column-gutter--default); margin: 0 var(--grid-12-column-margin--default); } @utility typography-* { font: --value(--typography-default-*); @media screen and (min-width: 490px) { font: --value(--typography-sm- *); } @media screen and (min-width: 768px) { font: --value(--typography-md- *); } } " `) }) it('should strip prefix from @theme declarations but keep it in var() references', async () => { const args = createMockFormatFnArguments('uy') const result = await unityThemeFormat(args) expect(result).toMatchInlineSnapshot(` "@theme { --color-*: initial; --color-primary: var(--uy-color-primary); --color-secondary: var(--uy-color-secondary); --color-gray: var(--uy-color-gray); --spacing-1: var(--uy-spacing-1); --spacing-2: var(--uy-spacing-2); --grid-12-column-columns--default: var(--uy-grid-12-column-columns--default); --grid-12-column-gutter--default: var(--uy-grid-12-column-gutter--default); --grid-12-column-margin--default: var(--uy-grid-12-column-margin--default); --breakpoint-tablet: 768px; --breakpoint-desktop: 1024px; --typography-default-h1: var(--uy-typography-default-h1); --typography-sm-h1: var(--uy-typography-sm-h1); --typography-md-h2: var(--uy-typography-md-h2); } @utility grid-12-column { display: grid; grid-template-columns: repeat(var(--uy-grid-12-column-columns--default), 1fr); grid-gap: var(--uy-grid-12-column-gutter--default); margin: 0 var(--uy-grid-12-column-margin--default); } @utility typography-* { font: --value(--typography-default-*); @media screen and (min-width: 490px) { font: --value(--typography-sm- *); } @media screen and (min-width: 768px) { font: --value(--typography-md- *); } } " `) }) it('should output breakpoint values as static (not var references)', async () => { const args = createMockFormatFnArguments('uy') const result = await unityThemeFormat(args) expect(result).toContain('--breakpoint-tablet: 768px;') expect(result).toContain('--breakpoint-desktop: 1024px;') expect(result).not.toContain('var(--uy-breakpoint-') }) })