libcss-w3d
Version:
CSS parser and selection library with w3d properties.
255 lines (222 loc) • 6.96 kB
JavaScript
/*
* test.js
* Copyright 2017 Lucas Neves <lcneves@gmail.com>
*
* This test uses the data file for NetSurf libcss's selection test.
* Part of the libcss.js project.
*/
;
const path = require('path');
const fs = require('fs');
const libcss = require('../index.js');
const DEFAULT_FONT_SIZE = 12;
const textRed = "\x1b[31m";
const textGreen = "\x1b[32m";
const textReset = "\x1b[0m";
var root = null;
var count = 0;
var elements = {};
var origin = '';
var media = '';
var targetMedia = '';
var succeeded = true;
function getElementById (identifier) {
if (typeof elements[identifier] === 'undefined')
throw new Error('Unable to find element with identifier "' + identifier
+ '"!');
return elements[identifier];
}
var handlers = {
getTagName: function (identifier) {
var element = getElementById(identifier);
return element.tagName;
},
getAttributes: function (identifier) {
var element = getElementById(identifier);
return element.attributes;
},
getSiblings: function (identifier) {
var element = getElementById(identifier);
var siblings = [];
if (element.parent && element.parent.tagName !== 'root') {
for (let child of element.parent.children) {
siblings.push({ tagName: child.tagName, identifier: child.id });
}
}
return siblings;
},
getAncestors: function (identifier) {
var element = getElementById(identifier);
var ancestors = [];
while (element.parent && element.parent.tagName !== 'root') {
element = element.parent;
ancestors.push({ tagName: element.tagName, identifier: element.id });
}
return ancestors;
},
isEmpty: function (identifier) {
var element = getElementById(identifier);
return (element.children[0] === undefined);
},
uaFontSize: function () {
return DEFAULT_FONT_SIZE * 10;
}
};
libcss.init(handlers);
function makeElement (tagName, parentElement, num) {
var element = {
id: num.toString(),
tagName: tagName,
children: [],
attributes: []
};
element.parent = parentElement;
if (parentElement && Array.isArray(parentElement.children)) {
parentElement.children.push(element);
}
elements[element.id] = element;
return element;
}
function parseExpected (data) {
var resultsArr = data.split('\n');
var resultsObj = {};
for (let line of resultsArr) {
let colon = line.indexOf(':');
if (colon > 0) {
let prop = line.substring(0, colon).trim();
let value = line.substring(colon + 1).trim();
resultsObj[prop] = value;
}
}
return resultsObj;
}
function elementDepth (line) {
var i = 0;
while (line[i] === ' ') i++;
return i;
}
function findParent(currentElement, currentDepth, newDepth) {
var parentElement = currentElement;
for (let i = newDepth; i - currentDepth < 1; i++) {
parentElement = parentElement.parent;
}
return parentElement;
}
var testFiles = [ 'tests1.dat', 'w3d.dat' ];
var paths = [];
// Attempt to find .dat files in LibCSS's select test dir; fallback to current
// directory if not found.
for (let f of testFiles) {
var dat_path = path.join(__dirname, '..', 'src', 'libcss-w3d', 'test', 'data',
'select', f);
try {
fs.statSync(dat_path, fs.constants.R_OK);
} catch (e) {
dat_path = path.join(__dirname, f);
}
paths.push(dat_path);
}
for (let dat_path of paths) {
runTest(dat_path);
}
function runTest (dat_path) {
var data = fs.readFileSync(dat_path, 'utf8');
console.info('Using data file ' + dat_path);
var testDataArr = data.split('#reset').map((item) => item.trim());
var testNum = 1;
for (let testData of testDataArr) {
if (!testData) continue;
if (testData.indexOf('#expected') === -1) continue;
let testParts = testData.split('#expected').map((item) => item.trim());
let expectedResults = parseExpected(testParts[1]);
root = makeElement('root', null, count++);
let currentElement = root;
let currentDepth = 0;
let queryElement = null;
let parsedCSS = [];
let lines = testParts[0].split('\n').map((item) => item.trim());
for (let line of lines) {
if (!line || line.indexOf('#') === 0) {
let lineArr = line.substring(1).trim().split(' ');
switch (lineArr[0]) {
case 'ua':
case 'user':
case 'author':
origin = lineArr[0];
media = (lineArr[1] === undefined) ? ['all'] : [lineArr[1]];
continue;
case 'tree':
targetMedia = (lineArr[1] === undefined) ? 'all' : lineArr[1];
continue;
case 'errors':
continue;
default:
// Must be CSS starting with an id selector
break;
}
}
if (line.indexOf('|') === 0) {
line = line.substring(1);
if (line.indexOf('=') !== -1) {
let params = line.split('=').map((item) => item.trim());
let attribute = { attribute: params[0], value: params[1] };
currentElement.attributes.push(attribute);
}
else {
let depth = elementDepth(line);
let parentElement = findParent(currentElement, currentDepth, depth);
let query = false;
let starIndex = line.indexOf('*');
if (starIndex !== -1) {
query = true;
line = line.slice(0, -1);
}
let newElement = makeElement(line.trim(), parentElement, count++);
if (query) {
queryElement = newElement;
}
currentElement = newElement;
currentDepth = depth;
}
}
else {
parsedCSS.push({ css: line, origin: origin, media: media });
libcss.addSheet(line, { origin: origin, media: media });
}
}
let results = libcss.getStyle(queryElement.id, { media: targetMedia });
let err = '';
for (let property in expectedResults) {
if (expectedResults.hasOwnProperty(property)) {
if (results[property] !== expectedResults[property]) {
err +=
'Expected: ' + property + ': ' + expectedResults[property] + '\n'
+ 'Verified: ' + property + ': ' + results[property] + '\n';
}
}
}
if (err) {
succeeded = false;
console.log('\n');
console.error('Test ' + testNum + textRed + ' FAIL!' + textReset);
console.error(err);
console.info('Tree:');
console.dir(root, { depth: null });
console.info('Querying element: ' + queryElement.id);
console.info("Querying media: " + targetMedia);
console.info('CSS:');
console.dir(parsedCSS);
console.log('\n');
} else {
console.info('Test ' + testNum + textGreen + ' PASS!' + textReset);
}
testNum++;
elements = {};
libcss.dropSheets();
}
if (succeeded)
console.info('Selection test succeeded!');
else
throw new Error('Selection test failed!');
console.log('');
}