Files
postcss/test/parse.js
T

144 lines
4.6 KiB
JavaScript

var Root = require('../lib/root');
var parse = require('../lib/parse');
var fs = require('fs');
var path = require('path');
var read = file => fs.readFileSync(__dirname + '/cases/parse/' + file);
describe('postcss.parse()', () => {
it('works with file reads', () => {
var css = fs.readFileSync(__dirname + '/cases/parse/atrule-empty.css');
parse(css).should.be.instanceOf(Root);
});
describe('empty file', () => {
it('parses UTF-8 BOM', () => {
parse('\uFEFF@host { a {\f} }');
});
it('parses empty file', () => {
parse('').should.eql({ type: 'root', rules: [], after: '' });
});
it('parses spaces', () => {
parse(" \n").should.eql({ type: 'root', rules: [], after: " \n" });
});
});
fs.readdirSync(__dirname + '/cases/parse/').forEach( (file) => {
if ( !file.match(/\.css$/) ) return;
it('parses ' + file, () => {
var css = parse(read(file), { from: '/' + file });
var json = read(file.replace(/\.css$/, '.json')).toString().trim();
JSON.stringify(css, null, 4).should.eql(json);
});
});
it('saves source file', () => {
var css = parse('a {}', { from: 'a.css' });
css.rules[0].source.file.should.eql(path.resolve('a.css'));
});
it('sets unique ID for file without name', () => {
var css1 = parse('a {}');
var css2 = parse('a {}');
css1.rules[0].source.id.should.match(/^\d+$/);
css2.rules[0].source.id.should.not.eql(css1.rules[0].source.id);
});
it('sets parent node', () => {
var css = parse(read('atrule-rules.css'));
var support = css.rules[0];
var keyframes = support.rules[0];
var from = keyframes.rules[0];
var decl = from.decls[0];
decl.parent.should.exactly(from);
from.parent.should.exactly(keyframes);
keyframes.parent.should.exactly(support);
support.parent.should.exactly(css);
});
describe('errors', () => {
it('throws on unclosed blocks', () => {
( () => parse('\na {\n') ).should
.throw(/:2:1: Unclosed block/);
});
it('fixes unclosed blocks in safe mode', () => {
parse('@media (screen) { a {\n', { safe: true })
.toString().should.eql('@media (screen) { a {\n}}');
parse('a { color', { safe: true })
.first.first.prop.should.eql('color');
});
it('throws on unnecessary block close', () => {
( () => parse('a {\n} }') ).should
.throw(/:2:3: Unexpected }/);
});
it('fixes unnecessary block close in safe mode', () => {
var root = parse('a {\n} }', { safe: true });
root.first.toString().should.eql('a {\n}');
root.after.should.eql(' }');
});
it('throws on unclosed comment', () => {
( () => parse('\n/*\n\n ') ).should
.throw(/:2:1: Unclosed comment/);
});
it('fixes unclosed comment in safe mode', () => {
var root = parse('a { /* b ', { safe: true });
root.toString().should.eql('a { /* b */}');
root.first.first.text.should.eql('b');
});
it('throws on unclosed quote', () => {
( () => parse('\n"\n\na ') ).should
.throw(/:2:1: Unclosed quote/);
});
it('fixes unclosed quote in safe mode', () => {
parse('a { content: "b', { safe: true }).
toString().should.eql('a { content: "b}');
});
it('throws on property without value', () => {
( () => parse("a { b;}") ).should
.throw(/Missing property value/);
( () => parse("a { b }") ).should
.throw(/Missing property value/);
});
it('fixes property without value in safe mode', () => {
var root = parse('a { color: white; one }', { safe: true });
root.first.decls.length.should.eql(1);
root.first.semicolon.should.be.true;
root.first.after.should.eql(' one ');
});
it('throws on nameless at-rule', () => {
( () => parse('@') ).should.throw(/At-rule without name/);
});
it('throws on block inside declarations', () => {
( () => parse("a {{}}") ).should.throw(/Unexpected \{/);
});
it('throw on rules in declarations at-rule', () => {
( () => parse('@page { a { } }') ).should.throw(/Unexpected \{/);
});
});
});