-/* jshint indent: false, multistr: true, quotmark: false */
-
var vows = require('vows');
-var assert = require('assert');
var path = require('path');
-var CleanCSS = require('../index');
+var optimizerContext = require('./test-helper').optimizerContext;
var lineBreak = require('os').EOL;
-var cssContext = function (groups, options) {
- var context = {};
-
- var clean = function (expected) {
- return function (source) {
- var minified = new CleanCSS(options).minify(source).styles;
- assert.equal(minified, expected);
- };
- };
-
- for (var g in groups) {
- var transformation = groups[g];
- if (typeof transformation == 'string')
- transformation = [transformation, transformation];
-
- context[g] = {
- topic: transformation[0],
- clean: clean(transformation[1])
- };
- }
-
- return context;
-};
-vows.describe('integration tests').addBatch({
- 'identity': cssContext({
- 'preserve minified content': 'a{color:#f10}'
- }),
- 'semicolons': cssContext({
- 'multiple semicolons': [
- 'a{color:#fff;;;width:0; ;}',
- 'a{color:#fff;width:0}'
- ],
- 'trailing semicolon': [
- 'a{color:#fff;}',
- 'a{color:#fff}'
- ],
- 'trailing semicolon and space': [
- 'a{color:#fff ; }',
- 'a{color:#fff}'
- ],
- 'comma and space': [
- 'a{color:rgba(0, 0, 5, .5)}',
- 'a{color:rgba(0,0,5,.5)}'
- ]
- }),
- 'whitespace': cssContext({
- 'one argument': [
- 'div a { color:#fff }',
- 'div a{color:#fff}'
- ],
- 'tabs': [
- 'div\t\ta{display:block}\tp{color:red}',
- 'div a{display:block}p{color:red}'
- ],
- 'line breaks #1': [
- 'div \na\r\n { width:500px }',
- 'div a{width:500px}'
- ],
- 'line breaks #2': [
- 'div \na\r\n, p { width:500px }',
- 'div a,p{width:500px}'
- ],
- 'line breaks with whitespace lines': [
- 'div \n \t\n \na\r\n, p { width:500px }',
- 'div a,p{width:500px}'
- ],
- 'multiple arguments': [
- 'a{color:#fff ; font-weight: bolder }',
- 'a{color:#fff;font-weight:bolder}'
- ],
- 'space delimited arguments': [
- 'a {border: 1px solid #f10; margin: 0 auto }',
- 'a{border:1px solid #f10;margin:0 auto}'
- ],
- 'at beginning': [
- ' a {color:#fff}',
- 'a{color:#fff}'
- ],
- 'at end': [
- 'a{color:#fff } ',
- 'a{color:#fff}'
- ],
- 'not inside calc method #1': [
- 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}',
- 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}'
- ],
- 'not inside calc method #2': [
- 'div{margin:-moz-calc(50% + 15px) -moz-calc(50% + 15px);margin:calc(50% + .5rem) calc(50% + .5rem)}',
- 'div{margin:-moz-calc(50% + 15px);margin:calc(50% + .5rem)}'
- ],
- 'not inside calc method with more parentheses': [
- 'div{height:-moz-calc((10% + 12px)/ 2 + 10em)}',
- 'div{height:-moz-calc((10% + 12px)/ 2 + 10em)}'
- ],
- 'not inside calc method with multiplication': [
- 'div{height:-moz-calc(3 * 2em + 10px)}',
- 'div{height:-moz-calc(3 * 2em + 10px)}'
- ],
- 'not inside calc method with brackets': [
- 'body{margin-left:calc(50vw + (1024px/2))}',
- 'body{margin-left:calc(50vw + (1024px/2))}'
- ],
- 'not inside calc method with brackets #2': [
- 'body{width:calc((978px * 2/3) - 30px)}',
- 'body{width:calc((978px * 2/3) - 30px)}'
- ],
- 'not inside calc method with brackets #3': [
- 'body{margin:calc(99.99% * 1/3 - (30px - 30px * 1/3) + 30px)}',
- 'body{margin:calc(99.99% * 1/3 - (30px - 30px * 1/3) + 30px)}'
- ],
- 'with space between braces': [
- 'body{width:calc( ( 100% - 12px) / 3 )}',
- 'body{width:calc((100% - 12px)/ 3)}'
- ],
- 'before colon': [
- '#test{padding-left :0}',
- '#test{padding-left:0}'
- ],
- 'before colon but not selectors #1': 'div :before{display:block}',
- 'before colon but not selectors #2': 'div ::-webkit-search-decoration{display:block}',
- 'before colon but not selectors #3': 'div :after{color:red}',
- 'windows breaks': [
- 'div>a{color:red\r\n }',
- 'div>a{color:red}'
- ],
- 'whitespace in media queries': [
- '@media ( min-width: 980px ) {\n#page .span4 {\nwidth: 250px;\n}\n\n.row {\nmargin-left: -10px;\n}\n}',
- '@media (min-width:980px){#page .span4{width:250px}.row{margin-left:-10px}}'
- ],
- 'line breaks in media queries123': [
- '@media\nonly screen and (max-width: 1319px) and (min--moz-device-pixel-ratio: 1.5),\nonly screen and (max-width: 1319px) and (-moz-min-device-pixel-ratio: 1.5)\n{ a { color:#000 } }',
- '@media only screen and (max-width:1319px) and (min--moz-device-pixel-ratio:1.5),only screen and (max-width:1319px) and (-moz-min-device-pixel-ratio:1.5){a{color:#000}}'
- ],
- 'in content preceded by #content': '#content{display:block}#foo{content:"\0BB "}',
- 'in content preceded by .content': '.content{display:block}#foo{content:"\0BB "}',
- 'in content preceded by line break': [
- '.content{display:block}#foo{' + lineBreak + 'content:"x"}',
- '.content{display:block}#foo{content:"x"}'
- ],
- 'after rgb': [
- 'a{text-shadow:rgb(255,0,1) 1px 1px}',
- 'a{text-shadow:#ff0001 1px 1px}'
- ],
- 'after rgba': [
- 'a{text-shadow:rgba(255,0,0,1) 0 1px}',
- 'a{text-shadow:rgba(255,0,0,1) 0 1px}'
- ],
- 'after hsl': [
- 'a{text-shadow:hsl(240,100%,40%) -1px 1px}',
- 'a{text-shadow:#00c -1px 1px}'
- ],
- 'after hsla': [
- 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}',
- 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}'
- ],
- 'inside background': [
- 'a{background:calc(100% - 2px) 10px no-repeat}',
- 'a{background:calc(100% - 2px) 10px no-repeat}'
- ],
- 'inside background with fraction unit': [
- 'a{background:calc(100% - 2px) .5em no-repeat}',
- 'a{background:calc(100% - 2px) .5em no-repeat}'
- ],
- 'inside background with urls': [
- 'a{background:url(image.png) no-repeat}',
- 'a{background:url(image.png) no-repeat}'
- ],
- 'inside background with rgba': [
- 'a{background:calc(100% - 10px) no-repeat}',
- 'a{background:calc(100% - 10px) no-repeat}'
- ],
- 'inside margin': [
- 'a{margin:calc(100% - 2px) calc(100% - 5px)}',
- 'a{margin:calc(100% - 2px) calc(100% - 5px)}'
- ],
- 'inside transform': [
- 'a{transform:translateX(10px) translateY(10px)}',
- 'a{transform:translateX(10px) translateY(10px)}'
- ],
- 'after :not #1': [
- 'li:not(.foo).bar{color:red}',
- 'li:not(.foo).bar{color:red}'
- ],
- 'after :not #2': [
- 'li:not(.foo)[data-type=none]{color:red}',
- 'li:not(.foo)[data-type=none]{color:red}'
- ],
- 'after :not #3': [
- 'li:not(.foo)#id{color:red}',
- 'li:not(.foo)#id{color:red}'
- ]
- }),
- 'whitespace with spaceAfterClosingBrace': cssContext({
- 'after rgb': [
- 'a{text-shadow:rgb(255,0,1) 1px 1px}',
- 'a{text-shadow:#ff0001 1px 1px}'
- ],
- 'after rgba': [
- 'a{text-shadow:rgba(255,0,0,1) 0 1px}',
- 'a{text-shadow:rgba(255,0,0,1) 0 1px}'
- ],
- 'after hsl': [
- 'a{text-shadow:hsl(240,100%,40%) -1px 1px}',
- 'a{text-shadow:#00c -1px 1px}'
- ],
- 'after hsla': [
- 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}',
- 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}'
- ],
- 'inside background': [
- 'a{background:calc(100% - 2px) 10px no-repeat}',
- 'a{background:calc(100% - 2px)10px no-repeat}'
- ],
- 'inside background with fraction unit': [
- 'a{background:calc(100% - 2px) .5em no-repeat}',
- 'a{background:calc(100% - 2px).5em no-repeat}'
- ],
- 'inside background with urls': [
- 'a{background:url(image.png) no-repeat}',
- 'a{background:url(image.png)no-repeat}'
- ],
- 'inside background with rgba': [
- 'a{background:calc(100% - 10px) no-repeat}',
- 'a{background:calc(100% - 10px)no-repeat}'
- ],
- 'inside margin': [
- 'a{margin:calc(100% - 2px) calc(100% - 5px)}',
- 'a{margin:calc(100% - 2px) calc(100% - 5px)}'
- ],
- 'inside transform': [
- 'a{transform:translateX(10px) translateY(10px)}',
- 'a{transform:translateX(10px)translateY(10px)}'
- ],
- 'inside @media': [
- '@media only screen and (max-width:1319px) and (min--moz-device-pixel-ratio:1.5){a{color:red}}',
- '@media only screen and (max-width:1319px)and (min--moz-device-pixel-ratio:1.5){a{color:red}}'
- ]
- }, { compatibility: { properties: { spaceAfterClosingBrace: false } } }),
- 'line breaks': cssContext({
- 'line breaks #1': [
- 'div\na\r\n{width:500px}',
- 'div a{width:500px}'
- ],
- 'line breaks #2': [
- 'div\na\r\n,p{width:500px}',
- 'div a,p{width:500px}'
- ],
- 'multiple line breaks #2': [
- 'div \r\n\r\na\r\n,p{width:500px}',
- 'div a,p{width:500px}'
- ],
- 'line breaks with whitespace lines': [
- 'div \n \t\n \na\r\n, p { width:500px }',
- 'div a,p{width:500px}'
- ],
- 'line breaks with multiple selectors': [
- 'p{width:500px}a{color:red}span{font-style:italic}',
- 'p{width:500px}' + lineBreak + 'a{color:red}' + lineBreak + 'span{font-style:italic}'
- ],
- 'charset not at beginning': [
- "a{ color: #f10; }\n@charset 'utf-8';\nb { font-weight: bolder}",
- "@charset 'utf-8';" + lineBreak + "a{color:#f10}" + lineBreak + "b{font-weight:bolder}"
- ],
- 'charset multiple charsets': [
- "@charset 'utf-8';\ndiv :before { display: block }\n@charset 'utf-8';\na { color: #f10 }",
- "@charset 'utf-8';" + lineBreak + "div :before{display:block}" + lineBreak + "a{color:#f10}"
- ],
- 'charset with double line break': [
- "@charset 'utf-8';" + lineBreak + lineBreak + "a{display:block}",
- "@charset 'utf-8';" + lineBreak + "a{display:block}"
- ],
- 'uppercase charset': [
- "@CHARSET 'utf-8';h1{color:red}",
- 'h1{color:red}'
- ],
- 'mixed case charset': [
- "@chArSET 'utf-8';h1{color:red}",
- 'h1{color:red}'
- ]
- }, { keepBreaks: true }),
- 'line breaks and important comments': cssContext({
- 'charset to beginning with comment removal': [
- "/*! some comment */" + lineBreak + lineBreak + "@charset 'utf-8';" + lineBreak + lineBreak + "a{display:block}",
- "@charset 'utf-8';" + lineBreak + "a{display:block}"
- ]
- }, { keepBreaks: true, keepSpecialComments: 0 }),
- 'selectors': cssContext({
- 'not expand + in selectors mixed with calc methods': [
- 'div{width:calc(50% + 3em)}div + div{width:100%}div:hover{width:calc(50% + 4em)}* > div {border:1px solid #f0f}',
- 'div{width:calc(50% + 3em)}div+div{width:100%}div:hover{width:calc(50% + 4em)}*>div{border:1px solid #f0f}'
- ],
- 'process selectors ending with -0 correctly': '.selector-0,a{display:block}',
- 'process selectors ending with -1 correctly': '.selector-1,a{display:block}'
- }),
- 'universal selector in ie8 compatibility mode': cssContext({
- '+html': [
- '*+html .foo{display:inline}',
- ''
- ],
- '+html:first-child': [
- '*:first-child+html .foo{display:inline}',
- ''
- ],
- 'complex': [
- '*:first-child+html .foo,.bar{display:inline}',
- '.bar{display:inline}'
- ]
- }, { compatibility: 'ie8' }),
- 'universal selector in ie7 compatibility mode': cssContext({
- '+html': '*+html .foo{display:inline}',
- ':first-child+html': '*:first-child+html .foo{display:inline}',
- 'complex': '*:first-child+html .foo,.bar{display:inline}'
- }, { compatibility: 'ie7' }),
- 'comments': cssContext({
- 'single line': [
- 'a{color:#fff}/* some comment*/p{height:10px/* other comment */}',
- 'a{color:#fff}p{height:10px}'
- ],
- 'multiline': [
- '/* \r\n multiline \n comment */a{color:rgba(0,0,0,0.8)}',
- 'a{color:rgba(0,0,0,.8)}'
- ],
- 'comment chars in comments': [
- '/* \r\n comment chars * inside / comments */a{color:#fff}',
- 'a{color:#fff}'
- ],
- 'comment inside block': [
- 'a{/* \r\n some comments */color:#fff}',
- 'a{color:#fff}'
- ],
- 'special comments': [
- '/*! special comment */a{color:#f10} /* normal comment */',
- '/*! special comment */a{color:#f10}'
- ],
- 'should keep exact structure': [
- '/*! \n a > span { } with some content */',
- '/*! \n a > span { } with some content */'
- ],
- 'should remove comments with forward slashes inside': [
- '/*////*/a{color:red}',
- 'a{color:red}'
- ],
- 'should properly handle line breaks and ** characters inside comments': [
- '/**====**\\\n/**2nd comment line/**===**/a{color:red}',
- 'a{color:red}'
- ],
- 'selector between comments': [
- '/*comment*/*/*comment*/{color:red}',
- '*{color:red}'
- ],
- 'inside url': [
- "p{background-image:url('/*')}/* */",
- "p{background-image:url(/*)}"
- ],
- 'inside url twice': [
- "p{background-image:url('/* */\" /*')}/* */",
- "p{background-image:url('/* */\" /*')}"
- ],
- 'inside url with more quotation': [
- "p{background-image:url('/*');content:\"\"/* */}",
- "p{background-image:url(/*);content:\"\"}"
- ],
- 'with quote marks': [
- '/*"*//* */',
- ''
- ],
- 'important after value': [
- 'div{color:red;/*!comment*/}',
- 'div{color:red/*!comment*/}'
- ],
- 'important between values': [
- 'div{color:red;/*!comment*/display:block}',
- 'div{color:red;/*!comment*/display:block}'
- ],
- 'important between and after values': [
- 'div{color:red;/*!comment1*/display:block;/*!comment2*/}',
- 'div{color:red;/*!comment1*/display:block/*!comment2*/}'
- ],
- 'two important after value': [
- 'div{color:red;/*!1*//*!2*/}',
- 'div{color:red/*!1*//*!2*/}'
- ]
- }),
- 'escaping': cssContext({
- 'escaped @ symbol in class name': '.pad--all0\\@sm{padding:0}',
- 'escaped @ symbol in id': '#id\\@sm{padding:0}',
- 'escaped slash': 'a{content:"\\\\"}',
- 'escaped quote': 'a{content:"\\\""}',
- 'escaped quote in selector name': [
- '.this-class\\\'s-got-an-apostrophe{color:red}a{color:#f00}',
- '.this-class\\\'s-got-an-apostrophe,a{color:red}'
- ],
- 'escaped quotes in selector name': [
- '.this-class\\\"s-got-an-apostrophes\\\'{color:red}a{color:#f00}',
- '.this-class\\\"s-got-an-apostrophes\\\',a{color:red}'
- ],
- 'escaped tab': 'a{content:"\\\t"}'
- }),
- 'important comments - one': cssContext({
- 'strip all but first': [
- '/*! important comment */a{color:red}/* some comment *//*! important comment */',
- '/*! important comment */a{color:red}'
- ]
- }, { keepSpecialComments: 1 }),
- 'important comments - none': cssContext({
- 'strip all': [
- '/*! important comment */a{color:red}/* some comment *//*! important comment */',
- 'a{color:red}'
- ],
- 'move charset before': [
- "/*! some comment */" + lineBreak + lineBreak + "@charset 'utf-8';" + lineBreak + lineBreak + "a{display:block}",
- "@charset 'utf-8';a{display:block}"
- ]
- }, { keepSpecialComments: 0 }),
- 'important comments - keepSpecialComments when a string': cssContext({
- 'strip all': [
- '/*! important comment */a{color:red}/* some comment *//*! important comment */',
- 'a{color:red}'
- ]
- }, { keepSpecialComments: '0' }),
- 'expressions': cssContext({
- 'empty': 'a{color:expression()}',
- 'method call': 'a{color:expression(this.parentNode.currentStyle.color)}',
- 'multiple call': 'a{color:expression(x = 0 , this.parentNode.currentStyle.color)}',
- 'mixed content': "a{zoom:expression(this.runtimeStyle[\"zoom\"] = '1', this.innerHTML = '')}",
- 'in comment': "/*! expression(this.runtimeStyle['zoom']) */",
- 'complex': 'a{width:expression((this.parentNode.innerWidth + this.parentNode.innerHeight) / 2 )}',
- 'with parentheses': "a{width:expression(this.parentNode.innerText == ')' ? '5px' : '10px' )}",
- 'open ended (broken)': "a{width:expression(this.parentNode.innerText == }",
- 'function call & advanced': 'a{zoom:expression(function (el){el.style.zoom="1"}(this))}'
- }),
- 'text content': cssContext({
- 'normal #1': 'a{content:"."}',
- 'normal #2': [
- 'a:before{content : "test\'s test"; }',
- 'a:before{content:"test\'s test"}'
- ],
- 'open quote': [
- 'a{content : open-quote;opacity:1}',
- 'a{content:open-quote;opacity:1}'
- ],
- 'close quote': [
- 'a{content: close-quote;clear:left}',
- 'a{content:close-quote;clear:left}'
- ],
- 'special characters': [
- 'a{content : " a > div { } "}',
- 'a{content:" a > div { } "}'
- ],
- 'with JSON': 'body::before{content:\'{ "current" : "small", "all" : ["small"], "position" : 0 }\'}'
- }),
- 'zero values': cssContext({
- 'with units': [
- 'a{margin:0px 0pt 0em 0%;padding: 0in 0cm 0mm 0pc;border-top-width:0ex}',
- 'a{margin:0;padding:0;border-top-width:0}'
- ],
- 'multiple into one': [
- 'a{margin:0 0 0 0;padding:0 0 0 0;border-width:0 0 0 0}',
- 'a{margin:0;padding:0;border-width:0}'
- ],
- 'background\'s none to zero': [
- 'a{background:none}',
- 'a{background:0 0}'
- ],
- 'border\'s none to none': 'a{border:none}p{border-top:none}',
- 'background:transparent to zero': [
- 'a{background:transparent}p{background:transparent url(logo.png)}',
- 'a{background:0 0}p{background:url(logo.png)}'
- ],
- 'outline:none to outline:0': [
- 'a{outline:none}',
- 'a{outline:0}'
- ],
- 'display:none not changed': 'a{display:none}',
- 'mixed zeros not changed': 'div{margin:0 0 1px 2px}',
- 'mixed zeros not changed #2': 'div{padding:0 1px 0 3px}',
- 'mixed zeros not changed #3': 'div{padding:10px 0 0 1px}',
- 'multiple zeros with fractions #1': [
- 'div{padding:0 0 0 0.5em}',
- 'div{padding:0 0 0 .5em}'
- ],
- 'multiple zeros with fractions #2': [
- 'div{padding:0 0 0 .5em}',
- 'div{padding:0 0 0 .5em}'
- ],
- 'rect zeros #1': 'div{clip:rect(0 0 0 0)}',
- 'rect zeros #2': [
- 'div{clip:rect(0px 0px 0px 0px)}',
- 'div{clip:rect(0 0 0 0)}'
- ],
- 'rect zeros #3': [
- 'div{clip:rect( 0px 0px 0px 0px )}',
- 'div{clip:rect(0 0 0 0)}'
- ],
- 'rect zeros #4': [
- 'div{clip:rect(0px, 0px, 0px, 0px)}',
- 'div{clip:rect(0,0,0,0)}'
- ],
- 'rect zeros #5': [
- 'div{clip:rect(0.5% 0px 0px 0px)}',
- 'div{clip:rect(.5% 0 0 0)}'
- ],
- 'rect zeros #6': [
- 'div{clip:rect(0px 0px 0px 10px)}',
- 'div{clip:rect(0 0 0 10px)}'
- ],
- 'box shadow zeros with four zeros': [
- 'a{box-shadow:0 0 0 0}',
- 'a{box-shadow:0 0}'
- ],
- 'box shadow with two zeros': 'a{box-shadow:0 0}',
- 'box shadow with three zeros and a fraction': [
- 'a{box-shadow:0 0 0 0.15em #EBEBEB}',
- 'a{box-shadow:0 0 0 .15em #EBEBEB}'
- ],
- 'box shadow with three zeros and a value': 'a{box-shadow:0 0 0 15px #EBEBEB}',
- 'prefixed box shadow zeros': [
- 'a{-webkit-box-shadow:0 0 0 0; -moz-box-shadow:0 0 0 0}',
- 'a{-webkit-box-shadow:0 0;-moz-box-shadow:0 0}'
- ],
- 'zero as .0 #1': [
- 'a{color:rgba(0,0,.0,1)}',
- 'a{color:rgba(0,0,0,1)}'
- ],
- 'zero as .0 #2': [
- 'body{margin:.0}',
- 'body{margin:0}'
- ],
- 'zero as .0 #3': [
- 'body{margin:.0em}',
- 'body{margin:0}'
- ],
- 'zero as .0 #4': [
- 'body{margin:.0 1em .0 .0}',
- 'body{margin:0 1em 0 0}'
- ],
- 'missing #1': [
- 'body{margin:2.em}',
- 'body{margin:2em}'
- ],
- 'missing #2': [
- 'p{opacity:1.}',
- 'p{opacity:1}'
- ],
- 'missing #3': [
- 'p{opacity:11.px}',
- 'p{opacity:11px}'
- ],
- 'minus zero as value to zero': [
- 'body{margin:-0}',
- 'body{margin:0}'
- ],
- 'minus zero in function to zero': [
- 'body{color:rgba(-0,-0,-0,-0)}',
- 'body{color:transparent}'
- ],
- 'minus zero px to zero': [
- 'body{margin:-0px}',
- 'body{margin:0}'
- ],
- 'zero em to zero': [
- 'body{margin:0.0em}',
- 'body{margin:0}'
- ]
- }),
- 'zero values in ie8 compatibility mode': cssContext({
- 'rems': 'div{width:0rem;height:0rem}'
- }, { compatibility: 'ie8' }),
- 'zero values in any other compatibility mode': cssContext({
- 'rems': [
- 'div{width:0rem;height:0rem}',
- 'div{width:0;height:0}'
- ]
- }, { compatibility: '*' }),
- 'shorthands': cssContext({
- 'padding - same 4 values': [
- 'div{padding:1px 1px 1px 1px}',
- 'div{padding:1px}'
- ],
- 'margin - same 4 values': [
- 'div{margin:1% 1% 1% 1%}',
- 'div{margin:1%}'
- ],
- 'border-width - same 4 values': [
- 'div{border-width:1em 1em 1em 1em}',
- 'div{border-width:1em}'
- ],
- 'border-style - same 4 values': [
- 'div{border-style:solid solid solid solid}',
- 'div{border-style:solid}'
- ],
- 'border-color - same 4 values': [
- 'div{border-color:red red red red}',
- 'div{border-color:red}'
- ],
- 'border-color - same 4 values as hex': [
- 'div{border-color:#f0f #f0f #f0f #f0f}',
- 'div{border-color:#f0f}'
- ],
- 'border-color - same 4 values as rgb': [
- 'div{border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(0,0,0)}',
- 'div{border-color:#000}'
- ],
- 'border-color - same 4 values as rgba': [
- 'div{border-color:rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(0,0,0,.5)}',
- 'div{border-color:rgba(0,0,0,.5)}'
- ],
- 'border-radius - same 4 values': [
- 'div{border-radius:3px 3px 3px 3px}',
- 'div{border-radius:3px}'
- ],
- 'border-radius - same 4 values with vendor prefixes': [
- 'div{-moz-border-radius:3px 3px 3px 3px;-o-border-radius:3px 3px 3px 3px;-webkit-border-radius:3px 3px 3px 3px;border-radius:3px 3px 3px 3px}',
- 'div{-moz-border-radius:3px;-o-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}'
- ],
- 'padding - same pairs': [
- 'div{padding:15.5em 10.5em 15.5em 10.5em}',
- 'div{padding:15.5em 10.5em}'
- ],
- 'margin - same 2nd and 4th value': [
- 'div{margin:1px 2px 3px 2px}',
- 'div{margin:1px 2px 3px}'
- ],
- 'padding - same 3 values': [
- 'div{padding:1px 1px 1px}',
- 'div{padding:1px}'
- ],
- 'padding - different 3 values': 'div{padding:1px 1em 1%}',
- 'margin - 3 callapsible values': [
- 'div{margin:1ex 2ex 1ex}',
- 'div{margin:1ex 2ex}'
- ],
- 'border-radius - same 3 values with one vendor prefixe': [
- 'div{-webkit-border-radius:3px 3px 3px;border-radius:3px 3px 3px}',
- 'div{-webkit-border-radius:3px;border-radius:3px}'
- ],
- 'border-color - same 2nd and 4th value as rgb': [
- 'div{border-color:rgb(0,0,0) rgb(34,0,0) rgb(255,0,0) rgb(34,0,0)}',
- 'div{border-color:#000 #200 red}'
- ],
- 'margin - 3 different values': 'div{margin:1px 1px 3px}',
- 'border width - 3 different values': 'div{border-width:1px 2px 3px}',
- 'padding - same 2 values': [
- 'div{padding:1px 1px}',
- 'div{padding:1px}'
- ],
- 'margin - same 2 values': [
- 'div{margin:5% 5%}',
- 'div{margin:5%}'
- ],
- 'border-width - same 2 values': [
- 'div{border-width:.5em .5em}',
- 'div{border-width:.5em}'
- ],
- 'different units': 'div{padding:1px 1em 1% 1rem}',
- 'fractions': [
- 'div{margin:.1em .1em .1em .1em}',
- 'div{margin:.1em}'
- ],
- 'preceeding value': [
- 'div{padding:010px 00015px}',
- 'div{padding:10px 15px}'
- ],
- 'preceeding value with fraction zeros': [
- 'div{padding:010.0em .05rem}',
- 'div{padding:10em .05rem}'
- ]
- }),
- 'units': cssContext({
- 'negative padding': [
- 'div{padding-left:2px;padding-top:-2px;padding-right:5px;padding-bottom:0}',
- 'div{padding-left:2px;padding-right:5px;padding-bottom:0}'
- ],
- 'negative padding after negative shorthand': [
- 'div{padding:-5px 0 0 0;padding-left:2px;padding-top:-2px;padding-right:5px;padding-bottom:0}',
- 'div{padding-left:2px;padding-right:5px;padding-bottom:0}'
- ],
- 'negative padding in calculations': [
- 'div{padding:calc(100% - 5px) 0 0 0}',
- 'div{padding:calc(100% - 5px) 0 0}'
- ]
- }),
- 'floats': cssContext({
- 'strips zero in fractions': [
- 'a{ margin-bottom: 0.5em}',
- 'a{margin-bottom:.5em}'
- ],
- 'not strips zero in fractions of numbers greater than zero': [
- 'a{ margin-bottom: 20.5em}',
- 'a{margin-bottom:20.5em}'
- ],
- 'strip fraction zero #1': [
- 'a{opacity:1.0}',
- 'a{opacity:1}'
- ],
- 'strip fraction zero #2': [
- 'a{opacity:15.000%}',
- 'a{opacity:15%}'
- ],
- 'strip fraction zero #3': [
- 'a{padding:15.55000em}',
- 'a{padding:15.55em}'
- ],
- 'strip fraction zero #4': 'a{padding:15.101em}',
- 'strip fraction zero #5': [
- 'a{border-width:0.20em 20.30em}',
- 'a{border-width:.2em 20.3em}'
- ],
- 'strip fraction zeros': [
- 'div{margin:1.000em 2.00em 3.100em 4.01em}',
- 'div{margin:1em 2em 3.1em 4.01em}'
- ],
- 'round pixels up to 2nd decimal place': [
- 'div{transform:translateY(-418.505123px)}',
- 'div{transform:translateY(-418.51px)}'
- ],
- 'round pixels down to 2nd decimal place': [
- 'div{transform:translateY(0.504123px)}',
- 'div{transform:translateY(.5px)}'
- ],
- 'do not round 2nd decimal place pixels': 'div{transform:translateY(20.55px)}',
- 'do not round percentages': 'div{left:20.505%}',
- 'do not round ems': 'div{font-size:1.505em}',
- 'rounds .9999 correctly': [
- 'a{stroke-width:.99999px}',
- 'a{stroke-width:1px}'
- ],
- 'rounds 9.995 correctly': [
- 'a{stroke-width:9.995px}',
- 'a{stroke-width:9.99px}'
- ]
- }),
- 'floats custom rounding': cssContext({
- 'rounds to 4 values': [
- 'div{transform:translateY(-418.505123px)}',
- 'div{transform:translateY(-418.5051px)}'
- ]
- }, { roundingPrecision: 4 }),
- 'floats disabled rounding': cssContext({
- 'does not round': [
- 'div{transform:translateY(-418.505123px)}',
- 'div{transform:translateY(-418.505123px)}'
- ]
- }, { roundingPrecision: -1 }),
- 'colors': cssContext({
- 'shorten rgb to standard hexadecimal format': [
- 'a{ color:rgb(5, 10, 15) }',
- 'a{color:#050a0f}'
- ],
- 'skip rgba shortening': [
- 'a{ color:rgba(5, 10, 15, 0.5)}',
- 'a{color:rgba(5,10,15,.5)}'
- ],
- 'shorten colors to 3 digit hex instead of 6 digit': [
- 'a{ background-color: #aa0000; color:rgb(0, 17, 255)}',
- 'a{background-color:#a00;color:#01f}'
- ],
- 'skip shortening IE filter colors': [
- 'a{ filter: chroma(color = "#ff0000")}',
- 'a{filter:chroma(color="#ff0000")}'
- ],
- 'color names to hex values': [
- 'a{color:white;border-color:black;background-color:fuchsia}p{background:yellow}',
- 'a{color:#fff;border-color:#000;background-color:#f0f}p{background:#ff0}'
- ],
- 'keep selectors with color name #1': ".black-and-white .foo{color:#fff;background-color:#000}",
- 'keep selectors with color name #2': ".go-blues{background:#000}",
- 'keep selectors with color name #3': "#top_white{background:#000}",
- 'keep selectors with color name #4': "a[data-sth=white]{background:#000}",
- 'color names to hex values with important': [
- 'a{color:white !important}',
- 'a{color:#fff!important}'
- ],
- 'color names to hex values in gradients': [
- 'p{background:linear-gradient(-90deg,black,white)}',
- 'p{background:linear-gradient(-90deg,#000,#fff)}'
- ],
- 'hex value to color name if shorter': [
- 'p{color:#f00}',
- 'p{color:red}'
- ],
- 'upper case hex value to color name if shorter': [
- 'p{color:#F00}',
- 'p{color:red}'
- ],
- 'upper case long hex value to color name if shorter': [
- 'p{color:#FF0000}',
- 'p{color:red}'
- ],
- 'hex value to color name in borders': [
- 'p{border:1px solid #f00}',
- 'p{border:1px solid red}'
- ],
- 'hex value to color name in gradients': [
- 'p{background:-moz-linear-gradient(-90deg,#000,#f00)}',
- 'p{background:-moz-linear-gradient(-90deg,#000,red)}'
- ],
- 'hex value to color name in gradients #2': [
- 'p{background:-webkit-gradient(linear, left top, left bottom, from(#000), to(#f00))}',
- 'p{background:-webkit-gradient(linear,left top,left bottom,from(#000),to(red))}'
- ],
- 'border color - keep unchanged': 'p{border:1px solid #f94311}',
- 'border color - hex to name': [
- 'p{border:1em dotted #f00}',
- 'p{border:1em dotted red}'
- ],
- 'border color - name to hex': [
- 'p{border:1em dotted white}',
- 'p{border:1em dotted #fff}'
- ],
- 'border color - rgb': [
- 'p{border:1em dotted rgb(255,0,0)}',
- 'p{border:1em dotted red}'
- ],
- 'colors and colons': 'a{background-image:linear-gradient(top,red,#e6e6e6)}',
- 'colors and parentheses': 'a{background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6))}',
- 'colors in ie filters': 'a{filter:chroma(color=#ffffff)}',
- 'colors in ie filters 2': "a{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#cccccc', endColorstr='#000000')}",
- 'colors in ie filters 3': "a{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#DDDDDD', endColorstr='#333333')}",
- 'rgb percents': 'a{color:rgb(100%,0%,0%)}',
- 'rgba percents': 'a{color:rgba(100%,0%,0%,.5)}',
- 'hsla percents': 'a{color:hsla(1,0%,0%,.5)}',
- 'hsla custom ': 'a{color:hsl(80,30%,50%,.5)}',
- 'hsl to hex #1': [
- 'a{color:hsl(0,0%,0%)}',
- 'a{color:#000}'
- ],
- 'hsl to hex #2': [
- 'a{color:hsl(0,100%,100%)}',
- 'a{color:#fff}'
- ],
- 'hsl to hex #3': [
- 'a{color:hsl(240,100%,50%)}',
- 'a{color:#00f}'
- ],
- 'hsl to hex #4': [
- 'a{color:hsl(240,100%,50%)}',
- 'a{color:#00f}'
- ],
- 'hsl to hex #5': [
- 'a{color:hsl(120,100%,25%)}',
- 'a{color:#007f00}'
- ],
- 'hsl to hex #6': [
- 'a{color:hsl(99,66%,33%)}',
- 'a{color:#438b1c}'
- ],
- 'hsl to hex #7': [
- 'a{color:hsl(360,100%,50%)}',
- 'a{color:red}'
- ],
- 'hsla not to hex': 'a{color:hsl(99,66%,33%,.5)}',
- 'hsl out of bounds #1': [
- 'a{color:hsl(120,200%,50%)}',
- 'a{color:#0f0}'
- ],
- 'hsl out of bounds #2': [
- 'a{color:hsl(120,-100%,50%)}',
- 'a{color:#7f7f7f}'
- ],
- 'hsl out of bounds #3': [
- 'a{color:hsl(480,100%,25%)}',
- 'a{color:#007f00}'
- ],
- 'hsl out of bounds #4': [
- 'a{color:hsl(-240,100%,75%)}',
- 'a{color:#7fff7f}'
- ],
- 'hsl out of bounds #5': [
- 'a{color:hsl(-600,100%,75%)}',
- 'a{color:#7fff7f}'
- ],
- 'hsl out of bounds #6': [
- 'a{color:hsl(0,0%,122%)}',
- 'a{color:#fff}'
- ],
- 'hsl out of bounds #7': [
- 'a{color:hsl(0,0%,-10%)}',
- 'a{color:#000}'
- ],
- 'rgb out of a lower bound': [
- 'a{color:rgb(-1,-1,-1)}',
- 'a{color:#000}'
- ],
- 'rgb out of an upper bound': [
- 'a{color:rgb(256,256,256)}',
- 'a{color:#fff}'
- ],
- 'turns rgba(0,0,0,0) to transparent': [
- 'a{color:rgba(0,0,0,0)}',
- 'a{color:transparent}'
- ],
- 'turns rgba(0.0,0.0,0.0,0) to transparent': [
- 'a{color:rgba(0.0,0.0,0.0,0)}',
- 'a{color:transparent}'
- ],
- 'turns hsla(0,0%,0%,0) to transparent': [
- 'a{color:hsla(0,0%,0%,0)}',
- 'a{color:transparent}'
- ],
- 'turns hsla(0,0,0,0) to transparent': [
- 'a{color:hsla(0,0,0,0)}',
- 'a{color:transparent}'
- ],
- 'turns hsla(0.0,0.0%,0.0%,0) to transparent': [
- 'a{color:hsla(0.0,0.0%,0.0%,0)}',
- 'a{color:transparent}'
- ],
- 'turns hsla(0.0,0.0,0.0,0) to transparent': [
- 'a{color:hsla(0.0,0.0,0.0,0)}',
- 'a{color:transparent}'
- ],
- 'keeps rgba(255,255,255,0)': 'a{color:rgba(255,255,255,0)}',
- 'keeps rgba(255,0,255,0)': 'a{color:rgba(255,0,255,0)}',
- 'keeps hsla(120,100%,50%,0)': 'a{color:hsla(120,100%,50%,0)}',
- 'keeps rgba(0,0,0,.5)': 'a{color:rgba(0,0,0,.5)}',
- 'keeps rgba(0,255,0,.5)': 'a{color:rgba(0,255,0,.5)}',
- 'keeps hsla(120,100%,50%,.5)': 'a{color:hsla(120,100%,50%,.5)}',
- 'keeps rgba(0,0,0,0) when inside a gradient': 'a{background:linear-gradient(0,#000,rgba(0,0,0,0))}',
- 'keeps hsla(120,100%,50%,0) when inside a gradient': 'a{background:linear-gradient(0,#000,hsla(120,100%,50%,0))}',
- 'removes only right transparent colors': [
- 'a{background-color:linear-gradient(0,#000,hsla(120,100%,50%,0)),rgba(0,0,0,0)}',
- 'a{background-color:linear-gradient(0,#000,hsla(120,100%,50%,0)),transparent}'
- ]
- }),
- 'border-radius': cssContext({
- 'border radius H+V 0/0': [
- 'a{border-radius:0 / 0}',
- 'a{border-radius:0}'
- ],
- 'border radius side H+V 0/0': [
- 'a{border-top-left-radius:0 / 0}',
- 'a{border-top-left-radius:0}'
- ],
- 'border radius H+V same values': [
- 'a{border-radius:5px / 5px}',
- 'a{border-radius:5px}'
- ],
- 'border radius side H+V same values': [
- 'a{border-top-left-radius:1em / 1em}',
- 'a{border-top-left-radius:1em}'
- ],
- 'border radius H+V same expanded values': [
- 'a{border-radius:5px 5px 5px 5px / 5px 5px}',
- 'a{border-radius:5px}'
- ]
- }),
- 'font weights': cssContext({
- 'font-weight:normal to 400': [
- 'p{font-weight:normal}',
- 'p{font-weight:400}'
- ],
- 'font-weight:bold to 700': [
- 'p{font-weight:bold}',
- 'p{font-weight:700}'
- ],
- 'font weight in font declarations': [
- 'body{font:normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif}',
- 'body{font:400 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif}'
- ],
- 'font weight in font declarations with fraction units': [
- 'p{font:bold .9rem Helvetica}',
- 'p{font:700 .9rem Helvetica}'
- ],
- 'multiple changes': [
- 'p{font-weight:bold!important;width:100%;font:normal 12px Helvetica}',
- 'p{font-weight:700!important;width:100%;font:400 12px Helvetica}'
- ],
- 'font weight in extended font declarations': 'a{font:normal normal normal 13px/20px Helvetica}',
- 'font weight where style and weight are declared': 'a{font:normal 300 100%/1.5 sans-serif}'
- }),
- 'unicode': cssContext({
- 'font-names': 'body{font-family:\\5FAE\\8F6F\\96C5\\9ED1,\\5B8B\\4F53,sans-serif}'
- }),
- 'urls': cssContext({
- 'keep urls without parentheses unchanged': 'a{background:url(/images/blank.png)}',
- 'keep non-encoded data URI unchanged': ".icon-logo{background-image:url('data:image/svg+xml;charset=US-ASCII')}",
- 'strip quotes from base64 encoded PNG data URI': [
- ".icon-logo{background-image:url('data:image/png;base64,iVBORw0')}",
- ".icon-logo{background-image:url(data:image/png;base64,iVBORw0)}"
- ],
- 'strip quotes from base64 encoded ICO data URI': [
- '.icon-logo{background-image:url("data:image/x-icon;base64,AAABAAEAEBA")}',
- '.icon-logo{background-image:url(data:image/x-icon;base64,AAABAAEAEBA)}'
- ],
- 'cut off url content on selector level': 'a{background:url(image/}',
- 'cut off url content on block level': [
- '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}',
- '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}'
- ],
- 'cut off url content on top level': [
- '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA',
- ''
- ],
- 'strip single parentheses': [
- "a{background:url('/images/blank.png')}",
- "a{background:url(/images/blank.png)}"
- ],
- 'strip double parentheses': [
- 'a{background:url("/images/blank.png")}',
- 'a{background:url(/images/blank.png)}'
- ],
- 'strip more': [
- 'p{background:url("/images/blank.png")}b{display:block}a{background:url("/images/blank2.png")}',
- 'p{background:url(/images/blank.png)}b{display:block}a{background:url(/images/blank2.png)}'
- ],
- 'not strip comments if spaces inside': [
- 'p{background:url("/images/long image name.png")}b{display:block}a{background:url("/images/no-spaces.png")}',
- 'p{background:url("/images/long image name.png")}b{display:block}a{background:url(/images/no-spaces.png)}'
- ],
- 'not add a space before url\'s hash': "a{background:url(/fonts/d90b3358-e1e2-4abb-ba96-356983a54c22.svg#d90b3358-e1e2-4abb-ba96-356983a54c22)}",
- 'keep urls from being stripped down #1': 'a{background:url(/image-1.0.png)}',
- 'keep urls from being stripped down #2': "a{background:url(/image-white.png)}",
- 'keep urls from being stripped down #3': 'a{background:url(/libraries/jquery-ui-1.10.1.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top #eee}',
- 'keep special markers in comments (so order is important)': '/*! __ESCAPED_URL_CLEAN_CSS0__ */a{display:block}',
- 'strip new line in urls': [
- 'a{background:url(/very/long/\
-path)}',
- 'a{background:url(/very/long/path)}'
- ],
- 'strip new line in urls which could be unquoted': [
- 'a{background:url("/very/long/\
-path")}',
- 'a{background:url(/very/long/path)}'
- ],
- 'uppercase': [
- 'a{background-image: URL("images/image.png");}',
- 'a{background-image:url(images/image.png)}'
- ]
- }),
- 'urls whitespace in compatibility mode': cssContext({
- 'keeps spaces as they are': '*{background:url(test.png) no-repeat}'
- }, { compatibility: 'ie8' }),
- 'urls quotes in compatibility mode': cssContext({
- 'keeps quotes as they are': [
- 'div{background:url("test.png")}',
- 'div{background:url("test.png")}'
- ]
- }, { compatibility: { properties: { urlQuotes: true } } }),
- 'urls rewriting - no root or target': cssContext({
- 'no @import': [
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'relative @import': [
- '@import url(test/fixtures/partials-relative/base.css);',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'relative @import twice': [
- '@import url(test/fixtures/partials-relative/extra/included.css);',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'absolute @import': [
- '@import url(/test/fixtures/partials-relative/base.css);',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'document-local reference': [
- 'svg{marker-end:url(#arrow)}',
- 'svg{marker-end:url(#arrow)}'
- ]
- }),
- 'urls rewriting - root but no target': cssContext({
- 'no @import': [
- 'a{background:url(../partials/extra/down.gif) no-repeat}',
- 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'relative @import': [
- '@import url(base.css);',
- 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'absolute @import': [
- '@import url(/test/fixtures/partials-relative/base.css);',
- 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'SVG': [
- "a{background-image:url(\"data:image/svg+xml,<svg version='1.1'/>\")}",
- "a{background-image:url(\"data:image/svg+xml,<svg version='1.1'/>\")}"
- ],
- 'document-local reference': [
- 'svg{marker-end:url(#arrow)}',
- 'svg{marker-end:url(#arrow)}'
- ],
- 'internal page': [
- 'a{background:url(about:blank)}',
- 'a{background:url(about:blank)}'
- ]
- }, {
- root: process.cwd(),
- relativeTo: path.join('test', 'fixtures', 'partials-relative')
- }),
- 'urls rewriting - no root but target as file': cssContext({
- 'no @import': [
- 'a{background:url(../partials/extra/down.gif) no-repeat}',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'relative @import': [
- '@import url(base.css);',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'absolute @import': [
- '@import url(/test/fixtures/partials-relative/base.css);',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'document-local reference': [
- 'svg{marker-end:url(#arrow)}',
- 'svg{marker-end:url(#arrow)}'
- ]
- }, {
- target: path.join(process.cwd(), 'test.css'),
- relativeTo: path.join('test', 'fixtures', 'partials-relative')
- }),
- 'urls rewriting - no root but target as a directory': cssContext({
- 'no @import': [
- 'a{background:url(../partials/extra/down.gif) no-repeat}',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'relative @import': [
- '@import url(base.css);',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'absolute @import': [
- '@import url(/test/fixtures/partials-relative/base.css);',
- 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'document-local reference': [
- 'svg{marker-end:url(#arrow)}',
- 'svg{marker-end:url(#arrow)}'
- ]
- }, {
- target: process.cwd(),
- relativeTo: path.join('test', 'fixtures', 'partials-relative')
- }),
- 'urls rewriting - no root but target as a missing directory': cssContext({
- 'url': [
- 'a{background:url(../partials/extra/down.gif) no-repeat}',
- 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'relative @import': [
- '@import url(base.css);',
- 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'absolute @import': [
- '@import url(/test/fixtures/partials-relative/base.css);',
- 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}'
- ]
- }, {
- target: path.join('test', 'fixtures2'),
- relativeTo: path.join('test', 'fixtures', 'partials-relative')
- }),
- 'urls rewriting - root and target': cssContext({
- 'no @import': [
- 'a{background:url(../partials/extra/down.gif) no-repeat}',
- 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'relative @import': [
- '@import url(base.css);',
- 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'absolute @import': [
- '@import url(/test/fixtures/partials-relative/base.css);',
- 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
- ],
- 'document-local reference': [
- 'svg{marker-end:url(#arrow)}',
- 'svg{marker-end:url(#arrow)}'
- ]
- }, {
- root: process.cwd(),
- target: path.join(process.cwd(), 'test.css'),
- relativeTo: path.join('test', 'fixtures', 'partials-relative')
- }),
- 'urls rewriting - rebase off': cssContext({
- 'keeps urls the same': [
- '@import url(base.css);',
- 'a{background:url(../partials/extra/down.gif) no-repeat}'
- ]
- }, {
- target: path.join(process.cwd(), 'test.css'),
- relativeTo: path.join('test', 'fixtures', 'partials-relative'),
- rebase: false
- }),
- 'fonts': cssContext({
- 'keep format quotation': [
- "@font-face{font-family:PublicVintage;src:url(/PublicVintage.otf) format('opentype')}",
- "@font-face{font-family:PublicVintage;src:url(/PublicVintage.otf) format('opentype')}"
- ],
- 'remove font family quotation': [
- "a{font-family:\"Helvetica\",'Arial'}",
- "a{font-family:Helvetica,Arial}"
- ],
- 'do not remove font family double quotation if space inside': 'a{font-family:"Courier New"}',
- 'do not remove font quotation if starts with a number': 'a{font:\'123font\'}',
- 'do not remove font family quotation if starts with a number': 'a{font-family:\'123font\'}',
- 'remove font quotation': [
- "a{font:12px/16px \"Helvetica\",'Arial'}",
- "a{font:12px/16px Helvetica,Arial}"
- ],
- 'remove font quotation #2': [
- "a{font:12px/16px \"Helvetica1_12\",'Arial_1451'}",
- "a{font:12px/16px Helvetica1_12,Arial_1451}"
- ],
- 'remove font quotation #3': [
- "a{font:12px/16px \"Helvetica-Regular\",'Arial-Bold'}",
- "a{font:12px/16px Helvetica-Regular,Arial-Bold}"
- ],
- 'do not remove quotation from enclosed JSON (weird, I know)': "p{font-family:'{ \"current\" : \"large\", \"all\" : [\"small\", \"medium\", \"large\"], \"position\" : 2 }'}"
- }),
- 'IE hacks': cssContext({
- 'star': 'a{*color:#fff}',
- 'unserscore': 'a{_color:#fff}',
- 'backslash': 'a{color:#fff\\9}',
- 'overriding by a star': 'a{color:red;display:block;*color:#fff}',
- 'overriding by a unserscore': 'a{color:red;display:block;_color:#fff}',
- 'overriding by a backslash': 'a{color:red;display:block;color:#fff\\9}',
- 'overriding a star': [
- 'a{*color:red;display:block;*color:#fff}',
- 'a{display:block;*color:#fff}'
- ],
- 'overriding a unserscore': [
- 'a{_color:red;display:block;_color:#fff}',
- 'a{display:block;_color:#fff}'
- ],
- 'overriding a backslash': [
- 'a{color:red\\9;display:block;color:#fff\\9}',
- 'a{display:block;color:#fff\\9}'
- ],
- 'overriding a star by a non-ajacent selector': 'a{color:red}.one{color:#000}a{*color:#fff}',
- 'overriding an underscore by a non-ajacent selector': 'a{color:red}.one{color:#000}a{_color:#fff}',
- 'overriding a backslash by a non-ajacent selector': 'a{color:red}.one{color:#fff}a{color:#fff\\9}',
- 'preserving backslash in overriddable': 'a{border:1px solid #ccc\\9}',
- 'keeps rgba(0,0,0,0)': 'a{color:rgba(0,0,0,0)}',
- 'keeps rgba(255,255,255,0)': 'a{color:rgba(255,255,255,0)}',
- 'keeps hsla(120,100%,50%,0)': 'a{color:hsla(120,100%,50%,0)}'
- }, { compatibility: 'ie8' }),
- 'IE hacks without IE compatibility': cssContext({
- 'star': [
- 'a{*color:#fff}',
- ''
- ],
- 'unserscore': [
- 'a{_color:#fff}',
- ''
- ],
- 'two in a row': [
- 'a{padding:0;*height:13px;*width:13px}',
- 'a{padding:0}'
- ],
- 'two in a row mixed': [
- 'a{padding:0;*height:13px;_width:13px}',
- 'a{padding:0}'
- ],
- 'backslash': [
- 'a{color:#fff\\9}',
- 'a{color:#fff\\9}'
- ]
- }),
- 'animations': cssContext({
- 'shorten': [
- '@keyframes test\n{ from\n { width:100px; }\n to { width:200px; }\n}',
- '@keyframes test{from{width:100px}to{width:200px}}'
- ],
- 'remove name quotes': [
- "@keyframes \"test1\"{a{display:block}}@keyframes 'test2'{a{display:block}}",
- "@keyframes test1{a{display:block}}@keyframes test2{a{display:block}}"
- ],
- 'not remove name quotes if whitespace inside': "@keyframes \"test 1\"{a{display:block}}@keyframes 'test 2'{a{display:block}}",
- 'remove name quotes for vendor prefixes': [
- "@-moz-keyframes 'test'{a{display:block}}@-o-keyframes 'test'{a{display:block}}@-webkit-keyframes 'test'{a{display:block}}",
- "@-moz-keyframes test{a{display:block}}@-o-keyframes test{a{display:block}}@-webkit-keyframes test{a{display:block}}"
- ],
- 'remove quotes in animation': [
- "div{animation:'test' 2s ease-in .5s 3}",
- "div{animation:test 2s ease-in .5s 3}"
- ],
- 'not remove quotes in animation when name with space inside': "div{animation:'test 1' 2s ease-in .5s 3}",
- 'remove quotes in vendor prefixed animation': [
- "div{-moz-animation:'test' 2s ease-in;-o-animation:'test' 2s ease-in;-webkit-animation:'test' 2s ease-in}",
- "div{-moz-animation:test 2s ease-in;-o-animation:test 2s ease-in;-webkit-animation:test 2s ease-in}"
- ],
- 'remove quotes in animation-name': [
- "div{animation-name:'test'}",
- "div{animation-name:test}"
- ],
- 'not remove quotes in animation-name when name with space inside': "div{animation-name:'test 1'}",
- 'remove quotes in vendor prefixed animation-name': [
- "div{-moz-animation-name:'test';-o-animation-name:'test';-webkit-animation-name:'test'}",
- "div{-moz-animation-name:test;-o-animation-name:test;-webkit-animation-name:test}"
- ]
- }),
- 'attributes': cssContext({
- 'should keep selector if no value': 'div[data-type]{border-color:red}',
- 'should keep selector if no quotation': 'div[data-type=something]{border-color:red}',
- 'should keep selector if equals in value': 'div[data-type="stupid=value"]{border-color:red}',
- 'should keep quotation if whitespace inside': 'div[data-type^=\'object 1\']{border-color:red}',
- 'should keep quotations if special characters inside': 'a[data-type="object+1"]{color:red}p[data-target="#some-place"]{color:#0f0}',
- 'should keep quotation if is a number': 'div[data-number=\'1\']{border-color:red}',
- 'should keep quotation if starts with a number': 'div[data-type^=\'1something\']{border-color:red}',
- 'should keep quotation if starts with a hyphen': 'div[data-type$=\'-something\']{border-color:red}',
- 'should keep quotation if key only (which is invalid)': 'div["data-type"]{color:red}',
- 'should strip quotation if is a word': [
- 'a[data-href=\'object\']{border-color:red}',
- 'a[data-href=object]{border-color:red}'
- ],
- 'should strip quotation if is a hyphen separated words': [
- 'a[data-href=\'object-1-two\']{border-color:red}',
- 'a[data-href=object-1-two]{border-color:red}'
- ],
- 'should strip quotations if is less specific selectors': [
- 'a[data-href*=\'object1\']{border-color:red}a[data-href|=\'object2\']{border-color:#0f0}',
- 'a[data-href*=object1]{border-color:red}a[data-href|=object2]{border-color:#0f0}'
- ],
- 'should keep special characters inside attributes #1': "a[data-css='color:white']{display:block}",
- 'should keep special characters inside attributes #2': 'a[href="/version-0.01.html"]{display:block}',
- 'should strip new lines inside attributes': [
- ".test[title='my very long \
-title']{display:block}",
- ".test[title='my very long title']{display:block}"
- ],
- 'should strip new lines inside attributes which can be unquoted': [
- ".test[title='my_very_long_\
-title']{display:block}",
- ".test[title=my_very_long_title]{display:block}"
- ],
- 'should strip whitespace between square brackets': [
- 'body[ data-title ]{color:red}',
- 'body[data-title]{color:red}'
- ],
- 'should strip whitespace inside square brackets': [
- 'body[ data-title = x ]{color:red}',
- 'body[data-title=x]{color:red}'
- ]
- }),
- 'ie filters': cssContext({
- 'short alpha': [
- // "a{ filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80); -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)';}",
- "a{ filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80)}",
- "a{filter:alpha(Opacity=80)}"
- ],
- 'short chroma': [
- 'a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191)}',
- 'a{filter:chroma(color=#919191)}'
- ],
- 'matrix filter spaces': [
- "a{filter:progid:DXImageTransform.Microsoft.Matrix(M11=0.984, M22=0.984, M12=0.17, M21=-0.17, SizingMethod='auto expand')}",
- "a{filter:progid:DXImageTransform.Microsoft.Matrix(M11=.984, M22=.984, M12=.17, M21=-.17, SizingMethod='auto expand')}"
- ],
- 'multiple filters (IE7 issue)': [
- "a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191) progid:DXImageTransform.Microsoft.Matrix(M11=0.984, M22=0.984, M12=0.17, M21=-0.17, SizingMethod='auto expand')}",
- "a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191) progid:DXImageTransform.Microsoft.Matrix(M11=.984, M22=.984, M12=.17, M21=-.17, SizingMethod='auto expand')}"
- ],
- 'AlphaImageLoader': [
- 'div{filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=images/skyline.jpg)}',
- 'div{filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=images/skyline.jpg)}'
- ]
- }),
- 'charsets': cssContext({
- 'not at beginning': [
- "a{ color: #f10; }@charset 'utf-8';b { font-weight: bolder}",
- "@charset 'utf-8';a{color:#f10}b{font-weight:bolder}"
- ],
- 'multiple charsets': [
- "@charset 'utf-8';div :before { display: block }@charset 'utf-8';a { color: #f10 }",
- "@charset 'utf-8';div :before{display:block}a{color:#f10}"
- ],
- 'charset and space after': [
- "@charset 'utf-8';" + lineBreak + lineBreak + "a{display:block}",
- "@charset 'utf-8';a{display:block}"
- ]
- }),
- 'important': cssContext({
- 'space before': [
- "body{background-color:#fff !important}",
- "body{background-color:#fff!important}"
- ],
- 'space between ! and important': [
- "body{background-color:#fff ! important}",
- "body{background-color:#fff!important}"
- ]
- }),
- 'empty elements': cssContext({
- 'single': [
- ' div p { \n}',
- ''
- ],
- 'between non-empty': [
- 'div {color:#fff} a{ } p{ line-height:1.35em}',
- 'div{color:#fff}p{line-height:1.35em}'
- ],
- 'just a semicolon': [
- 'div { ; }',
- ''
- ],
- 'inside @media': [
- "@media screen { .test {} } .test1 { color: green; }",
- ".test1{color:green}"
- ],
- 'inside nested @media': [
- '@media screen { @media (orientation:landscape) { @media (max-width:999px) { .test {} } } }',
- ''
- ],
- 'inside not empty @media': [
- "@media screen { .test {} .some { display:none } }",
- "@media screen{.some{display:none}}"
- ],
- 'inside nested not empty @media': [
- '@media screen { @media (orientation:landscape) { @media (max-width:999px) { .test {} } a {color:red} } }',
- '@media screen{@media (orientation:landscape){a{color:red}}}'
- ]
- }),
- 'empty @media': cssContext({
- 'simple': [
- '@media print{}',
- ''
- ],
- 'simple with and': [
- '@media print and screen{}',
- ''
- ],
- 'complex': [
- '@media print, (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {\n}',
- ''
- ]
- }),
- '@import': cssContext({
- 'empty': [
- "@import url();",
- ''
- ],
- 'of an unknown file': [
- "@import url('fake.css');",
- ''
- ],
- 'of an unknown file with a missing trailing semicolon': [
- "@import url(fake.css)",
- ''
- ],
- 'of a directory': [
- "@import url(test/fixtures/partials);",
- ''
- ],
- 'of a real file': [
- "@import url(test/fixtures/partials/one.css);",
- ".one{color:red}"
- ],
- 'of a real file twice': [
- "@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/one.css);",
- ".one{color:red}"
- ],
- 'of a real file with current path prefix': [
- "@import url(./test/fixtures/partials/one.css);",
- ".one{color:red}"
- ],
- 'of a real file with quoted path': [
- "@import url('test/fixtures/partials/one.css');",
- ".one{color:red}"
- ],
- 'of a real file with double-quoted path': [
- '@import url("test/fixtures/partials/one.css");',
- ".one{color:red}"
- ],
- 'of a real file with bare path': [
- "@import test/fixtures/partials/one.css;",
- ".one{color:red}"
- ],
- 'of a real file with bare quoted path': [
- "@import 'test/fixtures/partials/one.css';",
- ".one{color:red}"
- ],
- 'of a real file with bare double-quoted path': [
- '@import "test/fixtures/partials/one.css";',
- ".one{color:red}"
- ],
- 'of a real file with single simple media': [
- '@import url(test/fixtures/partials/one.css) screen;',
- "@media screen{.one{color:red}}"
- ],
- 'of a real file with multiple simple media': [
- '@import "test/fixtures/partials/one.css" screen, tv, print;',
- "@media screen,tv,print{.one{color:red}}"
- ],
- 'of a real file with complex media': [
- '@import \'test/fixtures/partials/one.css\' screen and (orientation:landscape);',
- "@media screen and (orientation:landscape){.one{color:red}}"
- ],
- 'of a real file with a missing trailing semicolon': [
- "@import url(test/fixtures/partials/one.css)",
- ''
- ],
- 'of a real files with a missing trailing semicolon': [
- "@import url(test/fixtures/partials/one.css)@import url(test/fixtures/partials/two.css)",
- ''
- ],
- 'of more files': [
- "@import url(test/fixtures/partials/one.css);\n\n@import url(test/fixtures/partials/extra/three.css);\n\na{display:block}",
- ".one{color:red}.three{color:#0f0}a{display:block}"
- ],
- 'of more files with media': [
- "@import url(test/fixtures/partials/one.css) screen;@import url(test/fixtures/partials/extra/three.css) tv;",
- "@media screen{.one{color:red}}@media tv{.three{color:#0f0}}"
- ],
- 'of multi-level, circular dependency file': [
- "@import url(test/fixtures/partials/two.css);",
- ".one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}"
- ],
- 'of a file with a relative resource path': [
- "@import url(test/fixtures/partials/three.css);",
- ".three{background-image:url(test/fixtures/partials/extra/down.gif)}"
- ],
- 'of a file with an absolute resource path': [
- "@import url(test/fixtures/partials/four.css);",
- ".four{background-image:url(/partials/extra/down.gif)}"
- ],
- 'of a file with a resource URI': [
- "@import url(test/fixtures/partials/five.css);",
- ".five{background:url(data:image/jpeg;base64,/9j/)}"
- ],
- 'cut off': [
- '@impo',
- ''
- ],
- 'cut off inside a comment': [
- '/* @impo',
- ''
- ],
- 'inside a comment': [
- '/* @import url(test/fixtures/partials/five.css); */a { color: red; }',
- 'a{color:red}'
- ],
- 'after a comment': [
- '/* @import url(test/fixtures/partials/one.css); */@import url(test/fixtures/partials/one.css);a { color: red; }',
- '.one,a{color:red}'
- ],
- 'used arbitrarily in comment': [
- '/* @import foo */a { color: red; }',
- 'a{color:red}'
- ],
- 'used arbitrarily in comment multiple times': [
- '/* @import foo */a { color: red; }\n/* @import bar */p { color: #fff; }',
- 'a{color:red}p{color:#fff}'
- ],
- 'used arbitrarily in comment including unrelated comment': [
- '/* foo */a { color: red; }/* bar *//* @import */',
- 'a{color:red}'
- ],
- 'of a file with a comment': [
- '@import url(test/fixtures/partials/comment.css);',
- 'a{display:block}'
- ],
- 'of a file (with media) with a comment': [
- '@import url(test/fixtures/partials/comment.css) screen and (device-height: 600px);',
- '@media screen and (device-height:600px){a{display:block}}'
- ],
- 'after standard content': [
- "a{display:block}@import url(test/fixtures/partials/one.css);body{margin:0}",
- "a{display:block}body{margin:0}"
- ],
- 'after quoted content': [
- "/*a{display:block}*/@import url(test/fixtures/partials/one.css);",
- ".one{color:red}"
- ],
- 'with double underscore': [
- '@import url(test/fixtures/partials/with__double_underscore.css);',
- '.one{color:green}'
- ],
- 'remote inside local': [
- '@import url(test/fixtures/partials/remote.css);',
- '@import url(http://jakubpawlowicz.com/styles.css);'
- ],
- 'remote inside local after content': [
- 'a{color:red}@import url(test/fixtures/partials/remote.css);',
- 'a{color:red}'
- ],
- 'remote inside local after imported content': [
- '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/remote.css);',
- '.one{color:red}'
- ]
- }, { root: process.cwd() }),
- 'malformed but still valid @import': cssContext({
- 'prefixed with whitespace': [
- " @import 'test/fixtures/partials/one.css';",
- ".one{color:red}"
- ],
- 'no whitespace between @import and filename': [
- "@import'test/fixtures/partials/one.css';",
- ".one{color:red}"
- ],
- 'extra whitespace between @import and filename': [
- "@import 'test/fixtures/partials/one.css';",
- ".one{color:red}"
- ],
- 'line break between @import and filename': [
- "@import " + lineBreak + "'test/fixtures/partials/one.css';",
- ".one{color:red}"
- ],
- 'extra whitespace prefix in file name': [
- "@import ' test/fixtures/partials/one.css';",
- ".one{color:red}"
- ],
- 'extra whitespace suffix in file name': [
- "@import 'test/fixtures/partials/one.css ';",
- ".one{color:red}"
- ],
- 'extra whitespace after': [
- "@import 'test/fixtures/partials/one.css' ;",
- ".one{color:red}"
- ],
- 'uppercase @import': [
- "@IMPORT 'test/fixtures/partials/one.css';",
- ".one{color:red}"
- ],
- 'extra whitespace between url and filename': [
- "@import url( test/fixtures/partials/one.css);",
- ".one{color:red}"
- ],
- 'extra whitespace prefix in file name - url': [
- "@import url(' test/fixtures/partials/one.css');",
- ".one{color:red}"
- ],
- 'extra whitespace suffix in file name - url': [
- "@import url('test/fixtures/partials/one.css ');",
- ".one{color:red}"
- ]
- }, { root: process.cwd() }),
- '@import with absolute paths': cssContext({
- 'of an unknown file': [
- "@import url(/fake.css);",
- ''
- ],
- 'of a real file': [
- "@import url(/partials/one.css);",
- ".one{color:red}"
- ],
- 'of a real file with quoted paths': [
- "@import url(\"/partials/one.css\");",
- ".one{color:red}"
- ],
- 'of two files with mixed paths': [
- "@import url(/partials/one.css);@import url(partials/extra/three.css);a{display:block}",
- ".one{color:red}.three{color:#0f0}a{display:block}"
- ],
- 'of a multi-level, circular dependency file': [
- "@import url(/partials/two.css);",
- ".one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}"
- ],
- 'of a multi-level, circular dependency file with mixed paths': [
- "@import url(/partials-absolute/base.css);",
- ".base2{border-width:0}.sub{padding:0}.base{margin:0}"
- ]
- }, { root: path.join(process.cwd(), 'test', 'fixtures') }),
- '@import with option processImport': cssContext({
- 'of an unknown file': [
- "@import url(/fake.css);",
- "@import url(/fake.css);"
- ],
- 'of an unknown file with extra whitespace': [
- "@import url( /fake.css );",
- "@import url(/fake.css);"
- ],
- 'of comment chars within import url': "@import 'necolas/normalize.css@*/normalize.css';"
- }, { processImport: false }),
- '@import with no import and no advanced': cssContext({
- 'empty body': [
- '@import url(//fonts.googleapis.com/css?family=Domine:700);body{/* comment */}body h1{font-family:Domine}',
- '@import url(//fonts.googleapis.com/css?family=Domine:700);body h1{font-family:Domine}'
- ],
- 'no empty body': '@import url(//fonts.googleapis.com/css?family=Domine:700);body{color:red}body h1{font-family:Domine}'
- }, { processImport: false, advanced: false }),
- '@import with no url': cssContext({
- 'matching too much': [
- '@import url(test.css);@font-face{font-family:"icomoon"}',
- '@import url(test.css);@font-face{font-family:icomoon}'
- ]
- }, { processImport: false, root: process.cwd(), relativeTo: process.cwd() }),
- 'duplicate selectors with disabled advanced processing': cssContext({
- 'of a duplicate selector': [
- 'a,a{color:red}',
- 'a{color:red}'
- ]
- }, { advanced: false }),
- 'line breaks with disabled advanced processing': cssContext({
- 'should be applied': [
- 'a{color:red}p{display:block}',
- 'a{color:red}' + lineBreak + 'p{display:block}'
- ]
- }, { advanced: false, keepBreaks: true }),
- 'invalid data tokenization': cssContext({
- 'extra top-level closing brace': [
- 'a{color:red}}p{width:auto}',
- 'a{color:red}p{width:auto}'
- ],
- 'extra top-level closing braces': [
- 'a{color:red}}}}p{width:auto}',
- 'a{color:red}p{width:auto}'
- ]
- }),
- 'duplicate selectors in a list': cssContext({
- 'of a duplicate selector': [
- 'a,a{color:red}',
- 'a{color:red}'
- ],
- 'of an unordered multiply repeated selector': [
- 'a,b,p,a{color:red}',
- 'a,b,p{color:red}'
- ],
- 'of an unordered multiply repeated selector within a block': [
- '@media screen{a,b,p,a{color:red}}',
- '@media screen{a,b,p{color:red}}'
- ],
- 'of an unordered multiply repeated complex selector within a block #1': [
- '@media screen{.link[data-path],a,p,.link[data-path]{color:red}}',
- '@media screen{.link[data-path],a,p{color:red}}'
- ],
- 'of an unordered multiply repeated complex selector within a block #2': [
- '@media screen{#foo[data-path^="bar bar"],a,p,#foo[data-path^="bar bar"]{color:red}}',
- '@media screen{#foo[data-path^="bar bar"],a,p{color:red}}'
- ]
- }),
- 'duplicate selectors in a scope': cssContext({
- 'of two successive selectors': [
- 'a{color:red}a{color:red}',
- 'a{color:red}'
- ],
- 'of two successive selectors with different body': [
- 'a{color:red}a{display:block}',
- 'a{color:red;display:block}'
- ],
- 'of many successive selectors': [
- 'a{color:red}a{color:red}a{color:red}a{color:red}',
- 'a{color:red}'
- ],
- 'of two non-successive selectors': [
- 'a{color:red}p{color:#fff}a{color:red}',
- 'p{color:#fff}a{color:red}'
- ],
- 'of many non-successive selectors': [
- 'div{width:100%}a{color:red}a{color:red}p{color:#fff}div{width:100%}ol{margin:0}p{color:#fff}',
- 'a{color:red}div{width:100%}ol{margin:0}p{color:#fff}'
- ],
- 'with global and media scope': [
- 'a{color:red}@media screen{a{color:red}p{width:100px}a{color:red}}',
- 'a{color:red}@media screen{p{width:100px}a{color:red}}'
- ],
- 'with two media scopes': [
- '@media (min-width:100px){a{color:red}}@media screen{a{color:red}p{width:100px}a{color:red}}',
- '@media (min-width:100px){a{color:red}}@media screen{p{width:100px}a{color:red}}'
- ]
- }),
- 'duplicate properties with aggressive merging disabled': cssContext({
- 'of (yet) unmergeable properties': 'a{display:inline-block;color:red;display:-moz-block}',
- 'of mergeable properties': [
- 'a{background:red;display:block;background:white}',
- 'a{background:#fff;display:block}'
- ]
- }, { aggressiveMerging: false }),
- 'same selectors': cssContext({
- 'of two non-adjacent selectors': [
- '.one{color:red}.two{color:#00f}.one{font-weight:700}',
- '.one{color:red;font-weight:700}.two{color:#00f}'
- ],
- 'of two adjacent single selectors': [
- '.one{color:red}.one{font-weight:700}',
- '.one{color:red;font-weight:700}'
- ],
- 'of three adjacent single selectors': [
- '.one{color:red}.one{font-weight:700}.one{font-size:12px}',
- '.one{color:red;font-weight:700;font-size:12px}'
- ],
- 'of two adjacent single, complex selectors': [
- '#box>.one{color:red}#box>.one{font-weight:700}',
- '#box>.one{color:red;font-weight:700}'
- ],
- 'of two adjacent multiple, complex selectors': [
- '#box>.one,.zero{color:red}#box>.one,.zero{font-weight:700}',
- '#box>.one,.zero{color:red;font-weight:700}'
- ],
- 'of two adjacent selectors with duplicate properties #1': [
- '.one{color:red}.one{color:#fff}',
- '.one{color:#fff}'
- ],
- 'of two adjacent selectors with duplicate properties #2': [
- '.one{color:red;font-weight:bold}.one{color:#fff;font-weight:400}',
- '.one{color:#fff;font-weight:400}'
- ],
- 'of two adjacent complex selectors with different selector order': [
- '.one,.two{color:red}.two,.one{line-height:1em}',
- '.one,.two{color:red;line-height:1em}'
- ],
- 'two adjacent with hex color definitions': [
- 'a:link,a:visited{color:#fff}.one{display:block}a:link,a:visited{color:red}',
- '.one{display:block}a:link,a:visited{color:red}'
- ],
- 'in two passes': [
- 'a{color:red}a{background:red}b{color:red}b{background:red}',
- 'a,b{color:red;background:red}'
- ],
- 'when overriden with a browser specific selector': 'a{color:red}::-webkit-scrollbar,a{color:#fff}',
- 'two same selectors over a block': [
- '.one{color:red}@media print{.two{display:block}}.one{display:none}',
- '@media print{.two{display:block}}.one{color:red;display:none}'
- ],
- 'two same bodies over a block': [
- '.one{color:red}@media print{.two{display:block}}.three{color:red}',
- '.one,.three{color:red}@media print{.two{display:block}}'
- ]
- }),
- 'same non-adjacent selectors': cssContext({
- 'with one redefined property': [
- 'a{color:red;display:block}.one{color:red}a{color:#fff;margin:2px}',
- '.one{color:red}a{display:block;color:#fff;margin:2px}'
- ],
- 'with intentionally redefined properties on joins': [
- 'a{display:inline-block;display:-moz-inline-box;color:red}.one{margin:12px}a{color:#fff;margin:2px}',
- '.one{margin:12px}a{display:inline-block;display:-moz-inline-box;color:#fff;margin:2px}'
- ],
- 'with intentionally redefined properties on multiple joins': [
- 'a{color:red}.one{font-size:12px}a{color:#fff;margin:2px}.two{margin:10px}a{margin:0}',
- '.one{font-size:12px}.two{margin:10px}a{color:#fff;margin:0}'
- ],
- 'with all redefined properties': [
- 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
- '.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}'
- ],
- 'many with all redefined properties': [
- 'a{padding:10px}.zero{color:transparent}a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
- '.zero{color:transparent}.one{font-size:12px}a{padding:10px;color:#fff;display:inline-block;margin:2px}'
- ],
- 'when overriden by an empty selector': [
- 'a{padding:10px}.one{color:red}a{}',
- 'a{padding:10px}.one{color:red}'
- ],
- 'when overriden by a complex selector': [
- 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}',
- '.one,a,p{color:red}a{margin:0}a,p{padding:0}'
- ],
- 'when overriden by complex selectors': [
- 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}.one,a{color:#fff}',
- 'a{margin:0}a,p{color:red;padding:0}.one,a{color:#fff}'
- ],
- 'when complex selector overriden by simple selectors': 'a,p{margin:0;color:red}a{color:#fff}',
- 'when complex selector overriden by complex and simple selectors': [
- 'a,p{margin:0;color:red}a{color:#fff}a,p{color:#00f}p{color:#0f0}',
- 'a,p{margin:0;color:#00f}p{color:#0f0}'
- ],
- 'when complex selector overriden by complex selectors': [
- '.one>.two,.three{color:red;line-height:1rem}#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}',
- '#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}'
- ],
- 'when undefined is used as a value': [
- '.one{text-shadow:undefined}p{font-size:14px}.one{font-size:12px}',
- 'p{font-size:14px}.one{text-shadow:undefined;font-size:12px}'
- ],
- 'when undefined is used as a value with reduction': [
- '.one{text-shadow:undefined}p{color:red}.one{font-size:12px;text-shadow:none}',
- 'p{color:red}.one{font-size:12px;text-shadow:none}'
- ],
- 'when overriden with a browser specific selector': 'a{color:red}p{display:block}::-moz-selection,a{color:#fff}',
- 'when same browser specific selector more than once': [
- 'a,::-moz-selection{color:red}p{display:block}a,::-moz-selection{color:#fff}',
- 'p{display:block}::-moz-selection,a{color:#fff}'
- ],
- 'with full property comparison': [
- '.one{height:7rem}.two{color:#fff}.one{line-height:7rem;color:red}',
- '.two{color:#fff}.one{height:7rem;line-height:7rem;color:red}'
- ],
- 'with two intermediate, non-overriding selectors': [
- '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}',
- '.one{color:red;margin:0;font-size:12px}.two{color:#fff}'
- ],
- 'with two intermediate, overriding more specific selectors': [
- '.one{color:red;margin:0}.two{font:12px serif}.one{font-size:12px}',
- '.two{font:12px serif}.one{color:red;margin:0;font-size:12px}'
- ],
- 'with granular selectors from the same shorthand': [
- '.one{color:red;margin:0}.two{font-weight:700}.one{font-size:12px}',
- '.one{color:red;margin:0;font-size:12px}.two{font-weight:700}'
- ],
- 'with three intermediate, non-overriding selectors': [
- '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}.three{color:#000}.one{padding:0}',
- '.one{color:red;margin:0;font-size:12px;padding:0}.two{color:#fff}.three{color:#000}'
- ],
- 'successive selectors': [
- 'footer,header{top:1.25em;bottom:1.25em}header{top:2.5em}footer{bottom:2.5em}',
- 'footer,header{top:1.25em;bottom:1.25em}header{top:2.5em}footer{bottom:2.5em}'
- ],
- 'over a @media block': [
- '.one{color:red;margin:0}@media{.two{font-weight:700}}.one{font-size:12px}',
- '.one{color:red;margin:0;font-size:12px}@media{.two{font-weight:700}}'
- ]
- }),
- 'rerun optimizers': cssContext({
- 'selectors reducible once': [
- '.one{color:red;margin:0}.two{color:red}.one{margin:0}',
- '.one,.two{color:red}.one{margin:0}'
- ]
- }),
- 'same bodies': cssContext({
- 'of two non-adjacent selectors': '.one{color:red}.two{color:#00f}.three{color:red}',
- 'of two adjacent single selectors': [
- '.one{color:red}.two{color:red}',
- '.one,.two{color:red}'
- ],
- 'of three adjacent complex, multiple selectors': [
- '.one{color:red}#two.three{color:red}.four>.five{color:red}',
- '#two.three,.four>.five,.one{color:red}'
- ],
- 'with repeated selectors': [
- '#zero>p,.one,.two{color:red}.two,#zero>p,.three{color:red}',
- '#zero>p,.one,.three,.two{color:red}'
- ],
- 'of element selectors': [
- 'p{color:red}a{color:#000}div{color:red}',
- 'div,p{color:red}a{color:#000}'
- ],
- 'of element selectors inside @media': [
- '@media screen{p{color:red}a{color:#000}div{color:red}}',
- '@media screen{div,p{color:red}a{color:#000}}'
- ],
- 'of element selectors with a class selector in between': [
- 'p{color:red}.a{color:#000}div{color:red}',
- 'p{color:red}.a{color:#000}div{color:red}'
- ],
- 'of element selectors with an empty class selector in between': [
- 'p{color:red}.a{}div{color:red}',
- 'div,p{color:red}'
- ]
- }),
- 'same bodies - IE8 compat': cssContext({
- 'of two supported selectors': [
- '.one:first-child{color:red}.two>.three{color:red}',
- '.one:first-child,.two>.three{color:red}'
- ],
- 'of supported and unsupported selector': '.one:first-child{color:red}.two:last-child{color:red}',
- 'of two unsupported selectors': '.one:nth-child(5){color:red}.two:last-child{color:red}'
- }, { compatibility: 'ie8' }),
- 'same bodies - IE7 compat': cssContext({
- 'of two supported selectors': [
- '.one{color:red}.two>.three{color:red}',
- '.one,.two>.three{color:red}'
- ],
- 'of supported and unsupported selector': '.one{color:red}.two:last-child{color:red}',
- 'of two unsupported selectors': '.one:before{color:red}.two:last-child{color:red}'
- }, { compatibility: 'ie7' }),
- 'same bodies - +adjacentSpace': cssContext({
- 'of two supported selectors': [
- '.one{color:red}.two + nav{color:red}',
- '.one,.two+ nav{color:red}'
- ]
- }, { compatibility: { selectors: { adjacentSpace: true } } }),
- 'units - IE8 compatibility': cssContext({
- 'rems': 'div{padding-top:16px;color:red;padding-top:1rem}'
- }, { compatibility: 'ie8' }),
- 'redefined more granular properties with property merging': cssContext({
- 'should merge background with background-attachment': [
- 'a{background:0;background-attachment:fixed}',
- 'a{background:0 fixed}'
- ],
- 'should NOT merge background with inherited background-attachment': [
- 'a{background:0;background-attachment:inherit}',
- 'a{background:0;background-attachment:inherit}'
- ],
- 'should merge background with background-color': [
- 'a{background:0;background-color:#9fce00}',
- 'a{background:0 #9fce00}'
- ],
- 'should NOT merge background with inherited background-color': [
- 'a{background:0;background-color:inherit}',
- 'a{background:0;background-color:inherit}'
- ],
- 'should NOT merge background with background-color set to none': [
- 'a{background:url(logo.png) center no-repeat;background-color:none}',
- 'a{background:url(logo.png) center no-repeat;background-color:none}'
- ],
- 'should merge background with background-image': [
- 'a{background:0;background-image:url(hello_world)}',
- 'a{background:url(hello_world) 0}'
- ],
- 'should NOT merge background with inherited background-image': [
- 'a{background:0;background-image:inherit}',
- 'a{background:0;background-image:inherit}'
- ],
- 'should merge background with background-position': [
- 'a{background:0;background-position:3px 4px}',
- 'a{background:3px 4px}'
- ],
- 'should NOT merge background with inherited background-position': [
- 'a{background:0;background-position:inherit}',
- 'a{background:0;background-position:inherit}'
- ],
- 'should merge background with background-repeat': [
- 'a{background:0;background-repeat:repeat-y}',
- 'a{background:0 repeat-y}'
- ],
- 'should NOT merge background with inherited background-repeat': [
- 'a{background:0;background-repeat:inherit}',
- 'a{background:0;background-repeat:inherit}'
- ],
- 'should merge outline with outline-color': [
- 'a{outline:1px;outline-color:#9fce00}',
- 'a{outline:#9fce00 1px}'
- ],
- 'should NOT merge outline with inherited outline-color': [
- 'a{outline:0;outline-color:inherit}',
- 'a{outline:0;outline-color:inherit}'
- ],
- 'should merge outline with outline-style': [
- 'a{outline:0;outline-style:dashed}',
- 'a{outline:dashed 0}'
- ],
- 'should NOT merge outline with inherited outline-style': [
- 'a{outline:0;outline-style:inherit}',
- 'a{outline:0;outline-style:inherit}'
- ],
- 'should merge outline with outline-width': [
- 'a{outline:0;outline-width:5px}',
- 'a{outline:5px}'
- ],
- 'should NOT merge outline with inherited outline-width': [
- 'a{outline:0;outline-width:inherit}',
- 'a{outline:0;outline-width:inherit}'
- ],
- 'should merge list-style with list-style-type': [
- 'li{list-style-type:disc;list-style:inside}',
- 'li{list-style:inside}'
- ]
- }),
- 'merging of rules': cssContext({
- 'rules without pseudo classes should be merged': [
- 'a{color:red}b{color:red}',
- 'a,b{color:red}'
- ],
- 'rules with well-supported pseudo classes should be merged #1': [
- 'a:focus{color:red}b{color:red}',
- 'a:focus,b{color:red}'
- ],
- 'rules with well-supported pseudo classes should be merged #2': [
- 'a:nth-of-type(1){color:red}b{color:red}',
- 'a:nth-of-type(1),b{color:red}'
- ],
- 'rules with well-supported pseudo classes should be merged #3': [
- 'a:first-of-type{color:red}b{color:red}',
- 'a:first-of-type,b{color:red}'
- ],
- 'rules with well-supported pseudo classes should be merged #4': [
- 'a:first-child{color:red}b{color:red}',
- 'a:first-child,b{color:red}'
- ],
- 'rules with prefixed pseudo classes should not be merged #1': [
- 'a:-moz-full-screen{color:red}b{color:red}',
- 'a:-moz-full-screen{color:red}b{color:red}'
- ],
- 'rules with prefixed pseudo classes should not be merged #2': [
- 'a:-moz-dir(rtl){color:red}b{color:red}',
- 'a:-moz-dir(rtl){color:red}b{color:red}'
- ],
- 'rules with not-so-well-supported pseudo classes should not be merged #1': [
- 'a:fullscreen{color:red}b{color:red}',
- 'a:fullscreen{color:red}b{color:red}'
- ],
- 'rules with not-so-well-supported pseudo classes should not be merged #2': [
- 'a:dir(ltr){color:red}b{color:red}',
- 'a:dir(ltr){color:red}b{color:red}'
- ],
- 'rules with not-so-well-supported pseudo classes should not be merged #3': [
- 'a:right{color:red}b{color:red}',
- 'a:right{color:red}b{color:red}'
- ],
- 'rules with not-so-well-supported pseudo classes should not be merged #4': [
- 'a:first{color:red}b{color:red}',
- 'a:first{color:red}b{color:red}'
- ]
- }),
- 'grouping with advanced optimizations': cssContext({
- '@-moz-document': '@-moz-document domain(mozilla.org){a{color:red}}',
- '@media': '@media{a{color:red}}',
- '@page': '@page{margin:.5em}',
- '@supports': '@supports (display:flexbox){.flex{display:flexbox}}',
- '@-ms-viewport': '@-ms-viewport{width:device-width}',
- '@-o-viewport': '@-o-viewport{width:device-width}',
- '@viewport': '@viewport{width:device-width}',
- '@counter-style': '@counter-style triangle{system:cyclic;symbols:‣;suffix:" "}'
- }),
- 'background size': cssContext({
- 'with background-position': 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}',
- 'with background-position and spaces': [
- 'a{background:url(top.jpg) 50% 0 / auto 25% no-repeat}',
- 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}'
- ],
- 'with background-position shorthands': 'a{background:url(top.jpg) 50px/25% no-repeat}',
- 'with background-position shorthands and spaces': [
- 'a{background:url(top.jpg) 0 / cover no-repeat}',
- 'a{background:url(top.jpg) 0/cover no-repeat}'
- ],
- 'with background-size property': [
- 'a{background:none;background-image:url(1.png);background-size:28px 28px}',
- 'a{background:url(1.png);background-size:28px 28px}'
- ]
- }),
- 'background position': cssContext({
- 'calc as a value': [
- '*{background:white calc(100% - 10px) center no-repeat;background-image:url(test.png)}',
- '*{background:calc(100% - 10px) center no-repeat #fff;background-image:url(test.png)}'
- ]
- }),
- 'background-clip': cssContext({
- 'inside background shorthand': [
- 'div{background:content-box #000}',
- 'div{background:content-box #000}'
- ]
- }),
- 'background size with +properties.backgroundSizeMerging': cssContext({
- 'with background-size property': [
- 'a{background:none;background-image:url(1.png);background-size:28px 28px}',
- 'a{background:url(1.png) 0 0/28px 28px}'
- ],
- 'important overriding': [
- 'a{background:url(a.jpg) !important; background-color:#fff !important; background-size:10px 10px !important}',
- 'a{background:url(a.jpg) 0 0/10px 10px #fff!important}'
- ]
- }, { compatibility: '+properties.backgroundSizeMerging' }),
- 'multiple backgrounds': cssContext({
- 'should not produce longer values': 'p{background:no-repeat;background-position:100% 0,0 100%,100% 100%,50% 50%}'
- }),
- 'misc advanced': cssContext({
- 'outline auto': [
- 'a{outline:5px auto -webkit-focus-ring-color}',
- 'a{outline:-webkit-focus-ring-color auto 5px}'
- ],
- 'border radius side H+V': [
- 'a{border-top-left-radius:2em / 1em}',
- 'a{border-top-left-radius:2em/1em}'
- ],
- 'border radius expanded H+V': [
- 'a{border-radius:1em 1em 1em 1em / 2em 2em 2em 2em}',
- 'a{border-radius:1em/2em}'
- ],
- 'border radius expanded H+V with mixed values #1': [
- 'a{border-radius:1em 2em 1em 2em / 1em 2em 3em 2em}',
- 'a{border-radius:1em 2em/1em 2em 3em}'
- ],
- 'border radius expanded H+V with mixed values #2': 'a{border-radius:1em/1em 1em 1em 2em}',
- 'border radius H+V': 'a{border-radius:50%/100%}',
- 'lost background position': [
- '.one{background:50% no-repeat}.one{background-image:url(/img.png)}',
- '.one{background:url(/img.png) 50% no-repeat}'
- ],
- 'unknown @ rule': '@unknown "test";h1{color:red}',
- 'property without a value': [
- 'a{color:}',
- ''
- ],
- 'properties without values': [
- 'a{padding:;border-radius: ;background:red}',
- 'a{background:red}'
- ]
- }),
- 'advanced in ie8 mode': cssContext({
- 'plain component to complex shorthand': [
- 'a{background:linear-gradient(to bottom,#000,#fff 4em) #000;background-color:#fff}',
- 'a{background:linear-gradient(to bottom,#000,#fff 4em) #000;background-color:#fff}'
- ],
- 'plain component to shorthand': [
- 'a{background:url(bg.png) #000;background-color:#fff}',
- 'a{background:url(bg.png) #fff}'
- ],
- 'merging rgba with standard colors': 'div{background-color:red;background:rgba(1,2,3,.5)}'
- }, { compatibility: 'ie8' }),
- 'viewport units': cssContext({
- 'shorthand margin with viewport width not changed': 'div{margin:5vw}'
- }),
- 'variables': cssContext({
- 'stripping': 'a{--border:#000}.one{border:1px solid var(--border)}',
- 'all values': 'a{--width:1px;--style:solid;--color:#000}.one{border:var(--width)var(--style)var(--color)}'
- })
-}).export(module);
+vows.describe('integration tests')
+ .addBatch(
+ optimizerContext('identity', {
+ 'preserve minified content': [
+ 'a{color:#f10}',
+ 'a{color:#f10}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('semicolons', {
+ 'multiple semicolons': [
+ 'a{color:#fff;;;width:0; ;}',
+ 'a{color:#fff;width:0}'
+ ],
+ 'trailing semicolon': [
+ 'a{color:#fff;}',
+ 'a{color:#fff}'
+ ],
+ 'trailing semicolon and space': [
+ 'a{color:#fff ; }',
+ 'a{color:#fff}'
+ ],
+ 'comma and space': [
+ 'a{color:rgba(0, 0, 5, .5)}',
+ 'a{color:rgba(0,0,5,.5)}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('whitespace', {
+ 'one argument': [
+ 'div a { color:#fff }',
+ 'div a{color:#fff}'
+ ],
+ 'tabs': [
+ 'div\t\ta{display:block}\tp{color:red}',
+ 'div a{display:block}p{color:red}'
+ ],
+ 'line breaks #1': [
+ 'div \na\r\n { width:500px }',
+ 'div a{width:500px}'
+ ],
+ 'line breaks #2': [
+ 'div \na\r\n, p { width:500px }',
+ 'div a,p{width:500px}'
+ ],
+ 'line breaks with whitespace lines': [
+ 'div \n \t\n \na\r\n, p { width:500px }',
+ 'div a,p{width:500px}'
+ ],
+ 'multiple arguments': [
+ 'a{color:#fff ; font-weight: bolder }',
+ 'a{color:#fff;font-weight:bolder}'
+ ],
+ 'space delimited arguments': [
+ 'a {border: 1px solid #f10; margin: 0 auto }',
+ 'a{border:1px solid #f10;margin:0 auto}'
+ ],
+ 'at beginning': [
+ ' a {color:#fff}',
+ 'a{color:#fff}'
+ ],
+ 'at end': [
+ 'a{color:#fff } ',
+ 'a{color:#fff}'
+ ],
+ 'not inside calc method #1': [
+ 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}',
+ 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}'
+ ],
+ 'not inside calc method #2': [
+ 'div{margin:-moz-calc(50% + 15px) -moz-calc(50% + 15px);margin:calc(50% + .5rem) calc(50% + .5rem)}',
+ 'div{margin:-moz-calc(50% + 15px);margin:calc(50% + .5rem)}'
+ ],
+ 'not inside calc method with more parentheses': [
+ 'div{height:-moz-calc((10% + 12px)/ 2 + 10em)}',
+ 'div{height:-moz-calc((10% + 12px)/ 2 + 10em)}'
+ ],
+ 'not inside calc method with multiplication': [
+ 'div{height:-moz-calc(3 * 2em + 10px)}',
+ 'div{height:-moz-calc(3 * 2em + 10px)}'
+ ],
+ 'not inside calc method with brackets': [
+ 'body{margin-left:calc(50vw + (1024px/2))}',
+ 'body{margin-left:calc(50vw + (1024px/2))}'
+ ],
+ 'not inside calc method with brackets #2': [
+ 'body{width:calc((978px * 2/3) - 30px)}',
+ 'body{width:calc((978px * 2/3) - 30px)}'
+ ],
+ 'not inside calc method with brackets #3': [
+ 'body{margin:calc(99.99% * 1/3 - (30px - 30px * 1/3) + 30px)}',
+ 'body{margin:calc(99.99% * 1/3 - (30px - 30px * 1/3) + 30px)}'
+ ],
+ 'with space between braces': [
+ 'body{width:calc( ( 100% - 12px) / 3 )}',
+ 'body{width:calc((100% - 12px)/ 3)}'
+ ],
+ 'before colon': [
+ '#test{padding-left :0}',
+ '#test{padding-left:0}'
+ ],
+ 'before colon but not selectors #1': [
+ 'div :before{display:block}',
+ 'div :before{display:block}'
+ ],
+ 'before colon but not selectors #2': [
+ 'div ::-webkit-search-decoration{display:block}',
+ 'div ::-webkit-search-decoration{display:block}'
+ ],
+ 'before colon but not selectors #3': [
+ 'div :after{color:red}',
+ 'div :after{color:red}'
+ ],
+ 'windows breaks': [
+ 'div>a{color:red\r\n }',
+ 'div>a{color:red}'
+ ],
+ 'whitespace in media queries': [
+ '@media ( min-width: 980px ) {\n#page .span4 {\nwidth: 250px;\n}\n\n.row {\nmargin-left: -10px;\n}\n}',
+ '@media (min-width:980px){#page .span4{width:250px}.row{margin-left:-10px}}'
+ ],
+ 'line breaks in media queries': [
+ '@media\nonly screen and (max-width: 1319px) and (min--moz-device-pixel-ratio: 1.5),\nonly screen and (max-width: 1319px) and (-moz-min-device-pixel-ratio: 1.5)\n{ a { color:#000 } }',
+ '@media only screen and (max-width:1319px) and (min--moz-device-pixel-ratio:1.5),only screen and (max-width:1319px) and (-moz-min-device-pixel-ratio:1.5){a{color:#000}}'
+ ],
+ 'in content preceded by #content': [
+ '#content{display:block}#foo{content:"\0BB "}',
+ '#content{display:block}#foo{content:"\0BB "}'
+ ],
+ 'in content preceded by .content': [
+ '.content{display:block}#foo{content:"\0BB "}',
+ '.content{display:block}#foo{content:"\0BB "}'
+ ],
+ 'in content preceded by line break': [
+ '.content{display:block}#foo{' + lineBreak + 'content:"x"}',
+ '.content{display:block}#foo{content:"x"}'
+ ],
+ 'after rgb': [
+ 'a{text-shadow:rgb(255,0,1) 1px 1px}',
+ 'a{text-shadow:#ff0001 1px 1px}'
+ ],
+ 'after rgba': [
+ 'a{text-shadow:rgba(255,0,0,1) 0 1px}',
+ 'a{text-shadow:rgba(255,0,0,1) 0 1px}'
+ ],
+ 'after hsl': [
+ 'a{text-shadow:hsl(240,100%,40%) -1px 1px}',
+ 'a{text-shadow:#00c -1px 1px}'
+ ],
+ 'after hsla': [
+ 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}',
+ 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}'
+ ],
+ 'inside background': [
+ 'a{background:calc(100% - 2px) 10px no-repeat}',
+ 'a{background:calc(100% - 2px) 10px no-repeat}'
+ ],
+ 'inside background with fraction unit': [
+ 'a{background:calc(100% - 2px) .5em no-repeat}',
+ 'a{background:calc(100% - 2px) .5em no-repeat}'
+ ],
+ 'inside background with urls': [
+ 'a{background:url(image.png) no-repeat}',
+ 'a{background:url(image.png) no-repeat}'
+ ],
+ 'inside background with rgba': [
+ 'a{background:calc(100% - 10px) no-repeat}',
+ 'a{background:calc(100% - 10px) no-repeat}'
+ ],
+ 'inside margin': [
+ 'a{margin:calc(100% - 2px) calc(100% - 5px)}',
+ 'a{margin:calc(100% - 2px) calc(100% - 5px)}'
+ ],
+ 'inside transform': [
+ 'a{transform:translateX(10px) translateY(10px)}',
+ 'a{transform:translateX(10px) translateY(10px)}'
+ ],
+ 'after :not #1': [
+ 'li:not(.foo).bar{color:red}',
+ 'li:not(.foo).bar{color:red}'
+ ],
+ 'after :not #2': [
+ 'li:not(.foo)[data-type=none]{color:red}',
+ 'li:not(.foo)[data-type=none]{color:red}'
+ ],
+ 'after :not #3': [
+ 'li:not(.foo)#id{color:red}',
+ 'li:not(.foo)#id{color:red}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('whitespace with spaceAfterClosingBrace', {
+ 'after rgb': [
+ 'a{text-shadow:rgb(255,0,1) 1px 1px}',
+ 'a{text-shadow:#ff0001 1px 1px}'
+ ],
+ 'after rgba': [
+ 'a{text-shadow:rgba(255,0,0,1) 0 1px}',
+ 'a{text-shadow:rgba(255,0,0,1) 0 1px}'
+ ],
+ 'after hsl': [
+ 'a{text-shadow:hsl(240,100%,40%) -1px 1px}',
+ 'a{text-shadow:#00c -1px 1px}'
+ ],
+ 'after hsla': [
+ 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}',
+ 'a{text-shadow:hsla(240,100%,40%,.5) -1px 1px}'
+ ],
+ 'inside background': [
+ 'a{background:calc(100% - 2px) 10px no-repeat}',
+ 'a{background:calc(100% - 2px)10px no-repeat}'
+ ],
+ 'inside background with fraction unit': [
+ 'a{background:calc(100% - 2px) .5em no-repeat}',
+ 'a{background:calc(100% - 2px).5em no-repeat}'
+ ],
+ 'inside background with urls': [
+ 'a{background:url(image.png) no-repeat}',
+ 'a{background:url(image.png)no-repeat}'
+ ],
+ 'inside background with rgba': [
+ 'a{background:calc(100% - 10px) no-repeat}',
+ 'a{background:calc(100% - 10px)no-repeat}'
+ ],
+ 'inside margin': [
+ 'a{margin:calc(100% - 2px) calc(100% - 5px)}',
+ 'a{margin:calc(100% - 2px) calc(100% - 5px)}'
+ ],
+ 'inside transform': [
+ 'a{transform:translateX(10px) translateY(10px)}',
+ 'a{transform:translateX(10px)translateY(10px)}'
+ ],
+ 'inside @media': [
+ '@media only screen and (max-width:1319px) and (min--moz-device-pixel-ratio:1.5){a{color:red}}',
+ '@media only screen and (max-width:1319px)and (min--moz-device-pixel-ratio:1.5){a{color:red}}'
+ ]
+ }, { compatibility: { properties: { spaceAfterClosingBrace: false } } })
+ )
+ .addBatch(
+ optimizerContext('line breaks', {
+ 'line breaks #1': [
+ 'div\na\r\n{width:500px}',
+ 'div a{width:500px}'
+ ],
+ 'line breaks #2': [
+ 'div\na\r\n,p{width:500px}',
+ 'div a,p{width:500px}'
+ ],
+ 'multiple line breaks #2': [
+ 'div \r\n\r\na\r\n,p{width:500px}',
+ 'div a,p{width:500px}'
+ ],
+ 'line breaks with whitespace lines': [
+ 'div \n \t\n \na\r\n, p { width:500px }',
+ 'div a,p{width:500px}'
+ ],
+ 'line breaks with multiple selectors': [
+ 'p{width:500px}a{color:red}span{font-style:italic}',
+ 'p{width:500px}' + lineBreak + 'a{color:red}' + lineBreak + 'span{font-style:italic}'
+ ],
+ 'charset not at beginning': [
+ 'a{ color: #f10; }\n@charset \'utf-8\';\nb { font-weight: bolder}',
+ '@charset \'utf-8\';' + lineBreak + 'a{color:#f10}' + lineBreak + 'b{font-weight:bolder}'
+ ],
+ 'charset multiple charsets': [
+ '@charset \'utf-8\';\ndiv :before { display: block }\n@charset \'utf-8\';\na { color: #f10 }',
+ '@charset \'utf-8\';' + lineBreak + 'div :before{display:block}' + lineBreak + 'a{color:#f10}'
+ ],
+ 'charset with double line break': [
+ '@charset \'utf-8\';' + lineBreak + lineBreak + 'a{display:block}',
+ '@charset \'utf-8\';' + lineBreak + 'a{display:block}'
+ ],
+ 'uppercase charset': [
+ '@CHARSET \'utf-8\';h1{color:red}',
+ 'h1{color:red}'
+ ],
+ 'mixed case charset': [
+ '@chArSET \'utf-8\';h1{color:red}',
+ 'h1{color:red}'
+ ]
+ }, { keepBreaks: true })
+ )
+ .addBatch(
+ optimizerContext('line breaks and important comments', {
+ 'charset to beginning with comment removal': [
+ '/*! some comment */' + lineBreak + lineBreak + '@charset \'utf-8\';' + lineBreak + lineBreak + 'a{display:block}',
+ '@charset \'utf-8\';' + lineBreak + 'a{display:block}'
+ ]
+ }, { keepBreaks: true, keepSpecialComments: 0 })
+ )
+ .addBatch(
+ optimizerContext('selectors', {
+ 'not expand + in selectors mixed with calc methods': [
+ 'div{width:calc(50% + 3em)}div + div{width:100%}div:hover{width:calc(50% + 4em)}* > div {border:1px solid #f0f}',
+ 'div{width:calc(50% + 3em)}div+div{width:100%}div:hover{width:calc(50% + 4em)}*>div{border:1px solid #f0f}'
+ ],
+ 'process selectors ending with -0 correctly': [
+ '.selector-0,a{display:block}',
+ '.selector-0,a{display:block}'
+ ],
+ 'process selectors ending with -1 correctly': [
+ '.selector-1,a{display:block}',
+ '.selector-1,a{display:block}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('universal selector in ie8 compatibility mode', {
+ '+html': [
+ '*+html .foo{display:inline}',
+ ''
+ ],
+ '+html:first-child': [
+ '*:first-child+html .foo{display:inline}',
+ ''
+ ],
+ 'complex': [
+ '*:first-child+html .foo,.bar{display:inline}',
+ '.bar{display:inline}'
+ ]
+ }, { compatibility: 'ie8' })
+ )
+ .addBatch(
+ optimizerContext('universal selector in ie7 compatibility mode', {
+ '+html': [
+ '*+html .foo{display:inline}',
+ '*+html .foo{display:inline}'
+ ],
+ ':first-child+html': [
+ '*:first-child+html .foo{display:inline}',
+ '*:first-child+html .foo{display:inline}'
+ ],
+ 'complex': [
+ '*:first-child+html .foo,.bar{display:inline}',
+ '*:first-child+html .foo,.bar{display:inline}'
+ ]
+ }, { compatibility: 'ie7' })
+ )
+ .addBatch(
+ optimizerContext('comments', {
+ 'single line': [
+ 'a{color:#fff}/* some comment*/p{height:10px/* other comment */}',
+ 'a{color:#fff}p{height:10px}'
+ ],
+ 'multiline': [
+ '/* \r\n multiline \n comment */a{color:rgba(0,0,0,0.8)}',
+ 'a{color:rgba(0,0,0,.8)}'
+ ],
+ 'comment chars in comments': [
+ '/* \r\n comment chars * inside / comments */a{color:#fff}',
+ 'a{color:#fff}'
+ ],
+ 'comment inside block': [
+ 'a{/* \r\n some comments */color:#fff}',
+ 'a{color:#fff}'
+ ],
+ 'special comments': [
+ '/*! special comment */a{color:#f10} /* normal comment */',
+ '/*! special comment */a{color:#f10}'
+ ],
+ 'should keep exact structure': [
+ '/*! \n a > span { } with some content */',
+ '/*! \n a > span { } with some content */'
+ ],
+ 'should remove comments with forward slashes inside': [
+ '/*////*/a{color:red}',
+ 'a{color:red}'
+ ],
+ 'should properly handle line breaks and ** characters inside comments': [
+ '/**====**\\\n/**2nd comment line/**===**/a{color:red}',
+ 'a{color:red}'
+ ],
+ 'selector between comments': [
+ '/*comment*/*/*comment*/{color:red}',
+ '*{color:red}'
+ ],
+ 'inside url': [
+ 'p{background-image:url(\'/*\')}/* */',
+ 'p{background-image:url(/*)}'
+ ],
+ 'inside url twice': [
+ 'p{background-image:url(\'/* */\" /*\')}/* */',
+ 'p{background-image:url(\'/* */\" /*\')}'
+ ],
+ 'inside url with more quotation': [
+ 'p{background-image:url(\'/*\');content:""/* */}',
+ 'p{background-image:url(/*);content:""}'
+ ],
+ 'with quote marks': [
+ '/*"*//* */',
+ ''
+ ],
+ 'important after value': [
+ 'div{color:red;/*!comment*/}',
+ 'div{color:red/*!comment*/}'
+ ],
+ 'important between values': [
+ 'div{color:red;/*!comment*/display:block}',
+ 'div{color:red;/*!comment*/display:block}'
+ ],
+ 'important between and after values': [
+ 'div{color:red;/*!comment1*/display:block;/*!comment2*/}',
+ 'div{color:red;/*!comment1*/display:block/*!comment2*/}'
+ ],
+ 'two important after value': [
+ 'div{color:red;/*!1*//*!2*/}',
+ 'div{color:red/*!1*//*!2*/}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('escaping', {
+ 'escaped @ symbol in class name': [
+ '.pad--all0\\@sm{padding:0}',
+ '.pad--all0\\@sm{padding:0}'
+ ],
+ 'escaped @ symbol in id': [
+ '#id\\@sm{padding:0}',
+ '#id\\@sm{padding:0}'
+ ],
+ 'escaped slash': [
+ 'a{content:"\\\\"}',
+ 'a{content:"\\\\"}'
+ ],
+ 'escaped quote': [
+ 'a{content:"\\\""}',
+ 'a{content:"\\\""}'
+ ],
+ 'escaped quote in selector name': [
+ '.this-class\\\'s-got-an-apostrophe{color:red}a{color:#f00}',
+ '.this-class\\\'s-got-an-apostrophe,a{color:red}'
+ ],
+ 'escaped quotes in selector name': [
+ '.this-class\\\"s-got-an-apostrophes\\\'{color:red}a{color:#f00}',
+ '.this-class\\\"s-got-an-apostrophes\\\',a{color:red}'
+ ],
+ 'escaped tab': [
+ 'a{content:"\\\t"}',
+ 'a{content:"\\\t"}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('important comments - one', {
+ 'strip all but first': [
+ '/*! important comment */a{color:red}/* some comment *//*! important comment */',
+ '/*! important comment */a{color:red}'
+ ]
+ }, { keepSpecialComments: 1 })
+ )
+ .addBatch(
+ optimizerContext('important comments - none', {
+ 'strip all': [
+ '/*! important comment */a{color:red}/* some comment *//*! important comment */',
+ 'a{color:red}'
+ ],
+ 'move charset before': [
+ '/*! some comment */' + lineBreak + lineBreak + '@charset \'utf-8\';' + lineBreak + lineBreak + 'a{display:block}',
+ '@charset \'utf-8\';a{display:block}'
+ ]
+ }, { keepSpecialComments: 0 })
+ )
+ .addBatch(
+ optimizerContext('important comments - keepSpecialComments when a string', {
+ 'strip all': [
+ '/*! important comment */a{color:red}/* some comment *//*! important comment */',
+ 'a{color:red}'
+ ]
+ }, { keepSpecialComments: '0' })
+ )
+ .addBatch(
+ optimizerContext('expressions', {
+ 'empty': [
+ 'a{color:expression()}',
+ 'a{color:expression()}'
+ ],
+ 'method call': [
+ 'a{color:expression(this.parentNode.currentStyle.color)}',
+ 'a{color:expression(this.parentNode.currentStyle.color)}'
+ ],
+ 'multiple call': [
+ 'a{color:expression(x = 0 , this.parentNode.currentStyle.color)}',
+ 'a{color:expression(x = 0 , this.parentNode.currentStyle.color)}'
+ ],
+ 'mixed content': [
+ 'a{zoom:expression(this.runtimeStyle["zoom"] = "1", this.innerHTML = "")}',
+ 'a{zoom:expression(this.runtimeStyle["zoom"] = "1", this.innerHTML = "")}'
+ ],
+ 'in comment': [
+ '/*! expression(this.runtimeStyle["zoom"]) */',
+ '/*! expression(this.runtimeStyle["zoom"]) */'
+ ],
+ 'complex': [
+ 'a{width:expression((this.parentNode.innerWidth + this.parentNode.innerHeight) / 2 )}',
+ 'a{width:expression((this.parentNode.innerWidth + this.parentNode.innerHeight) / 2 )}'
+ ],
+ 'with parentheses': [
+ 'a{width:expression(this.parentNode.innerText == ")" ? "5px" : "10px" )}',
+ 'a{width:expression(this.parentNode.innerText == ")" ? "5px" : "10px" )}'
+ ],
+ 'open ended (broken)': [
+ 'a{width:expression(this.parentNode.innerText == }',
+ 'a{width:expression(this.parentNode.innerText == }'
+ ],
+ 'function call & advanced': [
+ 'a{zoom:expression(function (el){el.style.zoom="1"}(this))}',
+ 'a{zoom:expression(function (el){el.style.zoom="1"}(this))}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('text content', {
+ 'normal #1': [
+ 'a{content:"."}',
+ 'a{content:"."}'
+ ],
+ 'normal #2': [
+ 'a:before{content : "test\'s test"; }',
+ 'a:before{content:"test\'s test"}'
+ ],
+ 'open quote': [
+ 'a{content : open-quote;opacity:1}',
+ 'a{content:open-quote;opacity:1}'
+ ],
+ 'close quote': [
+ 'a{content: close-quote;clear:left}',
+ 'a{content:close-quote;clear:left}'
+ ],
+ 'special characters': [
+ 'a{content : " a > div { } "}',
+ 'a{content:" a > div { } "}'
+ ],
+ 'with JSON': [
+ 'body::before{content:\'{ "current" : "small", "all" : ["small"], "position" : 0 }\'}',
+ 'body::before{content:\'{ "current" : "small", "all" : ["small"], "position" : 0 }\'}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('zero values', {
+ 'with units': [
+ 'a{margin:0px 0pt 0em 0%;padding: 0in 0cm 0mm 0pc;border-top-width:0ex}',
+ 'a{margin:0;padding:0;border-top-width:0}'
+ ],
+ 'multiple into one': [
+ 'a{margin:0 0 0 0;padding:0 0 0 0;border-width:0 0 0 0}',
+ 'a{margin:0;padding:0;border-width:0}'
+ ],
+ 'background\'s none to zero': [
+ 'a{background:none}',
+ 'a{background:0 0}'
+ ],
+ 'border\'s none to none': [
+ 'a{border:none}p{border-top:none}',
+ 'a{border:none}p{border-top:none}'
+ ],
+ 'background:transparent to zero': [
+ 'a{background:transparent}p{background:transparent url(logo.png)}',
+ 'a{background:0 0}p{background:url(logo.png)}'
+ ],
+ 'outline:none to outline:0': [
+ 'a{outline:none}',
+ 'a{outline:0}'
+ ],
+ 'display:none not changed': [
+ 'a{display:none}',
+ 'a{display:none}'
+ ],
+ 'mixed zeros not changed': [
+ 'div{margin:0 0 1px 2px}',
+ 'div{margin:0 0 1px 2px}'
+ ],
+ 'mixed zeros not changed #2': [
+ 'div{padding:0 1px 0 3px}',
+ 'div{padding:0 1px 0 3px}'
+ ],
+ 'mixed zeros not changed #3': [
+ 'div{padding:10px 0 0 1px}',
+ 'div{padding:10px 0 0 1px}'
+ ],
+ 'multiple zeros with fractions #1': [
+ 'div{padding:0 0 0 0.5em}',
+ 'div{padding:0 0 0 .5em}'
+ ],
+ 'multiple zeros with fractions #2': [
+ 'div{padding:0 0 0 .5em}',
+ 'div{padding:0 0 0 .5em}'
+ ],
+ 'rect zeros #1': [
+ 'div{clip:rect(0 0 0 0)}',
+ 'div{clip:rect(0 0 0 0)}'
+ ],
+ 'rect zeros #2': [
+ 'div{clip:rect(0px 0px 0px 0px)}',
+ 'div{clip:rect(0 0 0 0)}'
+ ],
+ 'rect zeros #3': [
+ 'div{clip:rect( 0px 0px 0px 0px )}',
+ 'div{clip:rect(0 0 0 0)}'
+ ],
+ 'rect zeros #4': [
+ 'div{clip:rect(0px, 0px, 0px, 0px)}',
+ 'div{clip:rect(0,0,0,0)}'
+ ],
+ 'rect zeros #5': [
+ 'div{clip:rect(0.5% 0px 0px 0px)}',
+ 'div{clip:rect(.5% 0 0 0)}'
+ ],
+ 'rect zeros #6': [
+ 'div{clip:rect(0px 0px 0px 10px)}',
+ 'div{clip:rect(0 0 0 10px)}'
+ ],
+ 'box shadow zeros with four zeros': [
+ 'a{box-shadow:0 0 0 0}',
+ 'a{box-shadow:0 0}'
+ ],
+ 'box shadow with two zeros': [
+ 'a{box-shadow:0 0}',
+ 'a{box-shadow:0 0}'
+ ],
+ 'box shadow with three zeros and a fraction': [
+ 'a{box-shadow:0 0 0 0.15em #EBEBEB}',
+ 'a{box-shadow:0 0 0 .15em #EBEBEB}'
+ ],
+ 'box shadow with three zeros and a value': [
+ 'a{box-shadow:0 0 0 15px #EBEBEB}',
+ 'a{box-shadow:0 0 0 15px #EBEBEB}'
+ ],
+ 'prefixed box shadow zeros': [
+ 'a{-webkit-box-shadow:0 0 0 0; -moz-box-shadow:0 0 0 0}',
+ 'a{-webkit-box-shadow:0 0;-moz-box-shadow:0 0}'
+ ],
+ 'zero as .0 #1': [
+ 'a{color:rgba(0,0,.0,1)}',
+ 'a{color:rgba(0,0,0,1)}'
+ ],
+ 'zero as .0 #2': [
+ 'body{margin:.0}',
+ 'body{margin:0}'
+ ],
+ 'zero as .0 #3': [
+ 'body{margin:.0em}',
+ 'body{margin:0}'
+ ],
+ 'zero as .0 #4': [
+ 'body{margin:.0 1em .0 .0}',
+ 'body{margin:0 1em 0 0}'
+ ],
+ 'missing #1': [
+ 'body{margin:2.em}',
+ 'body{margin:2em}'
+ ],
+ 'missing #2': [
+ 'p{opacity:1.}',
+ 'p{opacity:1}'
+ ],
+ 'missing #3': [
+ 'p{opacity:11.px}',
+ 'p{opacity:11px}'
+ ],
+ 'minus zero as value to zero': [
+ 'body{margin:-0}',
+ 'body{margin:0}'
+ ],
+ 'minus zero in function to zero': [
+ 'body{color:rgba(-0,-0,-0,-0)}',
+ 'body{color:transparent}'
+ ],
+ 'minus zero px to zero': [
+ 'body{margin:-0px}',
+ 'body{margin:0}'
+ ],
+ 'zero em to zero': [
+ 'body{margin:0.0em}',
+ 'body{margin:0}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('zero values in ie8 compatibility mode', {
+ 'rems': [
+ 'div{width:0rem;height:0rem}',
+ 'div{width:0rem;height:0rem}'
+ ]
+ }, { compatibility: 'ie8' })
+ )
+ .addBatch(
+ optimizerContext('zero values in any other compatibility mode', {
+ 'rems': [
+ 'div{width:0rem;height:0rem}',
+ 'div{width:0;height:0}'
+ ]
+ }, { compatibility: '*' })
+ )
+ .addBatch(
+ optimizerContext('shorthands', {
+ 'padding - same 4 values': [
+ 'div{padding:1px 1px 1px 1px}',
+ 'div{padding:1px}'
+ ],
+ 'margin - same 4 values': [
+ 'div{margin:1% 1% 1% 1%}',
+ 'div{margin:1%}'
+ ],
+ 'border-width - same 4 values': [
+ 'div{border-width:1em 1em 1em 1em}',
+ 'div{border-width:1em}'
+ ],
+ 'border-style - same 4 values': [
+ 'div{border-style:solid solid solid solid}',
+ 'div{border-style:solid}'
+ ],
+ 'border-color - same 4 values': [
+ 'div{border-color:red red red red}',
+ 'div{border-color:red}'
+ ],
+ 'border-color - same 4 values as hex': [
+ 'div{border-color:#f0f #f0f #f0f #f0f}',
+ 'div{border-color:#f0f}'
+ ],
+ 'border-color - same 4 values as rgb': [
+ 'div{border-color:rgb(0,0,0) rgb(0,0,0) rgb(0,0,0) rgb(0,0,0)}',
+ 'div{border-color:#000}'
+ ],
+ 'border-color - same 4 values as rgba': [
+ 'div{border-color:rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(0,0,0,.5) rgba(0,0,0,.5)}',
+ 'div{border-color:rgba(0,0,0,.5)}'
+ ],
+ 'border-radius - same 4 values': [
+ 'div{border-radius:3px 3px 3px 3px}',
+ 'div{border-radius:3px}'
+ ],
+ 'border-radius - same 4 values with vendor prefixes': [
+ 'div{-moz-border-radius:3px 3px 3px 3px;-o-border-radius:3px 3px 3px 3px;-webkit-border-radius:3px 3px 3px 3px;border-radius:3px 3px 3px 3px}',
+ 'div{-moz-border-radius:3px;-o-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}'
+ ],
+ 'padding - same pairs': [
+ 'div{padding:15.5em 10.5em 15.5em 10.5em}',
+ 'div{padding:15.5em 10.5em}'
+ ],
+ 'margin - same 2nd and 4th value': [
+ 'div{margin:1px 2px 3px 2px}',
+ 'div{margin:1px 2px 3px}'
+ ],
+ 'padding - same 3 values': [
+ 'div{padding:1px 1px 1px}',
+ 'div{padding:1px}'
+ ],
+ 'padding - different 3 values': [
+ 'div{padding:1px 1em 1%}',
+ 'div{padding:1px 1em 1%}'
+ ],
+ 'margin - 3 callapsible values': [
+ 'div{margin:1ex 2ex 1ex}',
+ 'div{margin:1ex 2ex}'
+ ],
+ 'border-radius - same 3 values with one vendor prefixe': [
+ 'div{-webkit-border-radius:3px 3px 3px;border-radius:3px 3px 3px}',
+ 'div{-webkit-border-radius:3px;border-radius:3px}'
+ ],
+ 'border-color - same 2nd and 4th value as rgb': [
+ 'div{border-color:rgb(0,0,0) rgb(34,0,0) rgb(255,0,0) rgb(34,0,0)}',
+ 'div{border-color:#000 #200 red}'
+ ],
+ 'margin - 3 different values': [
+ 'div{margin:1px 1px 3px}',
+ 'div{margin:1px 1px 3px}'
+ ],
+ 'border width - 3 different values': [
+ 'div{border-width:1px 2px 3px}',
+ 'div{border-width:1px 2px 3px}'
+ ],
+ 'padding - same 2 values': [
+ 'div{padding:1px 1px}',
+ 'div{padding:1px}'
+ ],
+ 'margin - same 2 values': [
+ 'div{margin:5% 5%}',
+ 'div{margin:5%}'
+ ],
+ 'border-width - same 2 values': [
+ 'div{border-width:.5em .5em}',
+ 'div{border-width:.5em}'
+ ],
+ 'different units': [
+ 'div{padding:1px 1em 1% 1rem}',
+ 'div{padding:1px 1em 1% 1rem}'
+ ],
+ 'fractions': [
+ 'div{margin:.1em .1em .1em .1em}',
+ 'div{margin:.1em}'
+ ],
+ 'preceeding value': [
+ 'div{padding:010px 00015px}',
+ 'div{padding:10px 15px}'
+ ],
+ 'preceeding value with fraction zeros': [
+ 'div{padding:010.0em .05rem}',
+ 'div{padding:10em .05rem}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('units', {
+ 'negative padding': [
+ 'div{padding-left:2px;padding-top:-2px;padding-right:5px;padding-bottom:0}',
+ 'div{padding-left:2px;padding-right:5px;padding-bottom:0}'
+ ],
+ 'negative padding after negative shorthand': [
+ 'div{padding:-5px 0 0 0;padding-left:2px;padding-top:-2px;padding-right:5px;padding-bottom:0}',
+ 'div{padding-left:2px;padding-right:5px;padding-bottom:0}'
+ ],
+ 'negative padding in calculations': [
+ 'div{padding:calc(100% - 5px) 0 0 0}',
+ 'div{padding:calc(100% - 5px) 0 0}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('floats', {
+ 'strips zero in fractions': [
+ 'a{ margin-bottom: 0.5em}',
+ 'a{margin-bottom:.5em}'
+ ],
+ 'not strips zero in fractions of numbers greater than zero': [
+ 'a{ margin-bottom: 20.5em}',
+ 'a{margin-bottom:20.5em}'
+ ],
+ 'strip fraction zero #1': [
+ 'a{opacity:1.0}',
+ 'a{opacity:1}'
+ ],
+ 'strip fraction zero #2': [
+ 'a{opacity:15.000%}',
+ 'a{opacity:15%}'
+ ],
+ 'strip fraction zero #3': [
+ 'a{padding:15.55000em}',
+ 'a{padding:15.55em}'
+ ],
+ 'strip fraction zero #4': [
+ 'a{padding:15.101em}',
+ 'a{padding:15.101em}'
+ ],
+ 'strip fraction zero #5': [
+ 'a{border-width:0.20em 20.30em}',
+ 'a{border-width:.2em 20.3em}'
+ ],
+ 'strip fraction zeros': [
+ 'div{margin:1.000em 2.00em 3.100em 4.01em}',
+ 'div{margin:1em 2em 3.1em 4.01em}'
+ ],
+ 'round pixels up to 2nd decimal place': [
+ 'div{transform:translateY(-418.505123px)}',
+ 'div{transform:translateY(-418.51px)}'
+ ],
+ 'round pixels down to 2nd decimal place': [
+ 'div{transform:translateY(0.504123px)}',
+ 'div{transform:translateY(.5px)}'
+ ],
+ 'do not round 2nd decimal place pixels': [
+ 'div{transform:translateY(20.55px)}',
+ 'div{transform:translateY(20.55px)}'
+ ],
+ 'do not round percentages': [
+ 'div{left:20.505%}',
+ 'div{left:20.505%}'
+ ],
+ 'do not round ems': [
+ 'div{font-size:1.505em}',
+ 'div{font-size:1.505em}'
+ ],
+ 'rounds .9999 correctly': [
+ 'a{stroke-width:.99999px}',
+ 'a{stroke-width:1px}'
+ ],
+ 'rounds 9.995 correctly': [
+ 'a{stroke-width:9.995px}',
+ 'a{stroke-width:9.99px}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('floats custom rounding', {
+ 'rounds to 4 values': [
+ 'div{transform:translateY(-418.505123px)}',
+ 'div{transform:translateY(-418.5051px)}'
+ ]
+ }, { roundingPrecision: 4 })
+ )
+ .addBatch(
+ optimizerContext('floats disabled rounding', {
+ 'does not round': [
+ 'div{transform:translateY(-418.505123px)}',
+ 'div{transform:translateY(-418.505123px)}'
+ ]
+ }, { roundingPrecision: -1 })
+ )
+ .addBatch(
+ optimizerContext('colors', {
+ 'shorten rgb to standard hexadecimal format': [
+ 'a{ color:rgb(5, 10, 15) }',
+ 'a{color:#050a0f}'
+ ],
+ 'skip rgba shortening': [
+ 'a{ color:rgba(5, 10, 15, 0.5)}',
+ 'a{color:rgba(5,10,15,.5)}'
+ ],
+ 'shorten colors to 3 digit hex instead of 6 digit': [
+ 'a{ background-color: #aa0000; color:rgb(0, 17, 255)}',
+ 'a{background-color:#a00;color:#01f}'
+ ],
+ 'skip shortening IE filter colors': [
+ 'a{ filter: chroma(color = "#ff0000")}',
+ 'a{filter:chroma(color="#ff0000")}'
+ ],
+ 'color names to hex values': [
+ 'a{color:white;border-color:black;background-color:fuchsia}p{background:yellow}',
+ 'a{color:#fff;border-color:#000;background-color:#f0f}p{background:#ff0}'
+ ],
+ 'keep selectors with color name #1': [
+ '.black-and-white .foo{color:#fff;background-color:#000}',
+ '.black-and-white .foo{color:#fff;background-color:#000}'
+ ],
+ 'keep selectors with color name #2': [
+ '.go-blues{background:#000}',
+ '.go-blues{background:#000}'
+ ],
+ 'keep selectors with color name #3': [
+ '#top_white{background:#000}',
+ '#top_white{background:#000}'
+ ],
+ 'keep selectors with color name #4': [
+ 'a[data-sth=white]{background:#000}',
+ 'a[data-sth=white]{background:#000}'
+ ],
+ 'color names to hex values with important': [
+ 'a{color:white !important}',
+ 'a{color:#fff!important}'
+ ],
+ 'color names to hex values in gradients': [
+ 'p{background:linear-gradient(-90deg,black,white)}',
+ 'p{background:linear-gradient(-90deg,#000,#fff)}'
+ ],
+ 'hex value to color name if shorter': [
+ 'p{color:#f00}',
+ 'p{color:red}'
+ ],
+ 'upper case hex value to color name if shorter': [
+ 'p{color:#F00}',
+ 'p{color:red}'
+ ],
+ 'upper case long hex value to color name if shorter': [
+ 'p{color:#FF0000}',
+ 'p{color:red}'
+ ],
+ 'hex value to color name in borders': [
+ 'p{border:1px solid #f00}',
+ 'p{border:1px solid red}'
+ ],
+ 'hex value to color name in gradients': [
+ 'p{background:-moz-linear-gradient(-90deg,#000,#f00)}',
+ 'p{background:-moz-linear-gradient(-90deg,#000,red)}'
+ ],
+ 'hex value to color name in gradients #2': [
+ 'p{background:-webkit-gradient(linear, left top, left bottom, from(#000), to(#f00))}',
+ 'p{background:-webkit-gradient(linear,left top,left bottom,from(#000),to(red))}'
+ ],
+ 'border color - keep unchanged': [
+ 'p{border:1px solid #f94311}',
+ 'p{border:1px solid #f94311}'
+ ],
+ 'border color - hex to name': [
+ 'p{border:1em dotted #f00}',
+ 'p{border:1em dotted red}'
+ ],
+ 'border color - name to hex': [
+ 'p{border:1em dotted white}',
+ 'p{border:1em dotted #fff}'
+ ],
+ 'border color - rgb': [
+ 'p{border:1em dotted rgb(255,0,0)}',
+ 'p{border:1em dotted red}'
+ ],
+ 'colors and colons': [
+ 'a{background-image:linear-gradient(top,red,#e6e6e6)}',
+ 'a{background-image:linear-gradient(top,red,#e6e6e6)}'
+ ],
+ 'colors and parentheses': [
+ 'a{background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6))}',
+ 'a{background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6))}'
+ ],
+ 'colors in ie filters': [
+ 'a{filter:chroma(color=#ffffff)}',
+ 'a{filter:chroma(color=#ffffff)}'
+ ],
+ 'colors in ie filters 2': [
+ 'a{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#cccccc\', endColorstr=\'#000000\')}',
+ 'a{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#cccccc\', endColorstr=\'#000000\')}'
+ ],
+ 'colors in ie filters 3': [
+ 'a{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#DDDDDD\', endColorstr=\'#333333\')}',
+ 'a{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#DDDDDD\', endColorstr=\'#333333\')}'
+ ],
+ 'rgb percents': [
+ 'a{color:rgb(100%,0%,0%)}',
+ 'a{color:rgb(100%,0%,0%)}'
+ ],
+ 'rgba percents': [
+ 'a{color:rgba(100%,0%,0%,.5)}',
+ 'a{color:rgba(100%,0%,0%,.5)}'
+ ],
+ 'hsla percents': [
+ 'a{color:hsla(1,0%,0%,.5)}',
+ 'a{color:hsla(1,0%,0%,.5)}'
+ ],
+ 'hsla custom ': [
+ 'a{color:hsl(80,30%,50%,.5)}',
+ 'a{color:hsl(80,30%,50%,.5)}'
+ ],
+ 'hsl to hex #1': [
+ 'a{color:hsl(0,0%,0%)}',
+ 'a{color:#000}'
+ ],
+ 'hsl to hex #2': [
+ 'a{color:hsl(0,100%,100%)}',
+ 'a{color:#fff}'
+ ],
+ 'hsl to hex #3': [
+ 'a{color:hsl(240,100%,50%)}',
+ 'a{color:#00f}'
+ ],
+ 'hsl to hex #4': [
+ 'a{color:hsl(240,100%,50%)}',
+ 'a{color:#00f}'
+ ],
+ 'hsl to hex #5': [
+ 'a{color:hsl(120,100%,25%)}',
+ 'a{color:#007f00}'
+ ],
+ 'hsl to hex #6': [
+ 'a{color:hsl(99,66%,33%)}',
+ 'a{color:#438b1c}'
+ ],
+ 'hsl to hex #7': [
+ 'a{color:hsl(360,100%,50%)}',
+ 'a{color:red}'
+ ],
+ 'hsla not to hex': [
+ 'a{color:hsl(99,66%,33%,.5)}',
+ 'a{color:hsl(99,66%,33%,.5)}'
+ ],
+ 'hsl out of bounds #1': [
+ 'a{color:hsl(120,200%,50%)}',
+ 'a{color:#0f0}'
+ ],
+ 'hsl out of bounds #2': [
+ 'a{color:hsl(120,-100%,50%)}',
+ 'a{color:#7f7f7f}'
+ ],
+ 'hsl out of bounds #3': [
+ 'a{color:hsl(480,100%,25%)}',
+ 'a{color:#007f00}'
+ ],
+ 'hsl out of bounds #4': [
+ 'a{color:hsl(-240,100%,75%)}',
+ 'a{color:#7fff7f}'
+ ],
+ 'hsl out of bounds #5': [
+ 'a{color:hsl(-600,100%,75%)}',
+ 'a{color:#7fff7f}'
+ ],
+ 'hsl out of bounds #6': [
+ 'a{color:hsl(0,0%,122%)}',
+ 'a{color:#fff}'
+ ],
+ 'hsl out of bounds #7': [
+ 'a{color:hsl(0,0%,-10%)}',
+ 'a{color:#000}'
+ ],
+ 'rgb out of a lower bound': [
+ 'a{color:rgb(-1,-1,-1)}',
+ 'a{color:#000}'
+ ],
+ 'rgb out of an upper bound': [
+ 'a{color:rgb(256,256,256)}',
+ 'a{color:#fff}'
+ ],
+ 'turns rgba(0,0,0,0) to transparent': [
+ 'a{color:rgba(0,0,0,0)}',
+ 'a{color:transparent}'
+ ],
+ 'turns rgba(0.0,0.0,0.0,0) to transparent': [
+ 'a{color:rgba(0.0,0.0,0.0,0)}',
+ 'a{color:transparent}'
+ ],
+ 'turns hsla(0,0%,0%,0) to transparent': [
+ 'a{color:hsla(0,0%,0%,0)}',
+ 'a{color:transparent}'
+ ],
+ 'turns hsla(0,0,0,0) to transparent': [
+ 'a{color:hsla(0,0,0,0)}',
+ 'a{color:transparent}'
+ ],
+ 'turns hsla(0.0,0.0%,0.0%,0) to transparent': [
+ 'a{color:hsla(0.0,0.0%,0.0%,0)}',
+ 'a{color:transparent}'
+ ],
+ 'turns hsla(0.0,0.0,0.0,0) to transparent': [
+ 'a{color:hsla(0.0,0.0,0.0,0)}',
+ 'a{color:transparent}'
+ ],
+ 'keeps rgba(255,255,255,0)': [
+ 'a{color:rgba(255,255,255,0)}',
+ 'a{color:rgba(255,255,255,0)}'
+ ],
+ 'keeps rgba(255,0,255,0)': [
+ 'a{color:rgba(255,0,255,0)}',
+ 'a{color:rgba(255,0,255,0)}'
+ ],
+ 'keeps hsla(120,100%,50%,0)': [
+ 'a{color:hsla(120,100%,50%,0)}',
+ 'a{color:hsla(120,100%,50%,0)}'
+ ],
+ 'keeps rgba(0,0,0,.5)': [
+ 'a{color:rgba(0,0,0,.5)}',
+ 'a{color:rgba(0,0,0,.5)}'
+ ],
+ 'keeps rgba(0,255,0,.5)': [
+ 'a{color:rgba(0,255,0,.5)}',
+ 'a{color:rgba(0,255,0,.5)}'
+ ],
+ 'keeps hsla(120,100%,50%,.5)': [
+ 'a{color:hsla(120,100%,50%,.5)}',
+ 'a{color:hsla(120,100%,50%,.5)}'
+ ],
+ 'keeps rgba(0,0,0,0) when inside a gradient': [
+ 'a{background:linear-gradient(0,#000,rgba(0,0,0,0))}',
+ 'a{background:linear-gradient(0,#000,rgba(0,0,0,0))}'
+ ],
+ 'keeps hsla(120,100%,50%,0) when inside a gradient': [
+ 'a{background:linear-gradient(0,#000,hsla(120,100%,50%,0))}',
+ 'a{background:linear-gradient(0,#000,hsla(120,100%,50%,0))}'
+ ],
+ 'removes only right transparent colors': [
+ 'a{background-color:linear-gradient(0,#000,hsla(120,100%,50%,0)),rgba(0,0,0,0)}',
+ 'a{background-color:linear-gradient(0,#000,hsla(120,100%,50%,0)),transparent}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('border-radius', {
+ 'border radius H+V 0/0': [
+ 'a{border-radius:0 / 0}',
+ 'a{border-radius:0}'
+ ],
+ 'border radius side H+V 0/0': [
+ 'a{border-top-left-radius:0 / 0}',
+ 'a{border-top-left-radius:0}'
+ ],
+ 'border radius H+V same values': [
+ 'a{border-radius:5px / 5px}',
+ 'a{border-radius:5px}'
+ ],
+ 'border radius side H+V same values': [
+ 'a{border-top-left-radius:1em / 1em}',
+ 'a{border-top-left-radius:1em}'
+ ],
+ 'border radius H+V same expanded values': [
+ 'a{border-radius:5px 5px 5px 5px / 5px 5px}',
+ 'a{border-radius:5px}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('font weights', {
+ 'font-weight:normal to 400': [
+ 'p{font-weight:normal}',
+ 'p{font-weight:400}'
+ ],
+ 'font-weight:bold to 700': [
+ 'p{font-weight:bold}',
+ 'p{font-weight:700}'
+ ],
+ 'font weight in font declarations': [
+ 'body{font:normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif}',
+ 'body{font:400 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif}'
+ ],
+ 'font weight in font declarations with fraction units': [
+ 'p{font:bold .9rem Helvetica}',
+ 'p{font:700 .9rem Helvetica}'
+ ],
+ 'multiple changes': [
+ 'p{font-weight:bold!important;width:100%;font:normal 12px Helvetica}',
+ 'p{font-weight:700!important;width:100%;font:400 12px Helvetica}'
+ ],
+ 'font weight in extended font declarations': [
+ 'a{font:normal normal normal 13px/20px Helvetica}',
+ 'a{font:normal normal normal 13px/20px Helvetica}'
+ ],
+ 'font weight where style and weight are declared': [
+ 'a{font:normal 300 100%/1.5 sans-serif}',
+ 'a{font:normal 300 100%/1.5 sans-serif}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('unicode', {
+ 'font-names': [
+ 'body{font-family:\\5FAE\\8F6F\\96C5\\9ED1,\\5B8B\\4F53,sans-serif}',
+ 'body{font-family:\\5FAE\\8F6F\\96C5\\9ED1,\\5B8B\\4F53,sans-serif}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('urls', {
+ 'keep urls without parentheses unchanged': [
+ 'a{background:url(/images/blank.png)}',
+ 'a{background:url(/images/blank.png)}'
+ ],
+ 'keep non-encoded data URI unchanged': [
+ '.icon-logo{background-image:url(\'data:image/svg+xml;charset=US-ASCII\')}',
+ '.icon-logo{background-image:url(\'data:image/svg+xml;charset=US-ASCII\')}'
+ ],
+ 'strip quotes from base64 encoded PNG data URI': [
+ '.icon-logo{background-image:url(\'data:image/png;base64,iVBORw0\')}',
+ '.icon-logo{background-image:url(data:image/png;base64,iVBORw0)}'
+ ],
+ 'strip quotes from base64 encoded ICO data URI': [
+ '.icon-logo{background-image:url("data:image/x-icon;base64,AAABAAEAEBA")}',
+ '.icon-logo{background-image:url(data:image/x-icon;base64,AAABAAEAEBA)}'
+ ],
+ 'cut off url content on selector level': [
+ 'a{background:url(image/}',
+ 'a{background:url(image/}'
+ ],
+ 'cut off url content on block level': [
+ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}',
+ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}'
+ ],
+ 'cut off url content on top level': [
+ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA',
+ ''
+ ],
+ 'strip single parentheses': [
+ 'a{background:url(\'/images/blank.png\')}',
+ 'a{background:url(/images/blank.png)}'
+ ],
+ 'strip double parentheses': [
+ 'a{background:url("/images/blank.png")}',
+ 'a{background:url(/images/blank.png)}'
+ ],
+ 'strip more': [
+ 'p{background:url("/images/blank.png")}b{display:block}a{background:url("/images/blank2.png")}',
+ 'p{background:url(/images/blank.png)}b{display:block}a{background:url(/images/blank2.png)}'
+ ],
+ 'not strip comments if spaces inside': [
+ 'p{background:url("/images/long image name.png")}b{display:block}a{background:url("/images/no-spaces.png")}',
+ 'p{background:url("/images/long image name.png")}b{display:block}a{background:url(/images/no-spaces.png)}'
+ ],
+ 'not add a space before url\'s hash': [
+ 'a{background:url(/fonts/d90b3358-e1e2-4abb-ba96-356983a54c22.svg#d90b3358-e1e2-4abb-ba96-356983a54c22)}',
+ 'a{background:url(/fonts/d90b3358-e1e2-4abb-ba96-356983a54c22.svg#d90b3358-e1e2-4abb-ba96-356983a54c22)}'
+ ],
+ 'keep urls from being stripped down #1': [
+ 'a{background:url(/image-1.0.png)}',
+ 'a{background:url(/image-1.0.png)}'
+ ],
+ 'keep urls from being stripped down #2': [
+ 'a{background:url(/image-white.png)}',
+ 'a{background:url(/image-white.png)}'
+ ],
+ 'keep urls from being stripped down #3': [
+ 'a{background:url(/libraries/jquery-ui-1.10.1.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top #eee}',
+ 'a{background:url(/libraries/jquery-ui-1.10.1.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top #eee}'
+ ],
+ 'keep special markers in comments (so order is important)': [
+ '/*! __ESCAPED_URL_CLEAN_CSS0__ */a{display:block}',
+ '/*! __ESCAPED_URL_CLEAN_CSS0__ */a{display:block}'
+ ],
+ 'strip new line in urls': [
+ 'a{background:url(/very/long/' + lineBreak + 'path)}',
+ 'a{background:url(/very/long/path)}'
+ ],
+ 'strip new line in urls which could be unquoted': [
+ 'a{background:url("/very/long/' + lineBreak + 'path")}',
+ 'a{background:url(/very/long/path)}'
+ ],
+ 'uppercase': [
+ 'a{background-image: URL("images/image.png");}',
+ 'a{background-image:url(images/image.png)}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('urls whitespace in compatibility mode', {
+ 'keeps spaces as they are': [
+ '*{background:url(test.png) no-repeat}',
+ '*{background:url(test.png) no-repeat}'
+ ]
+ }, { compatibility: 'ie8' })
+ )
+ .addBatch(
+ optimizerContext('urls quotes in compatibility mode', {
+ 'keeps quotes as they are': [
+ 'div{background:url("test.png")}',
+ 'div{background:url("test.png")}'
+ ]
+ }, { compatibility: { properties: { urlQuotes: true } } })
+ )
+ .addBatch(
+ optimizerContext('urls rewriting - no root or target', {
+ 'no @import': [
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'relative @import': [
+ '@import url(test/fixtures/partials-relative/base.css);',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'relative @import twice': [
+ '@import url(test/fixtures/partials-relative/extra/included.css);',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'absolute @import': [
+ '@import url(/test/fixtures/partials-relative/base.css);',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'document-local reference': [
+ 'svg{marker-end:url(#arrow)}',
+ 'svg{marker-end:url(#arrow)}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('urls rewriting - root but no target', {
+ 'no @import': [
+ 'a{background:url(../partials/extra/down.gif) no-repeat}',
+ 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'relative @import': [
+ '@import url(base.css);',
+ 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'absolute @import': [
+ '@import url(/test/fixtures/partials-relative/base.css);',
+ 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'SVG': [
+ 'a{background-image:url("data:image/svg+xml,<svg version=\'1.1\'/>")}',
+ 'a{background-image:url("data:image/svg+xml,<svg version=\'1.1\'/>")}'
+ ],
+ 'document-local reference': [
+ 'svg{marker-end:url(#arrow)}',
+ 'svg{marker-end:url(#arrow)}'
+ ],
+ 'internal page': [
+ 'a{background:url(about:blank)}',
+ 'a{background:url(about:blank)}'
+ ]
+ }, {
+ root: process.cwd(),
+ relativeTo: path.join('test', 'fixtures', 'partials-relative')
+ })
+ )
+ .addBatch(
+ optimizerContext('urls rewriting - no root but target as file', {
+ 'no @import': [
+ 'a{background:url(../partials/extra/down.gif) no-repeat}',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'relative @import': [
+ '@import url(base.css);',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'absolute @import': [
+ '@import url(/test/fixtures/partials-relative/base.css);',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'document-local reference': [
+ 'svg{marker-end:url(#arrow)}',
+ 'svg{marker-end:url(#arrow)}'
+ ]
+ }, {
+ target: path.join(process.cwd(), 'test.css'),
+ relativeTo: path.join('test', 'fixtures', 'partials-relative')
+ })
+ )
+ .addBatch(
+ optimizerContext('urls rewriting - no root but target as a directory', {
+ 'no @import': [
+ 'a{background:url(../partials/extra/down.gif) no-repeat}',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'relative @import': [
+ '@import url(base.css);',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'absolute @import': [
+ '@import url(/test/fixtures/partials-relative/base.css);',
+ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'document-local reference': [
+ 'svg{marker-end:url(#arrow)}',
+ 'svg{marker-end:url(#arrow)}'
+ ]
+ }, {
+ target: process.cwd(),
+ relativeTo: path.join('test', 'fixtures', 'partials-relative')
+ })
+ )
+ .addBatch(
+ optimizerContext('urls rewriting - no root but target as a missing directory', {
+ 'url': [
+ 'a{background:url(../partials/extra/down.gif) no-repeat}',
+ 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'relative @import': [
+ '@import url(base.css);',
+ 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'absolute @import': [
+ '@import url(/test/fixtures/partials-relative/base.css);',
+ 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}'
+ ]
+ }, {
+ target: path.join('test', 'fixtures2'),
+ relativeTo: path.join('test', 'fixtures', 'partials-relative')
+ })
+ )
+ .addBatch(
+ optimizerContext('urls rewriting - root and target', {
+ 'no @import': [
+ 'a{background:url(../partials/extra/down.gif) no-repeat}',
+ 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'relative @import': [
+ '@import url(base.css);',
+ 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'absolute @import': [
+ '@import url(/test/fixtures/partials-relative/base.css);',
+ 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}'
+ ],
+ 'document-local reference': [
+ 'svg{marker-end:url(#arrow)}',
+ 'svg{marker-end:url(#arrow)}'
+ ]
+ }, {
+ root: process.cwd(),
+ target: path.join(process.cwd(), 'test.css'),
+ relativeTo: path.join('test', 'fixtures', 'partials-relative')
+ })
+ )
+ .addBatch(
+ optimizerContext('urls rewriting - rebase off', {
+ 'keeps urls the same': [
+ '@import url(base.css);',
+ 'a{background:url(../partials/extra/down.gif) no-repeat}'
+ ]
+ }, {
+ target: path.join(process.cwd(), 'test.css'),
+ relativeTo: path.join('test', 'fixtures', 'partials-relative'),
+ rebase: false
+ })
+ )
+ .addBatch(
+ optimizerContext('fonts', {
+ 'keep format quotation': [
+ '@font-face{font-family:PublicVintage;src:url(/PublicVintage.otf) format("opentype")}',
+ '@font-face{font-family:PublicVintage;src:url(/PublicVintage.otf) format("opentype")}'
+ ],
+ 'remove font family quotation': [
+ 'a{font-family:"Helvetica",\'Arial\'}',
+ 'a{font-family:Helvetica,Arial}'
+ ],
+ 'do not remove font family double quotation if space inside': [
+ 'a{font-family:"Courier New"}',
+ 'a{font-family:"Courier New"}'
+ ],
+ 'do not remove font quotation if starts with a number': [
+ 'a{font:\'123font\'}',
+ 'a{font:\'123font\'}'
+ ],
+ 'do not remove font family quotation if starts with a number': [
+ 'a{font-family:\'123font\'}',
+ 'a{font-family:\'123font\'}'
+ ],
+ 'remove font quotation': [
+ 'a{font:12px/16px "Helvetica",\'Arial\'}',
+ 'a{font:12px/16px Helvetica,Arial}'
+ ],
+ 'remove font quotation #2': [
+ 'a{font:12px/16px "Helvetica1_12",\'Arial_1451\'}',
+ 'a{font:12px/16px Helvetica1_12,Arial_1451}'
+ ],
+ 'remove font quotation #3': [
+ 'a{font:12px/16px "Helvetica-Regular",\'Arial-Bold\'}',
+ 'a{font:12px/16px Helvetica-Regular,Arial-Bold}'
+ ],
+ 'do not remove quotation from enclosed JSON (weird, I know)': [
+ 'p{font-family:\'{ "current" : "large", "all" : ["small", "medium", "large"], "position" : 2 }\'}',
+ 'p{font-family:\'{ "current" : "large", "all" : ["small", "medium", "large"], "position" : 2 }\'}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('IE hacks', {
+ 'star': [
+ 'a{*color:#fff}',
+ 'a{*color:#fff}'
+ ],
+ 'unserscore': [
+ 'a{_color:#fff}',
+ 'a{_color:#fff}'
+ ],
+ 'backslash': [
+ 'a{color:#fff\\9}',
+ 'a{color:#fff\\9}'
+ ],
+ 'overriding by a star': [
+ 'a{color:red;display:block;*color:#fff}',
+ 'a{color:red;display:block;*color:#fff}'
+ ],
+ 'overriding by a unserscore': [
+ 'a{color:red;display:block;_color:#fff}',
+ 'a{color:red;display:block;_color:#fff}'
+ ],
+ 'overriding by a backslash': [
+ 'a{color:red;display:block;color:#fff\\9}',
+ 'a{color:red;display:block;color:#fff\\9}'
+ ],
+ 'overriding a star': [
+ 'a{*color:red;display:block;*color:#fff}',
+ 'a{display:block;*color:#fff}'
+ ],
+ 'overriding a unserscore': [
+ 'a{_color:red;display:block;_color:#fff}',
+ 'a{display:block;_color:#fff}'
+ ],
+ 'overriding a backslash': [
+ 'a{color:red\\9;display:block;color:#fff\\9}',
+ 'a{display:block;color:#fff\\9}'
+ ],
+ 'overriding a star by a non-ajacent selector': [
+ 'a{color:red}.one{color:#000}a{*color:#fff}',
+ 'a{color:red}.one{color:#000}a{*color:#fff}'
+ ],
+ 'overriding an underscore by a non-ajacent selector': [
+ 'a{color:red}.one{color:#000}a{_color:#fff}',
+ 'a{color:red}.one{color:#000}a{_color:#fff}'
+ ],
+ 'overriding a backslash by a non-ajacent selector': [
+ 'a{color:red}.one{color:#fff}a{color:#fff\\9}',
+ 'a{color:red}.one{color:#fff}a{color:#fff\\9}'
+ ],
+ 'preserving backslash in overriddable': [
+ 'a{border:1px solid #ccc\\9}',
+ 'a{border:1px solid #ccc\\9}'
+ ],
+ 'keeps rgba(0,0,0,0)': [
+ 'a{color:rgba(0,0,0,0)}',
+ 'a{color:rgba(0,0,0,0)}'
+ ],
+ 'keeps rgba(255,255,255,0)': [
+ 'a{color:rgba(255,255,255,0)}',
+ 'a{color:rgba(255,255,255,0)}'
+ ],
+ 'keeps hsla(120,100%,50%,0)': [
+ 'a{color:hsla(120,100%,50%,0)}',
+ 'a{color:hsla(120,100%,50%,0)}'
+ ]
+ }, { compatibility: 'ie8' })
+ )
+ .addBatch(
+ optimizerContext('IE hacks without IE compatibility', {
+ 'star': [
+ 'a{*color:#fff}',
+ ''
+ ],
+ 'unserscore': [
+ 'a{_color:#fff}',
+ ''
+ ],
+ 'two in a row': [
+ 'a{padding:0;*height:13px;*width:13px}',
+ 'a{padding:0}'
+ ],
+ 'two in a row mixed': [
+ 'a{padding:0;*height:13px;_width:13px}',
+ 'a{padding:0}'
+ ],
+ 'backslash': [
+ 'a{color:#fff\\9}',
+ 'a{color:#fff\\9}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('animations', {
+ 'shorten': [
+ '@keyframes test\n{ from\n { width:100px; }\n to { width:200px; }\n}',
+ '@keyframes test{from{width:100px}to{width:200px}}'
+ ],
+ 'remove name quotes': [
+ '@keyframes "test1"{a{display:block}}@keyframes \'test2\'{a{display:block}}',
+ '@keyframes test1{a{display:block}}@keyframes test2{a{display:block}}'
+ ],
+ 'not remove name quotes if whitespace inside': [
+ '@keyframes "test 1"{a{display:block}}@keyframes \'test 2\'{a{display:block}}',
+ '@keyframes "test 1"{a{display:block}}@keyframes \'test 2\'{a{display:block}}'
+ ],
+ 'remove name quotes for vendor prefixes': [
+ '@-moz-keyframes \'test\'{a{display:block}}@-o-keyframes \'test\'{a{display:block}}@-webkit-keyframes \'test\'{a{display:block}}',
+ '@-moz-keyframes test{a{display:block}}@-o-keyframes test{a{display:block}}@-webkit-keyframes test{a{display:block}}'
+ ],
+ 'remove quotes in animation': [
+ 'div{animation:\'test\' 2s ease-in .5s 3}',
+ 'div{animation:test 2s ease-in .5s 3}'
+ ],
+ 'not remove quotes in animation when name with space inside': [
+ 'div{animation:\'test 1\' 2s ease-in .5s 3}',
+ 'div{animation:\'test 1\' 2s ease-in .5s 3}'
+ ],
+ 'remove quotes in vendor prefixed animation': [
+ 'div{-moz-animation:\'test\' 2s ease-in;-o-animation:\'test\' 2s ease-in;-webkit-animation:\'test\' 2s ease-in}',
+ 'div{-moz-animation:test 2s ease-in;-o-animation:test 2s ease-in;-webkit-animation:test 2s ease-in}'
+ ],
+ 'remove quotes in animation-name': [
+ 'div{animation-name:\'test\'}',
+ 'div{animation-name:test}'
+ ],
+ 'not remove quotes in animation-name when name with space inside': [
+ 'div{animation-name:\'test 1\'}',
+ 'div{animation-name:\'test 1\'}'
+ ],
+ 'remove quotes in vendor prefixed animation-name': [
+ 'div{-moz-animation-name:\'test\';-o-animation-name:\'test\';-webkit-animation-name:\'test\'}',
+ 'div{-moz-animation-name:test;-o-animation-name:test;-webkit-animation-name:test}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('attributes', {
+ 'should keep selector if no value': [
+ 'div[data-type]{border-color:red}',
+ 'div[data-type]{border-color:red}'
+ ],
+ 'should keep selector if no quotation': [
+ 'div[data-type=something]{border-color:red}',
+ 'div[data-type=something]{border-color:red}'
+ ],
+ 'should keep selector if equals in value': [
+ 'div[data-type="stupid=value"]{border-color:red}',
+ 'div[data-type="stupid=value"]{border-color:red}'
+ ],
+ 'should keep quotation if whitespace inside': [
+ 'div[data-type^=\'object 1\']{border-color:red}',
+ 'div[data-type^=\'object 1\']{border-color:red}'
+ ],
+ 'should keep quotations if special characters inside': [
+ 'a[data-type="object+1"]{color:red}p[data-target="#some-place"]{color:#0f0}',
+ 'a[data-type="object+1"]{color:red}p[data-target="#some-place"]{color:#0f0}'
+ ],
+ 'should keep quotation if is a number': [
+ 'div[data-number=\'1\']{border-color:red}',
+ 'div[data-number=\'1\']{border-color:red}'
+ ],
+ 'should keep quotation if starts with a number': [
+ 'div[data-type^=\'1something\']{border-color:red}',
+ 'div[data-type^=\'1something\']{border-color:red}'
+ ],
+ 'should keep quotation if starts with a hyphen': [
+ 'div[data-type$=\'-something\']{border-color:red}',
+ 'div[data-type$=\'-something\']{border-color:red}'
+ ],
+ 'should keep quotation if key only (which is invalid)': [
+ 'div["data-type"]{color:red}',
+ 'div["data-type"]{color:red}'
+ ],
+ 'should strip quotation if is a word': [
+ 'a[data-href=\'object\']{border-color:red}',
+ 'a[data-href=object]{border-color:red}'
+ ],
+ 'should strip quotation if is a hyphen separated words': [
+ 'a[data-href=\'object-1-two\']{border-color:red}',
+ 'a[data-href=object-1-two]{border-color:red}'
+ ],
+ 'should strip quotations if is less specific selectors': [
+ 'a[data-href*=\'object1\']{border-color:red}a[data-href|=\'object2\']{border-color:#0f0}',
+ 'a[data-href*=object1]{border-color:red}a[data-href|=object2]{border-color:#0f0}'
+ ],
+ 'should keep special characters inside attributes #1': [
+ 'a[data-css=\'color:white\']{display:block}',
+ 'a[data-css=\'color:white\']{display:block}'
+ ],
+ 'should keep special characters inside attributes #2': [
+ 'a[href="/version-0.01.html"]{display:block}',
+ 'a[href="/version-0.01.html"]{display:block}'
+ ],
+ 'should strip new lines inside attributes': [
+ '.test[title="my very long ' + lineBreak + 'title"]{display:block}',
+ '.test[title="my very long title"]{display:block}'
+ ],
+ 'should strip new lines inside attributes which can be unquoted': [
+ '.test[title="my_very_long_' + lineBreak + 'title"]{display:block}',
+ '.test[title=my_very_long_title]{display:block}'
+ ],
+ 'should strip whitespace between square brackets': [
+ 'body[ data-title ]{color:red}',
+ 'body[data-title]{color:red}'
+ ],
+ 'should strip whitespace inside square brackets': [
+ 'body[ data-title = x ]{color:red}',
+ 'body[data-title=x]{color:red}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('ie filters', {
+ 'short alpha': [
+ // 'a{ filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80); -ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)';}',
+ 'a{ filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80)}',
+ 'a{filter:alpha(Opacity=80)}'
+ ],
+ 'short chroma': [
+ 'a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191)}',
+ 'a{filter:chroma(color=#919191)}'
+ ],
+ 'matrix filter spaces': [
+ 'a{filter:progid:DXImageTransform.Microsoft.Matrix(M11=0.984, M22=0.984, M12=0.17, M21=-0.17, SizingMethod=\'auto expand\')}',
+ 'a{filter:progid:DXImageTransform.Microsoft.Matrix(M11=.984, M22=.984, M12=.17, M21=-.17, SizingMethod=\'auto expand\')}'
+ ],
+ 'multiple filters (IE7 issue)': [
+ 'a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191) progid:DXImageTransform.Microsoft.Matrix(M11=0.984, M22=0.984, M12=0.17, M21=-0.17, SizingMethod=\'auto expand\')}',
+ 'a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191) progid:DXImageTransform.Microsoft.Matrix(M11=.984, M22=.984, M12=.17, M21=-.17, SizingMethod=\'auto expand\')}'
+ ],
+ 'AlphaImageLoader': [
+ 'div{filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=images/skyline.jpg)}',
+ 'div{filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=images/skyline.jpg)}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('charsets', {
+ 'not at beginning': [
+ 'a{ color: #f10; }@charset \'utf-8\';b { font-weight: bolder}',
+ '@charset \'utf-8\';a{color:#f10}b{font-weight:bolder}'
+ ],
+ 'multiple charsets': [
+ '@charset \'utf-8\';div :before { display: block }@charset \'utf-8\';a { color: #f10 }',
+ '@charset \'utf-8\';div :before{display:block}a{color:#f10}'
+ ],
+ 'charset and space after': [
+ '@charset \'utf-8\';' + lineBreak + lineBreak + 'a{display:block}',
+ '@charset \'utf-8\';a{display:block}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('important', {
+ 'space before': [
+ 'body{background-color:#fff !important}',
+ 'body{background-color:#fff!important}'
+ ],
+ 'space between ! and important': [
+ 'body{background-color:#fff ! important}',
+ 'body{background-color:#fff!important}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('empty elements', {
+ 'single': [
+ ' div p { \n}',
+ ''
+ ],
+ 'between non-empty': [
+ 'div {color:#fff} a{ } p{ line-height:1.35em}',
+ 'div{color:#fff}p{line-height:1.35em}'
+ ],
+ 'just a semicolon': [
+ 'div { ; }',
+ ''
+ ],
+ 'inside @media': [
+ '@media screen { .test {} } .test1 { color: green; }',
+ '.test1{color:green}'
+ ],
+ 'inside nested @media': [
+ '@media screen { @media (orientation:landscape) { @media (max-width:999px) { .test {} } } }',
+ ''
+ ],
+ 'inside not empty @media': [
+ '@media screen { .test {} .some { display:none } }',
+ '@media screen{.some{display:none}}'
+ ],
+ 'inside nested not empty @media': [
+ '@media screen { @media (orientation:landscape) { @media (max-width:999px) { .test {} } a {color:red} } }',
+ '@media screen{@media (orientation:landscape){a{color:red}}}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('empty @media', {
+ 'simple': [
+ '@media print{}',
+ ''
+ ],
+ 'simple with and': [
+ '@media print and screen{}',
+ ''
+ ],
+ 'complex': [
+ '@media print, (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) {\n}',
+ ''
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('@import', {
+ 'empty': [
+ '@import url();',
+ ''
+ ],
+ 'of an unknown file': [
+ '@import url(\'fake.css\');',
+ ''
+ ],
+ 'of an unknown file with a missing trailing semicolon': [
+ '@import url(fake.css)',
+ ''
+ ],
+ 'of a directory': [
+ '@import url(test/fixtures/partials);',
+ ''
+ ],
+ 'of a real file': [
+ '@import url(test/fixtures/partials/one.css);',
+ '.one{color:red}'
+ ],
+ 'of a real file twice': [
+ '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/one.css);',
+ '.one{color:red}'
+ ],
+ 'of a real file with current path prefix': [
+ '@import url(./test/fixtures/partials/one.css);',
+ '.one{color:red}'
+ ],
+ 'of a real file with quoted path': [
+ '@import url(\'test/fixtures/partials/one.css\');',
+ '.one{color:red}'
+ ],
+ 'of a real file with double-quoted path': [
+ '@import url("test/fixtures/partials/one.css");',
+ '.one{color:red}'
+ ],
+ 'of a real file with bare path': [
+ '@import test/fixtures/partials/one.css;',
+ '.one{color:red}'
+ ],
+ 'of a real file with bare quoted path': [
+ '@import "test/fixtures/partials/one.css";',
+ '.one{color:red}'
+ ],
+ 'of a real file with bare double-quoted path': [
+ '@import "test/fixtures/partials/one.css";',
+ '.one{color:red}'
+ ],
+ 'of a real file with single simple media': [
+ '@import url(test/fixtures/partials/one.css) screen;',
+ '@media screen{.one{color:red}}'
+ ],
+ 'of a real file with multiple simple media': [
+ '@import "test/fixtures/partials/one.css" screen, tv, print;',
+ '@media screen,tv,print{.one{color:red}}'
+ ],
+ 'of a real file with complex media': [
+ '@import \'test/fixtures/partials/one.css\' screen and (orientation:landscape);',
+ '@media screen and (orientation:landscape){.one{color:red}}'
+ ],
+ 'of a real file with a missing trailing semicolon': [
+ '@import url(test/fixtures/partials/one.css)',
+ ''
+ ],
+ 'of a real files with a missing trailing semicolon': [
+ '@import url(test/fixtures/partials/one.css)@import url(test/fixtures/partials/two.css)',
+ ''
+ ],
+ 'of more files': [
+ '@import url(test/fixtures/partials/one.css);\n\n@import url(test/fixtures/partials/extra/three.css);\n\na{display:block}',
+ '.one{color:red}.three{color:#0f0}a{display:block}'
+ ],
+ 'of more files with media': [
+ '@import url(test/fixtures/partials/one.css) screen;@import url(test/fixtures/partials/extra/three.css) tv;',
+ '@media screen{.one{color:red}}@media tv{.three{color:#0f0}}'
+ ],
+ 'of multi-level, circular dependency file': [
+ '@import url(test/fixtures/partials/two.css);',
+ '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}'
+ ],
+ 'of a file with a relative resource path': [
+ '@import url(test/fixtures/partials/three.css);',
+ '.three{background-image:url(test/fixtures/partials/extra/down.gif)}'
+ ],
+ 'of a file with an absolute resource path': [
+ '@import url(test/fixtures/partials/four.css);',
+ '.four{background-image:url(/partials/extra/down.gif)}'
+ ],
+ 'of a file with a resource URI': [
+ '@import url(test/fixtures/partials/five.css);',
+ '.five{background:url(data:image/jpeg;base64,/9j/)}'
+ ],
+ 'cut off': [
+ '@impo',
+ ''
+ ],
+ 'cut off inside a comment': [
+ '/* @impo',
+ ''
+ ],
+ 'inside a comment': [
+ '/* @import url(test/fixtures/partials/five.css); */a { color: red; }',
+ 'a{color:red}'
+ ],
+ 'after a comment': [
+ '/* @import url(test/fixtures/partials/one.css); */@import url(test/fixtures/partials/one.css);a { color: red; }',
+ '.one,a{color:red}'
+ ],
+ 'used arbitrarily in comment': [
+ '/* @import foo */a { color: red; }',
+ 'a{color:red}'
+ ],
+ 'used arbitrarily in comment multiple times': [
+ '/* @import foo */a { color: red; }\n/* @import bar */p { color: #fff; }',
+ 'a{color:red}p{color:#fff}'
+ ],
+ 'used arbitrarily in comment including unrelated comment': [
+ '/* foo */a { color: red; }/* bar *//* @import */',
+ 'a{color:red}'
+ ],
+ 'of a file with a comment': [
+ '@import url(test/fixtures/partials/comment.css);',
+ 'a{display:block}'
+ ],
+ 'of a file (with media) with a comment': [
+ '@import url(test/fixtures/partials/comment.css) screen and (device-height: 600px);',
+ '@media screen and (device-height:600px){a{display:block}}'
+ ],
+ 'after standard content': [
+ 'a{display:block}@import url(test/fixtures/partials/one.css);body{margin:0}',
+ 'a{display:block}body{margin:0}'
+ ],
+ 'after quoted content': [
+ '/*a{display:block}*/@import url(test/fixtures/partials/one.css);',
+ '.one{color:red}'
+ ],
+ 'with double underscore': [
+ '@import url(test/fixtures/partials/with__double_underscore.css);',
+ '.one{color:green}'
+ ],
+ 'remote inside local': [
+ '@import url(test/fixtures/partials/remote.css);',
+ '@import url(http://jakubpawlowicz.com/styles.css);'
+ ],
+ 'remote inside local after content': [
+ 'a{color:red}@import url(test/fixtures/partials/remote.css);',
+ 'a{color:red}'
+ ],
+ 'remote inside local after imported content': [
+ '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/remote.css);',
+ '.one{color:red}'
+ ]
+ }, { root: process.cwd() })
+ )
+ .addBatch(
+ optimizerContext('malformed but still valid @import', {
+ 'prefixed with whitespace': [
+ ' @import \'test/fixtures/partials/one.css\';',
+ '.one{color:red}'
+ ],
+ 'no whitespace between @import and filename': [
+ '@import\'test/fixtures/partials/one.css\';',
+ '.one{color:red}'
+ ],
+ 'extra whitespace between @import and filename': [
+ '@import \'test/fixtures/partials/one.css\';',
+ '.one{color:red}'
+ ],
+ 'line break between @import and filename': [
+ '@import ' + lineBreak + '\'test/fixtures/partials/one.css\';',
+ '.one{color:red}'
+ ],
+ 'extra whitespace prefix in file name': [
+ '@import \' test/fixtures/partials/one.css\';',
+ '.one{color:red}'
+ ],
+ 'extra whitespace suffix in file name': [
+ '@import \'test/fixtures/partials/one.css \';',
+ '.one{color:red}'
+ ],
+ 'extra whitespace after': [
+ '@import \'test/fixtures/partials/one.css\' ;',
+ '.one{color:red}'
+ ],
+ 'uppercase @import': [
+ '@IMPORT \'test/fixtures/partials/one.css\';',
+ '.one{color:red}'
+ ],
+ 'extra whitespace between url and filename': [
+ '@import url( test/fixtures/partials/one.css);',
+ '.one{color:red}'
+ ],
+ 'extra whitespace prefix in file name - url': [
+ '@import url(\' test/fixtures/partials/one.css\');',
+ '.one{color:red}'
+ ],
+ 'extra whitespace suffix in file name - url': [
+ '@import url(\'test/fixtures/partials/one.css \');',
+ '.one{color:red}'
+ ]
+ }, { root: process.cwd() })
+ )
+ .addBatch(
+ optimizerContext('@import with absolute paths', {
+ 'of an unknown file': [
+ '@import url(/fake.css);',
+ ''
+ ],
+ 'of a real file': [
+ '@import url(/partials/one.css);',
+ '.one{color:red}'
+ ],
+ 'of a real file with quoted paths': [
+ '@import url("/partials/one.css");',
+ '.one{color:red}'
+ ],
+ 'of two files with mixed paths': [
+ '@import url(/partials/one.css);@import url(partials/extra/three.css);a{display:block}',
+ '.one{color:red}.three{color:#0f0}a{display:block}'
+ ],
+ 'of a multi-level, circular dependency file': [
+ '@import url(/partials/two.css);',
+ '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}'
+ ],
+ 'of a multi-level, circular dependency file with mixed paths': [
+ '@import url(/partials-absolute/base.css);',
+ '.base2{border-width:0}.sub{padding:0}.base{margin:0}'
+ ]
+ }, { root: path.join(process.cwd(), 'test', 'fixtures') })
+ )
+ .addBatch(
+ optimizerContext('@import with option processImport', {
+ 'of an unknown file': [
+ '@import url(/fake.css);',
+ '@import url(/fake.css);'
+ ],
+ 'of an unknown file with extra whitespace': [
+ '@import url( /fake.css );',
+ '@import url(/fake.css);'
+ ],
+ 'of comment chars within import url': [
+ '@import \'necolas/normalize.css@*/normalize.css\';',
+ '@import \'necolas/normalize.css@*/normalize.css\';'
+ ]
+ }, { processImport: false })
+ )
+ .addBatch(
+ optimizerContext('@import with no import and no advanced', {
+ 'empty body': [
+ '@import url(//fonts.googleapis.com/css?family=Domine:700);body{/* comment */}body h1{font-family:Domine}',
+ '@import url(//fonts.googleapis.com/css?family=Domine:700);body h1{font-family:Domine}'
+ ],
+ 'no empty body': [
+ '@import url(//fonts.googleapis.com/css?family=Domine:700);body{color:red}body h1{font-family:Domine}',
+ '@import url(//fonts.googleapis.com/css?family=Domine:700);body{color:red}body h1{font-family:Domine}'
+ ]
+ }, { processImport: false, advanced: false })
+ )
+ .addBatch(
+ optimizerContext('@import with no url', {
+ 'matching too much': [
+ '@import url(test.css);@font-face{font-family:"icomoon"}',
+ '@import url(test.css);@font-face{font-family:icomoon}'
+ ]
+ }, { processImport: false, root: process.cwd(), relativeTo: process.cwd() })
+ )
+ .addBatch(
+ optimizerContext('duplicate selectors with disabled advanced processing', {
+ 'of a duplicate selector': [
+ 'a,a{color:red}',
+ 'a{color:red}'
+ ]
+ }, { advanced: false })
+ )
+ .addBatch(
+ optimizerContext('line breaks with disabled advanced processing', {
+ 'should be applied': [
+ 'a{color:red}p{display:block}',
+ 'a{color:red}' + lineBreak + 'p{display:block}'
+ ]
+ }, { advanced: false, keepBreaks: true })
+ )
+ .addBatch(
+ optimizerContext('invalid data tokenization', {
+ 'extra top-level closing brace': [
+ 'a{color:red}}p{width:auto}',
+ 'a{color:red}p{width:auto}'
+ ],
+ 'extra top-level closing braces': [
+ 'a{color:red}}}}p{width:auto}',
+ 'a{color:red}p{width:auto}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('duplicate selectors in a list', {
+ 'of a duplicate selector': [
+ 'a,a{color:red}',
+ 'a{color:red}'
+ ],
+ 'of an unordered multiply repeated selector': [
+ 'a,b,p,a{color:red}',
+ 'a,b,p{color:red}'
+ ],
+ 'of an unordered multiply repeated selector within a block': [
+ '@media screen{a,b,p,a{color:red}}',
+ '@media screen{a,b,p{color:red}}'
+ ],
+ 'of an unordered multiply repeated complex selector within a block #1': [
+ '@media screen{.link[data-path],a,p,.link[data-path]{color:red}}',
+ '@media screen{.link[data-path],a,p{color:red}}'
+ ],
+ 'of an unordered multiply repeated complex selector within a block #2': [
+ '@media screen{#foo[data-path^="bar bar"],a,p,#foo[data-path^="bar bar"]{color:red}}',
+ '@media screen{#foo[data-path^="bar bar"],a,p{color:red}}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('duplicate selectors in a scope', {
+ 'of two successive selectors': [
+ 'a{color:red}a{color:red}',
+ 'a{color:red}'
+ ],
+ 'of two successive selectors with different body': [
+ 'a{color:red}a{display:block}',
+ 'a{color:red;display:block}'
+ ],
+ 'of many successive selectors': [
+ 'a{color:red}a{color:red}a{color:red}a{color:red}',
+ 'a{color:red}'
+ ],
+ 'of two non-successive selectors': [
+ 'a{color:red}p{color:#fff}a{color:red}',
+ 'p{color:#fff}a{color:red}'
+ ],
+ 'of many non-successive selectors': [
+ 'div{width:100%}a{color:red}a{color:red}p{color:#fff}div{width:100%}ol{margin:0}p{color:#fff}',
+ 'a{color:red}div{width:100%}ol{margin:0}p{color:#fff}'
+ ],
+ 'with global and media scope': [
+ 'a{color:red}@media screen{a{color:red}p{width:100px}a{color:red}}',
+ 'a{color:red}@media screen{p{width:100px}a{color:red}}'
+ ],
+ 'with two media scopes': [
+ '@media (min-width:100px){a{color:red}}@media screen{a{color:red}p{width:100px}a{color:red}}',
+ '@media (min-width:100px){a{color:red}}@media screen{p{width:100px}a{color:red}}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('duplicate properties with aggressive merging disabled', {
+ 'of (yet) unmergeable properties': [
+ 'a{display:inline-block;color:red;display:-moz-block}',
+ 'a{display:inline-block;color:red;display:-moz-block}'
+ ],
+ 'of mergeable properties': [
+ 'a{background:red;display:block;background:white}',
+ 'a{background:#fff;display:block}'
+ ]
+ }, { aggressiveMerging: false })
+ )
+ .addBatch(
+ optimizerContext('same selectors', {
+ 'of two non-adjacent selectors': [
+ '.one{color:red}.two{color:#00f}.one{font-weight:700}',
+ '.one{color:red;font-weight:700}.two{color:#00f}'
+ ],
+ 'of two adjacent single selectors': [
+ '.one{color:red}.one{font-weight:700}',
+ '.one{color:red;font-weight:700}'
+ ],
+ 'of three adjacent single selectors': [
+ '.one{color:red}.one{font-weight:700}.one{font-size:12px}',
+ '.one{color:red;font-weight:700;font-size:12px}'
+ ],
+ 'of two adjacent single, complex selectors': [
+ '#box>.one{color:red}#box>.one{font-weight:700}',
+ '#box>.one{color:red;font-weight:700}'
+ ],
+ 'of two adjacent multiple, complex selectors': [
+ '#box>.one,.zero{color:red}#box>.one,.zero{font-weight:700}',
+ '#box>.one,.zero{color:red;font-weight:700}'
+ ],
+ 'of two adjacent selectors with duplicate properties #1': [
+ '.one{color:red}.one{color:#fff}',
+ '.one{color:#fff}'
+ ],
+ 'of two adjacent selectors with duplicate properties #2': [
+ '.one{color:red;font-weight:bold}.one{color:#fff;font-weight:400}',
+ '.one{color:#fff;font-weight:400}'
+ ],
+ 'of two adjacent complex selectors with different selector order': [
+ '.one,.two{color:red}.two,.one{line-height:1em}',
+ '.one,.two{color:red;line-height:1em}'
+ ],
+ 'two adjacent with hex color definitions': [
+ 'a:link,a:visited{color:#fff}.one{display:block}a:link,a:visited{color:red}',
+ '.one{display:block}a:link,a:visited{color:red}'
+ ],
+ 'in two passes': [
+ 'a{color:red}a{background:red}b{color:red}b{background:red}',
+ 'a,b{color:red;background:red}'
+ ],
+ 'when overriden with a browser specific selector': [
+ 'a{color:red}::-webkit-scrollbar,a{color:#fff}',
+ 'a{color:red}::-webkit-scrollbar,a{color:#fff}'
+ ],
+ 'two same selectors over a block': [
+ '.one{color:red}@media print{.two{display:block}}.one{display:none}',
+ '@media print{.two{display:block}}.one{color:red;display:none}'
+ ],
+ 'two same bodies over a block': [
+ '.one{color:red}@media print{.two{display:block}}.three{color:red}',
+ '.one,.three{color:red}@media print{.two{display:block}}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('same non-adjacent selectors', {
+ 'with one redefined property': [
+ 'a{color:red;display:block}.one{color:red}a{color:#fff;margin:2px}',
+ '.one{color:red}a{display:block;color:#fff;margin:2px}'
+ ],
+ 'with intentionally redefined properties on joins': [
+ 'a{display:inline-block;display:-moz-inline-box;color:red}.one{margin:12px}a{color:#fff;margin:2px}',
+ '.one{margin:12px}a{display:inline-block;display:-moz-inline-box;color:#fff;margin:2px}'
+ ],
+ 'with intentionally redefined properties on multiple joins': [
+ 'a{color:red}.one{font-size:12px}a{color:#fff;margin:2px}.two{margin:10px}a{margin:0}',
+ '.one{font-size:12px}.two{margin:10px}a{color:#fff;margin:0}'
+ ],
+ 'with all redefined properties': [
+ 'a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
+ '.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}'
+ ],
+ 'many with all redefined properties': [
+ 'a{padding:10px}.zero{color:transparent}a{color:red;display:block}.one{font-size:12px}a{color:#fff;display:inline-block;margin:2px}',
+ '.zero{color:transparent}.one{font-size:12px}a{padding:10px;color:#fff;display:inline-block;margin:2px}'
+ ],
+ 'when overriden by an empty selector': [
+ 'a{padding:10px}.one{color:red}a{}',
+ 'a{padding:10px}.one{color:red}'
+ ],
+ 'when overriden by a complex selector': [
+ 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}',
+ '.one,a,p{color:red}a{margin:0}a,p{padding:0}'
+ ],
+ 'when overriden by complex selectors': [
+ 'a{padding:10px;margin:0;color:red}.one{color:red}a,p{color:red;padding:0}.one,a{color:#fff}',
+ 'a{margin:0}a,p{color:red;padding:0}.one,a{color:#fff}'
+ ],
+ 'when complex selector overriden by simple selectors': [
+ 'a,p{margin:0;color:red}a{color:#fff}',
+ 'a,p{margin:0;color:red}a{color:#fff}'
+ ],
+ 'when complex selector overriden by complex and simple selectors': [
+ 'a,p{margin:0;color:red}a{color:#fff}a,p{color:#00f}p{color:#0f0}',
+ 'a,p{margin:0;color:#00f}p{color:#0f0}'
+ ],
+ 'when complex selector overriden by complex selectors': [
+ '.one>.two,.three{color:red;line-height:1rem}#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}',
+ '#zero,.one>.two,.three,.www{color:#fff;margin:0}a{color:red}.one>.two,.three{line-height:2rem;font-size:1.5rem}'
+ ],
+ 'when undefined is used as a value': [
+ '.one{text-shadow:undefined}p{font-size:14px}.one{font-size:12px}',
+ 'p{font-size:14px}.one{text-shadow:undefined;font-size:12px}'
+ ],
+ 'when undefined is used as a value with reduction': [
+ '.one{text-shadow:undefined}p{color:red}.one{font-size:12px;text-shadow:none}',
+ 'p{color:red}.one{font-size:12px;text-shadow:none}'
+ ],
+ 'when overriden with a browser specific selector': [
+ 'a{color:red}p{display:block}::-moz-selection,a{color:#fff}',
+ 'a{color:red}p{display:block}::-moz-selection,a{color:#fff}'
+ ],
+ 'when same browser specific selector more than once': [
+ 'a,::-moz-selection{color:red}p{display:block}a,::-moz-selection{color:#fff}',
+ 'p{display:block}::-moz-selection,a{color:#fff}'
+ ],
+ 'with full property comparison': [
+ '.one{height:7rem}.two{color:#fff}.one{line-height:7rem;color:red}',
+ '.two{color:#fff}.one{height:7rem;line-height:7rem;color:red}'
+ ],
+ 'with two intermediate, non-overriding selectors': [
+ '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}',
+ '.one{color:red;margin:0;font-size:12px}.two{color:#fff}'
+ ],
+ 'with two intermediate, overriding more specific selectors': [
+ '.one{color:red;margin:0}.two{font:12px serif}.one{font-size:12px}',
+ '.two{font:12px serif}.one{color:red;margin:0;font-size:12px}'
+ ],
+ 'with granular selectors from the same shorthand': [
+ '.one{color:red;margin:0}.two{font-weight:700}.one{font-size:12px}',
+ '.one{color:red;margin:0;font-size:12px}.two{font-weight:700}'
+ ],
+ 'with three intermediate, non-overriding selectors': [
+ '.one{color:red;margin:0}.two{color:#fff}.one{font-size:12px}.three{color:#000}.one{padding:0}',
+ '.one{color:red;margin:0;font-size:12px;padding:0}.two{color:#fff}.three{color:#000}'
+ ],
+ 'successive selectors': [
+ 'footer,header{top:1.25em;bottom:1.25em}header{top:2.5em}footer{bottom:2.5em}',
+ 'footer,header{top:1.25em;bottom:1.25em}header{top:2.5em}footer{bottom:2.5em}'
+ ],
+ 'over a @media block': [
+ '.one{color:red;margin:0}@media{.two{font-weight:700}}.one{font-size:12px}',
+ '.one{color:red;margin:0;font-size:12px}@media{.two{font-weight:700}}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('rerun optimizers', {
+ 'selectors reducible once': [
+ '.one{color:red;margin:0}.two{color:red}.one{margin:0}',
+ '.one,.two{color:red}.one{margin:0}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('same bodies', {
+ 'of two non-adjacent selectors': [
+ '.one{color:red}.two{color:#00f}.three{color:red}',
+ '.one{color:red}.two{color:#00f}.three{color:red}'
+ ],
+ 'of two adjacent single selectors': [
+ '.one{color:red}.two{color:red}',
+ '.one,.two{color:red}'
+ ],
+ 'of three adjacent complex, multiple selectors': [
+ '.one{color:red}#two.three{color:red}.four>.five{color:red}',
+ '#two.three,.four>.five,.one{color:red}'
+ ],
+ 'with repeated selectors': [
+ '#zero>p,.one,.two{color:red}.two,#zero>p,.three{color:red}',
+ '#zero>p,.one,.three,.two{color:red}'
+ ],
+ 'of element selectors': [
+ 'p{color:red}a{color:#000}div{color:red}',
+ 'div,p{color:red}a{color:#000}'
+ ],
+ 'of element selectors inside @media': [
+ '@media screen{p{color:red}a{color:#000}div{color:red}}',
+ '@media screen{div,p{color:red}a{color:#000}}'
+ ],
+ 'of element selectors with a class selector in between': [
+ 'p{color:red}.a{color:#000}div{color:red}',
+ 'p{color:red}.a{color:#000}div{color:red}'
+ ],
+ 'of element selectors with an empty class selector in between': [
+ 'p{color:red}.a{}div{color:red}',
+ 'div,p{color:red}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('same bodies - IE8 compat', {
+ 'of two supported selectors': [
+ '.one:first-child{color:red}.two>.three{color:red}',
+ '.one:first-child,.two>.three{color:red}'
+ ],
+ 'of supported and unsupported selector': [
+ '.one:first-child{color:red}.two:last-child{color:red}',
+ '.one:first-child{color:red}.two:last-child{color:red}'
+ ],
+ 'of two unsupported selectors': [
+ '.one:nth-child(5){color:red}.two:last-child{color:red}',
+ '.one:nth-child(5){color:red}.two:last-child{color:red}'
+ ]
+ }, { compatibility: 'ie8' })
+ )
+ .addBatch(
+ optimizerContext('same bodies - IE7 compat', {
+ 'of two supported selectors': [
+ '.one{color:red}.two>.three{color:red}',
+ '.one,.two>.three{color:red}'
+ ],
+ 'of supported and unsupported selector': [
+ '.one{color:red}.two:last-child{color:red}',
+ '.one{color:red}.two:last-child{color:red}'
+ ],
+ 'of two unsupported selectors': [
+ '.one:before{color:red}.two:last-child{color:red}',
+ '.one:before{color:red}.two:last-child{color:red}'
+ ]
+ }, { compatibility: 'ie7' })
+ )
+ .addBatch(
+ optimizerContext('same bodies - +adjacentSpace', {
+ 'of two supported selectors': [
+ '.one{color:red}.two + nav{color:red}',
+ '.one,.two+ nav{color:red}'
+ ]
+ }, { compatibility: { selectors: { adjacentSpace: true } } })
+ )
+ .addBatch(
+ optimizerContext('units - IE8 compatibility', {
+ 'rems': [
+ 'div{padding-top:16px;color:red;padding-top:1rem}',
+ 'div{padding-top:16px;color:red;padding-top:1rem}'
+ ]
+ }, { compatibility: 'ie8' })
+ )
+ .addBatch(
+ optimizerContext('redefined more granular properties with property merging', {
+ 'should merge background with background-attachment': [
+ 'a{background:0;background-attachment:fixed}',
+ 'a{background:0 fixed}'
+ ],
+ 'should NOT merge background with inherited background-attachment': [
+ 'a{background:0;background-attachment:inherit}',
+ 'a{background:0;background-attachment:inherit}'
+ ],
+ 'should merge background with background-color': [
+ 'a{background:0;background-color:#9fce00}',
+ 'a{background:0 #9fce00}'
+ ],
+ 'should NOT merge background with inherited background-color': [
+ 'a{background:0;background-color:inherit}',
+ 'a{background:0;background-color:inherit}'
+ ],
+ 'should NOT merge background with background-color set to none': [
+ 'a{background:url(logo.png) center no-repeat;background-color:none}',
+ 'a{background:url(logo.png) center no-repeat;background-color:none}'
+ ],
+ 'should merge background with background-image': [
+ 'a{background:0;background-image:url(hello_world)}',
+ 'a{background:url(hello_world) 0}'
+ ],
+ 'should NOT merge background with inherited background-image': [
+ 'a{background:0;background-image:inherit}',
+ 'a{background:0;background-image:inherit}'
+ ],
+ 'should merge background with background-position': [
+ 'a{background:0;background-position:3px 4px}',
+ 'a{background:3px 4px}'
+ ],
+ 'should NOT merge background with inherited background-position': [
+ 'a{background:0;background-position:inherit}',
+ 'a{background:0;background-position:inherit}'
+ ],
+ 'should merge background with background-repeat': [
+ 'a{background:0;background-repeat:repeat-y}',
+ 'a{background:0 repeat-y}'
+ ],
+ 'should NOT merge background with inherited background-repeat': [
+ 'a{background:0;background-repeat:inherit}',
+ 'a{background:0;background-repeat:inherit}'
+ ],
+ 'should merge outline with outline-color': [
+ 'a{outline:1px;outline-color:#9fce00}',
+ 'a{outline:#9fce00 1px}'
+ ],
+ 'should NOT merge outline with inherited outline-color': [
+ 'a{outline:0;outline-color:inherit}',
+ 'a{outline:0;outline-color:inherit}'
+ ],
+ 'should merge outline with outline-style': [
+ 'a{outline:0;outline-style:dashed}',
+ 'a{outline:dashed 0}'
+ ],
+ 'should NOT merge outline with inherited outline-style': [
+ 'a{outline:0;outline-style:inherit}',
+ 'a{outline:0;outline-style:inherit}'
+ ],
+ 'should merge outline with outline-width': [
+ 'a{outline:0;outline-width:5px}',
+ 'a{outline:5px}'
+ ],
+ 'should NOT merge outline with inherited outline-width': [
+ 'a{outline:0;outline-width:inherit}',
+ 'a{outline:0;outline-width:inherit}'
+ ],
+ 'should merge list-style with list-style-type': [
+ 'li{list-style-type:disc;list-style:inside}',
+ 'li{list-style:inside}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('merging of rules', {
+ 'rules without pseudo classes should be merged': [
+ 'a{color:red}b{color:red}',
+ 'a,b{color:red}'
+ ],
+ 'rules with well-supported pseudo classes should be merged #1': [
+ 'a:focus{color:red}b{color:red}',
+ 'a:focus,b{color:red}'
+ ],
+ 'rules with well-supported pseudo classes should be merged #2': [
+ 'a:nth-of-type(1){color:red}b{color:red}',
+ 'a:nth-of-type(1),b{color:red}'
+ ],
+ 'rules with well-supported pseudo classes should be merged #3': [
+ 'a:first-of-type{color:red}b{color:red}',
+ 'a:first-of-type,b{color:red}'
+ ],
+ 'rules with well-supported pseudo classes should be merged #4': [
+ 'a:first-child{color:red}b{color:red}',
+ 'a:first-child,b{color:red}'
+ ],
+ 'rules with prefixed pseudo classes should not be merged #1': [
+ 'a:-moz-full-screen{color:red}b{color:red}',
+ 'a:-moz-full-screen{color:red}b{color:red}'
+ ],
+ 'rules with prefixed pseudo classes should not be merged #2': [
+ 'a:-moz-dir(rtl){color:red}b{color:red}',
+ 'a:-moz-dir(rtl){color:red}b{color:red}'
+ ],
+ 'rules with not-so-well-supported pseudo classes should not be merged #1': [
+ 'a:fullscreen{color:red}b{color:red}',
+ 'a:fullscreen{color:red}b{color:red}'
+ ],
+ 'rules with not-so-well-supported pseudo classes should not be merged #2': [
+ 'a:dir(ltr){color:red}b{color:red}',
+ 'a:dir(ltr){color:red}b{color:red}'
+ ],
+ 'rules with not-so-well-supported pseudo classes should not be merged #3': [
+ 'a:right{color:red}b{color:red}',
+ 'a:right{color:red}b{color:red}'
+ ],
+ 'rules with not-so-well-supported pseudo classes should not be merged #4': [
+ 'a:first{color:red}b{color:red}',
+ 'a:first{color:red}b{color:red}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('grouping with advanced optimizations', {
+ '@-moz-document': [
+ '@-moz-document domain(mozilla.org){a{color:red}}',
+ '@-moz-document domain(mozilla.org){a{color:red}}'
+ ],
+ '@media': [
+ '@media{a{color:red}}',
+ '@media{a{color:red}}'
+ ],
+ '@page': [
+ '@page{margin:.5em}',
+ '@page{margin:.5em}'
+ ],
+ '@supports': [
+ '@supports (display:flexbox){.flex{display:flexbox}}',
+ '@supports (display:flexbox){.flex{display:flexbox}}'
+ ],
+ '@-ms-viewport': [
+ '@-ms-viewport{width:device-width}',
+ '@-ms-viewport{width:device-width}'
+ ],
+ '@-o-viewport': [
+ '@-o-viewport{width:device-width}',
+ '@-o-viewport{width:device-width}'
+ ],
+ '@viewport': [
+ '@viewport{width:device-width}',
+ '@viewport{width:device-width}'
+ ],
+ '@counter-style': [
+ '@counter-style triangle{system:cyclic;symbols:‣;suffix:" "}',
+ '@counter-style triangle{system:cyclic;symbols:‣;suffix:" "}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('background size', {
+ 'with background-position': [
+ 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}',
+ 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}'
+ ],
+ 'with background-position and spaces': [
+ 'a{background:url(top.jpg) 50% 0 / auto 25% no-repeat}',
+ 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}'
+ ],
+ 'with background-position shorthands': [
+ 'a{background:url(top.jpg) 50px/25% no-repeat}',
+ 'a{background:url(top.jpg) 50px/25% no-repeat}'
+ ],
+ 'with background-position shorthands and spaces': [
+ 'a{background:url(top.jpg) 0 / cover no-repeat}',
+ 'a{background:url(top.jpg) 0/cover no-repeat}'
+ ],
+ 'with background-size property': [
+ 'a{background:none;background-image:url(1.png);background-size:28px 28px}',
+ 'a{background:url(1.png);background-size:28px 28px}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('background position', {
+ 'calc as a value': [
+ '*{background:white calc(100% - 10px) center no-repeat;background-image:url(test.png)}',
+ '*{background:calc(100% - 10px) center no-repeat #fff;background-image:url(test.png)}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('background-clip', {
+ 'inside background shorthand': [
+ 'div{background:content-box #000}',
+ 'div{background:content-box #000}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('background size with +properties.backgroundSizeMerging', {
+ 'with background-size property': [
+ 'a{background:none;background-image:url(1.png);background-size:28px 28px}',
+ 'a{background:url(1.png) 0 0/28px 28px}'
+ ],
+ 'important overriding': [
+ 'a{background:url(a.jpg) !important; background-color:#fff !important; background-size:10px 10px !important}',
+ 'a{background:url(a.jpg) 0 0/10px 10px #fff!important}'
+ ]
+ }, { compatibility: '+properties.backgroundSizeMerging' })
+ )
+ .addBatch(
+ optimizerContext('multiple backgrounds', {
+ 'should not produce longer values': [
+ 'p{background:no-repeat;background-position:100% 0,0 100%,100% 100%,50% 50%}',
+ 'p{background:no-repeat;background-position:100% 0,0 100%,100% 100%,50% 50%}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('misc advanced', {
+ 'outline auto': [
+ 'a{outline:5px auto -webkit-focus-ring-color}',
+ 'a{outline:-webkit-focus-ring-color auto 5px}'
+ ],
+ 'border radius side H+V': [
+ 'a{border-top-left-radius:2em / 1em}',
+ 'a{border-top-left-radius:2em/1em}'
+ ],
+ 'border radius expanded H+V': [
+ 'a{border-radius:1em 1em 1em 1em / 2em 2em 2em 2em}',
+ 'a{border-radius:1em/2em}'
+ ],
+ 'border radius expanded H+V with mixed values #1': [
+ 'a{border-radius:1em 2em 1em 2em / 1em 2em 3em 2em}',
+ 'a{border-radius:1em 2em/1em 2em 3em}'
+ ],
+ 'border radius expanded H+V with mixed values #2': [
+ 'a{border-radius:1em/1em 1em 1em 2em}',
+ 'a{border-radius:1em/1em 1em 1em 2em}'
+ ],
+ 'border radius H+V': [
+ 'a{border-radius:50%/100%}',
+ 'a{border-radius:50%/100%}'
+ ],
+ 'lost background position': [
+ '.one{background:50% no-repeat}.one{background-image:url(/img.png)}',
+ '.one{background:url(/img.png) 50% no-repeat}'
+ ],
+ 'unknown @ rule': [
+ '@unknown "test";h1{color:red}',
+ '@unknown "test";h1{color:red}'
+ ],
+ 'property without a value': [
+ 'a{color:}',
+ ''
+ ],
+ 'properties without values': [
+ 'a{padding:;border-radius: ;background:red}',
+ 'a{background:red}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('advanced in ie8 mode', {
+ 'plain component to complex shorthand': [
+ 'a{background:linear-gradient(to bottom,#000,#fff 4em) #000;background-color:#fff}',
+ 'a{background:linear-gradient(to bottom,#000,#fff 4em) #000;background-color:#fff}'
+ ],
+ 'plain component to shorthand': [
+ 'a{background:url(bg.png) #000;background-color:#fff}',
+ 'a{background:url(bg.png) #fff}'
+ ],
+ 'merging rgba with standard colors': [
+ 'div{background-color:red;background:rgba(1,2,3,.5)}',
+ 'div{background-color:red;background:rgba(1,2,3,.5)}'
+ ]
+ }, { compatibility: 'ie8' })
+ )
+ .addBatch(
+ optimizerContext('viewport units', {
+ 'shorthand margin with viewport width not changed': [
+ 'div{margin:5vw}',
+ 'div{margin:5vw}'
+ ]
+ })
+ )
+ .addBatch(
+ optimizerContext('variables', {
+ 'stripping': [
+ 'a{--border:#000}.one{border:1px solid var(--border)}',
+ 'a{--border:#000}.one{border:1px solid var(--border)}'
+ ],
+ 'all values': [
+ 'a{--width:1px;--style:solid;--color:#000}.one{border:var(--width)var(--style)var(--color)}',
+ 'a{--width:1px;--style:solid;--color:#000}.one{border:var(--width)var(--style)var(--color)}'
+ ]
+ })
+ )
+ .export(module);