libs/@guardian/source/lib/jest-matchers/toMatchCSS.ts (45 lines of code) (raw):

import type { Warning } from 'lightningcss'; import { transform } from 'lightningcss'; expect.extend({ /** * Uses lightningcss library to normalise and compare given CSS * * @param received - The CSS to compare * @param expected - The expected result * @param options - Specify whether the CSS being compared is a fragment (not wrapped in a selector) */ toMatchCSS( received: string, expected: string, options: CSSMatcherOptions = {}, ): jest.CustomMatcherResult { const { isFragment = false } = options; // We wrap the CSS in a selector if it is a fragment to ensure it is valid. const recievedCSS = isFragment ? `* { ${received} }` : received; const expectedCSS = isFragment ? `* { ${expected} }` : expected; try { const normalisedReceivedCSS = transform({ code: Buffer.from(recievedCSS, 'utf8'), filename: '', }); const normalisedExpectedCSS = transform({ code: Buffer.from(expectedCSS, 'utf8'), filename: '', }); if ( normalisedReceivedCSS.code.toString() !== normalisedExpectedCSS.code.toString() ) { throw new Error( 'Received CSS does not match expected CSS\n\n' + normalisedReceivedCSS.code.toString(), ); } return { pass: true, message: () => '', }; } catch (error) { const message = (error as Warning).message; if (!message) { throw error; } return { pass: false, message: () => message, }; } }, });