use `lightningcss` and `prettier` for `toMatchFormattedCss`
Lightning CSS applies some optimizations and prettier ensures that the
output is always formatted in the same way.
In a future version, we will be using Lightning CSS to apply
optimizations like handling the nesting, optimizing selectors, sorting
declarations, simplifying colors and so on.
To guarantee that we have the same output in both the normal version and
OXIDE version, we can apply lightningcss in our tests so that it always
produces correct results in both version with the same optimizations
applied.
This also aliases `toMatchCss` to `toMatchFormattedCss` so that we can
guarantee the same output. This has a small caveat where `lightningcss`
is pretty strict. It will complain about `@media screen(md) {}` for
example. This is correct because it is not valid CSS, but we eventually
take care of it.
In this case, we will catch the error and use prettier instead (since
this should only happen in tests that doesn't use end-to-end tests, but
uses a more specialized test instead). If prettier still finds an error,
we will ensure to throw the original error.
Eventually, all the "lower" level tests, should probably become higher
level end-to-end tests. But let's do everything step by step!
690 lines
18 KiB
JavaScript
690 lines
18 KiB
JavaScript
import fs from 'fs'
|
|
import path from 'path'
|
|
|
|
import { html, run, css, defaults } from './util/run'
|
|
|
|
test('basic usage', () => {
|
|
let config = {
|
|
content: [path.resolve(__dirname, './basic-usage.test.html')],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
let expectedPath = path.resolve(__dirname, './basic-usage.test.css')
|
|
let expected = fs.readFileSync(expectedPath, 'utf8')
|
|
|
|
expect(result.css).toMatchFormattedCss(expected)
|
|
})
|
|
})
|
|
|
|
test('all plugins are executed that match a candidate', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="bg-green-light bg-green"></div>` }],
|
|
theme: {
|
|
colors: {
|
|
green: {
|
|
light: 'green',
|
|
},
|
|
},
|
|
},
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
|
|
.bg-green {
|
|
/* Empty on purpose */
|
|
}
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
.bg-green-light {
|
|
--tw-bg-opacity: 1;
|
|
background-color: rgb(0 128 0 / var(--tw-bg-opacity));
|
|
}
|
|
|
|
.bg-green {
|
|
/* Empty on purpose */
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
test('per-plugin colors with the same key can differ when using a custom colors object', () => {
|
|
let config = {
|
|
content: [
|
|
{
|
|
raw: html`
|
|
<div class="bg-theme text-theme">This should be green text on red background.</div>
|
|
`,
|
|
},
|
|
],
|
|
theme: {
|
|
// colors & theme MUST be plain objects
|
|
// If they're functions here the test passes regardless
|
|
colors: {
|
|
theme: {
|
|
bg: 'red',
|
|
text: 'green',
|
|
},
|
|
},
|
|
extend: {
|
|
textColor: {
|
|
theme: {
|
|
DEFAULT: 'green',
|
|
},
|
|
},
|
|
backgroundColor: {
|
|
theme: {
|
|
DEFAULT: 'red',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
.bg-theme {
|
|
--tw-bg-opacity: 1;
|
|
background-color: rgb(255 0 0 / var(--tw-bg-opacity));
|
|
}
|
|
.text-theme {
|
|
--tw-text-opacity: 1;
|
|
color: rgb(0 128 0 / var(--tw-text-opacity));
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
test('default ring color can be a function', () => {
|
|
function color(variable) {
|
|
return function ({ opacityVariable, opacityValue }) {
|
|
if (opacityValue !== undefined) {
|
|
return `rgba(${variable}, ${opacityValue})`
|
|
}
|
|
if (opacityVariable !== undefined) {
|
|
return `rgba(${variable}, var(${opacityVariable}, 1))`
|
|
}
|
|
return `rgb(${variable})`
|
|
}
|
|
}
|
|
|
|
let config = {
|
|
content: [
|
|
{
|
|
raw: html` <div class="ring"></div> `,
|
|
},
|
|
],
|
|
|
|
theme: {
|
|
extend: {
|
|
ringColor: {
|
|
DEFAULT: color('var(--red)'),
|
|
},
|
|
},
|
|
},
|
|
plugins: [],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: 'rgba(var(--red), 0.5)' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('falsy config values still work', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="inset-0"></div>` }],
|
|
theme: {
|
|
inset: {
|
|
0: 0,
|
|
},
|
|
},
|
|
plugins: [],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
.inset-0 {
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('shadows support values without a leading zero', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="shadow-one shadow-two"></div>` }],
|
|
theme: {
|
|
boxShadow: {
|
|
one: '0.5rem 0.5rem 0.5rem #0005',
|
|
two: '.5rem .5rem .5rem #0005',
|
|
},
|
|
},
|
|
plugins: [],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
.shadow-one {
|
|
--tw-shadow: 0.5rem 0.5rem 0.5rem #0005;
|
|
--tw-shadow-colored: 0.5rem 0.5rem 0.5rem var(--tw-shadow-color);
|
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
|
|
var(--tw-shadow);
|
|
}
|
|
.shadow-two {
|
|
--tw-shadow: 0.5rem 0.5rem 0.5rem #0005;
|
|
--tw-shadow-colored: 0.5rem 0.5rem 0.5rem var(--tw-shadow-color);
|
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
|
|
var(--tw-shadow);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('can scan extremely long classes without crashing', () => {
|
|
let val = 'cols-' + '-a'.repeat(65536)
|
|
let config = {
|
|
content: [{ raw: html`<div class="${val}"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css``)
|
|
})
|
|
})
|
|
|
|
it('does not produce duplicate output when seeing variants preceding a wildcard (*)', () => {
|
|
let config = {
|
|
content: [{ raw: html`underline focus:*` }],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
|
|
* {
|
|
color: red;
|
|
}
|
|
|
|
.combined,
|
|
* {
|
|
text-align: center;
|
|
}
|
|
|
|
@layer base {
|
|
* {
|
|
color: blue;
|
|
}
|
|
|
|
.combined,
|
|
* {
|
|
color: red;
|
|
}
|
|
}
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
* {
|
|
color: blue;
|
|
}
|
|
|
|
.combined,
|
|
* {
|
|
color: red;
|
|
}
|
|
|
|
${defaults}
|
|
|
|
.underline {
|
|
text-decoration-line: underline;
|
|
}
|
|
|
|
* {
|
|
color: red;
|
|
}
|
|
|
|
.combined,
|
|
* {
|
|
text-align: center;
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('can parse box shadows with variables', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="shadow-lg"></div>` }],
|
|
theme: {
|
|
boxShadow: {
|
|
lg: 'var(--a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0)',
|
|
},
|
|
},
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
.shadow-lg {
|
|
--tw-shadow: var(--a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0);
|
|
--tw-shadow-colored: 0 35px 60px -15px var(--tw-shadow-color),
|
|
0 0 1px var(--tw-shadow-color);
|
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
|
|
var(--tw-shadow);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('should generate styles using :not(.unknown-class) even if `.unknown-class` does not exist', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div></div>` }],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind components;
|
|
|
|
@layer components {
|
|
div:not(.unknown-class) {
|
|
color: red;
|
|
}
|
|
}
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
div:not(.unknown-class) {
|
|
color: red;
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('supports multiple backgrounds as arbitrary values even if only some are quoted', () => {
|
|
let config = {
|
|
content: [
|
|
{
|
|
raw: html`<div
|
|
class="bg-[url('/images/one-two-three.png'),linear-gradient(to_right,_#eeeeee,_#000000)]"
|
|
></div>`,
|
|
},
|
|
],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
.bg-\[url\(\'\/images\/one-two-three\.png\'\)\,
|
|
linear-gradient\(to_right\,
|
|
_\#eeeeee\,
|
|
_\#000000\)\] {
|
|
background-image: url('/images/one-two-three.png'), linear-gradient(to right, #eee, #000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (1)', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="ring"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: 'rgb(59 130 246 / 0.5)' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (2)', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="ring"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
theme: {
|
|
ringOpacity: {
|
|
DEFAULT: 0.75,
|
|
},
|
|
},
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: 'rgb(59 130 246 / 0.75)' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (1)', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="ring"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
theme: {
|
|
ringColor: {
|
|
DEFAULT: '#ff7f7f',
|
|
},
|
|
},
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: 'rgb(255 127 127 / 0.5)' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (2)', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="ring"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
theme: {
|
|
ringColor: {
|
|
DEFAULT: '#ff7f7f00',
|
|
},
|
|
},
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: 'rgb(255 127 127 / 0.5)' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (1)', () => {
|
|
let config = {
|
|
future: { respectDefaultRingColorOpacity: true },
|
|
content: [{ raw: html`<div class="ring"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: '#3b82f67f' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (2)', () => {
|
|
let config = {
|
|
future: { respectDefaultRingColorOpacity: true },
|
|
content: [{ raw: html`<div class="ring"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
theme: {
|
|
ringOpacity: {
|
|
DEFAULT: 0.75,
|
|
},
|
|
},
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: '#3b82f67f' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (1)', () => {
|
|
let config = {
|
|
future: { respectDefaultRingColorOpacity: true },
|
|
content: [{ raw: html`<div class="ring"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
theme: {
|
|
ringColor: {
|
|
DEFAULT: '#ff7f7f',
|
|
},
|
|
},
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: '#ff7f7f' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (2)', () => {
|
|
let config = {
|
|
future: { respectDefaultRingColorOpacity: true },
|
|
content: [{ raw: html`<div class="ring"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
theme: {
|
|
ringColor: {
|
|
DEFAULT: '#ff7f7f00',
|
|
},
|
|
},
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind base;
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
${defaults({ defaultRingColor: '#ff7f7f00' })}
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('A bare ring-opacity utility is not supported when not using respectDefaultRingColorOpacity', () => {
|
|
let config = {
|
|
content: [{ raw: html`<div class="ring-opacity"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
theme: {
|
|
ringOpacity: {
|
|
DEFAULT: '0.33',
|
|
},
|
|
},
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css``)
|
|
})
|
|
})
|
|
|
|
it('A bare ring-opacity utility is supported when using respectDefaultRingColorOpacity', () => {
|
|
let config = {
|
|
future: { respectDefaultRingColorOpacity: true },
|
|
content: [{ raw: html`<div class="ring-opacity"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
theme: {
|
|
ringOpacity: {
|
|
DEFAULT: '0.33',
|
|
},
|
|
},
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
.ring-opacity {
|
|
--tw-ring-opacity: 0.33;
|
|
}
|
|
`)
|
|
})
|
|
})
|
|
|
|
it('Ring color utilities are generated when using respectDefaultRingColorOpacity', () => {
|
|
let config = {
|
|
future: { respectDefaultRingColorOpacity: true },
|
|
content: [{ raw: html`<div class="ring ring-blue-500"></div>` }],
|
|
corePlugins: { preflight: false },
|
|
}
|
|
|
|
let input = css`
|
|
@tailwind utilities;
|
|
`
|
|
|
|
return run(input, config).then((result) => {
|
|
expect(result.css).toMatchFormattedCss(css`
|
|
.ring {
|
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width)
|
|
var(--tw-ring-offset-color);
|
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width))
|
|
var(--tw-ring-color);
|
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
|
}
|
|
.ring-blue-500 {
|
|
--tw-ring-opacity: 1;
|
|
--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity));
|
|
}
|
|
`)
|
|
})
|
|
})
|