From caeab5e77024a073f01e4654005f2e9012b4e923 Mon Sep 17 00:00:00 2001 From: Daniel Del Core Date: Thu, 16 Apr 2020 17:33:11 +1000 Subject: [PATCH] feat: add support for not and fix a couple of bugs --- packages/jest/src/__tests__/matchers.test.tsx | 57 +++++++++++++++++++ packages/jest/src/matchers.tsx | 41 +++++++++---- 2 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 packages/jest/src/__tests__/matchers.test.tsx diff --git a/packages/jest/src/__tests__/matchers.test.tsx b/packages/jest/src/__tests__/matchers.test.tsx new file mode 100644 index 000000000..de1182ca2 --- /dev/null +++ b/packages/jest/src/__tests__/matchers.test.tsx @@ -0,0 +1,57 @@ +import { render } from '@testing-library/react'; +import React from 'react'; +import '@compiled/css-in-js'; + +it('should detect styles', () => { + const { getByText } = render( +
+ hello world +
+ ); + + expect(getByText('hello world')).toHaveCompiledCss('font-size', '12px'); +}); + +it('should detect missing styles', () => { + const { getByText } = render(
hello world
); + + expect(getByText('hello world')).not.toHaveCompiledCss('color', 'blue'); +}); + +it('should detect multiple styles', () => { + const { getByText } = render(
hello world
); + + expect(getByText('hello world')).toHaveCompiledCss({ + fontSize: '12px', + color: 'blue', + }); +}); + +it('should detect single missing styles', () => { + const { getByText } = render(
hello world
); + + expect(getByText('hello world')).not.toHaveCompiledCss({ + zindex: '9999', + }); +}); + +it('should detect multiple missing styles', () => { + const { getByText } = render(
hello world
); + + expect(getByText('hello world')).not.toHaveCompiledCss({ + backgroundColor: 'yellow', + zindex: '9999', + }); +}); + +it('should detect evaluated rule from array styles', () => { + const base = { fontSize: 12 }; + const next = ` font-size: 15px; `; + + const { getByText } = render(
hello world
); + expect(getByText('hello world')).toHaveCompiledCss('font-size', '15px'); + expect(getByText('hello world')).toHaveCompiledCss('font-size', '12px'); +}); diff --git a/packages/jest/src/matchers.tsx b/packages/jest/src/matchers.tsx index 11c8abad4..cef0b40c5 100644 --- a/packages/jest/src/matchers.tsx +++ b/packages/jest/src/matchers.tsx @@ -1,7 +1,14 @@ -export const toHaveCompiledCss: jest.CustomMatcher = ( +const kebabCase = (str: string) => + str + .replace(/([a-z])([A-Z])/g, '$1-$2') + .replace(/\s+/g, '-') + .toLowerCase(); + +export function toHaveCompiledCss( + this: jest.MatcherUtils, element: HTMLElement, ...args: [{ [key: string]: string } | string, string] -) => { +): jest.CustomMatcherResult { const [property, value] = args; const properties = typeof property === 'string' ? { [property]: value } : property; let styleElement = element.parentElement && element.parentElement.querySelector('style'); @@ -17,10 +24,6 @@ export const toHaveCompiledCss: jest.CustomMatcher = ( } } - const stylesToFind = Object.keys(properties).map( - property => `${property}:${properties[property]}` - ); - if (!styleElement) { return { pass: false, @@ -36,18 +39,34 @@ export const toHaveCompiledCss: jest.CustomMatcher = ( let css = styleElement.textContent || ''; if (styles && Object.keys(styles).length > 0) { - Object.entries(styles).forEach(([key, value]: any) => { + Object.entries(styles).forEach(([key, value]: [string, any]) => { // Replace all instances of var with the value. // We split and join to replace all instances without needing to jump into a dynamic regex. css = css.split(`var(${key})`).join(value); }); } + + const stylesToFind = Object.keys(properties).map( + property => `${kebabCase(property)}:${properties[property]}` + ); + const foundStyles = stylesToFind.filter(styleToFind => css.includes(styleToFind)); const notFoundStyles = stylesToFind.filter(styleToFind => !css.includes(styleToFind)); + const includedSelector = css.includes(`.${element.className}`); - if (css.includes(`.${element.className}`) && notFoundStyles.length === 0) { + if (includedSelector && foundStyles.length > 0 && notFoundStyles.length === 0) { return { pass: true, - message: () => '', + message: !this.isNot + ? () => '' + : () => `Found "${foundStyles.join(', ')}" on <${element.nodeName.toLowerCase()} ${styles && + `style={${JSON.stringify(styles)}}`}> element. + + Reconciled css (css variables replaced with actual values): + ${css} + + Original css: + ${(styleElement && styleElement.textContent) || ''} + `, }; } @@ -58,11 +77,11 @@ export const toHaveCompiledCss: jest.CustomMatcher = ( )}" on <${element.nodeName.toLowerCase()} ${styles && `style={${JSON.stringify(styles)}}`}> element. -Reconciled css (css variables were replaced with actual values): +Reconciled css (css variables replaced with actual values): ${css} Original css: ${(styleElement && styleElement.textContent) || ''} `, }; -}; +}