diff options
Diffstat (limited to 'stylis.js/test')
-rw-r--r-- | stylis.js/test/Middleware.js | 82 | ||||
-rw-r--r-- | stylis.js/test/Parser.js | 930 | ||||
-rw-r--r-- | stylis.js/test/Prefixer.js | 178 | ||||
-rw-r--r-- | stylis.js/test/Tokenizer.js | 9 |
4 files changed, 1199 insertions, 0 deletions
diff --git a/stylis.js/test/Middleware.js b/stylis.js/test/Middleware.js new file mode 100644 index 0000000..4d867ad --- /dev/null +++ b/stylis.js/test/Middleware.js @@ -0,0 +1,82 @@ +import {compile, serialize, stringify, middleware, rulesheet, prefixer, namespace} from "../index.js" + +const stack = [] + +describe('Middleware', () => { + test('rulesheet', () => { + serialize(compile(`@import url('something.com/file.css');.user{ h1 {width:0;} @media{width:1;}@keyframes name{from{width:0;}to{width:1;}}}`), middleware([prefixer, stringify, rulesheet(value => stack.push(value))])) + expect(stack).to.deep.equal([ + `@import url('something.com/file.css');`, + `.user h1{width:0;}`, + `@media{.user{width:1;}}`, + `@-webkit-keyframes name{from{width:0;}to{width:1;}}`, + `@keyframes name{from{width:0;}to{width:1;}}`, + ]) + }) + + test('namespace', () => { + expect(serialize(compile(`.user{width:0; :global(p,a){width:1;} h1 {width:1; h2:last-child {width:2} h2 h3 {width:3}}}`), middleware([namespace, stringify]))).to.equal([ + `.user{width:0;}`, `p,a{width:1;}`, `h1.user.user{width:1;}`, `h1.user h2:last-child.user{width:2;}`, `h1.user h2 h3.user{width:3;}` + ].join('')) + }) + + test('comments', () => { + expect(serialize(compile(`/*@noflip*/ .user{//noflip\n\n}`), middleware([value => value.type === 'comm' ? 'color:red;' : '', stringify]))).to.deep.equal([ + `color:red;.user{color:red;}` + ].join()) + }) + + test('prefixer', () => { + expect(serialize(compile(`.user{h1:last-child{clip-path:none;}`), middleware([prefixer, stringify]))).to.equal([ + `.user h1:last-child{-webkit-clip-path:none;clip-path:none;}`, + ].join('')) + + expect(serialize(compile(`@keyframes name{from{transform: rotate(0deg);}to{transform: rotate(360deg);}}`), middleware([prefixer, stringify]))).to.equal([ + `@-webkit-keyframes name{from{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg);}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg);}}`, + `@keyframes name{from{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg);}to{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg);}}` + ].join('')) + + expect(serialize(compile(`a:read-only{color:red;}`), middleware([prefixer, stringify]))).to.equal([ + `a:-moz-read-only{color:red;}`, `a:read-only{color:red;}` + ].join('')) + + expect(serialize(compile(`a:read-write{color:red;}`), middleware([prefixer, stringify]))).to.equal([ + `a:-moz-read-write{color:red;}`, `a:read-write{color:red;}` + ].join('')) + + expect(serialize(compile(`a::placeholder{color:red;}`), middleware([prefixer, stringify]))).to.equal([ + `a::-webkit-input-placeholder{color:red;}`, `a::-moz-placeholder{color:red;}`, `a:-ms-input-placeholder{color:red;}`, `a::placeholder{color:red;}` + ].join('')) + + expect(serialize(compile(`textarea::placeholder{font-size:14px;@media{font-size:16px;}}`), middleware([prefixer, stringify]))).to.equal([ + `textarea::-webkit-input-placeholder{font-size:14px;}textarea::-moz-placeholder{font-size:14px;}textarea:-ms-input-placeholder{font-size:14px;}textarea::placeholder{font-size:14px;}`, + `@media{textarea::-webkit-input-placeholder{font-size:16px;}textarea::-moz-placeholder{font-size:16px;}textarea:-ms-input-placeholder{font-size:16px;}textarea::placeholder{font-size:16px;}}` + ].join('')) + + expect(serialize(compile(`div:read-write{background-color:red;span{background-color:green;}}`), middleware([prefixer, stringify]))).to.equal([ + `div:-moz-read-write{background-color:red;}`, + `div:read-write{background-color:red;}`, + `div:-moz-read-write span{background-color:green;}`, + `div:read-write span{background-color:green;}` + ].join('')) + + expect(serialize(compile(`div:read-write span{background-color:hotpink;}`), middleware([prefixer, stringify]))).to.equal([ + `div:-moz-read-write span{background-color:hotpink;}`, + `div:read-write span{background-color:hotpink;}` + ].join('')) + + expect(serialize(compile(`.read-write:read-write,.read-only:read-only,.placeholder::placeholder{background-color:hotpink;}`), middleware([prefixer, stringify]))).to.equal([ + `.read-write:-moz-read-write{background-color:hotpink;}`, + `.read-only:-moz-read-only{background-color:hotpink;}`, + `.placeholder::-webkit-input-placeholder{background-color:hotpink;}`, + `.placeholder::-moz-placeholder{background-color:hotpink;}`, + `.placeholder:-ms-input-placeholder{background-color:hotpink;}`, + `.read-write:read-write,.read-only:read-only,.placeholder::placeholder{background-color:hotpink;}`, + ].join('')) + + expect(serialize(compile(`:read-write{background-color:hotpink;}`), middleware([prefixer, stringify]))).to.equal([ + `:-moz-read-write{background-color:hotpink;}`, + `:read-write{background-color:hotpink;}` + ].join('')) + }) +}) diff --git a/stylis.js/test/Parser.js b/stylis.js/test/Parser.js new file mode 100644 index 0000000..3bed9a9 --- /dev/null +++ b/stylis.js/test/Parser.js @@ -0,0 +1,930 @@ +import {compile, serialize, stringify} from "../index.js" + +const stylis = string => serialize(compile(`.user{${string}}`), stringify) + +describe('Parser', () => { + test('unnested', () => { + expect(serialize(compile(`--foo:none;@supports{--bar:none;}`), stringify)).to.equal(`--foo:none;@supports{--bar:none;}`) + }) + + test('escape', () => { + expect( + stylis(` + height:calc(\\))\t!important; + `) + ).to.equal(`.user{height:calc(\\))!important;}`) + }) + + test('calc', () => { + expect( + stylis(` + height:calc( 100vh - 1px ); + height:calc( + 100vh - + 1px + ); + `) + ).to.equal(`.user{height:calc( 100vh - 1px );height:calc(\n 100vh -\n 1px\n );}`) + }) + + test('at-rules', () => { + expect( + stylis(` + @-ms-viewport { + width:device-width; + } + @viewport { + width:device-width; + } + @page & { + invalid:true; + } + @page { + size:A4 landscape; + } + @document url(://www.w3.org/),url-prefix(//www.w3.org/),domain(mozilla.org),regexp("https:.*") { + body { + color: red; + } + } + @viewport { + min-width:640px; + max-width:800px; + } + @counter-style list { + system:fixed; + symbols:url(); + suffix:" "; + } + @-moz-document url-prefix() { + .selector { + color:lime; + } + } + @page { + color:red; + @bottom-right { + content: counter(pages); + margin-right: 1cm; + } + width: none; + } + `) + ).to.equal([ + `@-ms-viewport{width:device-width;}`, + `@viewport{width:device-width;}`, + `@page &{invalid:true;}`, + `@page{size:A4 landscape;}`, + `@document url(://www.w3.org/),url-prefix(//www.w3.org/),domain(mozilla.org),regexp("https:.*"){.user body{color:red;}}`, + `@viewport{min-width:640px;max-width:800px;}`, + `@counter-style list{system:fixed;symbols:url();suffix:" ";}`, + `@-moz-document url-prefix(){.user .selector{color:lime;}}`, + `@page{color:red;@bottom-right{content:counter(pages);margin-right:1cm;}width:none;}` + ].join('')) + }) + + test('universal selector', () => { + expect( + stylis(` + * { + color:red; + } + svg { + &, & * { + fill: currentColor; + } + } + * * {color:hotpink;} + `) + ).to.equal([ + `.user *{color:red;}`, + `.user svg,.user svg *{fill:currentColor;}`, + `.user * *{color:hotpink;}` + ].join('')) + }) + + test('flat', () => { + expect( + stylis(` + color:20px; + font-size:20px + `) + ).to.equal(`.user{color:20px;font-size:20px;}`) + }) + + test('namespace', () => { + expect( + stylis(` + & { + color:red; + } + `) + ).to.equal(`.user{color:red;}`) + }) + + test('& in a string', () => { + expect( + stylis(` + & [href="https://css-tricks.com?a=1&b=2"] { + color:red; + } + `) + ).to.equal(`.user [href="https://css-tricks.com?a=1&b=2"]{color:red;}`) + }) + + test('comments', () => { + expect( + stylis(` + // line comment + // color: red; + /** + * removes block comments and line comments, + * there's a fire in the house // there is + */ + button /* + // what's + xxx + */ + {color: blue;} + // hello + button /* 1 */ + { + color: red; /* 2 */ + } + /*! 1 */ + color: red; + /*! 2 */ + h1 { + /*! 1 */ + color: red; + /*! 2 */ + color: red; + /*! 3 */ + } + `) + ).to.equal([ + `.user{color:red;}`, + `.user button{color:blue;}.user button{color:red;}`, + `.user h1{color:red;color:red;}` + ].join('')) + }) + + test('&', () => { + expect( + stylis(` + & { + color:blue; + } + &&& { + color:red; + } + & + & { + color:red; + } + .wrapper button& { + color:red; + } + &:hover & { + color: green; + } + div:hover & { + color: green; + } + div:hover & { + h1 & { + color:red; + } + } + `) + ).to.equal([ + `.user{color:blue;}`, + `.user.user.user{color:red;}`, + `.user+.user{color:red;}`, + `.wrapper button.user{color:red;}`, + `.user:hover .user{color:green;}`, + `div:hover .user{color:green;}`, + `h1 div:hover .user{color:red;}` + ].join('')) + }) + + test('&:before', () => { + expect( + stylis(` + &:before{ + color:blue; + } + `) + ).to.equal(`.user:before{color:blue;}`) + }) + + test('& :hover', () => { + expect( + stylis(` + & :hover{ + color:blue; + } + `) + ).to.equal(`.user :hover{color:blue;}`) + }) + + test('div :hover', () => { + expect( + stylis(` + div :hover { + color:blue; + } + `) + ).to.equal(`.user div :hover{color:blue;}`) + }) + + test('@import', () => { + expect(stylis(`@import url('http://example.com');`)).to.equal(`@import url('http://example.com');`) + }) + + test('@supports', () => { + expect( + stylis(` + @supports (display:block) { + color:red; + h1 { + color:red; + h2 { + color:blue; + } + } + display:none; + } + @supports (appearance: none) { + color:red; + } + @supports (backdrop-filter: blur(10px)) { + backdrop-filter: blur(10px); + } + `) + ).to.equal([ + '@supports (display:block){.user{color:red;display:none;}.user h1{color:red;}.user h1 h2{color:blue;}}', + '@supports (appearance: none){.user{color:red;}}', + '@supports (backdrop-filter: blur(10px)){.user{backdrop-filter:blur(10px);}}' + ].join('')) + }) + + test('@media', () => { + expect( + stylis(` + @media (max-width:600px) { + color:red; + h1 { + color:red; + h2 { + color:blue; + } + } + display:none; + } + @media (min-width:576px) { + &.card-deck { + .card { + &:not(:first-child) { + margin-left:15px; + } + &:not(:last-child) { + margin-right:15px; + } + } + } + } + @supports (display:block) { + @media (min-width:10px) { + background-color:seagreen; + } + } + @media (max-width:600px) { + & { color:red } + } + &:hover { + color:orange + } + `) + ).to.equal([ + '@media (max-width:600px){.user{color:red;display:none;}.user h1{color:red;}.user h1 h2{color:blue;}}', + '@media (min-width:576px){.user.card-deck .card:not(:first-child){margin-left:15px;}.user.card-deck .card:not(:last-child){margin-right:15px;}}', + '@supports (display:block){@media (min-width:10px){.user{background-color:seagreen;}}}', + '@media (max-width:600px){.user{color:red;}}.user:hover{color:orange;}' + ].join('')) + }) + + test('@media specifity', () => { + expect( + stylis(` + > #box-not-working { + background:red; + padding-left:8px; + width:10px; + @media only screen and (min-width:10px) { + width: calc(10px + 90px * (100vw - 10px) / 90); + } + @media only screen and (min-width:90px) { + width: 90px; + } + height: 10px; + @media only screen and (min-width:10px) { + height: calc(10px + 90px * (100vw - 10px) / 90); + } + @media only screen and (min-width:90px) { + height: 90px; + } + } + `) + ).to.equal([ + '.user >#box-not-working{background:red;padding-left:8px;width:10px;height:10px;}', + '@media only screen and (min-width:10px){.user >#box-not-working{width:calc(10px + 90px * (100vw - 10px) / 90);}}', + '@media only screen and (min-width:90px){.user >#box-not-working{width:90px;}}', + '@media only screen and (min-width:10px){.user >#box-not-working{height:calc(10px + 90px * (100vw - 10px) / 90);}}', + '@media only screen and (min-width:90px){.user >#box-not-working{height:90px;}}' + ].join('')) + }) + + test('@font-face', () => { + expect( + stylis(` + @font-face { + font-family:Pangolin; + src:url('Pangolin-Regular.ttf') format('truetype'); + } + `) + ).to.equal( + `@font-face{font-family:Pangolin;src:url('Pangolin-Regular.ttf') format('truetype');}` + ) + }) + + test('multiple selectors', () => { + expect( + stylis(` + span, h1 { + color:red; + } + h1, &:after, &:before { + color:red; + } + `) + ).to.equal([ + `.user span,.user h1{color:red;}`, + `.user h1,.user:after,.user:before{color:red;}` + ].join('')) + }) + + test('[title="a,b"] and :matches(a,b)', () => { + expect( + stylis(` + .test:matches(a,b,c), .test { + color:blue; + } + .test[title=","] { + color:red; + } + [title="a,b,c, something"], h1, [title="a,b,c"] { + color:red + } + [title="a"], + [title="b"] { + color:red; + } + `) + ).to.equal([ + `.user .test:matches(a,b,c),.user .test{color:blue;}`, + `.user .test[title=","]{color:red;}`, + `.user [title="a,b,c, something"],.user h1,.user [title="a,b,c"]{color:red;}`, + `.user [title="a"],.user [title="b"]{color:red;}` + ].join('')) + }) + + test('quotes', () => { + expect( + stylis(` + .foo:before { + content:".hello {world}"; + content:".hello {world} ' "; + content:'.hello {world} " '; + } + `) + ).to.equal(`.user .foo:before{content:".hello {world}";content:".hello {world} ' ";content:'.hello {world} " ';}`) + }) + + test('quotes - escaping', () => { + expect( + stylis(` + .foo:before { + content:"\\""; + content:"\\\\\\""; + + content:'\\''; + content:'\\\\\\''; + } + `) + ).to.equal(`.user .foo:before{content:"\\"";content:"\\\\\\"";content:'\\'';content:'\\\\\\'';}`) + }) + + test('remove empty css', () => { + expect( + stylis(`& { }`) + ).to.equal(``) + }) + + test('urls', () => { + expect( + stylis(` + background:url(http://url.com/}); + background:url(http://url.com//1234) '('; // sdsd + background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAAABCAIAAADsEU8HAAAACXBIW` + + `XMAAAsTAAALEwEAmpwYAAAAIklEQVQI12P8//8/Aw4wbdq0rKysAZG1trbGJXv06FH8sgDIJBbBfp+hFAAAAABJRU5ErkJggg==");` + ) + ).to.equal([ + `.user{background:url(http://url.com/});`, + `background:url(http://url.com//1234) '(';`, + `background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAAABCAIAAADsEU8HAAAACXBIW`, + `XMAAAsTAAALEwEAmpwYAAAAIklEQVQI12P8//8/Aw4wbdq0rKysAZG1trbGJXv06FH8sgDIJBbBfp+hFAAAAABJRU5ErkJggg==");}` + ].join('')) + }) + + test('last semicolon omission', () => { + expect( + stylis(` + .content { + color:red + } + .content { + color:blue + } + `) + ).to.equal( + [`.user .content{color:red;}`, `.user .content{color:blue;}`].join('') + ) + }) + + test(':matches(:not())', () => { + expect( + stylis(` + h1:matches(.a,.b,:not(.c)) { + display: none + } + `) + ).to.equal(`.user h1:matches(.a,.b,:not(.c)){display:none;}`) + }) + + test('@keyframes', () => { + expect(serialize(compile(` + @-webkit-keyframes slidein { + to { transform:translate(20px); } + } + @keyframes slidein { + to { transform:translate(20px); } + } + @keyframes hahaha { + 0%, + 1%{t:0} + } + @keyframes infinite-spinning { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + `), stringify)).to.equal([ + `@-webkit-keyframes slidein{to{transform:translate(20px);}}`, + `@keyframes slidein{to{transform:translate(20px);}}`, + `@keyframes hahaha{0%,1%{t:0;}}`, + `@keyframes infinite-spinning{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}` + ].join('')) + }) + + test('edge cases', () => { + expect( + stylis(` + @media (min-width:537px) { + border-bottom:4px solid red; + } + &::placeholder { + color:pink; + } + .a {color:'red'} + .b {color:"red"} + .a {color:red;}[role=button]{color:red;} + .b {padding:30 3} + .c {v-text-anchor: middle;} + `) + ).to.equal([ + `@media (min-width:537px){.user{border-bottom:4px solid red;}}`, + `.user::placeholder{color:pink;}`, + `.user .a{color:'red';}`, + `.user .b{color:"red";}`, + `.user .a{color:red;}`, + `.user [role=button]{color:red;}`, + `.user .b{padding:30 3;}`, + `.user .c{v-text-anchor:middle;}` + ].join('')) + }) + + test('whitespace', () => { + expect( + stylis(` + @import\r\n "./a.css"; + + div { + ${'width:0; '} + } + .foo { + color : hotpink; + } + `) + ).to.equal([ + `@import "./a.css";`, + `.user div{width:0;}`, + `.user .foo{color:hotpink;}` + ].join('')) + }) + + test('no trailing semi-colons', () => { + expect(stylis(` + h2 { + display:none + } + div:hover + { + color:red + } + `)).to.equal([ + '.user h2{display:none;}', + '.user div:hover{color:red;}' + ].join('')) + }) + + test('multiline declaration', () => { + expect(stylis(` + html { + background: + linear-gradient(0deg, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), + url(/static/background.svg); + } + `)).to.equal(`.user html{background:linear-gradient(0deg, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)),url(/static/background.svg);}`) + }) + + test('nesting selector multiple levels', () => { + expect( + stylis(` + a { + a { + a { + a { + a { + a { + a { + a { + a { + a { + a { + a { + color:red; + } + } + } + } + } + } + } + } + } + } + } + } + `) + ).to.equal(`.user a a a a a a a a a a a a{color:red;}`) + }) + + test('nesting @media multiple levels', () => { + expect( + stylis(` + div { + @media { + a { + color:red; + + @media { + h1 { + color:hotpink; + } + } + } + } + } + `) + ).to.equal([`@media{.user div a{color:red;}`, `@media{.user div a h1{color:hotpink;}}}`].join('')) + }) + + test('noop tail I', () => { + expect(stylis(`color:red/**/`)).to.equal(`.user{color:red;}`) + }) + + test('noop tail II', () => { + expect(stylis(`color:red//`,)).to.equal('.user{color:red;}') + }) + + test('noop tail III', () => { + expect(stylis(`color:red[]`)).to.equal(`.user{color:red[];}`) + }) + + test('noop tail IV', () => { + expect(stylis(`color:red()`)).to.equal(`.user{color:red();}`) + }) + + test('noop tail V', () => { + expect(stylis(`color:red''`)).to.equal(`.user{color:red'';}`) + }) + + test('noop tail VI', () => { + expect(stylis(`color:red""`)).to.equal(`.user{color:red"";}`) + }) + + test('noop tail VII', () => { + expect(stylis(`h1{color:red/**}`)).to.equal(`.user h1{color:red;}`) + }) + + test('context character I', () => { + expect(stylis(`.a{color:red;/* } */}`)).to.equal(`.user .a{color:red;}`) + }) + + test('context character II', () => { + expect(stylis(`.a{color:red;/*}*/}`)).to.equal(`.user .a{color:red;}`) + }) + + test('context character III', () => { + expect(stylis(`.a{color:red;/*{*/}`)).to.equal(`.user .a{color:red;}`) + }) + + test('context character IV', () => { + expect(stylis(`.a{/**/color:red}`)).to.equal(`.user .a{color:red;}`) + }) + + test('context character V', () => { + expect(stylis(`.a{color:red;/*//color:blue;*/}`)).to.equal(`.user .a{color:red;}`) + }) + + test('context character VI', () => { + expect( + stylis( + `background: url("img}.png");.a {background: url("img}.png");}` + ) + ).to.equal([ + `.user{background:url("img}.png");}`, + `.user .a{background:url("img}.png");}` + ].join('')) + }) + + test('context character VII', () => { + expect( + stylis(`background: url(img}.png);.a {background: url(img}.png);}`) + ).to.equal([ + `.user{background:url(img}.png);}`, + `.user .a{background:url(img}.png);}` + ].join('')) + }) + + test('context character VIII', () => { + expect( + stylis(`background: url[img}.png];.a {background: url[img}.png];}`) + ).to.equal([ + `.user{background:url[img}.png];}`, + `.user .a{background:url[img}.png];}` + ].join('')) + }) + + test('`--` in an identifier (#220)', () => { + expect( + stylis(` + .block--modifier { + color: hotpink; + } + .card { + color: black; + } + `) + ).to.equal([ + `.user .block--modifier{color:hotpink;}`, + `.user .card{color:black;}` + ].join('')) + }) + + test('comments in rules not increasing depth of consecutive rules (#154)', () => { + expect( + stylis(` + font-size:2rem; + .one{color:black;/* foo */} + .two{color:black;/* bar */} + .three{color:black;/* baz */} + `) + ).to.equal([ + '.user{font-size:2rem;}', + '.user .one{color:black;}', + '.user .two{color:black;}', + '.user .three{color:black;}' + ].join('')) + }) + + test('comment in a group of selectors inside a media query (#152)', () => { + expect( + stylis(` + @media (min-width: 400px) { + div /* comment */ { + border-left:1px solid hotpink; + } + span { + border-top:none; + } + } + `) + ).to.equal(`@media (min-width: 400px){.user div{border-left:1px solid hotpink;}.user span{border-top:none;}}`) + }) + + test('comment - bang at the start (#114)', () => { + expect(serialize(compile(`/*! test */body{color:red;}`), stringify)).to.equal('body{color:red;}') + }) + + test('parenthesis in string literal I (#151)', () => { + expect( + stylis(` + @media only screen and (max-width: 320px){ + background: url("${'image_(1).jpg'}"); + } + + @media only screen and (min-width:321px) { + background: url("${'image_(1).jpg'}"); + } + `) + ).to.equal([ + `@media only screen and (max-width: 320px){.user{background:url("${'image_(1).jpg'}");}}`, + `@media only screen and (min-width:321px){.user{background:url("${'image_(1).jpg'}");}}` + ].join('')) + }) + + test('parenthesis in string literal II (#123)', () => { + expect( + stylis(` + .a { + background: url("${'image_(1).jpg'})"); + } + + .b { + background: url("abc"); + } + `) + ).to.equal([ + `.user .a{background:url("image_(1).jpg)");}`, + `.user .b{background:url("abc");}` + ].join('')) + }) + + test('parenthesis in string literal III (#128)', () => { + expect( + stylis(` + .icon { + background:url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M14.117.323L8.044 6.398 2.595.323a1.105 1.105 0 0 0-1.562 1.562L6.482 7.96.323 14.119a1.105 1.105 0 0 0 1.562 1.562L7.96 9.608l5.449 6.073a1.103 1.103 0 1 0 1.56-1.562L9.517 8.046l6.159-6.161a1.103 1.103 0 1 0-1.56-1.562z' fill='rgba(85, 85, 85, 0.5)'/%3E%3C/svg%3E"); + } + + div { + background: cyan; + } + `) + ).to.equal([ + `.user .icon{background:url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='12' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M14.117.323L8.044 6.398 2.595.323a1.105 1.105 0 0 0-1.562 1.562L6.482 7.96.323 14.119a1.105 1.105 0 0 0 1.562 1.562L7.96 9.608l5.449 6.073a1.103 1.103 0 1 0 1.56-1.562L9.517 8.046l6.159-6.161a1.103 1.103 0 1 0-1.56-1.562z' fill='rgba(85, 85, 85, 0.5)'/%3E%3C/svg%3E");}`, + `.user div{background:cyan;}` + ].join('')) + }) + + test('parenthesis in string literal IV (#116)', () => { + expect( + stylis(` + .a .b .c { + width: calc(100% / "func()"); + } + + .d { + background: yellow; + } + `) + ).to.equal([ + `.user .a .b .c{width:calc(100% / "func()");}`, + `.user .d{background:yellow;}` + ].join('')) + }) + + test('nested parenthesis', () => { + expect(stylis(`width: calc(calc(1) + 10);`)).to.equal(`.user{width:calc(calc(1) + 10);}`) + }) + + test('css variables edge cases (#144, #173)', () => { + expect( + stylis(` + --braces: { }; + --at-keyword-unknown-block: @foobar {}; + --at-keyword-known-block: @media {}; + --cdo-at-top-level: <!--; + --cdc-at-top-level: -->; + --semicolon-not-top-level: (;); + --cdo-not-top-level: (<!--); + --cdc-not-top-level: (-->); + --ampersand-preserved: foo & bar; + `) + ).to.equal(`.user{` + [ + `--braces:{};`, + `--at-keyword-unknown-block:@foobar{};`, + `--at-keyword-known-block:@media{};`, + `--cdo-at-top-level:<!--;`, + `--cdc-at-top-level:-->;`, + `--semicolon-not-top-level:(;);`, + `--cdo-not-top-level:(<!--);`, + `--cdc-not-top-level:(-->);`, + `--ampersand-preserved:foo & bar;` + ].join('') +'}') + }) + + test('does not hang on unterminated block comment (#129)', () => { + expect(stylis(`/*`)).to.equal(``) + }) + + test('does not hang on unterminated function', () => { + expect(stylis(`(`)).to.equal(``) + }) + + test('handles single `/` in a value', () => { + expect(stylis(`font: 12px/14px serif;`)).to.equal(`.user{font:12px/14px serif;}`) + }) + + test('nested', () => { + expect(stylis(` + div { + h2 { + color:red; + h3 { + color:blue; + } + } + } + + .foo & { + width:1px; + &:hover { + color:black; + } + li { + color:white; + } + } + + h1, div { + color:red; + h2, + &:before { + color:red; + } + color:blue; + header { + font-size:12px; + } + @media { + color:red; + } + @media { + color:blue; + } + } + + &.foo { + &.bar { + color:orange + } + } + + &.foo { + &.bar { + &.barbar { + color:orange + } + } + } + `)).to.equal([ + `.user div h2{color:red;}`+ + `.user div h2 h3{color:blue;}`+ + `.foo .user{width:1px;}`+ + `.foo .user:hover{color:black;}`+ + `.foo .user li{color:white;}`+ + `.user h1,.user div{color:red;color:blue;}`+ + `.user h1 h2,.user div h2,.user h1:before,.user div:before{color:red;}`+ + `.user h1 header,.user div header{font-size:12px;}`+ + `@media{.user h1,.user div{color:red;}}`+ + `@media{.user h1,.user div{color:blue;}}`+ + `.user.foo.bar{color:orange;}`+ + `.user.foo.bar.barbar{color:orange;}` + ].join('')) + }) +}) diff --git a/stylis.js/test/Prefixer.js b/stylis.js/test/Prefixer.js new file mode 100644 index 0000000..c744804 --- /dev/null +++ b/stylis.js/test/Prefixer.js @@ -0,0 +1,178 @@ +import {prefix} from "../index.js" + +describe('Prefixer', () => { + test('flex-box', () => { + expect(prefix(`display:block;`, 7)).to.equal(['display:block;'].join()) + expect(prefix(`display:flex!important;`, 7)).to.equal([`display:-webkit-box!important;`, `display:-webkit-flex!important;`, `display:-ms-flexbox!important;`, `display:flex!important;`].join('')) + expect(prefix(`display:inline-flex;`, 7)).to.equal([`display:-webkit-inline-box;`, `display:-webkit-inline-flex;`, `display:-ms-inline-flexbox;`, `display:inline-flex;`].join('')) + expect(prefix(`display:inline-box;`, 7)).to.equal([`-webkit-display:inline-box;`, `display:inline-box;`].join('')) + expect(prefix(`flex:inherit;`, 4)).to.equal([`-webkit-flex:inherit;`, `-ms-flex:inherit;`, `flex:inherit;`].join('')) + expect(prefix(`flex-grow:none;`, 9)).to.equal([`-webkit-box-flex:none;`, `-webkit-flex-grow:none;`, `-ms-flex-positive:none;`, `flex-grow:none;`].join('')) + expect(prefix(`flex-shrink:none;`, 11)).to.equal([`-webkit-flex-shrink:none;`, `-ms-flex-negative:none;`, `flex-shrink:none;`].join('')) + expect(prefix(`flex-basis:none;`, 10)).to.equal([`-webkit-flex-basis:none;`, `-ms-flex-preferred-size:none;`, `flex-basis:none;`].join('')) + expect(prefix(`align-self:value;`, 10)).to.equal([`-webkit-align-self:value;`, `-ms-flex-item-align:value;`, `align-self:value;`].join('')) + expect(prefix(`align-self:flex-start;`, 10)).to.equal([`-webkit-align-self:flex-start;`, `-ms-flex-item-align:flex-start;`, `align-self:flex-start;`].join('')) + expect(prefix(`align-self:flex-end;`, 10)).to.equal([`-webkit-align-self:flex-end;`, `-ms-flex-item-align:flex-end;`, `align-self:flex-end;`].join('')) + expect(prefix(`align-content:value;`, 13)).to.equal([`-webkit-align-content:value;`, `-ms-flex-line-pack:value;`, `align-content:value;`].join('')) + expect(prefix(`align-content:flex-start;`, 13)).to.equal([`-webkit-align-content:flex-start;`, `-ms-flex-line-pack:flex-start;`, `align-content:flex-start;`].join('')) + expect(prefix(`align-content:flex-end;`, 13)).to.equal([`-webkit-align-content:flex-end;`, `-ms-flex-line-pack:flex-end;`, `align-content:flex-end;`].join('')) + expect(prefix(`align-items:value;`, 11)).to.equal([`-webkit-align-items:value;`, `-webkit-box-align:value;`, `-ms-flex-align:value;`, `align-items:value;`].join('')) + expect(prefix(`justify-content:flex-end;`, 15)).to.equal([`-webkit-box-pack:end;`, `-ms-flex-pack:end;`, `-webkit-justify-content:flex-end;`, `justify-content:flex-end;`].join('')) + expect(prefix(`justify-content:flex-start;`, 15)).to.equal([`-webkit-box-pack:start;`, `-ms-flex-pack:start;`, `-webkit-justify-content:flex-start;`, `justify-content:flex-start;`].join('')) + expect(prefix(`justify-content:justify;`, 15)).to.equal([`-webkit-box-pack:justify;`, `-ms-flex-pack:justify;`, `-webkit-justify-content:justify;`, `justify-content:justify;`].join('')) + expect(prefix(`justify-content:space-between;`, 15)).to.equal([`-webkit-box-pack:justify;`, `-webkit-justify-content:space-between;`, `justify-content:space-between;`].join('')) + expect(prefix(`justify-items:center;`, 13)).to.equal([`justify-items:center;`].join('')) + expect(prefix(`order:flex;`, 5)).to.equal([`-webkit-order:flex;`, `-ms-flex-order:flex;`, `order:flex;`].join('')) + expect(prefix(`flex-direction:column;`, 14)).to.equal([`-webkit-flex-direction:column;`, `-ms-flex-direction:column;`, `flex-direction:column;`].join('')) + }) + + test('transform', () => { + expect(prefix(`transform:rotate(30deg);`, 9)).to.equal([`-webkit-transform:rotate(30deg);`, `-moz-transform:rotate(30deg);`, `-ms-transform:rotate(30deg);`, `transform:rotate(30deg);`].join('')) + }) + + test('cursor', () => { + expect(prefix(`cursor:none;`, 6)).to.equal([`cursor:none;`].join('')) + expect(prefix(`cursor:grab;`, 6)).to.equal([`cursor:-webkit-grab;`, `cursor:grab;`].join('')) + expect(prefix(`cursor:image-set(url(foo.jpg) 2x), pointer;`, 6)).to.equal([ + `cursor:-webkit-image-set(url(foo.jpg) 2x), pointer;`, + `cursor:image-set(url(foo.jpg) 2x), pointer;` + ].join('')) + expect(prefix(`cursor:image-set(url(foo.jpg) 2x), grab;`, 6)).to.equal([ + `cursor:-webkit-image-set(url(foo.jpg) 2x), -webkit-grab;`, + `cursor:image-set(url(foo.jpg) 2x), grab;` + ].join('')) + }) + + test('backface-visibility', () => { + expect(prefix(`backface-visibility:hidden;`, 19)).to.equal([`-webkit-backface-visibility:hidden;`, `backface-visibility:hidden;`].join('')) + }) + + test('transition', () => { + expect(prefix(`transition:transform 1s,transform all 400ms,text-transform;`, 10)).to.equal([ + `-webkit-transition:-webkit-transform 1s,-webkit-transform all 400ms,text-transform;`, + `transition:transform 1s,transform all 400ms,text-transform;` + ].join('')) + }) + + test('writing-mode', () => { + expect(prefix(`writing-mode:none;`, 12)).to.equal([`-webkit-writing-mode:none;`, `-ms-writing-mode:none;`, `writing-mode:none;`].join('')) + expect(prefix(`writing-mode:vertical-lr;`, 12)).to.equal([`-webkit-writing-mode:vertical-lr;`, `-ms-writing-mode:tb;`, `writing-mode:vertical-lr;`].join('')) + expect(prefix(`writing-mode:vertical-rl;`, 12)).to.equal([`-webkit-writing-mode:vertical-rl;`, `-ms-writing-mode:tb-rl;`, `writing-mode:vertical-rl;`].join('')) + expect(prefix(`writing-mode:horizontal-tb;`, 12)).to.equal([`-webkit-writing-mode:horizontal-tb;`, `-ms-writing-mode:lr;`, `writing-mode:horizontal-tb;`].join('')) + expect(prefix(`writing-mode:sideways-rl;`, 12)).to.equal([`-webkit-writing-mode:sideways-rl;`, `-ms-writing-mode:tb-rl;`, `writing-mode:sideways-rl;`].join('')) + expect(prefix(`writing-mode:sideways-lr;`, 12)).to.equal([`-webkit-writing-mode:sideways-lr;`, `-ms-writing-mode:tb;`, `writing-mode:sideways-lr;`].join('')) + }) + + test('columns', () => { + expect(prefix(`columns:auto;`, 7)).to.equal([`-webkit-columns:auto;`, `columns:auto;`].join('')) + expect(prefix(`column-count:auto;`, 12)).to.equal([`-webkit-column-count:auto;`, `column-count:auto;`].join('')) + expect(prefix(`column-fill:auto;`, 11)).to.equal([`-webkit-column-fill:auto;`, `column-fill:auto;`].join('')) + expect(prefix(`column-gap:auto;`, 10)).to.equal([`-webkit-column-gap:auto;`, `column-gap:auto;`].join('')) + expect(prefix(`column-rule:auto;`, 11)).to.equal([`-webkit-column-rule:auto;`, `column-rule:auto;`].join('')) + expect(prefix(`column-rule-color:auto;`, 17)).to.equal([`-webkit-column-rule-color:auto;`, `column-rule-color:auto;`].join('')) + expect(prefix(`column-rule-style:auto;`, 17)).to.equal([`-webkit-column-rule-style:auto;`, `column-rule-style:auto;`].join('')) + expect(prefix(`column-rule-width:auto;`, 17)).to.equal([`-webkit-column-rule-width:auto;`, `column-rule-width:auto;`].join('')) + expect(prefix(`column-span:auto;`, 11)).to.equal([`-webkit-column-span:auto;`, `column-span:auto;`].join('')) + expect(prefix(`column-width:auto;`, 12)).to.equal([`-webkit-column-width:auto;`, `column-width:auto;`].join('')) + }) + + test('text', () => { + expect(prefix(`text-align:left;`, 10)).to.equal([`text-align:left;`].join('')) + expect(prefix(`text-transform:none;`, 14)).to.equal([`text-transform:none;`].join('')) + expect(prefix(`text-shadow:none;`, 11)).to.equal([`text-shadow:none;`].join('')) + expect(prefix(`text-size-adjust:none;`, 16)).to.equal([`-webkit-text-size-adjust:none;`, `-moz-text-size-adjust:none;`, `-ms-text-size-adjust:none;`, `text-size-adjust:none;`].join('')) + expect(prefix(`text-decoration:none;`, 15)).to.equal([`-webkit-text-decoration:none;`, `text-decoration:none;`].join('')) + }) + + test('mask', () => { + expect(prefix(`mask:none;`, 10)).to.equal([`-webkit-mask:none;`, `mask:none;`].join('')) + expect(prefix(`mask-image:none;`, 10)).to.equal([`-webkit-mask-image:none;`, `mask-image:none;`].join('')) + expect(prefix(`mask-image:linear-gradient(#fff);`, 10)).to.equal([`-webkit-mask-image:linear-gradient(#fff);`, `mask-image:linear-gradient(#fff);`].join('')) + expect(prefix(`mask-mode:none;`, 10)).to.equal([`-webkit-mask-mode:none;`, `mask-mode:none;`].join('')) + expect(prefix(`mask-clip:none;`, 10)).to.equal([`-webkit-mask-clip:none;`, `mask-clip:none;`].join('')) + expect(prefix(`mask-size:none;`, 10)).to.equal([`-webkit-mask-size:none;`, `mask-size:none;`].join('')) + expect(prefix(`mask-repeat:none;`, 10)).to.equal([`-webkit-mask-repeat:none;`, `mask-repeat:none;`].join('')) + expect(prefix(`mask-origin:none;`, 10)).to.equal([`-webkit-mask-origin:none;`, `mask-origin:none;`].join('')) + expect(prefix(`mask-position:none;`, 10)).to.equal([`-webkit-mask-position:none;`, `mask-position:none;`].join('')) + expect(prefix(`mask-composite:none;`, 10)).to.equal([`-webkit-mask-composite:none;`, `mask-composite:none;`].join('')) + }) + + test('filter', () => { + expect(prefix(`filter:grayscale(100%);`, 6)).to.equal([`-webkit-filter:grayscale(100%);`, `filter:grayscale(100%);`].join('')) + expect(prefix(`fill:red;`, 4)).to.equal([`fill:red;`].join('')) + }) + + test('position', () => { + expect(prefix(`position:relative;`, 8)).to.equal([`position:relative;`].join('')) + expect(prefix(`position:sticky;`, 8)).to.equal([`-webkit-position:sticky;`, `position:sticky;`].join('')) + }) + + test('box', () => { + expect(prefix(`box-decoration-break:slice;`, 20)).to.equal([`-webkit-box-decoration-break:slice;`, `box-decoration-break:slice;`].join('')) + expect(prefix(`box-sizing:border-box;`, 10)).to.equal([`box-sizing:border-box;`].join('')) + }) + + test('clip', () => { + expect(prefix(`clip-path:none;`, 9)).to.equal([`-webkit-clip-path:none;`, `clip-path:none;`].join('')) + }) + + test('size', () => { + expect(prefix(`width:auto;`, 5)).to.equal([`width:auto;`].join('')) + expect(prefix(`width:unset;`, 5)).to.equal([`width:unset;`].join('')) + expect(prefix(`width:initial;`, 5)).to.equal([`width:initial;`].join('')) + expect(prefix(`width:inherit;`, 5)).to.equal([`width:inherit;`].join('')) + expect(prefix(`width:10;`, 5)).to.equal([`width:10;`].join('')) + expect(prefix(`width:min();`, 5)).to.equal([`width:min();`].join('')) + expect(prefix(`width:var(--foo-content);`, 5)).to.equal([`width:var(--foo-content);`].join('')) + expect(prefix(`width:var(-content);`, 5)).to.equal([`width:var(-content);`].join('')) + expect(prefix(`width:var(--max-content);`, 5)).to.equal([`width:var(--max-content);`].join('')) + expect(prefix(`width:--max-content;`, 5)).to.equal([`width:--max-content;`].join('')) + expect(prefix(`width:fit-content;`, 5)).to.equal([`width:-webkit-fit-content;`, `width:-moz-content;`, `width:fit-content;`].join('')) + expect(prefix(`min-width:max-content;`, 9)).to.equal([`min-width:-webkit-max-content;`, `min-width:-moz-max-content;`, `min-width:max-content;`].join('')) + expect(prefix(`max-width:min-content;`, 9)).to.equal([`max-width:-webkit-min-content;`, `max-width:-moz-min-content;`, `max-width:min-content;`].join('')) + expect(prefix(`height:fill-available;`, 6)).to.equal([`height:-webkit-fill-available;`, `height:-moz-available;`, `height:fill-available;`].join('')) + expect(prefix(`max-height:fit-content;`, 10)).to.equal([`max-height:-webkit-fit-content;`, `max-height:-moz-content;`, `max-height:fit-content;`].join('')) + expect(prefix(`width:stretch;`, 5)).to.equal([`width:-webkit-fill-available;`, `width:-moz-available;`, `width:fill-available;`, `width:stretch;`].join('')) + expect(prefix(`width:stretch !important;`, 5)).to.equal([`width:-webkit-fill-available !important;`, `width:-moz-available !important;`, `width:fill-available !important;`, `width:stretch !important;`].join('')) + expect(prefix(`min-block-size:max-content;`, 14)).to.equal([`min-block-size:-webkit-max-content;`, `min-block-size:-moz-max-content;`, `min-block-size:max-content;`].join('')) + expect(prefix(`min-inline-size:max-content;`, 15)).to.equal([`min-inline-size:-webkit-max-content;`, `min-inline-size:-moz-max-content;`, `min-inline-size:max-content;`].join('')) + }) + + test('zoom', () => { + expect(prefix(`min-zoom:0;`, 8)).to.equal([`min-zoom:0;`].join('')) + }) + + test('background', () => { + expect(prefix(`background:none;`, 10)).to.equal([`background:none;`].join('')) + expect(prefix(`background:image-set(url(foo.jpg) 2x);`, 10)).to.equal([`background:-webkit-image-set(url(foo.jpg) 2x);`, `background:image-set(url(foo.jpg) 2x);`].join('')) + expect(prefix(`background-image:image-set(url(foo.jpg) 2x);`, 16)).to.equal([`background-image:-webkit-image-set(url(foo.jpg) 2x);`, `background-image:image-set(url(foo.jpg) 2x);`].join('')) + }) + + test('background-clip', () => { + expect(prefix(`background-clip:text;`, 15)).to.equal([`-webkit-background-clip:text;`, `background-clip:text;`].join('')) + }) + + test('margin-inline', () => { + expect(prefix(`margin-inline-start:20px;`, 19)).to.equal([`-webkit-margin-start:20px;`, `margin-inline-start:20px;`].join('')) + expect(prefix(`margin-inline-end:20px;`, 17)).to.equal([`-webkit-margin-end:20px;`, `margin-inline-end:20px;`].join('')) + }) + + test('user-select', () => { + expect(prefix(`user-select:none;`, 11)).to.equal([`-webkit-user-select:none;`, `-moz-user-select:none;`, `-ms-user-select:none;`, `user-select:none;`].join('')) + }) + + test('appearance', () => { + expect(prefix(`appearance:none;`, 10)).to.equal([`-webkit-appearance:none;`, `-moz-appearance:none;`, `-ms-appearance:none;`, `appearance:none;`].join('')) + }) + + test('animation', () => { + expect(prefix(`animation:inherit;`, 9)).to.equal([`-webkit-animation:inherit;`, `animation:inherit;`].join('')) + expect(prefix(`animation-duration:0.6s;`, 18)).to.equal([`-webkit-animation-duration:0.6s;`, `animation-duration:0.6s;`].join('')) + expect(prefix(`animation-name:slidein;`, 14)).to.equal([`-webkit-animation-name:slidein;`, `animation-name:slidein;`].join('')) + expect(prefix(`animation-iteration-count:infinite;`, 25)).to.equal([`-webkit-animation-iteration-count:infinite;`, `animation-iteration-count:infinite;`].join('')) + expect(prefix(`animation-timing-function:cubic-bezier(0.1,0.7,1.0,0.1);`, 25)).to.equal([ + `-webkit-animation-timing-function:cubic-bezier(0.1,0.7,1.0,0.1);`, + `animation-timing-function:cubic-bezier(0.1,0.7,1.0,0.1);` + ].join('')) + }) +}) diff --git a/stylis.js/test/Tokenizer.js b/stylis.js/test/Tokenizer.js new file mode 100644 index 0000000..2be5bb3 --- /dev/null +++ b/stylis.js/test/Tokenizer.js @@ -0,0 +1,9 @@ +import {tokenize} from "../index.js" + +describe('Tokenizer', () => { + test('tokenize', () => { + expect(tokenize('h1 h2 (h1 h2) 1 / 3 * 2 + 1 [1 2] "1 2" a')).to.deep.equal([ + 'h1', ' ', 'h2', ' ', '(h1 h2)', ' ', '1', ' ', '/', ' ', '3', ' ', '*', ' ', '2', ' ', '+', ' ', '1', ' ', '[1 2]', ' ', '"1 2"', ' ', 'a' + ]) + }) +}) |