* bump `lightningcss` * allow for non-standard selector combinators such as `::deep` * just use Prettier when comparing CSS results We were using 2 different engines where the stable one was not using Lightning CSS and the Oxide one was using Lightning CSS. To ensure that we didn't have to rewrite every single test expectation, the `toMatchFormattedCss` parsed both the actual and expected value using Lightning CSS (to make the result similar), then it used Prettier to make it... pretty. Right now we _only_ use Lightning CSS, which means that we can drop the additional lightningcss format step and just use Prettier on both the actual and expected values. Pretty also only prettifies the CSS, it doesn't rewrite it. E.g.: `@media (min-width: 768px)` will not be optimized to `@media (width >= 768px)`, that's something that Lightning CSS does for us. This will require some changes in our test output, but it will be consistent afterwards because there won't be hidden transformation steps anymore. Because up until now it could be that the actual result was `color: black` but the tests showed `color: #000` (because it is shorter). This change will reflect reality. * update tests based on previous commit * only use `toMatchFormattedCss` instead of `toMatchCss` They both do the exact same thing right now. While `toMatchCss` is shorter, `toMatchFormattedCss` makes a bit more sense since we are comparing the Prettier results. * update integration tests
250 lines
4.6 KiB
JavaScript
250 lines
4.6 KiB
JavaScript
import postcss from 'postcss'
|
|
import postcssNested from 'postcss-nested'
|
|
import plugin from '../../../src/postcss-plugins/nesting'
|
|
import { visitorSpyPlugin } from './plugins.js'
|
|
|
|
it('should be possible to load a custom nesting plugin', async () => {
|
|
let input = css`
|
|
.foo {
|
|
color: black;
|
|
@screen md {
|
|
color: blue;
|
|
}
|
|
}
|
|
`
|
|
|
|
expect(
|
|
await run(input, function (root) {
|
|
root.walkRules((rule) => {
|
|
rule.selector += '-modified'
|
|
})
|
|
})
|
|
).toMatchFormattedCss(css`
|
|
.foo-modified {
|
|
color: black;
|
|
@media screen(md) {
|
|
color: blue;
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
it('should be possible to load a custom nesting plugin by name (string) instead', async () => {
|
|
let input = css`
|
|
.foo {
|
|
color: black;
|
|
@screen md {
|
|
color: blue;
|
|
}
|
|
}
|
|
`
|
|
|
|
expect(await run(input, 'postcss-nested')).toMatchFormattedCss(css`
|
|
.foo {
|
|
color: black;
|
|
}
|
|
|
|
@media screen(md) {
|
|
.foo {
|
|
color: blue;
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
it('should default to the bundled postcss-nested plugin (no options)', async () => {
|
|
let input = css`
|
|
.foo {
|
|
color: black;
|
|
@screen md {
|
|
color: blue;
|
|
}
|
|
}
|
|
`
|
|
|
|
expect(await run(input)).toMatchFormattedCss(css`
|
|
.foo {
|
|
color: black;
|
|
}
|
|
|
|
@media screen(md) {
|
|
.foo {
|
|
color: blue;
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
it('should default to the bundled postcss-nested plugin (empty options)', async () => {
|
|
let input = css`
|
|
.foo {
|
|
color: black;
|
|
@screen md {
|
|
color: blue;
|
|
}
|
|
}
|
|
`
|
|
|
|
expect(await run(input, {})).toMatchFormattedCss(css`
|
|
.foo {
|
|
color: black;
|
|
}
|
|
|
|
@media screen(md) {
|
|
.foo {
|
|
color: blue;
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
it('should be possible to use postcss-nested plugin with options', async () => {
|
|
let input = css`
|
|
.foo {
|
|
color: black;
|
|
@screen md {
|
|
color: blue;
|
|
}
|
|
}
|
|
`
|
|
|
|
expect(await run(input, postcssNested({ noIsPseudoSelector: true }))).toMatchFormattedCss(css`
|
|
.foo {
|
|
color: black;
|
|
}
|
|
|
|
@media screen(md) {
|
|
.foo {
|
|
color: blue;
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('@screen rules are replaced with media queries', async () => {
|
|
let input = css`
|
|
.foo {
|
|
color: black;
|
|
@screen md {
|
|
color: blue;
|
|
}
|
|
}
|
|
`
|
|
|
|
expect(await run(input, postcssNested)).toMatchFormattedCss(css`
|
|
.foo {
|
|
color: black;
|
|
}
|
|
|
|
@media screen(md) {
|
|
.foo {
|
|
color: blue;
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('@screen rules can work with `@apply`', async () => {
|
|
let input = css`
|
|
.foo {
|
|
@apply bg-black;
|
|
@screen md {
|
|
@apply bg-blue-500;
|
|
}
|
|
}
|
|
`
|
|
|
|
expect(await run(input, postcssNested)).toMatchFormattedCss(css`
|
|
.foo {
|
|
@apply bg-black;
|
|
}
|
|
|
|
@media screen(md) {
|
|
.foo {
|
|
@apply bg-blue-500;
|
|
}
|
|
}
|
|
`)
|
|
})
|
|
|
|
test('nesting does not break downstream plugin visitors', async () => {
|
|
let input = css`
|
|
.foo {
|
|
color: black;
|
|
}
|
|
@supports (color: blue) {
|
|
.foo {
|
|
color: blue;
|
|
}
|
|
}
|
|
/* Comment */
|
|
`
|
|
|
|
let spyPlugin = visitorSpyPlugin()
|
|
|
|
let plugins = [plugin(postcssNested), spyPlugin.plugin]
|
|
|
|
let result = await run(input, plugins)
|
|
|
|
expect(result).toMatchFormattedCss(css`
|
|
.foo {
|
|
color: black;
|
|
}
|
|
@supports (color: blue) {
|
|
.foo {
|
|
color: blue;
|
|
}
|
|
}
|
|
/* Comment */
|
|
`)
|
|
|
|
expect(spyPlugin.spies.Once).toHaveBeenCalled()
|
|
expect(spyPlugin.spies.OnceExit).toHaveBeenCalled()
|
|
expect(spyPlugin.spies.Root).toHaveBeenCalled()
|
|
expect(spyPlugin.spies.Rule).toHaveBeenCalled()
|
|
expect(spyPlugin.spies.AtRule).toHaveBeenCalled()
|
|
expect(spyPlugin.spies.Comment).toHaveBeenCalled()
|
|
expect(spyPlugin.spies.Declaration).toHaveBeenCalled()
|
|
})
|
|
|
|
// ---
|
|
|
|
function indentRecursive(node, indent = 0) {
|
|
node.each &&
|
|
node.each((child, i) => {
|
|
if (!child.raws.before || child.raws.before.includes('\n')) {
|
|
child.raws.before = `\n${node.type !== 'rule' && i > 0 ? '\n' : ''}${' '.repeat(indent)}`
|
|
}
|
|
child.raws.after = `\n${' '.repeat(indent)}`
|
|
indentRecursive(child, indent + 1)
|
|
})
|
|
}
|
|
|
|
function formatNodes(root) {
|
|
indentRecursive(root)
|
|
if (root.first) {
|
|
root.first.raws.before = ''
|
|
}
|
|
}
|
|
|
|
async function run(input, options) {
|
|
let plugins = []
|
|
|
|
if (Array.isArray(options)) {
|
|
plugins = options
|
|
} else {
|
|
plugins.push(options === undefined ? plugin : plugin(options))
|
|
}
|
|
|
|
plugins.push(formatNodes)
|
|
|
|
let result = await postcss(plugins).process(input, {
|
|
from: undefined,
|
|
})
|
|
|
|
return result.toString()
|
|
}
|
|
|
|
function css(templates) {
|
|
return templates.join('')
|
|
}
|