uselesscss
Version:
Trim bloat from your CSS by only including rules that will actually be active.
629 lines (627 loc) • 26.8 kB
JavaScript
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)
})
})
})