import type { TransformOptions } from '../../test-utils'; import { transform as transformCode } from '../../test-utils'; describe('styled component behaviour', () => { beforeAll(() => { process.env.AUTOPREFIXER = 'off'; }); afterAll(() => { delete process.env.AUTOPREFIXER; }); const transform = (code: string, opts: TransformOptions = {}) => transformCode(code, { pretty: false, ...opts }); it('should generate styled object call expression component code', () => { const code = ` import { styled } from '@compiled/react'; const ListItem = styled.div({ fontSize: '20px', }); `; const actual = transform(code, { pretty: true }); expect(actual).toMatchInlineSnapshot(` "import { forwardRef } from "react"; import * as React from "react"; import { ax, ix, CC, CS } from "@compiled/react/runtime"; const _ = "._1wybgktf{font-size:20px}"; const ListItem = forwardRef( ({ as: C = "div", style: __cmpls, ...__cmplp }, __cmplr) => { if (__cmplp.innerRef) { throw new Error("Please use 'ref' instead of 'innerRef'."); } return ( {[_]} ); } ); if (process.env.NODE_ENV !== "production") { ListItem.displayName = "ListItem"; } " `); }); it('should generate styled tagged template expression component code', () => { const code = ` import { styled } from '@compiled/react'; const ListItem = styled.div\` font-size: 20px; \`; `; const actual = transform(code, { pretty: true }); expect(actual).toMatchInlineSnapshot(` "import { forwardRef } from "react"; import * as React from "react"; import { ax, ix, CC, CS } from "@compiled/react/runtime"; const _ = "._1wybgktf{font-size:20px}"; const ListItem = forwardRef( ({ as: C = "div", style: __cmpls, ...__cmplp }, __cmplr) => { if (__cmplp.innerRef) { throw new Error("Please use 'ref' instead of 'innerRef'."); } return ( {[_]} ); } ); if (process.env.NODE_ENV !== "production") { ListItem.displayName = "ListItem"; } " `); }); it('should add an identifier nonce to the style element', () => { const code = ` import { styled } from '@compiled/react'; const ListItem = styled.div\` font-size: \${props => props.color}px; \`; `; const actual = transform(code, { nonce: '__webpack_nonce__' }); expect(actual).toInclude(' { const actual = transform(` import { styled } from '@compiled/react'; const styles = { fontSize: 12 }; const ListItem = styled.div([ styles, \`color: blue;\`, { fontWeight: 500 } ]); `); expect(actual).toIncludeMultiple(['{font-size:12px}', '{color:blue}', '{font-weight:500}']); }); it('should not destructure valid html attributes from props', () => { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.font({ color: props => props.color, }); `); expect(actual).toIncludeMultiple(['"--_xexnhp":ix(__cmplp.color)', ' { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div({ fontSize: props => props.textSize, color: props => props.color, }); `); expect(actual).toIncludeMultiple([ 'const{textSize,...__cmpldp}=__cmplp;', '"--_8t6091":ix(__cmplp.textSize)', ' { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div\` font-size: \${props => props.textSize}px; \`; `); expect(actual).toInclude('"--_8t6091":ix(__cmplp.textSize,"px")'); }); it('should prefix interpolation', () => { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div\` font-size: -\${props => props.textSize}px; \`; `); expect(actual).toInclude('"--_8t6091-":ix(__cmplp.textSize,"px","-")'); }); it('creates a separate var name for positive and negative values of the same interpolation', () => { const actual = transform(` import { styled } from '@compiled/react'; const random = Math.random; const LayoutRight = styled.aside\` margin-right: -\${random() * 5}px; margin-left: \${random() * 5}px; \`; `); expect(actual).toIncludeMultiple([ '._2hwxjtuq{margin-right:var(--_1hnpmp1-)}', '._18u01s7m{margin-left:var(--_1hnpmp1)}', '"--_1hnpmp1-":ix(random()*5,"px","-")', '"--_1hnpmp1":ix(random()*5,"px")', 'ax(["_2hwxjtuq _18u01s7m",__cmplp.className]', ]); }); it('should compose a component using tagged template expression', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` color: red; \`; const ListItem = styled(Component)\` font-size: 20px; \`; `); expect(actual).toIncludeMultiple(['as:C=Component', ' { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ color: 'red', }); const ListItem = styled(Component)({ fontSize: 20 }); `); expect(actual).toIncludeMultiple(['as:C=Component', ' { const actual = transform(` import { styled } from '@compiled/react'; const fontSize = '20px'; const ListItem = styled.div\` font-size: \${fontSize}; \`; `); expect(actual).toInclude('{font-size:20px}'); }); it('should transform an arrow function with a body into an IIFE', () => { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div({ color: props => { return props.color; }, }); `); expect(actual).toIncludeMultiple([ '{color:var(--_63bh2t)}', '"--_63bh2t":ix((()=>{return __cmplp.color;})())', ]); }); it('should transform an arrow function with a body into an IIFE by preventing passing down invalid html attributes to the node', () => { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div({ fontSize: props => { return props.textSize; }, }); `); expect(actual).toIncludeMultiple([ '{font-size:var(--_1eiw442)}', 'const{textSize,...__cmpldp}=__cmplp;', '"--_1eiw442":ix((()=>{return __cmplp.textSize;})())', ]); }); it('should move suffix and prefix of a dynamic arrow function with a body into an IIFE', () => { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div({ content: \`"$\{props => { return props.color; }}"\` }); `); expect(actual).toIncludeMultiple([ '{content:var(--_63bh2t)}', '"--_63bh2t":ix((()=>{return __cmplp.color;})(),"\\"","\\"")', ]); }); it('should collect args as styles', () => { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div( { color: 'darkorchid' }, { fontSize: 12 }, ); `); expect(actual).toIncludeMultiple([ '{color:darkorchid}', '{font-size:12px}', 'ax(["_syaz1paq _1wyb1fwx",__cmplp.className])', ]); }); it('should not throw when template literal CSS has no terminating semicolon', () => { expect(() => { transform(` import { styled } from '@compiled/react'; const ListItem = styled.div( \`color: red\`, { fontSize: 20 } ); `); }).not.toThrow(); }); it('should handle destructuring in interpolation functions', () => { const code = ` import { styled } from '@compiled/react'; import colors from 'colors'; export const BadgeSkeleton = styled.span\` background-color: \${({ isLoading }) => (isLoading ? colors.N20 : colors.N40)}; color: \${({ loading: l }) => (l ? colors.N50 : colors.N10)}; border-color: \${(propz) => (propz.loading ? colors.N100 : colors.N200)}; display: \${({ state: { loading } }) => loading ? 'none' : 'inherit'}; opacity: \${({ width, ...rest }) => rest.isLoading ? 0 : 1}; \`; `; const actual = transform(code, { pretty: true }); expect(actual).toMatchInlineSnapshot(` "import { forwardRef } from "react"; import * as React from "react"; import { ax, ix, CC, CS } from "@compiled/react/runtime"; import colors from "colors"; const _0 = "._tzy4kb7n{opacity:1}"; const _9 = "._tzy4idpf{opacity:0}"; const _8 = "._1e0c1kw7{display:inherit}"; const _7 = "._1e0cglyw{display:none}"; const _6 = "._1h6d1qzc{border-color:var(--_96ptk)}"; const _5 = "._1h6d1c5w{border-color:var(--_5rpikm)}"; const _4 = "._syazs2l2{color:var(--_1oii75x)}"; const _3 = "._syaz1c44{color:var(--_1ytezyk)}"; const _2 = "._bfhk1lco{background-color:var(--_kcgnsd)}"; const _ = "._bfhkhk3l{background-color:var(--_16ldrz5)}"; export const BadgeSkeleton = forwardRef( ({ as: C = "span", style: __cmpls, ...__cmplp }, __cmplr) => { if (__cmplp.innerRef) { throw new Error("Please use 'ref' instead of 'innerRef'."); } const { isLoading, state, ...__cmpldp } = __cmplp; return ( {[_, _2, _3, _4, _5, _6, _7, _8, _9, _0]} ); } ); if (process.env.NODE_ENV !== "production") { BadgeSkeleton.displayName = "BadgeSkeleton"; } " `); }); it('should handle an animation that references an inline @keyframes', () => { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div\` @keyframes fadeOut { from { opacity: 1; } 50% { opacity: 0.5; } to { opacity: 0; } } animation: fadeOut 2s ease-in-out; \`; `); expect(actual).toIncludeMultiple([ 'const _="._y44vk4ag{animation:fadeOut 2s ease-in-out}"', 'const _2="@keyframes fadeOut{0%{opacity:1}50%{opacity:0.5}to{opacity:0}}"', '{[_,_2]}', 'className={ax(["_y44vk4ag",__cmplp.className])}', ]); }); it('should not blow up with an expanding property', () => { expect(() => transform(` import { styled } from '@compiled/react'; export const BoardContent = styled.span\` flex: 1; \`; `) ).not.toThrow(); }); it('should omit classes on rules with no value in string literal', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` color: ; background-color: undefined; border-color: null; ::after { content: ''; } \`; `); expect(actual).toIncludeMultiple([ "_aetr1yyf:after{content:''}", 'className={ax(["_aetr1yyf",__cmplp.className])}', ]); }); it('should omit classes on rules with no value in object', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ color: '', backgroundColor: undefined, borderColor: null, '::after': { content: '', } }); `); expect(actual).toIncludeMultiple([ '_aetrb3bt:after{content:\\"\\"}', 'className={ax(["_aetrb3bt",__cmplp.className])}', ]); }); it('should apply no classes when styles have no value inside selector', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ ':hover': { fontSize: undefined, } }); `); expect(actual).toInclude('className={ax(["",__cmplp.className])}'); }); it('should omit styles with no value inside selector', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ ':hover': { color: 'red', fontSize: undefined, } }); `); expect(actual).toIncludeMultiple([ '._30l35scu:hover{color:red}', 'className={ax(["_30l35scu",__cmplp.className])}', ]); }); it('should apply conditional CSS with ternary operator', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.button\` color: \${(props) => (props.isPrimary ? 'blue' : 'red')}; /* annoying-comment */ text-decoration-line: \${({ isDone }) => isDone ? 'line-through' : 'none'}; -webkit-line-clamp: \${({ isClamped }) => isClamped ? 3 : 1}; font-size: 30px; border: 2px solid blue; padding: 8px; \`; `); expect(actual).toIncludeMultiple([ '._syaz5scu{color:red}', '._syaz13q2{color:blue}', '._1hms1911{text-decoration-line:line-through}', '._1hmsglyw{text-decoration-line:none}', '._1yyj11wp{-webkit-line-clamp:3}', '._1yyjkb7n{-webkit-line-clamp:1}', '._19bvftgi{padding-left:8px}', '._n3tdftgi{padding-bottom:8px}', '._u5f3ftgi{padding-right:8px}', '._ca0qftgi{padding-top:8px}', '._19itlf8h{border:2px solid blue}', '._1wyb1ul9{font-size:30px}', 'ax(["_19itlf8h _ca0qftgi _u5f3ftgi _n3tdftgi _19bvftgi _1wyb1ul9",__cmplp.isPrimary?"_syaz13q2":"_syaz5scu",__cmplp.isDone?"_1hms1911":"_1hmsglyw",__cmplp.isClamped?"_1yyj11wp":"_1yyjkb7n",__cmplp.className])', ]); }); it('should apply conditional CSS with ternary operators and suffix', () => { const actual = transform(` import { styled } from '@compiled/react'; const ListItem = styled.div\` border-radius: \${(props) => props.isRounded ? 10 : 1}px !important; \`; `); expect(actual).toIncludeMultiple([ '._2rko19el{border-radius:10px!important}', '._2rko1aa3{border-radius:1px!important}', `ax([\"\",__cmplp.isRounded?\"_2rko19el\":\"_2rko1aa3\",__cmplp.className])`, ]); }); it('should apply conditional CSS with ternary operator for object styles', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.button({ color: (props) => (props.isPrimary ? 'blue' : 'red'), marginLeft: \`\${({ isLast }) => isLast ? 5 : 10}px\`, marginRight: ({ isLast }) => \`\${isLast ? 5 : 10}px\`, }); `); expect(actual).toIncludeMultiple([ '._syaz5scu{color:red}', '._syaz13q2{color:blue}', '._18u014y2{margin-left:5px}', '._18u019bv{margin-left:10px}', '._2hwx14y2{margin-right:5px}', '._2hwx19bv{margin-right:10px}', 'ax(["",__cmplp.isPrimary?"_syaz13q2":"_syaz5scu",__cmplp.isLast?"_18u014y2":"_18u019bv",__cmplp.isLast?"_2hwx14y2":"_2hwx19bv",__cmplp.className])', ]); }); it('should apply conditional CSS with ternary operator and tagged templates branches', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.button\` color: \${(props) => (props.isPrimary ? \`blue\` : \`red\`)}; \`; `); expect(actual).toIncludeMultiple([ '._syaz5scu{color:red}', '._syaz13q2{color:blue}', `ax([\"\",__cmplp.isPrimary?\"_syaz13q2\":\"_syaz5scu\",__cmplp.className])`, ]); }); it('should apply conditional CSS with ternary operators, template literal branches containing props', () => { const actual = transform(` import { styled } from '@compiled/react'; import { CUSTOM_WIDTH } from './constants'; const ListItem = styled.div\` width: \${(props) => props.useCustomWidth ? \`\${CUSTOM_WIDTH}px\` : '100%'}; \`; `); expect(actual).toIncludeMultiple([ '._1bsb1osq{width:100%}', '._1bsby2bc{width:var(--_znisgh)}', 'style={{...__cmpls,"--_znisgh":ix(CUSTOM_WIDTH,"px")}}', `ax([\"\",__cmplp.useCustomWidth?\"_1bsby2bc\":\"_1bsb1osq\",__cmplp.className])`, ]); }); it('should apply conditional CSS with multiple ternary operators', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.button\` color: \${(props) => (props.isPrimary ? 'blue' : 'red')}; border: \${(props) => (props.isPrimary ? '1px solid blue' : '1px solid red')}; font-size: 30px; \`; `); expect(actual).toIncludeMultiple([ '._19it107e{border:1px solid red}', '._19it1nsd{border:1px solid blue}', '._syaz5scu{color:red}', '._syaz13q2{color:blue}', '._1wyb1ul9{font-size:30px}', `ax([\"_1wyb1ul9\",__cmplp.isPrimary?\"_syaz13q2\":\"_syaz5scu\",__cmplp.isPrimary?\"_19it1nsd\":\"_19it107e\",__cmplp.className]`, ]); }); it('should apply conditional CSS with nested ternary operators', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.button\` color: \${(props) => (props.isPrimary ? props.isDisabled ? 'black' : 'blue' : 'red')}; font-size: 30px; border: 2px solid blue; padding: 8px; \`; `); expect(actual).toIncludeMultiple([ '._19bvftgi{padding-left:8px}', '._n3tdftgi{padding-bottom:8px}', '._u5f3ftgi{padding-right:8px}', '._ca0qftgi{padding-top:8px}', '._19itlf8h{border:2px solid blue}', '._1wyb1ul9{font-size:30px}', '._syaz5scu{color:red}', '._syaz13q2{color:blue}', '._syaz11x8{color:black}', `ax([\"_19itlf8h _ca0qftgi _u5f3ftgi _n3tdftgi _19bvftgi _1wyb1ul9\",__cmplp.isPrimary?__cmplp.isDisabled?\"_syaz11x8\":\"_syaz13q2\":\"_syaz5scu\",__cmplp.className])`, ]); }); it('should apply conditional CSS with template literal', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` color: red; background: white; border: 3px solid yellow; \${props => props.isPrimary && ({ color: 'blue' })}; \`; `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._19it7fe6{border:3px solid yellow}', '._bfhk1x77{background-color:white}', '._syaz5scu{color:red}', 'className={ax(["_bfhk1x77 _19it7fe6 _syaz5scu",__cmplp.isPrimary&&"_syaz13q2",__cmplp.className])}', ]); }); it('should apply conditional CSS with template literal and nested ternary operators', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` background: white; \${props => props.isPrimary ? props.isDisabled ? { color: 'black' } : { color: 'blue' } : { color: 'red' }}; \`; `); expect(actual).toIncludeMultiple([ '._bfhk1x77{background-color:white}', '._syaz11x8{color:black}', '._syaz13q2{color:blue}', '._syaz5scu{color:red}', ]); }); it('should apply conditional CSS with template literal, nested ternary operators, and different types', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` background: white; \${props => props.isPrimary ? props.isDisabled ? { color: 'black' } : 'color: blue' : \`color: red\`}; \`; `); expect(actual).toIncludeMultiple([ '._bfhk1x77{background-color:white}', '._syaz11x8{color:black}', '._syaz13q2{color:blue}', '._syaz5scu{color:red}', 'className={ax(["_bfhk1x77",__cmplp.isPrimary?__cmplp.isDisabled?"_syaz11x8":"_syaz13q2":"_syaz5scu",__cmplp.className])}', ]); }); it('should apply conditional CSS with template literal and multiple props lines', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` color: red; \${props => props.isPrimary && ({ color: 'blue' })}; \${props => props.isBolded && ({ fontWeight: 'bold' })}; \`; `); expect(actual).toIncludeMultiple([ '._k48p8n31{font-weight:bold}', '._syaz13q2{color:blue}', '._syaz5scu{color:red}', 'className={ax(["_syaz5scu",__cmplp.isPrimary&&"_syaz13q2",__cmplp.isBolded&&"_k48p8n31",__cmplp.className])}', ]); }); it('should not allow a logical statement with a conditional right-hand side', () => { expect(() => transform(` import { styled } from '@compiled/react'; const Component = styled.div\` \${props => props.isShown && (props.isPrimary ? { color: 'blue' } : { color: 'green' })}; \`; `) ).toThrow( 'This ConditionalExpression was unable to have its styles extracted — try to define them statically using Compiled APIs instead' ); }); it('should apply conditional CSS when using "key: value" in string form', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` \${props => props.isPrimary ? 'color: green' : \`color: red\`}; \`; `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', '._syaz5scu{color:red}', 'className={ax(["",__cmplp.isPrimary?"_syazbf54":"_syaz5scu",__cmplp.className])}', ]); }); it('should apply nested conditional CSS when using "key: value" in string form', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` \${props => props.isPrimary ? 'color: blue' : props.isGreen ? 'color: green' : 'color: red'}; \`; `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', '._syaz13q2{color:blue}', '._syaz5scu{color:red}', 'className={ax(["",__cmplp.isPrimary?"_syaz13q2":__cmplp.isGreen?"_syazbf54":"_syaz5scu",__cmplp.className])}', ]); }); it('should apply conditional CSS when using "key: value; key: value; ..." in string form', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` \${props => props.isPrimary ? 'color: green; font-size: 12px;' : \`color: red; font-size: 16px;\`}; \`; `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', '._syaz5scu{color:red}', '._1wyb1fwx{font-size:12px}', '._1wybexct{font-size:16px}', 'className={ax(["",__cmplp.isPrimary?"_syazbf54 _1wyb1fwx":"_syaz5scu _1wybexct",__cmplp.className])}', ]); }); it('should apply conditional CSS when using inline mixins', () => { const actual = transform(` import { styled, css } from '@compiled/react'; const Component = styled.div\` \${props => props.isPrimary ? css\`color: green\` : css({ color: 'red' })}; \`; `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', '._syaz5scu{color:red}', 'className={ax(["",__cmplp.isPrimary?"_syazbf54":"_syaz5scu",__cmplp.className])}', ]); }); it('should apply unconditional before and after a conditional css rule with template literal', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` color: red; background: white; \${props => props.isPrimary && ({ color: 'blue' })}; border: 3px solid yellow; \`; `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._19it7fe6{border:3px solid yellow}', '._bfhk1x77{background-color:white}', '._syaz5scu{color:red}', '{ax(["_bfhk1x77 _19it7fe6 _syaz5scu",__cmplp.isPrimary&&"_syaz13q2",__cmplp.className])}', ]); }); it('should apply unconditional after a conditional css rule with template literal', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` \${props => props.isPrimary && ({ color: 'blue' })}; border: 3px solid yellow; color: red; background: white; \`; `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._bfhk1x77{background-color:white}', '._syaz5scu{color:red}', '._19it7fe6{border:3px solid yellow}', '{ax(["_19it7fe6 _bfhk1x77 _syaz5scu",__cmplp.isPrimary&&"_syaz13q2",__cmplp.className])}', ]); }); it('should apply unconditional CSS with props', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( props => ({ color: props.primary }), ); `); expect(actual).toIncludeMultiple([ 'const _="._syaz1q2z{color:var(--_1r7cl4y)}"', '"--_1r7cl4y":ix(__cmplp.primary)', 'className={ax(["_syaz1q2z",__cmplp.className])}', ]); }); it('should apply unconditional CSS with and without props', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { background: 'red' }, props => ({ color: props.primary }), ); `); expect(actual).toIncludeMultiple([ '._syaz1q2z{color:var(--_1r7cl4y)}', '._bfhk5scu{background-color:red}', '--_1r7cl4y":ix(__cmplp.primary)}', 'className={ax(["_bfhk5scu _syaz1q2z",__cmplp.className])}', ]); }); it('should apply conditional CSS with object styles', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { color: 'red' }, props => props.isPrimary && ({ color: 'blue' }), ); `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._syaz5scu{color:red}', 'className={ax(["_syaz5scu",__cmplp.isPrimary&&"_syaz13q2",__cmplp.className])}', ]); }); it('should apply conditional CSS with object styles and multiple props lines', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { color: 'red' }, props => props.isPrimary && ({ color: 'blue' }), props => props.isBolded && ({ fontWeight: 'bold' }), ); `); expect(actual).toIncludeMultiple([ '._k48p8n31{font-weight:bold}', '._syaz13q2{color:blue}', '._syaz5scu{color:red}', 'className={ax(["_syaz5scu",__cmplp.isPrimary&&"_syaz13q2",__cmplp.isBolded&&"_k48p8n31",__cmplp.className])}', ]); }); it('should apply unconditional before and after a conditional css rule with object styles', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { color: 'red' }, props => props.isPrimary && ({ color: 'blue' }), { border: '1px solid black'}, ); `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._19it97hw{border:1px solid black}', '._syaz5scu{color:red}', '{ax(["_19it97hw _syaz5scu",__cmplp.isPrimary&&"_syaz13q2",__cmplp.className])}', ]); }); it('should apply conditional CSS with object styles regardless declaration order', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( props => props.isPrimary && ({ color: 'red' }), { color: 'blue' }, ); `); expect(actual).toIncludeMultiple([ '._syaz5scu{color:red}', '._syaz13q2{color:blue}', 'className={ax(["_syaz13q2",__cmplp.isPrimary&&"_syaz5scu",__cmplp.className])}', ]); }); it('should apply multi conditional logical expression', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { color: 'red' }, props => (props.isPrimary || props.isMaybe) && ({ color: 'blue' }), ); `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._syaz5scu{color:red}', '{ax(["_syaz5scu",(__cmplp.isPrimary||__cmplp.isMaybe)&&"_syaz13q2",__cmplp.className])}', ]); }); it('should apply multi conditional logical expression with different props lines and syntax styles', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { color: 'red' }, (props) => props.isPrimary && { color: 'blue' }, { fontWeight: (props) => (props.isBolded ? 'bold' : 'normal')} ); `); expect(actual).toIncludeMultiple([ '._k48p8n31{font-weight:bold}', '._k48p4jg8{font-weight:normal}', '._syaz13q2{color:blue}', '._syaz5scu{color:red}', '{ax(["_syaz5scu",__cmplp.isPrimary&&"_syaz13q2",__cmplp.isBolded?"_k48p8n31":"_k48p4jg8",__cmplp.className])}/>', ]); }); it('should apply the same CSS property with unconditional as default and multiple logical expressions', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { color: 'red' }, props => props.isPrimary && (props.isBolded || props.isFoo) && ({ color: 'blue' }), ); `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._syaz5scu{color:red}', '{ax(["_syaz5scu",__cmplp.isPrimary&&(__cmplp.isBolded||__cmplp.isFoo)&&"_syaz13q2",__cmplp.className])}', ]); }); it('should apply conditional CSS with ternary and boolean in the same line', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { fontSize: '20px' }, props => props.isPrimary && props.isBolded ? ({ color: 'blue' }) : ({ color: 'red'}), ); `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._syaz5scu{color:red}', '._1wybgktf{font-size:20px}', 'className={ax(["_1wybgktf",__cmplp.isPrimary&&__cmplp.isBolded?"_syaz13q2":"_syaz5scu",__cmplp.className])}/', ]); }); it('should only evaluate the last unconditional CSS rule for each property', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( { color: 'red' }, { color: 'white', background: 'black' }, { color: 'orange'}, { background: 'white'}, ); `); expect(actual).toIncludeMultiple([ '._bfhk1x77{background-color:white}', '._syazruxl{color:orange}', 'className={ax(["_bfhk1x77 _syazruxl",__cmplp.className])}', ]); }); it('should only add falsy condition when truthy condition has no value', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( props => props.isPrimary ? undefined : { color: 'green', background: 'black' }, ); `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', '._bfhk11x8{background-color:black}', 'className={ax(["",!__cmplp.isPrimary&&"_bfhk11x8 _syazbf54",__cmplp.className])}', ]); }); it('should only add truthy condition when falsy condition has no value', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div( props => props.isPrimary ? { color: 'green', background: 'black' } : undefined, ); `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', '._bfhk11x8{background-color:black}', 'className={ax(["",__cmplp.isPrimary&&"_bfhk11x8 _syazbf54",__cmplp.className])}', ]); }); it('should apply logical test to class when a conditional branch contains undefined value', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` color: \${props => props.isPrimary ? 'green' : undefined}; \`; `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', 'className={ax(["",__cmplp.isPrimary&&"_syazbf54",__cmplp.className])}', ]); }); it('should apply logical test to class when a conditional branch contains null value', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ color: props => props.isPrimary ? null : 'green', }); `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', 'className={ax(["",!__cmplp.isPrimary&&"_syazbf54",__cmplp.className])}', ]); }); it('should apply logical test to class when a conditional branch contains empty string value', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ color: props => props.isPrimary ? '' : 'green', }); `); expect(actual).toIncludeMultiple([ '._syazbf54{color:green}', 'className={ax(["",!__cmplp.isPrimary&&"_syazbf54",__cmplp.className])}', ]); }); it('should apply logical test to class when a conditional branch contains empty value inside selector', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ ':hover': { color: props => props.isPrimary ? 'green' : '', } }); `); expect(actual).toIncludeMultiple([ '._30l3bf54:hover{color:green}', 'className={ax(["",__cmplp.isPrimary&&"_30l3bf54",__cmplp.className])}', ]); }); it('should apply logical test to class when a conditional branch contains empty value inside selector', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ ':hover': { color: props => props.isPrimary ? 'green' : '', } }); `); expect(actual).toIncludeMultiple([ '._30l3bf54:hover{color:green}', 'className={ax(["",__cmplp.isPrimary&&"_30l3bf54",__cmplp.className])}', ]); }); it('should apply no classes when both conditional branches contains empty values', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ color: props => props.isPrimary ? undefined : null, }); `); expect(actual).toInclude('className={ax(["",__cmplp.className])}'); }); it('should conditionally apply CSS mixins', () => { const actual = transform(` import { styled, css } from '@compiled/react'; const dark = css\` background-color: black; color: white; \`; const light = css({ 'background-color': 'white', color: 'black', }); const Component = styled.div\` \${(props) => (props.isDark ? dark : light)}; font-size: 30px; \`; `); expect(actual).toIncludeMultiple([ '._syaz11x8{color:black}', '._bfhk1x77{background-color:white}', '._syaz1x77{color:white}', '_bfhk11x8{background-color:black}', '_1wyb1ul9{font-size:30px}', 'className={ax(["_1wyb1ul9",__cmplp.isDark?"_bfhk11x8 _syaz1x77":"_bfhk1x77 _syaz11x8",__cmplp.className])}', ]); }); it('falls back to using CSS variable when conditional is not sole expression in statement', () => { const actual = transform(` import { styled } from '@compiled/react'; const gutter = 10; const Component = styled.div\` width: calc(\${gutter}px + \${({ isLarge }) => isLarge ? 100 : 50}px); \`; `); expect(actual).toIncludeMultiple([ '._1bsb1dlf{width:calc(10px + var(--_1e9pbah))}', '"--_1e9pbah":ix(__cmplp.isLarge?100:50,"px")', '{ax(["_1bsb1dlf",__cmplp.className])}', ]); }); it('falls back to using CSS variable when conditional followed by another expression in statement', () => { const actual = transform(` import { styled } from '@compiled/react'; const gutter = 10; const Component = styled.div\` width: calc(\${({ isLarge }) => isLarge ? 100 : 50}px - \${gutter}px); \`; `); expect(actual).toIncludeMultiple([ '._1bsb5cma{width:calc(var(--_1e9pbah) - 10px)}', '"--_1e9pbah":ix(__cmplp.isLarge?100:50,"px")', '{ax(["_1bsb5cma",__cmplp.className])}', ]); }); it('falls back to using CSS variable when conditional is inside quotes', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` :before { content: '\${({ isOpen }) => isOpen ? 'show less' : 'show more'}'; } \`; `); expect(actual).toIncludeMultiple([ '._1kt91xca:before{content:var(--_8txsa8)}', '"--_8txsa8":ix(__cmplp.isOpen?\'show less\':\'show more\',"\'","\'")', '{ax(["_1kt91xca",__cmplp.className])}', ]); }); it('should apply conditional CSS to related selector', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` background: url('data:image/svg+xml; ... '); color: \${({ isSelected }) => isSelected ? 'blue' : 'yellow'}; :hover { border: \${({ isHover }) => isHover ? '1px solid white' : '2px solid black'}; } \`; `); expect(actual).toIncludeMultiple([ "._11q7qm1v{background:url('data:image/svg+xml; ... ')}", '._syaz13q2{color:blue}', '._syaz1gy6{color:yellow}', '._bfw71j9v:hover{border:1px solid white}', '_bfw7l468:hover{border:2px solid black}', '{ax(["_11q7qm1v",__cmplp.isSelected?"_syaz13q2":"_syaz1gy6",__cmplp.isHover?"_bfw71j9v":"_bfw7l468",__cmplp.className])}', ]); }); it('should apply conditional CSS to related selector with object styles', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div({ color: ({ isSelected }) => isSelected ? 'blue' : 'yellow', ':hover': { border: ({ isHover }) => isHover ? '1px solid white' : '2px solid black', } }); `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._syaz1gy6{color:yellow}', '._bfw71j9v:hover{border:1px solid white}', '_bfw7l468:hover{border:2px solid black}', '{ax(["",__cmplp.isSelected?"_syaz13q2":"_syaz1gy6",__cmplp.isHover?"_bfw71j9v":"_bfw7l468",__cmplp.className])}', ]); }); it('should apply conditional CSS to related nested selector', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` color: \${({ isSelected }) => isSelected ? 'blue' : 'yellow'}; :hover { border: \${({ isHover }) => isHover ? '1px solid white' : '2px solid black'}; background-color: cyan; :before { content: "Don't break closure parsing }"; display: \${({ isBefore }) => isBefore ? 'inherit' : 'inline'}; } } \`; `); expect(actual).toIncludeMultiple([ '._syaz13q2{color:blue}', '._syaz1gy6{color:yellow}', '._bfw71j9v:hover{border:1px solid white}', '_bfw7l468:hover{border:2px solid black}', '._irr31i1c:hover{background-color:cyan}', '._vw871qok:hover:before{content:\\"Don\'t break closure parsing }\\"}', '._1jly1kw7:hover:before{display:inherit}', '._1jly1nu9:hover:before{display:inline}', '{ax(["_irr31i1c _vw871qok",__cmplp.isSelected?"_syaz13q2":"_syaz1gy6",__cmplp.isHover?"_bfw71j9v":"_bfw7l468",__cmplp.isBefore?"_1jly1kw7":"_1jly1nu9",__cmplp.className])}', ]); }); it('does not conflict conditional CSS with above selectors', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` > span:first-type-of { color: red; } :hover { background-color: cyan; } :focus { border-radius: \${({ isFocus }) => isFocus ? 3 : 2}px; } \`; `); expect(actual).toIncludeMultiple([ '._1oey5scu >span:first-type-of{color:red}', '._irr31i1c:hover{background-color:cyan}', '._vn891l7b:focus{border-radius:3px}', '._vn89yh40:focus{border-radius:2px}', '{ax(["_1oey5scu _irr31i1c",__cmplp.isFocus?"_vn891l7b":"_vn89yh40",__cmplp.className])}', ]); }); it('does not conflict conditional CSS with below selectors', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` :focus { border-radius: \${({ isFocus }) => isFocus ? 3 : 2}px; } > span:first-type-of { color: red; } :hover { background-color: cyan; } \`; `); expect(actual).toIncludeMultiple([ '._1oey5scu >span:first-type-of{color:red}', '._irr31i1c:hover{background-color:cyan}', '._vn891l7b:focus{border-radius:3px}', '._vn89yh40:focus{border-radius:2px}', '{ax(["_1oey5scu _irr31i1c",__cmplp.isFocus?"_vn891l7b":"_vn89yh40",__cmplp.className])}', ]); }); it('does not conflict conditional CSS with surrounding selectors', () => { const actual = transform(` import { styled } from '@compiled/react'; const Component = styled.div\` > span:first-type-of { color: red; } :focus { border-radius: \${({ isFocus }) => isFocus ? 3 : 2}px; } :hover { background-color: cyan; } \`; `); expect(actual).toIncludeMultiple([ '._1oey5scu >span:first-type-of{color:red}', '._irr31i1c:hover{background-color:cyan}', '._vn891l7b:focus{border-radius:3px}', '._vn89yh40:focus{border-radius:2px}', '{ax(["_1oey5scu _irr31i1c",__cmplp.isFocus?"_vn891l7b":"_vn89yh40",__cmplp.className])}', ]); }); });