import fs from 'fs' import path from 'path' import * as sharedState from '../src/lib/sharedState' import { crosscheck, run, html, css, defaults } from './util/run' crosscheck(() => { test('important boolean', () => { let config = { important: true, darkMode: 'class', content: [ { raw: html`
`, }, ], corePlugins: { preflight: false }, plugins: [ function ({ addComponents, addUtilities }) { addComponents( { '.btn': { button: 'yes', }, }, { respectImportant: true } ) addComponents( { '@font-face': { 'font-family': 'Inter', }, '@page': { margin: '1cm', }, }, { respectImportant: true } ) addUtilities( { '.custom-util': { button: 'no', }, }, { respectImportant: false } ) }, ], } let input = css` @tailwind base; @tailwind components; @layer components { .custom-component { @apply font-bold; } .custom-important-component { @apply text-center !important; } } @tailwind utilities; ` return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` ${defaults} .container { width: 100%; } @media (min-width: 640px) { .container { max-width: 640px; } } @media (min-width: 768px) { .container { max-width: 768px; } } @media (min-width: 1024px) { .container { max-width: 1024px; } } @media (min-width: 1280px) { .container { max-width: 1280px; } } @media (min-width: 1536px) { .container { max-width: 1536px; } } .btn { button: yes !important; } @font-face { font-family: Inter; } @page { margin: 1cm; } .custom-component { font-weight: 700; } .custom-important-component { text-align: center !important; } @keyframes spin { to { transform: rotate(360deg); } } .animate-spin { animation: 1s linear infinite spin !important; } .font-bold { font-weight: 700 !important; } .custom-util { button: no; } .group:hover .group-hover\:focus-within\:text-left:focus-within { text-align: left !important; } :is([dir='rtl'] .rtl\:active\:text-center:active) { text-align: center !important; } @media (prefers-reduced-motion: no-preference) { .motion-safe\:hover\:text-center:hover { text-align: center !important; } } :is(.dark .dark\:focus\:text-left:focus) { text-align: left !important; } @media (min-width: 768px) { .md\:hover\:text-right:hover { text-align: right !important; } } `) }) }) // This is in a describe block so we can use `afterEach` :) describe('duplicate elision', () => { let filePath = path.resolve(__dirname, './important-boolean-duplicates.test.html') afterEach(async () => await fs.promises.unlink(filePath)) test('important rules are not duplicated when rebuilding', async () => { let config = { important: true, content: [filePath], } await fs.promises.writeFile( config.content[0], html`
` ) let input = css` @tailwind utilities; ` let result = await run(input, config) let allContexts = Array.from(sharedState.contextMap.values()) let context = allContexts[allContexts.length - 1] let ruleCacheSize1 = context.ruleCache.size expect(result.css).toMatchFormattedCss(css` .ml-2 { margin-left: 0.5rem !important; } .ml-4 { margin-left: 1rem !important; } `) await fs.promises.writeFile( config.content[0], html`
` ) result = await run(input, config) let ruleCacheSize2 = context.ruleCache.size expect(result.css).toMatchFormattedCss(css` .ml-2 { margin-left: 0.5rem !important; } .ml-4 { margin-left: 1rem !important; } .ml-6 { margin-left: 1.5rem !important; } `) // The rule cache was effectively doubling in size previously // because the rule cache was never de-duped // This ensures this behavior doesn't return expect(ruleCacheSize2 - ruleCacheSize1).toBeLessThan(10) }) }) })