import dedent from 'dedent';
import prettier from 'prettier';
import collect from '../src/collect';
const prettyPrint = (src: string) => prettier.format(src, { parser: 'scss' });
const testCollect = (html: string, css: string) => {
const { critical, other } = collect(html, css);
test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot());
test('other', () => expect(prettyPrint(other)).toMatchSnapshot());
};
const html = dedent`
`;
describe('collects complex css', () => {
const css = dedent`
.lotus {
vertical-align: top;
}
@media (max-width: 1200px) {
.lotus {
vertical-align: bottom;
}
}
@supports (object-fit: cover) {
.unrelated-nested {
float: left;
animation: custom-animation;
}
.unrelated-nested2 {
float: left;
}
}
@supports (object-fit: contain) {
.lotus {
object-fit: contain;
}
.linaria::before,
.linaria::after {
content: '';
object-fit: contain;
}
}
@keyframes custom-animation {
0% { opacity: 0 }
50% { opacity: 0 }
100% { opacity: 1 }
}
.linaria {
float: left;
flex: 1;
animation: custom-animation .2s;
}
.linaria:hover {
float: right;
}
.linaria > span,
.linaria + .linaria,
.linaria ~ div {
display: none;
}
.linaria > span {
display: none;
}
.linaria::after {
display: block;
}
.unrelated {
animation-name: custom-animation;
}
.unrelated2 {
animation: custom-animation .3s;
}
.lily {
color: #fff;
}
[data-theme=dark] .lily {
color: #000;
}
.unrelated3 {
flex: 0;
}
.linaria ~ div {}
.linaria.linaria2{}
`;
testCollect(html, css);
});
describe('simple class name', () => {
const css = dedent`
.linaria {}
.classname {}
`;
testCollect(html, css);
});
describe('classname in @rule', () => {
const css = dedent`
@supports (object-fit: cover) { .linaria {} }
@media (min-width: 600px) { .linaria {} }
@charset () { .linaria {} }
@import () { .linaria {} }
@namespace () { .linaria {} }
@media () { .linaria {} }
@supports () { .linaria {} }
@document () { .linaria {} }
@page () { .linaria {} }
@keyframes () { .linaria {} }
@viewport () { .linaria {} }
@counter-style () { .linaria {} }
@font-feature-values () { .linaria {} }
@supports (object-fit: cover) { .other {} }
@media (min-width: 600px) { .other {} }
@charset () { .other {} }
@import () { .other {} }
@namespace () { .other {} }
@media () { .other {} }
@supports () { .other {} }
@document () { .other {} }
@page () { .other {} }
@keyframes () { .other {} }
@viewport () { .other {} }
@counter-style () { .other {} }
@font-feature-values () { .other {} }
`;
testCollect(html, css);
});
describe('works with CSS combinators', () => {
const css = dedent`
.linaria + span {}
.linaria ~ div {}
.linaria > a {}
.linaria b {}
.other + span {}
.other ~ div {}
.other > a {}
.other b {}
`;
testCollect(html, css);
});
describe('works with pseudo-class and pseudo-elements', () => {
const css = dedent`
.linaria:active {}
.linaria::before {}
.other:active {}
.other::before {}
`;
testCollect(html, css);
});
describe('works with global css', () => {
const css = dedent`
body { font-size: 13.37px; }
html { -webkit-font-smoothing: antialiased; }
h1 { font-weight: bold; }
.linaria:active {}
.linaria::before {}
.other:active {}
.other::before {}
`;
const { critical, other } = collect(html, css);
test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot());
test('other', () => expect(prettyPrint(other)).toMatchSnapshot());
});
describe('handles top-level @font-face', () => {
const css = dedent`
@font-face {
font-family: MyFont;
font-weight: normal;
font-style: normal;
src: url(MyFont.woff);
}
`;
const { critical, other } = collect(html, css);
test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot());
test('other', () => expect(prettyPrint(other)).toMatchSnapshot());
});
// there was a bug when the whole atrule was included for each child rule
describe('include atrule once', () => {
const css = dedent`
@media screen {
body {
font-size: 10px;
}
h1 {
font-size: 20px;
}
.class {
font-size: 15px;
}
}
`;
const { critical, other } = collect(html, css);
test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot());
test('other', () => expect(prettyPrint(other)).toMatchSnapshot());
});
describe('ignore empty class attribute', () => {
const code = dedent`
`;
const css = dedent`
.not-exist {}
`;
const { critical } = collect(code, css);
test('critical should be empty', () => expect(critical).toEqual(''));
});
test('does not match selectors in ignoredClasses list', () => {
const code = dedent`
`;
const css = dedent`
.linaria.dir {}
.linaria.ltr {}
.lily {}
`;
const { critical, other } = collect(code, css, {
ignoredClasses: ['ltr', 'dir'],
});
expect(critical).toMatchInlineSnapshot(`".lily {}"`);
expect(other).toMatchInlineSnapshot(`".linaria.dir {}.linaria.ltr {}"`);
});
test('does not match selectors in blockedClasses list', () => {
const code = dedent`
`;
const css = dedent`
.linaria.ltr {}
.linaria.rtl {}
.lily {}
`;
const { critical, other } = collect(code, css, { blockedClasses: ['rtl'] });
expect(critical).toMatchInlineSnapshot(`".linaria.ltr {}.lily {}"`);
expect(other).toMatchInlineSnapshot(`".linaria.rtl {}"`);
});
test('does not match child selectors in blockedClasses list for media queries', () => {
const code = dedent`
`;
const css = dedent`
@media only screen and (max-width:561.5px) {
.dir-ltr.left_6_3_l9xil3s {
padding-left: 24px !important;
}
.dir-rtl.left_6_3_l9xil3s {
padding-right: 24px !important;
}
}
`;
const { critical, other } = collect(code, css, {
blockedClasses: ['dir-rtl'],
});
expect(critical).toMatchInlineSnapshot(`
"@media only screen and (max-width:561.5px) {
.dir-ltr.left_6_3_l9xil3s {
padding-left: 24px !important;
}
}"
`);
expect(other).toMatchInlineSnapshot(`
"@media only screen and (max-width:561.5px) {
.dir-rtl.left_6_3_l9xil3s {
padding-right: 24px !important;
}
}"
`);
});