UNPKG

uselesscss

Version:

Trim bloat from your CSS by only including rules that will actually be active.

629 lines (627 loc) 26.8 kB
import 'mocha' import { assert } from 'chai' import Useless from '../src/uselesscss' import fs from 'fs' import cheerio from 'cheerio' import cssLib from 'css' describe('lib', function () { let blankHtmlTemplate = '' let $ before(function () { blankHtmlTemplate = fs.readFileSync('./test/html/blank.html', 'utf8') }) beforeEach(function () { $ = cheerio.load(blankHtmlTemplate) }) /** * Test cases follow pattern specified in https://www.w3.org/TR/css3-selectors/#selectors */ describe('Empty cases', function () { it('Should return an empty string if no CSS is provided', function () { let html = blankHtmlTemplate let actual = Useless(html) assert.strictEqual('', actual) }) it('Should return an empty string if no CSS is used', function () { $('body').append('<p class="bold">Hello, world!</p>') let ast = cssLib.parse('a {color: red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) }) describe('Universal selector', function () { it('Should always include universal selector', function () { let ast = cssLib.parse('*{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) }) describe('Type selector', function () { it('Should include type selectors from CSS, if they\'re present in HTML', function () { $('body').append('<a href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('Should exclude type selectors from CSS, if they\'re not present in HTML', function () { $('body').append('<a href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('p{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) }) describe('Attribute selector', function () { it('E[foo] postive case', function () { $('body').append('<a foo href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E[bar]: negative case', function () { $('body').append('<a foo href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[bar]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E[foo="bar"] positive case', function () { $('body').append('<a foo="bar" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo="bar"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E[foo="bar"] negative case', function () { $('body').append('<a foo="baz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo="bar"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E[foo~="bar"] positive case', function () { $('body').append('<a foo="foo bar baz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo~="bar"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E[foo~="bar"] negative case', function () { $('body').append('<a foo="foo bar baz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo~="buzz"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E[foo^="bar"] positive case', function () { $('body').append('<a foo="barbaz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo^="bar"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E[foo^="bar"] negative case', function () { $('body').append('<a foo="barbaz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo^="arbaz"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E[foo$="bar"] positive case', function () { $('body').append('<a foo="barbaz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo$="arbaz"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E[foo$="bar"] negative case', function () { $('body').append('<a foo="barbaz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo$="arba"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E[foo*="bar"] positive case', function () { $('body').append('<a foo="barbaz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo*="arba"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E[foo*="bar"] negative case', function () { $('body').append('<a foo="barbaz" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[foo*="buzz"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E[lang|="en"] positive case', function () { $('body').append('<a lang="zh-Hant" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[lang|="zh"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E[lang|="en"] negative case', function () { $('body').append('<a lang="zh-Hant" href="http://github.com/asimpletune/uselesscss">useless</a>') let ast = cssLib.parse('a[lang|="hant"]{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) }) describe('Structural pseudo-classes', function () { it(':root should always apply', function () { let ast = cssLib.parse(':root{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:nth-child(an+b) positive case', function () { $('body').append('<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>') let ast = cssLib.parse('div:nth-child(2n+1){color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:nth-child(an+b) negative case', function () { $('body').append('<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>') let ast = cssLib.parse('div:nth-child(7){color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E:nth-last-child(an+b) positive case', function () { $('body').append('<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>') let ast = cssLib.parse('div:nth-last-child(2n+1){color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:nth-last-child(an+b) negative case', function () { $('body').append('<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>') let ast = cssLib.parse('div:nth-last-child(7){color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E:nth-of-type(an+b) positive case', function () { $('body').append('<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>') let ast = cssLib.parse('div:nth-of-type(2n+1){color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:nth-of-type(an+b) negative case', function () { $('body').append('<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>') let ast = cssLib.parse('div:nth-of-type(7){color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E:nth-last-of-type(an+b) positive case', function () { $('body').append('<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>') let ast = cssLib.parse('div:nth-last-of-type(2n+1){color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:nth-last-of-type(an+b) negative case', function () { $('body').append('<div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div>') let ast = cssLib.parse('div:nth-last-of-type(7){color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E:first-child positive case', function () { $('body').append('<div><span>1</span><span>2</span></div>') let ast = cssLib.parse('span:first-child{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:first-child negative case', function () { $('body').append('<div><span>1</span><span>2</span></div>') let ast = cssLib.parse('p:first-child{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E:last-child positive case', function () { $('body').append('<div><span>1</span><span>2</span></div>') let ast = cssLib.parse('span:last-child{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:last-child negative case', function () { $('body').append('<div><span>1</span><span>2</span></div>') let ast = cssLib.parse('p:last-child{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E:only-child positive case', function () { $('body').append('<div><span>1</span></div>') let ast = cssLib.parse('span:only-child{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:only-child negative case', function () { $('body').append('<div><span>1</span><span>2</span></div>') let ast = cssLib.parse('span:only-child{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E:only-of-type positive case', function () { $('body').append('<div><span>1</span><p>2</p></div>') let ast = cssLib.parse('span:only-of-type{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:only-of-type negative case', function () { $('body').append('<div><p>1</p><p>2</p></div>') let ast = cssLib.parse('p:only-of-type{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E:empty positive case', function () { $('body').append('<div><span></span><span>2</span></div>') let ast = cssLib.parse('span:empty{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:first-child negative case', function () { $('body').append('<div><span>1</span><span>2</span></div>') let ast = cssLib.parse('span:empty{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) }) describe('Link pseudo-classes', function () { it(':link positive case', function () { $('body').append('<div><a>Always unvisited</a></div>') let ast = cssLib.parse('a:link{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it(':link negtive case', function () { $('body').append('<div></div>') let ast = cssLib.parse('a:link{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) $('div').append('<a>Always unvisited</a>') ast = cssLib.parse(':link{color:red;}') html = $.root().html() css = cssLib.stringify(ast) actual = Useless(html, css) assert.strictEqual('', actual) }) it(':visited positive case', function () { $('body').append('<div><a>Always unvisited</a></div>') let ast = cssLib.parse('a:visited{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it(':visited negtive case', function () { $('body').append('<div></div>') let ast = cssLib.parse('a:visited{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) $('div').append('<a>Always unvisited</a>') ast = cssLib.parse(':visited{color:red;}') html = $.root().html() css = cssLib.stringify(ast) actual = Useless(html, css) assert.strictEqual('', actual) }) }) describe('User action pseudo-classes', function () { it(':active positive case', function () { $('body').append('<div><a>Always unvisited</a></div>') let ast = cssLib.parse('a:active{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it(':active negtive case', function () { $('body').append('<div></div>') let ast = cssLib.parse('a:active{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) $('div').append('<a>Always unvisited</a>') ast = cssLib.parse(':active{color:red;}') html = $.root().html() css = cssLib.stringify(ast) actual = Useless(html, css) assert.strictEqual('', actual) }) it(':hover positive case', function () { $('body').append('<div><a>Always unvisited</a></div>') let ast = cssLib.parse('a:hover{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it(':hover negtive case', function () { $('body').append('<div></div>') let ast = cssLib.parse('a:hover{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) $('div').append('<a>Always unvisited</a>') ast = cssLib.parse(':hover{color:red;}') html = $.root().html() css = cssLib.stringify(ast) actual = Useless(html, css) assert.strictEqual('', actual) }) it(':focus positive case', function () { $('body').append('<div><a>Always unvisited</a></div>') let ast = cssLib.parse('a:focus{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it(':focus negtive case', function () { $('body').append('<div></div>') let ast = cssLib.parse('a:focus{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) $('div').append('<a>Always unvisited</a>') ast = cssLib.parse(':focus{color:red;}') html = $.root().html() css = cssLib.stringify(ast) actual = Useless(html, css) assert.strictEqual('', actual) }) }) describe('Unsupported pseudo-clases', function () { /* TODO: Revisit when I implement some of these */ it('E:target positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><a href="#more">Click to see more</a><p id="more">Here is more</p></div>') let ast = cssLib.parse('p:target {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) console.error('CSS', css) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:lang(en) positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><p lang="en_us">Hello, world!</p></div>') let ast = cssLib.parse('p:lang(en) {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:enabled positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><p lang="en_us">Hello, world!</p></div>') let ast = cssLib.parse('p:enabled {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:disabled positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><p lang="en_us">Hello, world!</p></div>') let ast = cssLib.parse('p:disabled {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E:checked positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><p lang="en_us">Hello, world!</p></div>') let ast = cssLib.parse('p:checked {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) }) describe('Unsupported pseudo-elements', function () { /* TODO: Revisit when I implement some of these */ it('E::first-line positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><a href="#more">Click to see more</a><p id="more">Here is more</p></div>') let ast = cssLib.parse('p::first-line {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) console.error('CSS', css) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E::first-letter positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><a href="#more">Click to see more</a><p id="more">Here is more</p></div>') let ast = cssLib.parse('p::first-letter {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) console.error('CSS', css) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E::before positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><a href="#more">Click to see more</a><p id="more">Here is more</p></div>') let ast = cssLib.parse('p::before {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) console.error('CSS', css) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E::after positive case should still be included if the rest of the selector would be active', function () { $('body').append('<div><a href="#more">Click to see more</a><p id="more">Here is more</p></div>') let ast = cssLib.parse('p::after {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) console.error('CSS', css) let actual = Useless(html, css) assert.strictEqual(css, actual) }) }) describe('Class selectors', function () { it('E.class positive case', function () { $('body').append('<div><a class="myclass">Always unvisited</a></div>') let ast = cssLib.parse('a.myclass{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E.class negtive case', function () { $('body').append('<div><a class="myOtherclass">Always unvisited</a></div>') let ast = cssLib.parse('a.active{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) }) describe('Id selectors', function () { it('E#id positive case', function () { $('body').append('<div><a id="myId">Always unvisited</a></div>') let ast = cssLib.parse('a#myId{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E#id negtive case', function () { $('body').append('<div><a id="myOtherId">Always unvisited</a></div>') let ast = cssLib.parse('a#myId{color:red;}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) }) describe('Combinator selectors', function () { it('E F (descendant) positive case', function () { $('body').append('<div><a id="myId">Always unvisited</a></div>') let ast = cssLib.parse('div a {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E F (descendant) negtive case', function () { $('body').append('<div><a id="myOtherId">Always unvisited</a></div>') let ast = cssLib.parse('div div {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E > F (child) positive case', function () { $('body').append('<div><a id="myOtherId">Always unvisited</a><ul><li>child but not descendant</li></ul></div>') let ast = cssLib.parse('ul > li {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E > F (child) negtive case', function () { $('body').append('<div><a id="myOtherId">Always unvisited</a><ul><li>child but not descendant</li></ul></div>') let ast = cssLib.parse('div > li {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E + F (adjacent sibling) positive case', function () { $('body').append('<div><ul><li class="odd"></li><li class="even"></li></ul></div>') let ast = cssLib.parse('li.odd + li.even {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E + F (adjacent sibling) negtive case', function () { $('body').append('<div><ul><li class="odd"></li><li class="even"></li><li class="odd"></li></ul></div>') let ast = cssLib.parse('li.odd + li.odd {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) it('E ~ F (general sibling) positive case', function () { $('body').append('<div><ul><li class="odd"></li><li class="even"></li><li class="odd"></li></ul></div>') let ast = cssLib.parse('li.odd ~ li.odd {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual(css, actual) }) it('E ~ F (general sibling) negtive case', function () { $('body').append('<div><ul><li class="odd"></li><li class="even"></li><li class="odd"></li></ul></div>') let ast = cssLib.parse('div + li.odd {color: "red";}') let html = $.root().html() let css = cssLib.stringify(ast) let actual = Useless(html, css) assert.strictEqual('', actual) }) }) })