tailwindcss/jest/customMatchers.js
Robin Malfait a4f1ff9052
Improve CSS output in tests to better reflect reality (#10454)
* drop empty lines when diffing output

* replace expected css with optimized lightningcss output

Lightning CSS generates a more optimal CSS output.

Right now the tests are setup in a way that both the generated css and
expected css are run through `lightningcss` to make sure that the output
is concistent for the `stable` and `oxide` engines. But this also means
that the expected output _could_ be larger (aka not optimized) and still
matches (after it runs through lightningcss).

By replacing this with the more optimal output we achieve a few things:

1. This better reflects reality since we will be using `lightningcss`.
2. This gets rid of unnecessary css.
3. Removed code!
2023-01-31 15:37:49 +01:00

141 lines
4.2 KiB
JavaScript

const prettier = require('prettier')
const { diff } = require('jest-diff')
const lightningcss = require('lightningcss')
function formatPrettier(input) {
return prettier.format(input, {
parser: 'css',
printWidth: 100,
})
}
function format(input) {
try {
return lightningcss
.transform({
filename: 'input.css',
code: Buffer.from(input),
minify: false,
targets: { chrome: 106 << 16 },
drafts: {
nesting: true,
customMedia: true,
},
})
.code.toString('utf8')
} catch (err) {
try {
// Lightning CSS is pretty strict, so it will fail for `@media screen(md) {}` for example,
// in that case we can fallback to prettier since it doesn't really care. However if an
// actual syntax error is made, then we still want to show the proper error.
return formatPrettier(input.replace(/\n/g, ''))
} catch {
let lines = err.source.split('\n')
let e = new Error(
[
'Error formatting using Lightning CSS:',
'',
...[
'```css',
...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line),
' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(),
...lines.slice(err.loc.line, err.loc.line + 2),
'```',
],
].join('\n')
)
if (Error.captureStackTrace) {
Error.captureStackTrace(e, toMatchFormattedCss)
}
throw e
}
}
}
function toMatchFormattedCss(received = '', argument = '') {
let options = {
comment: 'formatCSS(received) === formatCSS(argument)',
isNot: this.isNot,
promise: this.promise,
}
let formattedReceived = format(received)
let formattedArgument = format(argument)
let pass = formattedReceived === formattedArgument
let message = pass
? () => {
return (
this.utils.matcherHint('toMatchFormattedCss', undefined, undefined, options) +
'\n\n' +
`Expected: not ${this.utils.printExpected(formattedReceived)}\n` +
`Received: ${this.utils.printReceived(formattedArgument)}`
)
}
: () => {
let actual = formatPrettier(formattedReceived).replace(/\n\n/g, '\n')
let expected = formatPrettier(formattedArgument).replace(/\n\n/g, '\n')
let diffString = diff(expected, actual, {
expand: this.expand,
})
return (
this.utils.matcherHint('toMatchFormattedCss', undefined, undefined, options) +
'\n\n' +
(diffString && diffString.includes('- Expect')
? `Difference:\n\n${diffString}`
: `Expected: ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(actual)}`)
)
}
return { actual: received, message, pass }
}
expect.extend({
// Compare two CSS strings with all whitespace removed
// This is probably naive but it's fast and works well enough.
toMatchCss: toMatchFormattedCss,
toMatchFormattedCss: toMatchFormattedCss,
toIncludeCss(received, argument) {
let options = {
comment: 'stripped(received).includes(stripped(argument))',
isNot: this.isNot,
promise: this.promise,
}
let pass = format(received).includes(format(argument))
let message = pass
? () => {
return (
this.utils.matcherHint('toIncludeCss', undefined, undefined, options) +
'\n\n' +
`Expected: not ${this.utils.printExpected(formatPrettier(received))}\n` +
`Received: ${this.utils.printReceived(formatPrettier(argument))}`
)
}
: () => {
let actual = formatPrettier(received)
let expected = formatPrettier(argument)
let diffString = diff(expected, actual, {
expand: this.expand,
})
return (
this.utils.matcherHint('toIncludeCss', undefined, undefined, options) +
'\n\n' +
(diffString && diffString.includes('- Expect')
? `Difference:\n\n${diffString}`
: `Expected: ${this.utils.printExpected(expected)}\n` +
`Received: ${this.utils.printReceived(actual)}`)
)
}
return { actual: received, message, pass }
},
})