import type { TransformOptions } from '../../test-utils';
import { transform as transformCode } from '../../test-utils';
describe('css prop behaviour', () => {
beforeAll(() => {
process.env.AUTOPREFIXER = 'off';
});
afterAll(() => {
delete process.env.AUTOPREFIXER;
});
const transform = (code: string, opts: TransformOptions = {}) =>
transformCode(code, { pretty: false, ...opts });
it('should not apply class name when no styles are present', () => {
const actual = transform(`
import '@compiled/react';
');
});
it('should concat explicit use of class name prop from an identifier on an element', () => {
const actual = transform(`
import '@compiled/react';
const className = "foobar";
`);
expect(actual).toInclude('className={ax(["_1e0c1ule",className])}');
});
it('should pick up array composition', () => {
const actual = transform(`
import '@compiled/react';
const base = { color: 'black' };
const top = \` color: red; \`;
hello world
`);
expect(actual).toIncludeMultiple([
'._syaz5scu{color:red}',
'._syaz11x8{color:black}',
'
hello world
',
]);
});
it('should pick up complex array composition', () => {
const actual = transform(`
import { css } from '@compiled/react';
const base = { display: 'inline-block', color: 'black' };
const top = css({ 'font-size': '12px', width: '50px' });
hello world
`);
expect(actual).toIncludeMultiple([
'._1bsb12am{width:50px}',
'._1wyb1fwx{font-size:12px}',
'._syaz11x8{color:black}',
'._1e0c1o8l{display:inline-block}',
'
hello world
',
]);
});
it('should persist static style prop', () => {
const actual = transform(`
import '@compiled/react';
hello world
`);
expect(actual).toInclude(`{color:blue}`);
expect(actual).toInclude(
`
hello world
`
);
});
it('should concat explicit use of style prop on an element when destructured template', () => {
const actual = transform(`
import '@compiled/react';
const [color] = ['blue'];
hello world
`);
expect(actual).toInclude(`color:var(--_1ylxx6h)`);
expect(actual).toInclude(`style={{display:'block',\"--_1ylxx6h\":ix(color)}}`);
});
it('should place suffix into ix call', () => {
const actual = transform(`
import '@compiled/react';
import { useState } from 'react';
const size = useState(10);
hello world
`);
expect(actual).toInclude(`ix(size,"px")`);
});
it('should concat implicit use of class name prop where class name is a jsx expression', () => {
const actual = transform(`
import '@compiled/react';
const getFoo = () => 'foobar';
hello world
`);
expect(actual).toInclude('className={ax(["_1e0c1ule",getFoo()])}');
});
it('should allow inlined expressions as property values', () => {
const actual = transform(`
import '@compiled/react';
let hello = true;
hello = false;
hello world
`);
expect(actual).toInclude('color:var(--_15b8wfu)');
expect(actual).toInclude('font-size:10px');
expect(actual).toInclude(`style={{\"--_15b8wfu\":ix(hello?'red':'blue')}}`);
});
it('should inline multi interpolation constant variable', () => {
// See: https://codesandbox.io/s/dank-star-443ps?file=/src/index.js
const actual = transform(`
import '@compiled/react';
const N30 = 'gray';
hello world
`);
expect(actual).toInclude(
`{background-image:linear-gradient(45deg,gray 25%,transparent 25%),linear-gradient(-45deg,gray 25%,transparent 25%),linear-gradient(45deg,transparent 75%,gray 75%),linear-gradient(-45deg,transparent 75%,gray 75%)}`
);
});
it('should move dynamic multi interpolation variable into css variable', () => {
// See: https://codesandbox.io/s/dank-star-443ps?file=/src/index.js
const actual = transform(`
import '@compiled/react';
let N30 = 'gray';
N30 = 'blue';
hello world
`);
expect(actual).toInclude(
`{background-image:linear-gradient(45deg,var(--_1vrvste\) 25%,transparent 25%),linear-gradient(-45deg,var(--_1vrvste\) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--_1vrvste\) 75%),linear-gradient(-45deg,transparent 75%,var(--_1vrvste\) 75%)}`
);
expect(actual).toInclude('style={{"--_1vrvste":ix(N30)}}');
});
it('should allow expressions stored in a variable as shorthand property values', () => {
const actual = transform(`
import '@compiled/react';
let hello = true;
hello = false;
let color = hello ? 'red' : 'blue' ;
hello world
`);
expect(actual).toInclude('{color:var(--_1ylxx6h)}');
expect(actual).toInclude(`style={{\"--_1ylxx6h\":ix(color)}}`);
});
it('should allow expressions stored in a variable as property values', () => {
const actual = transform(`
import '@compiled/react';
let hello = true;
hello = false;
let colorsz = hello ? 'red' : 'blue' ;
hello world
`);
expect(actual).toInclude('{color:var(--_19p4bcs)}');
expect(actual).toInclude(`style={{\"--_19p4bcs\":ix(colorsz)}}`);
});
it('should remove css prop', () => {
const actual = transform(`
import '@compiled/react';
const color = 'blue';
hello world
`);
expect(actual).not.toInclude('css={');
});
it('should keep other props around', () => {
const actual = transform(`
import '@compiled/react';
const color = 'blue';
hello world
`);
expect(actual).toInclude('data-testid="yo"');
});
it('should add an identifier nonce to the style element', () => {
const code = `
import '@compiled/react';
`;
const actual = transform(code, { nonce: '__webpack_nonce__' });
expect(actual).toInclude('
{
const actual = transform(`
import '@compiled/react';
const fontSize = 20;
`);
expect(actual).toInclude(':hover{color:red}');
});
it('should bubble up top level pseduo inside a support atrule', () => {
const actual = transform(`
import '@compiled/react';
const fontSize = 20;
`);
expect(actual).toInclude(':hover{color:red}');
});
it('should handle an animation that references an inline @keyframes', () => {
const actual = transform(`
import { css } from '@compiled/react';
const styles = css\`
@keyframes fadeOut {
from {
opacity: 1;
}
50% {
opacity: 0.5;
}
to {
opacity: 0;
}
}
animation: fadeOut 2s ease-in-out;
\`;
hello world
`);
expect(actual).toIncludeMultiple([
'const _2="@keyframes fadeOut{0%{opacity:1}50%{opacity:0.5}to{opacity:0}}"',
'const _="._y44vk4ag{animation:fadeOut 2s ease-in-out}"',
'{[_,_2]}',
'className={ax(["_y44vk4ag"])}',
]);
});
it('should apply conditional logical expression object spread styles', () => {
const actual = transform(`
import '@compiled/react';
const Component = props => (
);
`);
expect(actual).toInclude('className={ax([props.isPrimary&&"_syaz13q2 _1wybgktf"])}');
});
it('should apply inverse conditional logical expression object spread', () => {
const actual = transform(`
import '@compiled/react';
const Component = props => (
);
`);
expect(actual).toInclude('className={ax([props.isPrimary||"_syaz13q2 _1wybgktf"])}');
});
it('should apply conditional logical expression object styles', () => {
const actual = transform(`
import '@compiled/react';
const Component = props => (
);
`);
expect(actual).toInclude('className={ax([props.isPrimary&&"_30l313q2 _e915gktf"])}');
});
it('should combine conditional logical expressions', () => {
const actual = transform(`
import '@compiled/react';
const Component = props => (
);
`);
expect(actual).toInclude(
'className={ax([props.isPrimary&&"_30l313q2",props.isPrimary&&props.isBold&&"_79b11fw0"])}'
);
});
it('should apply multi conditional logical expression', () => {
const actual = transform(`
import '@compiled/react';
const Component = props => (
);
`);
expect(actual).toInclude('ax([(props.isPrimary||props.isMaybe)&&"_syaz13q2 _1wybgktf"])');
});
it('should apply array logical-based conditional css', () => {
const actual = transform(`
import '@compiled/react';
const Component = props => (
);
`);
expect(actual).toInclude(
'ax(["_1wyb1ylp",(props.isPrimary||props.isMaybe)&&"_syaz13q2 _1wybgktf"])'
);
});
it('should apply array prop ternary-based inline conditional css', () => {
const actual = transform(`
import { css } from '@compiled/react';
const Component = ({ isPrimary }) => (
);
`);
expect(actual).toIncludeMultiple([
'._bfhk1x77{background-color:white}',
'._syaz11x8{color:black}',
'._bfhkbf54{background-color:green}',
'._syaz5scu{color:red}',
'._1wyb1fwx{font-size:12px}',
'',
]);
});
it('should apply array prop ternary-based conditional css that reference css variable declarations', () => {
const actual = transform(`
import { css } from '@compiled/react';
const positive = css({ background: 'white', color: 'black' });
const negative = css\`
background: green;
color: red;
\`;
const Component = ({ isPrimary }) => (
);
`);
expect(actual).toIncludeMultiple([
'._bfhk1x77{background-color:white}',
'._syaz11x8{color:black}',
'._bfhkbf54{background-color:green}',
'._syaz5scu{color:red}',
'._1wyb1fwx{font-size:12px}',
'',
]);
});
it('should apply partial logical-based conditional css rule', () => {
const actual = transform(`
import '@compiled/react';
const Component = props => (
hello world
);
`);
expect(actual).toInclude('ax([props.isPrimary&&"_syaz13q2 _1wybgktf","_19it97hw"])');
});
it('should apply unconditional before and after a conditional css rule', () => {
const actual = transform(`
import '@compiled/react';
const Component = props => (
hello world
);
`);
expect(actual).toInclude(
'ax(["_1wybo7ao",props.isPrimary&&"_syaz13q2 _1wybgktf","_19it97hw"])'
);
});
it('should use destructured props in conditional css rule', () => {
const actual = transform(`
import '@compiled/react';
const Component = ({ isPrimary }) => (
);
`);
expect(actual).toInclude('ax([isPrimary&&"_syaz13q2 _1wybgktf"])');
});
it('should retain keys for mapped react components', () => {
const actual = transform(`
import '@compiled/react';
['foo', 'bar'].map((str) => (
{str}
));
`);
expect(actual).toInclude('');
});
it('should not transform css prop with comment directive', () => {
const actual = transform(`
import { css } from '@compiled/react';
// @compiled-disable-next-line transform-css-prop
const RedDiv = ;
const GreenDiv = () => (
);
const BlueDiv = () => (
);
`);
expect(actual).toIncludeMultiple(["css={{color:'red'}}", 'css={null}', "css={{color:'blue'}}"]);
});
});