jsheets
Version:
A simple CSS preprocessor that interprets JavaScript
447 lines (421 loc) • 21 kB
JavaScript
var assert = require('assert')
var fs = require('fs')
var Parser = require('../lib/parser.js')
describe('parser', function () {
describe('parse', function () {
it('should return a string', function () {
var testParser = new Parser
assert.equal('string', typeof testParser.parse(''))
})
it('should return false if there\'s invalid any javascript in the jsheets', function () {
var testParser = new Parser
assert.ok(!testParser.parse('asdf'))
})
it('should take jsheets and return css', function () {
var testParser = new Parser
assert.equal('asdf', testParser.parse('["a", "s", "d", "f"].forEach(function (value) { css(value) })'))
assert.equal('div {\n display: block;\n}\ntroll', testParser.parse('div {\n display: block;\n}\n css(\'troll\')'))
assert.equal('div {\n display: block;\n }\ntrolltrolltrolltrolltrolltrolltrolltrolltrolltroll\n div { display: hidden; }', testParser.parse('div {\n display: block;\n }\n \n for(var i = 10; i > 0; i--) {\n css(\'troll\')\n }\n\n div { display: hidden; }'))
})
it('should return false if false is passed to it', function () {
var testParser = new Parser
assert.equal(false, testParser.parse(false))
})
it('should be able to set, use and reset variables', function () {
var testParser = new Parser
var testString
testParser.parse('$.someString = \'someString\'')
assert.equal('someString', testParser.context['$']['someString'])
testString = testParser.parse('$.someString = \'someOtherString\' \n div {display:$.someString}')
assert.equal(' div {display:someOtherString}', testString)
testString = testParser.parse('\n div {display:$.someString}')
assert.equal('\n div {display:someOtherString}', testString)
})
it('should keep variables in global space', function () {
var testParser = new Parser
assert.equal('a{...}\ntrue', testParser.parse('var testVar = true \na{...}\ncss(testVar)'))
})
it('should run the onEOF hook', function () {
var testParser = new Parser
testParser.context.hooks.EOF = [function () {return 'css'}]
assert.equal('\ncss', testParser.parse(''))
})
it('should run the onAfterParse hooks', function () {
var testParser = new Parser
testParser.context.hooks.afterParse.push(function (parsedJsheet) {
return '!'
})
assert.equal('!', testParser.parse('css(\'css\')'))
})
})
describe('runOnEOF', function () {
it('should add the returned value of a hook to the parsed css string', function () {
var testParser = new Parser
testParser.context.hooks.EOF = [function () {return 'css'}]
assert.equal('\ncss', testParser.runOnEOF())
})
})
describe('runOnAfterParse', function () {
it('should pass the parsed jsheet to the hook', function () {
var testParser = new Parser
testParser.context.hooks.afterParse.push(function (parsedJsheet) {
assert.equal('css', parsedJsheet)
})
testParser.runOnAfterParse('css')
})
it('should set the return value of a hook as the redered css', function () {
var testParser = new Parser
testParser.context.hooks.afterParse.push(function (parsedJsheet) {
return '!'
})
assert.equal('!', testParser.runOnAfterParse('css'))
})
})
describe('context.on', function () {
it('should take a string as a first argument and a function as a second', function () {
var testParser = new Parser
assert.ok(testParser.context.on('EOF', function () {}) !== false)
})
it('should push the function (2nd arg) to the array described by the 1st arg', function () {
var testParser = new Parser
assert.ok(testParser.context.hooks.EOF.length === 0)
testParser.context.on('EOF', function () {})
assert.ok(testParser.context.hooks.EOF.length > -1)
})
it('should return the position within the array', function () {
var testParser = new Parser
assert.equal(0, testParser.context.on('EOF', function () {}))
})
})
describe('getHooks', function () {
it('should take a hook name as its first argument', function () {
var testParser = new Parser
testParser.context.on('EOF', function () {})
assert.ok(testParser.getHooks('EOF'))
})
it('should return an array containing all hooks', function () {
var testParser = new Parser
testParser.context.on('EOF', function () {})
assert.ok(testParser.getHooks('EOF').length)
})
it('should cleanout the hooks array', function () {
var testParser = new Parser
testParser.context.on('EOF', function () {})
testParser.getHooks('EOF')
assert.equal(0, testParser.context.hooks.EOF.length)
})
})
describe('setHooks', function () {
it('should take an object containing all hooks as an argument', function () {
var testParser = new Parser
assert.ok(testParser.setHooks({EOF: []}))
})
it('should overwrite all hook arrays with the passed value', function () {
var testParser = new Parser
testParser.context.on('EOF', function () {})
testParser.context.on('EOF', function () {})
testParser.setHooks({EOF: [function () {return}]})
assert.equal(1, testParser.context.hooks.EOF.length)
})
})
describe('interpret', function () {
it('should exec js if the first position is js', function () {
var testParser = new Parser
assert.equal('asdf', testParser.interpret(['js', '["a", "s", "d", "f"].forEach(function (value) { css(value) })']))
})
it('should return the passed string if the first position is css', function () {
var testParser = new Parser
assert.equal('display: block', testParser.interpret(['css', 'display: block']))
})
})
describe('split', function () {
var testJcss
var testCss
var parseReturn
before(function () {
var testParser = new Parser
testJcss = '\n div {\n display: block;\n }\n\n css(".class { display: none; }")\n '
testCss = {css: '\n div {\n display: block;\n }',
js:'\n css(".class { display: none; }")\n '}
parseReturn = testParser.split(testJcss)
})
it('should return an array of three strings, the first is either js or css, the second is code and the third is the rest', function () {
assert.equal('object', typeof parseReturn)
assert.equal('string', typeof parseReturn[1])
assert.equal('string', typeof parseReturn[0])
assert.equal(3, parseReturn.length)
assert.ok(parseReturn[0] == 'js' || parseReturn[0] == 'css')
})
it('should interpret all line endings before and after css as css', function () {
assert.equal('\n', parseReturn[1][0])
assert.equal('\n', parseReturn[1][parseReturn[1].length - 1])
assert.equal('\n', parseReturn[1][parseReturn[1].length - 2])
})
it('should be able to handle only js or only css', function () {
var testParser = new Parser
assert.equal('css("div{display:block;}")', testParser.split('css("div{display:block;}")')[1])
assert.equal('div{display:block;}', testParser.split('div{display:block;}')[1])
})
it('should return false if the passed string is empty', function () {
var testParser = new Parser
assert.equal(false, testParser.split(''))
})
it('should mark css and js as such', function () {
var testParser = new Parser
assert.equal('div {\n display: block;\n }\n',
testParser.split('div {\n display: block;\n }\n \n for(var i = 10; i < 0; i--) {\n css(\'troll\')\n }\n ')[1])
assert.equal(' \n for(var i = 10; i < 0; i--) {\n css(\'troll\')\n }\n ',
testParser.split(' \n for(var i = 10; i < 0; i--) {\n css(\'troll\')\n }\n ')[1])
})
it('should return the rest as the third position and false if there is nothing left', function () {
var testParser = new Parser
assert.equal(' \n for(var i = 10; i < 0; i--) {\n css(\'troll\')\n }\n ',
testParser.split('div {\n display: block;\n }\n \n for(var i = 10; i < 0; i--) {\n css(\'troll\')\n }\n ')[2])
assert.equal(false,
testParser.split('div {\n display: block;\n }')[2])
})
it('should know all css selectors', function () {
var testParser = new Parser
var testCss = '{display: block;}'
assert.equal('css', testParser.split('*' + testCss)[0])
assert.equal('css', testParser.split('E' + testCss)[0])
assert.equal('css', testParser.split('E[foo]' + testCss)[0])
assert.equal('css', testParser.split('E[foo="bar"]' + testCss)[0])
assert.equal('css', testParser.split('E[foo~="bar"]' + testCss)[0])
assert.equal('css', testParser.split('E[foo^="bar"]' + testCss)[0])
assert.equal('css', testParser.split('E[foo$="bar"]' + testCss)[0])
assert.equal('css', testParser.split('E[foo*="bar"]' + testCss)[0])
assert.equal('css', testParser.split('E[foo|="en"]' + testCss)[0])
assert.equal('css', testParser.split('E:root' + testCss)[0])
assert.equal('css', testParser.split('E:nth-child(n)' + testCss)[0])
assert.equal('css', testParser.split('E:nth-last-child(n)' + testCss)[0])
assert.equal('css', testParser.split('E:nth-of-type(n)' + testCss)[0])
assert.equal('css', testParser.split('E:nth-last-of-type(n)' + testCss)[0])
assert.equal('css', testParser.split('E:first-child' + testCss)[0])
assert.equal('css', testParser.split('E:last-child' + testCss)[0])
assert.equal('css', testParser.split('E:first-of-type' + testCss)[0])
assert.equal('css', testParser.split('E:last-of-type' + testCss)[0])
assert.equal('css', testParser.split('E:only-child' + testCss)[0])
assert.equal('css', testParser.split('E:only-of-type' + testCss)[0])
assert.equal('css', testParser.split('E:empty' + testCss)[0])
assert.equal('css', testParser.split('E:link' + testCss)[0])
assert.equal('css', testParser.split('E:visited' + testCss)[0])
assert.equal('css', testParser.split('E:active' + testCss)[0])
assert.equal('css', testParser.split('E:hover' + testCss)[0])
assert.equal('css', testParser.split('E:focus' + testCss)[0])
assert.equal('css', testParser.split('E:target' + testCss)[0])
assert.equal('css', testParser.split('E:lang(fr)' + testCss)[0])
assert.equal('css', testParser.split('E:enabled' + testCss)[0])
assert.equal('css', testParser.split('E:disabled' + testCss)[0])
assert.equal('css', testParser.split('E:checked' + testCss)[0])
assert.equal('css', testParser.split('E::first-line' + testCss)[0])
assert.equal('css', testParser.split('E::first-letter' + testCss)[0])
assert.equal('css', testParser.split('E::before' + testCss)[0])
assert.equal('css', testParser.split('E::after' + testCss)[0])
assert.equal('css', testParser.split('E.warning' + testCss)[0])
assert.equal('css', testParser.split('E#myid' + testCss)[0])
assert.equal('css', testParser.split('E:not(s)' + testCss)[0])
assert.equal('css', testParser.split('E F' + testCss)[0])
assert.equal('css', testParser.split('E > F' + testCss)[0])
assert.equal('css', testParser.split('E + F' + testCss)[0])
assert.equal('css', testParser.split('E ~ F' + testCss)[0])
})
it('should be able to recognize mediaqueries as such', function () {
var testParser = new Parser
assert.equal('css', testParser.split('@media all and (min-width:500px) { … }')[0])
assert.equal('css', testParser.split('@media (min-width:500px) { … }')[0])
assert.equal('css', testParser.split('@media (orientation: portrait) { … }')[0])
assert.equal('css', testParser.split('@media all and (orientation: portrait) { … }')[0])
assert.equal('css', testParser.split('@media screen and (color), projection and (color) { … }')[0])
assert.equal('css', testParser.split('@media all and (min-color: 2) { … }')[0])
assert.equal('css', testParser.split('@media all { … }')[0])
assert.equal('css', testParser.split('@media { … }')[0])
})
it('should recognize all js as not css', function () {
var testParser = new Parser
assert.equal('js', testParser.split('if(true) {return false}')[0])
assert.equal('js', testParser.split('if(x = y) return something')[0])
assert.equal('js', testParser.split('while(someFun()) {i++}')[0])
assert.equal('js', testParser.split('arr[0] = {i: y}')[0])
assert.equal('js', testParser.split('arr[\'d\'] = {i: y}')[0])
assert.equal('js', testParser.split('arr[\'d\']={i: y}')[0])
})
it('should pass all css in strings as javascript', function () {
var testParser = new Parser
assert.equal('js', testParser.split('css(\'\
div {\
display: block;\
}\')')[0])
assert.equal('js', testParser.split('css(\'\n div {\n display: block;\n }\')')[0])
})
})
describe('parseCssVars', function () {
it('should take a string and return one', function () {
var testParser = new Parser
assert.equal('string', typeof testParser.parseCssVars(''))
})
it('should replace variables starting with `$.` with its values', function () {
var testParser = new Parser
testParser.context.$ = { s: 'something' }
assert.equal('something', testParser.parseCssVars('$.s'))
})
it('should replace function calls starting with `$.` with its return values', function () {
var testParser = new Parser
var someString = 'someString'
testParser.context.$ = { f: function () { return someString } }
assert.equal(someString, testParser.parseCssVars('$.f()'))
})
it('should be able to handle arguments passed to functions', function () {
var testParser = new Parser
testParser.context.$ = { add: function (n0, n1) { return n0 + n1 } }
assert.equal(2, testParser.parseCssVars('$.add(1,1)'))
})
it('should be able to pick out vars in the middle of css', function () {
var testParser = new Parser
testParser.context.$ = { str: 'block' }
assert.equal('div { display: block; }', testParser.parseCssVars('div { display: $.str; }'))
})
})
describe('splitAroundSubstring', function () {
it('should take two strings as arguments', function () {
var testParser = new Parser
assert.ok(testParser.splitAroundSubstring(' 1', ' 1 '))
})
it('should return an array of two strings', function () {
var testParser = new Parser
assert.equal('object', typeof testParser.splitAroundSubstring(' 1', ' 1 '))
assert.equal(2, testParser.splitAroundSubstring(' 1', ' 1 ').length)
assert.equal('string', typeof testParser.splitAroundSubstring(' 1', ' 1 ')[0])
assert.equal('string', typeof testParser.splitAroundSubstring(' 1', ' 1 ')[1])
})
it('should return two substrings of the second', function () {
var testParser = new Parser
var s1 = ' 1'
var s2 = ' 1 '
assert.ok(s2.indexOf(testParser.splitAroundSubstring(s1, s2)[0]) > -1)
assert.ok(s2.indexOf(testParser.splitAroundSubstring(s1, s2)[1]) > -1)
})
it('should return everything before the passed substring as the first return value if there is anything', function () {
var testParser = new Parser
assert.equal(' ', testParser.splitAroundSubstring('1 ', ' 1 ')[0])
})
it('should return a string including the substring as the second return value if the substring isn\'t at the start of the string', function () {
var testParser = new Parser
assert.equal('1 -', testParser.splitAroundSubstring('1 ', ' 1 -')[1])
})
})
describe('exec', function () {
it('should return a string', function () {
var testParser = new Parser
assert.equal('string', typeof testParser.exec(''))
})
it('should return false if the string that is passed isn\'t valid JS.', function () {
var testParser = new Parser
assert.equal(false, testParser.exec('yourmum'))
})
it('should provide a function `css` to the JS beeing execute', function () {
var testParser = new Parser
assert.equal('display: block', testParser.exec('css("display: block")'))
})
it('should exec JS', function () {
var testParser = new Parser
assert.equal('asdf', testParser.exec('["a", "s", "d", "f"].forEach(function (value) { css(value) })'))
})
it('should provide the require methode', function () {
var testParser = new Parser
assert.equal('function', testParser.exec('css(typeof require)'))
assert.equal('function', testParser.exec('css(typeof require(\'underscore\'))'))
})
})
describe('funcsToString', function () {
it('should take an array of functions as an argument', function () {
var testParser = new Parser
assert.ok(testParser.funcsToString([function a () {}]))
})
it('should return a string', function () {
var testParser = new Parser
assert.equal('string', typeof testParser.funcsToString([function a () {}]))
})
it('should join the functions with newlines', function () {
var testParser = new Parser
assert.ok(testParser.funcsToString([function a () {}, function a () {}]).indexOf('\n') > -1)
})
it('should add a newline in to the beginning of the string', function () {
var testParser = new Parser
assert.equal('\n', testParser.funcsToString([function a () {}])[0])
})
})
describe('include', function () {
var testDirectory = 'test7'
var testFile = testDirectory + '/testfile.jsheet'
before(function () {
fs.mkdirSync(testDirectory)
fs.writeFileSync(testFile, ' ')
})
it('should read and parse a jsheets file', function () {
var testParser = new Parser
var testFile = './testfile.jsheet'
fs.writeFileSync(testFile, 'css(\'div{display: block}\')')
assert.equal('div{display: block}', testParser.include(testFile))
fs.unlink(testFile)
})
it('should log an error and return an empty string if the jsheets is invalid or if the file doesn\'t exsist', function () {
var testParser = new Parser
var testFile = './testfile.jsheet'
assert.equal('', testParser.include('asddgere.cevrscs'))
fs.writeFileSync(testFile, 'css(\'div{display: block}\')yoomum')
assert.equal('', testParser.include(testFile))
fs.unlink(testFile)
})
it('execute in the same context, but empty the hooks', function () {
var testParser = new Parser
var testFile = './testfile.jsheet'
testParser.context.globalVar = true
fs.writeFileSync(testFile, '$.testVar = true; globalVar = false; onEOF.push(function () {})')
testParser.include(testFile)
assert.equal(true, testParser.context.$.testVar)
assert.ok(!testParser.context.globalVar)
assert.equal(0, testParser.context.hooks.EOF.length)
fs.unlink(testFile)
})
it('should be able to take whole directories as an argument', function () {
var testParser = new Parser
assert.equal('string', typeof testParser.include(testDirectory))
})
after(function () {
fs.unlinkSync(testFile)
fs.rmdirSync(testDirectory)
})
})
describe('makeIncludes', function () {
it('should replace calles to include in parsed jsheets files', function () {
var testParser = new Parser
var testFile = './testfile.jsheet'
fs.writeFileSync(testFile, 'css(\'div{display: block}\')')
assert.equal('div{display: block}', testParser.makeIncludes('include \'' + testFile + '\''))
fs.unlink(testFile)
})
})
describe('cleanContext', function () {
it('should clear the returnString', function () {
var testParser = new Parser
testParser.context.returnString = 'css'
testParser.cleanContext()
assert.equal('', testParser.context.returnString)
})
it('should return the current returnString', function () {
var testParser = new Parser
testParser.context.returnString = 'css'
assert.equal('css', testParser.cleanContext())
})
})
describe('mergeContext', function () {
it('should merge the passed context with this.context', function () {
var testParser = new Parser
var test2Parser = new Parser
testParser.context.somevar = true
testParser.mergeContext(test2Parser.context)
assert.ok(testParser.context.somevar)
})
})
})