Migration datamodels !
This commit is contained in:
9
node_modules/less/test/.eslintrc.json
generated
vendored
Normal file
9
node_modules/less/test/.eslintrc.json
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"browser": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6
|
||||
}
|
||||
}
|
||||
3
node_modules/less/test/README.md
generated
vendored
Normal file
3
node_modules/less/test/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Tests are generally organized in the `less/` folder by what options are set in index.js.
|
||||
|
||||
The main tests are located under `less/_main/`
|
||||
251
node_modules/less/test/browser/common.js
generated
vendored
Normal file
251
node_modules/less/test/browser/common.js
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
var logMessages = [];
|
||||
window.less = window.less || {};
|
||||
|
||||
var logLevel_debug = 4,
|
||||
logLevel_info = 3,
|
||||
logLevel_warn = 2,
|
||||
logLevel_error = 1;
|
||||
|
||||
// The amount of logging in the javascript console.
|
||||
// 3 - Debug, information and errors
|
||||
// 2 - Information and errors
|
||||
// 1 - Errors
|
||||
// 0 - None
|
||||
// Defaults to 2
|
||||
|
||||
less.loggers = [
|
||||
{
|
||||
debug: function(msg) {
|
||||
if (less.options.logLevel >= logLevel_debug) {
|
||||
logMessages.push(msg);
|
||||
}
|
||||
},
|
||||
info: function(msg) {
|
||||
if (less.options.logLevel >= logLevel_info) {
|
||||
logMessages.push(msg);
|
||||
}
|
||||
},
|
||||
warn: function(msg) {
|
||||
if (less.options.logLevel >= logLevel_warn) {
|
||||
logMessages.push(msg);
|
||||
}
|
||||
},
|
||||
error: function(msg) {
|
||||
if (less.options.logLevel >= logLevel_error) {
|
||||
logMessages.push(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
testLessEqualsInDocument = function () {
|
||||
testLessInDocument(testSheet);
|
||||
};
|
||||
|
||||
testLessErrorsInDocument = function (isConsole) {
|
||||
testLessInDocument(isConsole ? testErrorSheetConsole : testErrorSheet);
|
||||
};
|
||||
|
||||
testLessInDocument = function (testFunc) {
|
||||
var links = document.getElementsByTagName('link'),
|
||||
typePattern = /^text\/(x-)?less$/;
|
||||
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
|
||||
(links[i].type.match(typePattern)))) {
|
||||
testFunc(links[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ieFormat = function(text) {
|
||||
var styleNode = document.createElement('style');
|
||||
styleNode.setAttribute('type', 'text/css');
|
||||
var headNode = document.getElementsByTagName('head')[0];
|
||||
headNode.appendChild(styleNode);
|
||||
try {
|
||||
if (styleNode.styleSheet) {
|
||||
styleNode.styleSheet.cssText = text;
|
||||
} else {
|
||||
styleNode.innerText = text;
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error('Couldn\'t reassign styleSheet.cssText.');
|
||||
}
|
||||
var transformedText = styleNode.styleSheet ? styleNode.styleSheet.cssText : styleNode.innerText;
|
||||
headNode.removeChild(styleNode);
|
||||
return transformedText;
|
||||
};
|
||||
|
||||
testSheet = function (sheet) {
|
||||
it(sheet.id + ' should match the expected output', function (done) {
|
||||
var lessOutputId = sheet.id.replace('original-', ''),
|
||||
expectedOutputId = 'expected-' + lessOutputId,
|
||||
lessOutputObj,
|
||||
lessOutput,
|
||||
expectedOutputHref = document.getElementById(expectedOutputId).href,
|
||||
expectedOutput = loadFile(expectedOutputHref);
|
||||
|
||||
// Browser spec generates less on the fly, so we need to loose control
|
||||
less.pageLoadFinished
|
||||
.then(function () {
|
||||
lessOutputObj = document.getElementById(lessOutputId);
|
||||
lessOutput = lessOutputObj.styleSheet ? lessOutputObj.styleSheet.cssText :
|
||||
(lessOutputObj.innerText || lessOutputObj.innerHTML);
|
||||
|
||||
expectedOutput
|
||||
.then(function (text) {
|
||||
if (window.navigator.userAgent.indexOf('MSIE') >= 0 ||
|
||||
window.navigator.userAgent.indexOf('Trident/') >= 0) {
|
||||
text = ieFormat(text);
|
||||
}
|
||||
|
||||
// Normalize URLs: convert absolute URLs back to relative for comparison
|
||||
// The browser resolves relative URLs when reading from DOM, but we want to compare against the original relative URLs
|
||||
lessOutput = lessOutput.replace(/url\("http:\/\/localhost:8081\/packages\/less\/node_modules\/@less\/test-data\/tests-unit\/([^"]+)"\)/g, 'url("$1")');
|
||||
// Also normalize directory-prefixed relative URLs (e.g., "at-rules/myfont.woff2" -> "myfont.woff2")
|
||||
// This happens because the browser resolves URLs relative to the HTML document location
|
||||
lessOutput = lessOutput.replace(/url\("([a-z-]+\/)([^"]+)"\)/g, 'url("$2")');
|
||||
// Also normalize @import statements that get resolved to absolute URLs
|
||||
lessOutput = lessOutput.replace(/@import "http:\/\/localhost:8081\/packages\/less\/node_modules\/@less\/test-data\/tests-unit\/([^"]+)"(.*);/g, '@import "$1"$2;');
|
||||
// Also normalize @import with directory prefix (e.g., "at-rules-keyword-comments/test.css" -> "test.css")
|
||||
lessOutput = lessOutput.replace(/@import "([a-z-]+\/)([^"]+)"(.*);/g, '@import "$2"$3;');
|
||||
|
||||
expect(lessOutput).to.equal(text);
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: do it cleaner - the same way as in css
|
||||
|
||||
function extractId(href) {
|
||||
return href.replace(/^[a-z-]+:\/+?[^\/]+/i, '') // Remove protocol & domain
|
||||
.replace(/^\//, '') // Remove root /
|
||||
.replace(/\.[a-zA-Z]+$/, '') // Remove simple extension
|
||||
.replace(/[^\.\w-]+/g, '-') // Replace illegal characters
|
||||
.replace(/\./g, ':'); // Replace dots with colons(for valid id)
|
||||
}
|
||||
|
||||
waitFor = function (waitFunc) {
|
||||
return new Promise(function (resolve) {
|
||||
var timeoutId = setInterval(function () {
|
||||
if (waitFunc()) {
|
||||
clearInterval(timeoutId);
|
||||
resolve();
|
||||
}
|
||||
}, 5);
|
||||
});
|
||||
};
|
||||
|
||||
testErrorSheet = function (sheet) {
|
||||
it(sheet.id + ' should match an error', function (done) {
|
||||
var lessHref = sheet.href,
|
||||
id = 'less-error-message:' + extractId(lessHref),
|
||||
errorHref = lessHref.replace(/.less$/, '.txt'),
|
||||
errorFile = loadFile(errorHref),
|
||||
actualErrorElement,
|
||||
actualErrorMsg;
|
||||
|
||||
// Less.js sets 10ms timer in order to add error message on top of page.
|
||||
waitFor(function () {
|
||||
actualErrorElement = document.getElementById(id);
|
||||
return actualErrorElement !== null;
|
||||
}).then(function () {
|
||||
var innerText = (actualErrorElement.innerHTML
|
||||
.replace(/<h3>|<\/?p>|<a href="[^"]*">|<\/a>|<ul>|<\/?pre( class="?[^">]*"?)?>|<\/li>|<\/?label>/ig, '')
|
||||
.replace(/<\/h3>/ig, ' ')
|
||||
.replace(/<li>|<\/ul>|<br>/ig, '\n'))
|
||||
.replace(/&/ig, '&')
|
||||
// for IE8
|
||||
.replace(/\r\n/g, '\n')
|
||||
.replace(/\. \nin/, '. in');
|
||||
actualErrorMsg = innerText
|
||||
.replace(/\n\d+/g, function (lineNo) {
|
||||
return lineNo + ' ';
|
||||
})
|
||||
.replace(/\n\s*in /g, ' in ')
|
||||
.replace(/\n{2,}/g, '\n')
|
||||
.replace(/\nStack Trace\n[\s\S]*/i, '')
|
||||
.replace(/\n$/, '')
|
||||
.trim();
|
||||
actualErrorMsg = actualErrorMsg
|
||||
.replace(/ in [\w\-]+\.less( on line \d+, column \d+)?:?$/, '') // Remove filename and optional line/column from end of error message
|
||||
.replace(/\{path\}/g, '')
|
||||
.replace(/\{pathrel\}/g, '')
|
||||
.replace(/\{pathhref\}/g, 'http://localhost:8081/packages/less/node_modules/@less/test-data/tests-error/eval/')
|
||||
.replace(/\{404status\}/g, ' (404)')
|
||||
.replace(/\{node\}[\s\S]*\{\/node\}/g, '')
|
||||
.replace(/\n$/, '')
|
||||
.trim();
|
||||
errorFile
|
||||
.then(function (errorTxt) {
|
||||
errorTxt = errorTxt
|
||||
.replace(/\{path\}/g, '')
|
||||
.replace(/\{pathrel\}/g, '')
|
||||
.replace(/\{pathhref\}/g, 'http://localhost:8081/packages/less/node_modules/@less/test-data/tests-error/eval/')
|
||||
.replace(/\{404status\}/g, ' (404)')
|
||||
.replace(/\{node\}[\s\S]*\{\/node\}/g, '')
|
||||
.replace(/\n$/, '')
|
||||
.trim();
|
||||
expect(actualErrorMsg).to.equal(errorTxt);
|
||||
if (errorTxt == actualErrorMsg) {
|
||||
actualErrorElement.style.display = 'none';
|
||||
}
|
||||
done();
|
||||
})
|
||||
.catch(function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
testErrorSheetConsole = function (sheet) {
|
||||
it(sheet.id + ' should match an error', function (done) {
|
||||
var lessHref = sheet.href,
|
||||
id = sheet.id.replace(/^original-less:/, 'less-error-message:'),
|
||||
errorHref = lessHref.replace(/.less$/, '.txt'),
|
||||
errorFile = loadFile(errorHref),
|
||||
actualErrorElement = document.getElementById(id),
|
||||
actualErrorMsg = logMessages[logMessages.length - 1]
|
||||
.replace(/\nStack Trace\n[\s\S]*/, '');
|
||||
|
||||
describe('the error', function () {
|
||||
expect(actualErrorElement).to.be.null;
|
||||
});
|
||||
|
||||
errorFile
|
||||
.then(function (errorTxt) {
|
||||
errorTxt
|
||||
.replace(/\{path\}/g, '')
|
||||
.replace(/\{pathrel\}/g, '')
|
||||
.replace(/\{pathhref\}/g, 'http://localhost:8081/browser/less/')
|
||||
.replace(/\{404status\}/g, ' (404)')
|
||||
.replace(/\{node\}.*\{\/node\}/g, '')
|
||||
.trim();
|
||||
expect(actualErrorMsg).to.equal(errorTxt);
|
||||
done();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
loadFile = function (href) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('GET', href, true);
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
resolve(request.responseText.replace(/\r/g, ''));
|
||||
}
|
||||
};
|
||||
request.send(null);
|
||||
});
|
||||
};
|
||||
3
node_modules/less/test/browser/css/global-vars/simple.css
generated
vendored
Normal file
3
node_modules/less/test/browser/css/global-vars/simple.css
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.test {
|
||||
color: red;
|
||||
}
|
||||
8
node_modules/less/test/browser/css/modify-vars/simple.css
generated
vendored
Normal file
8
node_modules/less/test/browser/css/modify-vars/simple.css
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
.testisimported {
|
||||
color: gainsboro;
|
||||
}
|
||||
.test {
|
||||
color1: green;
|
||||
color2: purple;
|
||||
scalar: 20;
|
||||
}
|
||||
3
node_modules/less/test/browser/css/plugin/plugin.css
generated
vendored
Normal file
3
node_modules/less/test/browser/css/plugin/plugin.css
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.test {
|
||||
val: http://localhost:8081/packages/less/tmp/browser/test-runner-browser.html;
|
||||
}
|
||||
4
node_modules/less/test/browser/css/postProcessor/postProcessor.css
generated
vendored
Normal file
4
node_modules/less/test/browser/css/postProcessor/postProcessor.css
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
hr {height:50px;}
|
||||
.test {
|
||||
color: white;
|
||||
}
|
||||
36
node_modules/less/test/browser/css/relative-urls/urls.css
generated
vendored
Normal file
36
node_modules/less/test/browser/css/relative-urls/urls.css
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/modify-this.css";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/modify-again.css";
|
||||
.modify {
|
||||
my-url: url("http://localhost:8081/packages/less/test/browser/less/imports/a.png");
|
||||
}
|
||||
.modify {
|
||||
my-url: url("http://localhost:8081/packages/less/test/browser/less/imports/b.png");
|
||||
}
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium), url(http://localhost:8081/packages/less/test/browser/less/relative-urls/fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(http://localhost:8081/packages/less/test/browser/less/relative-urls/images/image.jpg);
|
||||
background: url("#inline-svg");
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
.comma-delimited {
|
||||
background: url(http://localhost:8081/packages/less/test/browser/less/relative-urls/bg.jpg) no-repeat, url(http://localhost:8081/packages/less/test/browser/less/relative-urls/bg.png) repeat-x top left, url(http://localhost:8081/packages/less/test/browser/less/relative-urls/bg);
|
||||
}
|
||||
.values {
|
||||
url: url('http://localhost:8081/packages/less/test/browser/less/relative-urls/Trebuchet');
|
||||
}
|
||||
36
node_modules/less/test/browser/css/rewrite-urls/urls.css
generated
vendored
Normal file
36
node_modules/less/test/browser/css/rewrite-urls/urls.css
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/modify-this.css";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/modify-again.css";
|
||||
.modify {
|
||||
my-url: url("http://localhost:8081/packages/less/test/browser/less/imports/a.png");
|
||||
}
|
||||
.modify {
|
||||
my-url: url("http://localhost:8081/packages/less/test/browser/less/imports/b.png");
|
||||
}
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium), url(http://localhost:8081/packages/less/test/browser/less/rewrite-urls/fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(http://localhost:8081/packages/less/test/browser/less/rewrite-urls/images/image.jpg);
|
||||
background: url("#inline-svg");
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
.comma-delimited {
|
||||
background: url(http://localhost:8081/packages/less/test/browser/less/rewrite-urls/bg.jpg) no-repeat, url(http://localhost:8081/packages/less/test/browser/less/rewrite-urls/bg.png) repeat-x top left, url(http://localhost:8081/packages/less/test/browser/less/rewrite-urls/bg);
|
||||
}
|
||||
.values {
|
||||
url: url('http://localhost:8081/packages/less/test/browser/less/rewrite-urls/Trebuchet');
|
||||
}
|
||||
35
node_modules/less/test/browser/css/rootpath-relative/urls.css
generated
vendored
Normal file
35
node_modules/less/test/browser/css/rootpath-relative/urls.css
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
@import "https://www.github.com/cloudhead/imports/modify-this.css";
|
||||
@import "https://www.github.com/cloudhead/imports/modify-again.css";
|
||||
.modify {
|
||||
my-url: url("https://www.github.com/cloudhead/imports/a.png");
|
||||
}
|
||||
.modify {
|
||||
my-url: url("https://www.github.com/cloudhead/imports/b.png");
|
||||
}
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium), url(https://www.github.com/cloudhead/less.js/fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(https://www.github.com/cloudhead/less.js/images/image.jpg);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
.comma-delimited {
|
||||
background: url(https://www.github.com/cloudhead/less.js/bg.jpg) no-repeat, url(https://www.github.com/cloudhead/less.js/bg.png) repeat-x top left, url(https://www.github.com/cloudhead/less.js/bg);
|
||||
}
|
||||
.values {
|
||||
url: url('https://www.github.com/cloudhead/less.js/Trebuchet');
|
||||
}
|
||||
35
node_modules/less/test/browser/css/rootpath-rewrite-urls/urls.css
generated
vendored
Normal file
35
node_modules/less/test/browser/css/rootpath-rewrite-urls/urls.css
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
@import "https://www.github.com/cloudhead/imports/modify-this.css";
|
||||
@import "https://www.github.com/cloudhead/imports/modify-again.css";
|
||||
.modify {
|
||||
my-url: url("https://www.github.com/cloudhead/imports/a.png");
|
||||
}
|
||||
.modify {
|
||||
my-url: url("https://www.github.com/cloudhead/imports/b.png");
|
||||
}
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium), url(https://www.github.com/cloudhead/less.js/fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(https://www.github.com/cloudhead/less.js/images/image.jpg);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
.comma-delimited {
|
||||
background: url(https://www.github.com/cloudhead/less.js/bg.jpg) no-repeat, url(https://www.github.com/cloudhead/less.js/bg.png) repeat-x top left, url(https://www.github.com/cloudhead/less.js/bg);
|
||||
}
|
||||
.values {
|
||||
url: url('https://www.github.com/cloudhead/less.js/Trebuchet');
|
||||
}
|
||||
35
node_modules/less/test/browser/css/rootpath/urls.css
generated
vendored
Normal file
35
node_modules/less/test/browser/css/rootpath/urls.css
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
@import "https://localhost/modify-this.css";
|
||||
@import "https://localhost/modify-again.css";
|
||||
.modify {
|
||||
my-url: url("https://localhost/a.png");
|
||||
}
|
||||
.modify {
|
||||
my-url: url("https://localhost/b.png");
|
||||
}
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium), url(https://localhost/fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(https://localhost/images/image.jpg);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
.comma-delimited {
|
||||
background: url(https://localhost/bg.jpg) no-repeat, url(https://localhost/bg.png) repeat-x top left, url(https://localhost/bg);
|
||||
}
|
||||
.values {
|
||||
url: url('https://localhost/Trebuchet');
|
||||
}
|
||||
54
node_modules/less/test/browser/css/urls.css
generated
vendored
Normal file
54
node_modules/less/test/browser/css/urls.css
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/modify-this.css";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/modify-again.css";
|
||||
.modify {
|
||||
my-url: url("http://localhost:8081/packages/less/test/browser/less/a.png");
|
||||
}
|
||||
.modify {
|
||||
my-url: url("http://localhost:8081/packages/less/test/browser/less/b.png");
|
||||
}
|
||||
.gray-gradient {
|
||||
background: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201%201%22%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%25%22%20y1%3D%220%25%22%20x2%3D%220%25%22%20y2%3D%22100%25%22%3E%3Cstop%20offset%3D%220%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220%22%2F%3E%3Cstop%20offset%3D%2260%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.05%22%2F%3E%3Cstop%20offset%3D%2270%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.1%22%2F%3E%3Cstop%20offset%3D%2273%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.15%22%2F%3E%3Cstop%20offset%3D%2275%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.2%22%2F%3E%3Cstop%20offset%3D%2280%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.25%22%2F%3E%3Cstop%20offset%3D%2285%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.3%22%2F%3E%3Cstop%20offset%3D%2288%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.35%22%2F%3E%3Cstop%20offset%3D%2290%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.4%22%2F%3E%3Cstop%20offset%3D%2295%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.45%22%2F%3E%3Cstop%20offset%3D%22100%25%22%20stop-color%3D%22%23999999%22%20stop-opacity%3D%220.5%22%2F%3E%3C%2FlinearGradient%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22url(%23g)%22%20%2F%3E%3C%2Fsvg%3E');
|
||||
}
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium), url(http://localhost:8081/packages/less/test/browser/less/fonts.svg#MyGeometricModern) format("svg");
|
||||
not-a-comment: url(//z);
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(http://localhost:8081/packages/less/test/browser/less/images/image.jpg);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
.comma-delimited {
|
||||
background: url(http://localhost:8081/packages/less/test/browser/less/bg.jpg) no-repeat, url(http://localhost:8081/packages/less/test/browser/less/bg.png) repeat-x top left, url(http://localhost:8081/packages/less/test/browser/less/bg);
|
||||
}
|
||||
.values {
|
||||
url: url('http://localhost:8081/packages/less/test/browser/less/Trebuchet');
|
||||
}
|
||||
#data-uri {
|
||||
uri: url('http://localhost:8081/packages/less/test/data/image.jpg');
|
||||
}
|
||||
#data-uri-guess {
|
||||
uri: url('http://localhost:8081/packages/less/test/data/image.jpg');
|
||||
}
|
||||
#data-uri-ascii {
|
||||
uri-1: url('http://localhost:8081/packages/less/test/data/page.html');
|
||||
uri-2: url('http://localhost:8081/packages/less/test/data/page.html');
|
||||
}
|
||||
#svg-functions {
|
||||
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201%201%22%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%25%22%20y1%3D%220%25%22%20x2%3D%220%25%22%20y2%3D%22100%25%22%3E%3Cstop%20offset%3D%220%25%22%20stop-color%3D%22%23000000%22%2F%3E%3Cstop%20offset%3D%22100%25%22%20stop-color%3D%22%23ffffff%22%2F%3E%3C%2FlinearGradient%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22url(%23g)%22%20%2F%3E%3C%2Fsvg%3E');
|
||||
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201%201%22%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%25%22%20y1%3D%220%25%22%20x2%3D%220%25%22%20y2%3D%22100%25%22%3E%3Cstop%20offset%3D%220%25%22%20stop-color%3D%22%23000000%22%2F%3E%3Cstop%20offset%3D%223%25%22%20stop-color%3D%22%23ffa500%22%2F%3E%3Cstop%20offset%3D%22100%25%22%20stop-color%3D%22%23ffffff%22%2F%3E%3C%2FlinearGradient%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22url(%23g)%22%20%2F%3E%3C%2Fsvg%3E');
|
||||
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201%201%22%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%25%22%20y1%3D%220%25%22%20x2%3D%220%25%22%20y2%3D%22100%25%22%3E%3Cstop%20offset%3D%221%25%22%20stop-color%3D%22%23c4c4c4%22%2F%3E%3Cstop%20offset%3D%223%25%22%20stop-color%3D%22%23ffa500%22%2F%3E%3Cstop%20offset%3D%225%25%22%20stop-color%3D%22%23008000%22%2F%3E%3Cstop%20offset%3D%2295%25%22%20stop-color%3D%22%23ffffff%22%2F%3E%3C%2FlinearGradient%3E%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%221%22%20height%3D%221%22%20fill%3D%22url(%23g)%22%20%2F%3E%3C%2Fsvg%3E');
|
||||
}
|
||||
50
node_modules/less/test/browser/generator/benchmark.config.js
generated
vendored
Normal file
50
node_modules/less/test/browser/generator/benchmark.config.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
module.exports = {
|
||||
current: {
|
||||
// src is used to build list of less files to compile
|
||||
src: [
|
||||
'benchmark/benchmark.less'
|
||||
],
|
||||
options: {
|
||||
helpers: 'benchmark/browseroptions.js',
|
||||
specs: 'benchmark/browserspec.js',
|
||||
outfile: 'tmp/browser/test-runner-benchmark-current.html'
|
||||
}
|
||||
},
|
||||
v3_10_3: {
|
||||
// src is used to build list of less files to compile
|
||||
src: [
|
||||
'benchmark/benchmark.less'
|
||||
],
|
||||
options: {
|
||||
helpers: 'benchmark/browseroptions.js',
|
||||
specs: 'benchmark/browserspec.js',
|
||||
outfile: 'tmp/browser/test-runner-benchmark-v3_10_3.html',
|
||||
less: 'https://cdnjs.cloudflare.com/ajax/libs/less.js/3.10.3/less.min.js'
|
||||
}
|
||||
},
|
||||
v3_9_0: {
|
||||
// src is used to build list of less files to compile
|
||||
src: [
|
||||
'benchmark/benchmark.less'
|
||||
],
|
||||
options: {
|
||||
helpers: 'benchmark/browseroptions.js',
|
||||
specs: 'benchmark/browserspec.js',
|
||||
outfile: 'tmp/browser/test-runner-benchmark-v3_9_0.html',
|
||||
less: 'https://cdnjs.cloudflare.com/ajax/libs/less.js/3.9.0/less.min.js'
|
||||
}
|
||||
},
|
||||
v2_7_3: {
|
||||
// src is used to build list of less files to compile
|
||||
src: [
|
||||
'benchmark/benchmark.less'
|
||||
],
|
||||
options: {
|
||||
helpers: 'benchmark/browseroptions.js',
|
||||
specs: 'benchmark/browserspec.js',
|
||||
outfile: 'tmp/browser/test-runner-benchmark-v2_7_3.html',
|
||||
less: 'https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.3/less.min.js'
|
||||
}
|
||||
}
|
||||
}
|
||||
78
node_modules/less/test/browser/generator/generate.js
generated
vendored
Normal file
78
node_modules/less/test/browser/generator/generate.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
const template = require('./template')
|
||||
let config
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const globby = require('globby')
|
||||
const { runner } = require('../../mocha-playwright/runner')
|
||||
|
||||
|
||||
if (process.argv[2]) {
|
||||
config = require(`./${process.argv[2]}.config`)
|
||||
} else {
|
||||
config = require('./runner.config')
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate templates and run tests
|
||||
*/
|
||||
const tests = []
|
||||
const cwd = process.cwd()
|
||||
const tmpDir = path.join(cwd, 'tmp', 'browser')
|
||||
fs.ensureDirSync(tmpDir)
|
||||
fs.copySync(path.join(cwd, 'test', 'browser', 'common.js'), path.join(tmpDir, 'common.js'))
|
||||
|
||||
let numTests = 0
|
||||
let passedTests = 0
|
||||
let failedTests = 0
|
||||
|
||||
/** Will run the runners in a series */
|
||||
function runSerial(tasks) {
|
||||
var result = Promise.resolve()
|
||||
start = Date.now()
|
||||
tasks.forEach(task => {
|
||||
result = result.then(result => {
|
||||
if (result && result.result && result.result.stats) {
|
||||
const stats = result.result.stats
|
||||
numTests += stats.tests
|
||||
passedTests += stats.passes
|
||||
failedTests += stats.failures
|
||||
}
|
||||
return task()
|
||||
}, err => {
|
||||
console.log(err)
|
||||
failedTests += 1
|
||||
})
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
Object.entries(config).forEach(entry => {
|
||||
const test = entry[1]
|
||||
const paths = globby.sync(test.src)
|
||||
const templateString = template(paths, test.options.helpers, test.options.specs)
|
||||
fs.writeFileSync(path.join(cwd, test.options.outfile), templateString)
|
||||
tests.push(() => {
|
||||
const file = 'http://localhost:8081/packages/less/' + test.options.outfile
|
||||
console.log(file)
|
||||
return runner({
|
||||
file,
|
||||
timeout: 3500,
|
||||
args: ['disable-web-security', 'no-sandbox', 'disable-setuid-sandbox'],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
module.exports = () => runSerial(tests).then(() => {
|
||||
if (failedTests > 0) {
|
||||
process.stderr.write(failedTests + ' Failed, ' + passedTests + ' passed\n');
|
||||
} else {
|
||||
process.stdout.write('All Passed ' + passedTests + ' run\n');
|
||||
}
|
||||
if (failedTests) {
|
||||
process.on('exit', function() { process.reallyExit(1); });
|
||||
}
|
||||
process.exit()
|
||||
}, err => {
|
||||
process.stderr.write(err.message);
|
||||
process.exit()
|
||||
})
|
||||
184
node_modules/less/test/browser/generator/runner.config.js
generated
vendored
Normal file
184
node_modules/less/test/browser/generator/runner.config.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
var path = require('path');
|
||||
var resolve = require('resolve')
|
||||
var { forceCovertToBrowserPath } = require('./utils');
|
||||
|
||||
/** Root of repo */
|
||||
var testFolder = forceCovertToBrowserPath(path.dirname(resolve.sync('@less/test-data')));
|
||||
var testsUnitFolder = forceCovertToBrowserPath(path.join(testFolder, 'tests-unit'));
|
||||
var testsConfigFolder = forceCovertToBrowserPath(path.join(testFolder, 'tests-config'));
|
||||
var localTests = forceCovertToBrowserPath(path.resolve(__dirname, '..'));
|
||||
|
||||
module.exports = {
|
||||
main: {
|
||||
// src is used to build list of less files to compile
|
||||
src: [
|
||||
`${testsUnitFolder}/*/*.less`,
|
||||
`!${testsUnitFolder}/plugin-preeval/plugin-preeval.less`, // uses ES6 syntax
|
||||
// Don't test NPM import, obviously
|
||||
`!${testsUnitFolder}/plugin-module/plugin-module.less`,
|
||||
`!${testsUnitFolder}/import/import-module.less`,
|
||||
`!${testsUnitFolder}/javascript/javascript.less`,
|
||||
`!${testsUnitFolder}/urls/urls.less`,
|
||||
`!${testsUnitFolder}/empty/empty.less`,
|
||||
`!${testsUnitFolder}/color-functions/operations.less`, // conflicts with operations/operations.less
|
||||
// Exclude debug line numbers tests - these are Node.js only (dumpLineNumbers is deprecated)
|
||||
`!${testsConfigFolder}/debug/**/*.less`
|
||||
],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-main-options.js',
|
||||
specs: 'test/browser/runner-main-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-main.html'
|
||||
}
|
||||
},
|
||||
strictUnits: {
|
||||
src: [`${testsConfigFolder}/units/strict/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-strict-units-options.js',
|
||||
specs: 'test/browser/runner-strict-units-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-strict-units.html'
|
||||
}
|
||||
},
|
||||
errors: {
|
||||
src: [
|
||||
`${testFolder}/tests-error/eval/*.less`,
|
||||
`${testFolder}/tests-error/parse/*.less`,
|
||||
`${localTests}/less/errors/*.less`
|
||||
],
|
||||
options: {
|
||||
timeout: 20000,
|
||||
helpers: 'test/browser/runner-errors-options.js',
|
||||
specs: 'test/browser/runner-errors-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-errors.html'
|
||||
}
|
||||
},
|
||||
noJsErrors: {
|
||||
src: [`${testsConfigFolder}/no-js-errors/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-no-js-errors-options.js',
|
||||
specs: 'test/browser/runner-no-js-errors-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-no-js-errors.html'
|
||||
}
|
||||
},
|
||||
browser: {
|
||||
src: [
|
||||
`${localTests}/less/*.less`,
|
||||
`${localTests}/less/plugin/*.less`
|
||||
],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-browser-options.js',
|
||||
specs: 'test/browser/runner-browser-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-browser.html'
|
||||
}
|
||||
},
|
||||
relativeUrls: {
|
||||
src: [`${localTests}/less/relative-urls/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-relative-urls-options.js',
|
||||
specs: 'test/browser/runner-relative-urls-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-relative-urls.html'
|
||||
}
|
||||
},
|
||||
rewriteUrls: {
|
||||
src: [`${localTests}/less/rewrite-urls/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-rewrite-urls-options.js',
|
||||
specs: 'test/browser/runner-rewrite-urls-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-rewrite-urls.html'
|
||||
}
|
||||
},
|
||||
rootpath: {
|
||||
src: [`${localTests}/less/rootpath/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-rootpath-options.js',
|
||||
specs: 'test/browser/runner-rootpath-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-rootpath.html'
|
||||
}
|
||||
},
|
||||
rootpathRelative: {
|
||||
src: [`${localTests}/less/rootpath-relative/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-rootpath-relative-options.js',
|
||||
specs: 'test/browser/runner-rootpath-relative-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-rootpath-relative.html'
|
||||
}
|
||||
},
|
||||
rootpathRewriteUrls: {
|
||||
src: [`${localTests}/less/rootpath-rewrite-urls/*.less`],
|
||||
options: {
|
||||
helpers:
|
||||
'test/browser/runner-rootpath-rewrite-urls-options.js',
|
||||
specs: 'test/browser/runner-rootpath-rewrite-urls-spec.js',
|
||||
outfile:
|
||||
'tmp/browser/test-runner-rootpath-rewrite-urls.html'
|
||||
}
|
||||
},
|
||||
production: {
|
||||
src: [`${localTests}/less/production/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-production-options.js',
|
||||
specs: 'test/browser/runner-production-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-production.html'
|
||||
}
|
||||
},
|
||||
modifyVars: {
|
||||
src: [`${localTests}/less/modify-vars/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-modify-vars-options.js',
|
||||
specs: 'test/browser/runner-modify-vars-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-modify-vars.html'
|
||||
}
|
||||
},
|
||||
globalVars: {
|
||||
src: [`${localTests}/less/global-vars/*.less`],
|
||||
options: {
|
||||
helpers: 'test/browser/runner-global-vars-options.js',
|
||||
specs: 'test/browser/runner-global-vars-spec.js',
|
||||
outfile: 'tmp/browser/test-runner-global-vars.html'
|
||||
}
|
||||
},
|
||||
postProcessorPlugin: {
|
||||
src: [`${testsConfigFolder}/postProcessorPlugin/*.less`],
|
||||
options: {
|
||||
helpers: [
|
||||
'test/plugins/postprocess/index.js',
|
||||
'test/browser/runner-postProcessorPlugin-options.js'
|
||||
],
|
||||
specs: 'test/browser/runner-postProcessorPlugin.js',
|
||||
outfile:
|
||||
'tmp/browser/test-runner-post-processor-plugin.html'
|
||||
}
|
||||
},
|
||||
preProcessorPlugin: {
|
||||
src: [`${testsConfigFolder}/preProcessorPlugin/*.less`],
|
||||
options: {
|
||||
helpers: [
|
||||
'test/plugins/preprocess/index.js',
|
||||
'test/browser/runner-preProcessorPlugin-options.js'
|
||||
],
|
||||
specs: 'test/browser/runner-preProcessorPlugin.js',
|
||||
outfile: 'tmp/browser/test-runner-pre-processor-plugin.html'
|
||||
}
|
||||
},
|
||||
visitorPlugin: {
|
||||
src: [`${testsConfigFolder}/visitorPlugin/*.less`],
|
||||
options: {
|
||||
helpers: [
|
||||
'test/plugins/visitor/index.js',
|
||||
'test/browser/runner-VisitorPlugin-options.js'
|
||||
],
|
||||
specs: 'test/browser/runner-VisitorPlugin.js',
|
||||
outfile: 'tmp/browser/test-runner-visitor-plugin.html'
|
||||
}
|
||||
},
|
||||
filemanagerPlugin: {
|
||||
src: [`${testsConfigFolder}/filemanagerPlugin/*.less`],
|
||||
options: {
|
||||
helpers: [
|
||||
'test/plugins/filemanager/index.js',
|
||||
'test/browser/runner-filemanagerPlugin-options.js'
|
||||
],
|
||||
specs: 'test/browser/runner-filemanagerPlugin.js',
|
||||
outfile: 'tmp/browser/test-runner-filemanager-plugin.html'
|
||||
}
|
||||
}
|
||||
}
|
||||
2
node_modules/less/test/browser/generator/runner.js
generated
vendored
Normal file
2
node_modules/less/test/browser/generator/runner.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
const runner = require('./generate')
|
||||
runner()
|
||||
104
node_modules/less/test/browser/generator/template.js
generated
vendored
Normal file
104
node_modules/less/test/browser/generator/template.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
const html = require('html-template-tag')
|
||||
const path = require('path')
|
||||
const { forceCovertToBrowserPath } = require('./utils')
|
||||
|
||||
const webRoot = path.resolve(__dirname, '../../../../../');
|
||||
const mochaDir = forceCovertToBrowserPath(path.relative(webRoot, path.dirname(require.resolve('mocha'))))
|
||||
const chaiDir = forceCovertToBrowserPath(path.relative(webRoot, path.dirname(require.resolve('chai'))))
|
||||
const mochaTeamCityDir = forceCovertToBrowserPath(path.relative(webRoot, path.dirname(require.resolve('mocha-teamcity-reporter'))))
|
||||
|
||||
/**
|
||||
* Generates HTML templates from list of test sheets
|
||||
*/
|
||||
module.exports = (stylesheets, helpers, spec, less) => {
|
||||
if (!Array.isArray(helpers)) {
|
||||
helpers = [helpers]
|
||||
}
|
||||
return html`
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>Less.js Spec Runner</title>
|
||||
|
||||
<!-- for each test, generate CSS/LESS link tags -->
|
||||
$${stylesheets.map(function(fullLessName) {
|
||||
var pathParts = fullLessName.split('/');
|
||||
var fullCssName = fullLessName.replace(/less$/, 'css');
|
||||
|
||||
// Check if the CSS file exists in the same directory as the LESS file
|
||||
var fs = require('fs');
|
||||
var cssExists = fs.existsSync(fullCssName);
|
||||
|
||||
// If not, try the css/ directory for local browser tests
|
||||
if (!cssExists && fullLessName.includes('/test/browser/less/')) {
|
||||
var cssInCssDir = fullLessName.replace('/test/browser/less/', '/test/browser/css/').replace(/less$/, 'css');
|
||||
if (fs.existsSync(cssInCssDir)) {
|
||||
fullCssName = cssInCssDir;
|
||||
}
|
||||
}
|
||||
|
||||
var lessName = pathParts[pathParts.length - 1];
|
||||
var name = lessName.split('.')[0];
|
||||
return `
|
||||
<!-- the tags to be generated -->
|
||||
<link id="original-less:test-less-${name}" title="test-less-${name}" rel="stylesheet/less" type="text/css" href="/${path.relative(webRoot, fullLessName)}">
|
||||
<link id="expected-less:test-less-${name}" rel="stylesheet" type="text/css" href="/${path.relative(webRoot, fullCssName)}">
|
||||
` }).join('')}
|
||||
|
||||
$${helpers.map(helper => `
|
||||
<script src="../../${helper}"></script>
|
||||
`).join('')}
|
||||
|
||||
<link rel="stylesheet" href="/${mochaDir}/mocha.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- content -->
|
||||
<div id="mocha"></div>
|
||||
<script src="/${mochaDir}/mocha.js"></script>
|
||||
<script src="/${mochaTeamCityDir}/teamcityBrowser.js"></script>
|
||||
<script src="/${chaiDir}/chai.js"></script>
|
||||
<script>
|
||||
expect = chai.expect
|
||||
mocha.setup({
|
||||
ui: 'bdd',
|
||||
timeout: 2500
|
||||
});
|
||||
</script>
|
||||
<script src="common.js"></script>
|
||||
<script src="../../${spec}"></script>
|
||||
<script src="${less || 'less.min.js'}"></script>
|
||||
<script>
|
||||
/** Saucelabs config */
|
||||
onload = function() {
|
||||
var runner = mocha.run();
|
||||
|
||||
var failedTests = [];
|
||||
runner.on('end', function() {
|
||||
window.mochaResults = runner.stats;
|
||||
window.mochaResults.reports = failedTests;
|
||||
});
|
||||
|
||||
runner.on('fail', logFailure);
|
||||
|
||||
function logFailure(test, err){
|
||||
var flattenTitles = function(test){
|
||||
var titles = [];
|
||||
while (test.parent.title) {
|
||||
titles.push(test.parent.title);
|
||||
test = test.parent;
|
||||
}
|
||||
return titles.reverse();
|
||||
};
|
||||
|
||||
failedTests.push({name: test.title, result: false, message: err.message, stack: err.stack, titles: flattenTitles(test) });
|
||||
};
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
}
|
||||
14
node_modules/less/test/browser/generator/utils.js
generated
vendored
Normal file
14
node_modules/less/test/browser/generator/utils.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* utils for covert browser paths,
|
||||
* fix https://github.com/less/less.js/pull/4213
|
||||
*
|
||||
* @param {string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
function forceCovertToBrowserPath (path) {
|
||||
return (path || '').replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
forceCovertToBrowserPath
|
||||
}
|
||||
3
node_modules/less/test/browser/less/console-errors/test-error.less
generated
vendored
Normal file
3
node_modules/less/test/browser/less/console-errors/test-error.less
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.a {
|
||||
prop: (3 / #fff);
|
||||
}
|
||||
2
node_modules/less/test/browser/less/console-errors/test-error.txt
generated
vendored
Normal file
2
node_modules/less/test/browser/less/console-errors/test-error.txt
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
less: OperationError: Can't subtract or divide a color from a number in {pathhref}console-errors/test-error.less on line null, column 0:
|
||||
1 prop: (3 / #fff);
|
||||
3
node_modules/less/test/browser/less/errors/image-height-error.less
generated
vendored
Normal file
3
node_modules/less/test/browser/less/errors/image-height-error.less
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.test-height{
|
||||
height: image-height("../data/image.jpg")
|
||||
}
|
||||
4
node_modules/less/test/browser/less/errors/image-height-error.txt
generated
vendored
Normal file
4
node_modules/less/test/browser/less/errors/image-height-error.txt
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
RuntimeError: Error evaluating function `image-height`: Image size functions are not supported in browser version of less in image-height-error.less on line 2, column 11:
|
||||
1 .test-height{
|
||||
2 height: image-height("../data/image.jpg")
|
||||
3 }
|
||||
3
node_modules/less/test/browser/less/errors/image-size-error.less
generated
vendored
Normal file
3
node_modules/less/test/browser/less/errors/image-size-error.less
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.test-size{
|
||||
size: image-size("../data/image.jpg")
|
||||
}
|
||||
4
node_modules/less/test/browser/less/errors/image-size-error.txt
generated
vendored
Normal file
4
node_modules/less/test/browser/less/errors/image-size-error.txt
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
RuntimeError: Error evaluating function `image-size`: Image size functions are not supported in browser version of less in image-size-error.less on line 2, column 9:
|
||||
1 .test-size{
|
||||
2 size: image-size("../data/image.jpg")
|
||||
3 }
|
||||
3
node_modules/less/test/browser/less/errors/image-width-error.less
generated
vendored
Normal file
3
node_modules/less/test/browser/less/errors/image-width-error.less
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.test-width{
|
||||
width: image-width("../data/image.jpg")
|
||||
}
|
||||
4
node_modules/less/test/browser/less/errors/image-width-error.txt
generated
vendored
Normal file
4
node_modules/less/test/browser/less/errors/image-width-error.txt
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
RuntimeError: Error evaluating function `image-width`: Image size functions are not supported in browser version of less in image-width-error.less on line 2, column 10:
|
||||
1 .test-width{
|
||||
2 width: image-width("../data/image.jpg")
|
||||
3 }
|
||||
3
node_modules/less/test/browser/less/global-vars/simple.less
generated
vendored
Normal file
3
node_modules/less/test/browser/less/global-vars/simple.less
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.test {
|
||||
color: @global-var;
|
||||
}
|
||||
4
node_modules/less/test/browser/less/imports/urls.less
generated
vendored
Normal file
4
node_modules/less/test/browser/less/imports/urls.less
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
@import "modify-this.css";
|
||||
.modify {
|
||||
my-url: url("a.png");
|
||||
}
|
||||
4
node_modules/less/test/browser/less/imports/urls2.less
generated
vendored
Normal file
4
node_modules/less/test/browser/less/imports/urls2.less
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
@import "modify-again.css";
|
||||
.modify {
|
||||
my-url: url("b.png");
|
||||
}
|
||||
4
node_modules/less/test/browser/less/modify-vars/imports/simple2.less
generated
vendored
Normal file
4
node_modules/less/test/browser/less/modify-vars/imports/simple2.less
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
@var2: blue;
|
||||
.testisimported {
|
||||
color: gainsboro;
|
||||
}
|
||||
8
node_modules/less/test/browser/less/modify-vars/simple.less
generated
vendored
Normal file
8
node_modules/less/test/browser/less/modify-vars/simple.less
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
@import "imports/simple2";
|
||||
@var1: red;
|
||||
@scale: 10;
|
||||
.test {
|
||||
color1: @var1;
|
||||
color2: @var2;
|
||||
scalar: @scale
|
||||
}
|
||||
5
node_modules/less/test/browser/less/nested-gradient-with-svg-gradient/mixin-consumer.less
generated
vendored
Normal file
5
node_modules/less/test/browser/less/nested-gradient-with-svg-gradient/mixin-consumer.less
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
@import "svg-gradient-mixin.less";
|
||||
|
||||
.gray-gradient {
|
||||
.gradient-mixin(#999);
|
||||
}
|
||||
15
node_modules/less/test/browser/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less
generated
vendored
Normal file
15
node_modules/less/test/browser/less/nested-gradient-with-svg-gradient/svg-gradient-mixin.less
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
.gradient-mixin(@color) {
|
||||
background: svg-gradient(to bottom,
|
||||
fade(@color, 0%) 0%,
|
||||
fade(@color, 5%) 60%,
|
||||
fade(@color, 10%) 70%,
|
||||
fade(@color, 15%) 73%,
|
||||
fade(@color, 20%) 75%,
|
||||
fade(@color, 25%) 80%,
|
||||
fade(@color, 30%) 85%,
|
||||
fade(@color, 35%) 88%,
|
||||
fade(@color, 40%) 90%,
|
||||
fade(@color, 45%) 95%,
|
||||
fade(@color, 50%) 100%
|
||||
);
|
||||
}
|
||||
4
node_modules/less/test/browser/less/plugin/plugin.js
generated
vendored
Normal file
4
node_modules/less/test/browser/less/plugin/plugin.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
functions.add('func', function() {
|
||||
return less.anonymous(location.href);
|
||||
});
|
||||
4
node_modules/less/test/browser/less/plugin/plugin.less
generated
vendored
Normal file
4
node_modules/less/test/browser/less/plugin/plugin.less
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
@plugin "plugin";
|
||||
.test {
|
||||
val: func();
|
||||
}
|
||||
4
node_modules/less/test/browser/less/postProcessor/postProcessor.less
generated
vendored
Normal file
4
node_modules/less/test/browser/less/postProcessor/postProcessor.less
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
@color: white;
|
||||
.test {
|
||||
color: @color;
|
||||
}
|
||||
34
node_modules/less/test/browser/less/relative-urls/urls.less
generated
vendored
Normal file
34
node_modules/less/test/browser/less/relative-urls/urls.less
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
@import ".././imports/urls.less";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/urls2.less";
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium),
|
||||
url(fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(images/image.jpg);
|
||||
background: url("#inline-svg");
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
|
||||
.comma-delimited {
|
||||
background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
|
||||
}
|
||||
.values {
|
||||
@a: 'Trebuchet';
|
||||
url: url(@a);
|
||||
}
|
||||
34
node_modules/less/test/browser/less/rewrite-urls/urls.less
generated
vendored
Normal file
34
node_modules/less/test/browser/less/rewrite-urls/urls.less
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
@import ".././imports/urls.less";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/urls2.less";
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium),
|
||||
url(fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(images/image.jpg);
|
||||
background: url("#inline-svg");
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
|
||||
.comma-delimited {
|
||||
background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
|
||||
}
|
||||
.values {
|
||||
@a: 'Trebuchet';
|
||||
url: url(@a);
|
||||
}
|
||||
33
node_modules/less/test/browser/less/rootpath-relative/urls.less
generated
vendored
Normal file
33
node_modules/less/test/browser/less/rootpath-relative/urls.less
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
@import "../imports/urls.less";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/urls2.less";
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium),
|
||||
url(fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(images/image.jpg);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
|
||||
.comma-delimited {
|
||||
background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
|
||||
}
|
||||
.values {
|
||||
@a: 'Trebuchet';
|
||||
url: url(@a);
|
||||
}
|
||||
33
node_modules/less/test/browser/less/rootpath-rewrite-urls/urls.less
generated
vendored
Normal file
33
node_modules/less/test/browser/less/rootpath-rewrite-urls/urls.less
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
@import "../imports/urls.less";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/urls2.less";
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium),
|
||||
url(fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(images/image.jpg);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
|
||||
.comma-delimited {
|
||||
background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
|
||||
}
|
||||
.values {
|
||||
@a: 'Trebuchet';
|
||||
url: url(@a);
|
||||
}
|
||||
33
node_modules/less/test/browser/less/rootpath/urls.less
generated
vendored
Normal file
33
node_modules/less/test/browser/less/rootpath/urls.less
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
@import "../imports/urls.less";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/urls2.less";
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium),
|
||||
url(fonts.svg#MyGeometricModern) format("svg");
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(images/image.jpg);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
|
||||
.comma-delimited {
|
||||
background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
|
||||
}
|
||||
.values {
|
||||
@a: 'Trebuchet';
|
||||
url: url(@a);
|
||||
}
|
||||
62
node_modules/less/test/browser/less/urls.less
generated
vendored
Normal file
62
node_modules/less/test/browser/less/urls.less
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
@import "imports/urls.less";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/imports/urls2.less";
|
||||
@import "http://localhost:8081/packages/less/test/browser/less/nested-gradient-with-svg-gradient/mixin-consumer.less";
|
||||
@font-face {
|
||||
src: url("/fonts/garamond-pro.ttf");
|
||||
src: local(Futura-Medium),
|
||||
url(fonts.svg#MyGeometricModern) format("svg");
|
||||
not-a-comment: url(//z);
|
||||
}
|
||||
#shorthands {
|
||||
background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
|
||||
}
|
||||
#misc {
|
||||
background-image: url(images/image.jpg);
|
||||
}
|
||||
#data-uri {
|
||||
background: url(data:image/png;charset=utf-8;base64,
|
||||
kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
|
||||
k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
|
||||
kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
|
||||
background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
|
||||
background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
|
||||
}
|
||||
|
||||
#svg-data-uri {
|
||||
background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
|
||||
}
|
||||
|
||||
.comma-delimited {
|
||||
background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
|
||||
}
|
||||
.values {
|
||||
@a: 'Trebuchet';
|
||||
url: url(@a);
|
||||
}
|
||||
#data-uri {
|
||||
uri: data-uri('image/jpeg;base64', '../../data/image.jpg');
|
||||
}
|
||||
|
||||
#data-uri-guess {
|
||||
uri: data-uri('../../data/image.jpg');
|
||||
}
|
||||
|
||||
#data-uri-ascii {
|
||||
uri-1: data-uri('text/html', '../../data/page.html');
|
||||
uri-2: data-uri('../../data/page.html');
|
||||
}
|
||||
|
||||
#svg-functions {
|
||||
@colorlist1: black, white;
|
||||
background-image: svg-gradient(to bottom, @colorlist1);
|
||||
background-image: svg-gradient(to bottom, black white);
|
||||
background-image: svg-gradient(to bottom, black, orange 3%, white);
|
||||
@colorlist2: black, orange 3%, white;
|
||||
background-image: svg-gradient(to bottom, @colorlist2);
|
||||
@green_5: green 5%;
|
||||
@orange_percentage: 3%;
|
||||
@orange_color: orange;
|
||||
@colorlist3: (mix(black, white) + #444) 1%, @orange_color @orange_percentage, ((@green_5)), white 95%;
|
||||
background-image: svg-gradient(to bottom,@colorlist3);
|
||||
background-image: svg-gradient(to bottom, (mix(black, white) + #444) 1%, @orange_color @orange_percentage, ((@green_5)), white 95%);
|
||||
}
|
||||
3
node_modules/less/test/browser/runner-VisitorPlugin-options.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-VisitorPlugin-options.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: 'console',
|
||||
plugins: [VisitorPlugin]};
|
||||
3
node_modules/less/test/browser/runner-VisitorPlugin.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-VisitorPlugin.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js Visitor Plugin', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
51
node_modules/less/test/browser/runner-browser-options.js
generated
vendored
Normal file
51
node_modules/less/test/browser/runner-browser-options.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
var less = {
|
||||
logLevel: 4,
|
||||
errorReporting: 'console',
|
||||
javascriptEnabled: true,
|
||||
math: 'always'
|
||||
};
|
||||
|
||||
// test inline less in style tags by grabbing an assortment of less files and doing `@import`s
|
||||
var testFiles = ['charsets/charsets', 'color-functions/basic', 'comments/comments', 'css-3/css-3', 'strings/strings', 'media/media', 'mixins/mixins'],
|
||||
testSheets = [];
|
||||
|
||||
// setup style tags with less and link tags pointing to expected css output
|
||||
|
||||
/**
|
||||
* @todo - generate the node_modules path for this file and in templates
|
||||
*/
|
||||
var lessFolder = '../../node_modules/@less/test-data/tests-unit'
|
||||
var cssFolder = '../../node_modules/@less/test-data/tests-unit'
|
||||
|
||||
for (var i = 0; i < testFiles.length; i++) {
|
||||
var file = testFiles[i],
|
||||
lessPath = lessFolder + '/' + file + '.less',
|
||||
cssPath = cssFolder + '/' + file + '.css',
|
||||
lessStyle = document.createElement('style'),
|
||||
cssLink = document.createElement('link'),
|
||||
lessText = '@import "' + lessPath + '";';
|
||||
|
||||
lessStyle.type = 'text/less';
|
||||
lessStyle.id = file;
|
||||
lessStyle.href = file;
|
||||
|
||||
if (lessStyle.styleSheet === undefined) {
|
||||
lessStyle.appendChild(document.createTextNode(lessText));
|
||||
}
|
||||
|
||||
cssLink.rel = 'stylesheet';
|
||||
cssLink.type = 'text/css';
|
||||
cssLink.href = cssPath;
|
||||
cssLink.id = 'expected-' + file;
|
||||
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
|
||||
head.appendChild(lessStyle);
|
||||
|
||||
if (lessStyle.styleSheet) {
|
||||
lessStyle.styleSheet.cssText = lessText;
|
||||
}
|
||||
|
||||
head.appendChild(cssLink);
|
||||
testSheets[i] = lessStyle;
|
||||
}
|
||||
12
node_modules/less/test/browser/runner-browser-spec.js
generated
vendored
Normal file
12
node_modules/less/test/browser/runner-browser-spec.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
describe('less.js browser behaviour', function() {
|
||||
testLessEqualsInDocument();
|
||||
|
||||
it('has some log messages', function() {
|
||||
expect(logMessages.length).to.be.above(0);
|
||||
});
|
||||
|
||||
for (var i = 0; i < testFiles.length; i++) {
|
||||
var sheet = testSheets[i];
|
||||
testSheet(sheet);
|
||||
}
|
||||
});
|
||||
5
node_modules/less/test/browser/runner-console-errors.js
generated
vendored
Normal file
5
node_modules/less/test/browser/runner-console-errors.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
less.errorReporting = 'console';
|
||||
|
||||
describe('less.js error reporting console test', function() {
|
||||
testLessErrorsInDocument(true);
|
||||
});
|
||||
6
node_modules/less/test/browser/runner-errors-options.js
generated
vendored
Normal file
6
node_modules/less/test/browser/runner-errors-options.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
var less = {
|
||||
strictUnits: true,
|
||||
math: 'strict-legacy',
|
||||
logLevel: 4,
|
||||
javascriptEnabled: true
|
||||
};
|
||||
3
node_modules/less/test/browser/runner-errors-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-errors-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js error tests', function() {
|
||||
testLessErrorsInDocument();
|
||||
});
|
||||
5
node_modules/less/test/browser/runner-filemanagerPlugin-options.js
generated
vendored
Normal file
5
node_modules/less/test/browser/runner-filemanagerPlugin-options.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
var less = {
|
||||
logLevel: 4,
|
||||
errorReporting: 'console',
|
||||
plugins: [AddFilePlugin]
|
||||
};
|
||||
3
node_modules/less/test/browser/runner-filemanagerPlugin.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-filemanagerPlugin.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js filemanager Plugin', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
7
node_modules/less/test/browser/runner-global-vars-options.js
generated
vendored
Normal file
7
node_modules/less/test/browser/runner-global-vars-options.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
var less = {
|
||||
logLevel: 4,
|
||||
errorReporting: 'console',
|
||||
globalVars: {
|
||||
'@global-var': 'red'
|
||||
}
|
||||
};
|
||||
3
node_modules/less/test/browser/runner-global-vars-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-global-vars-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js global vars', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
17
node_modules/less/test/browser/runner-main-options.js
generated
vendored
Normal file
17
node_modules/less/test/browser/runner-main-options.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
var less = {
|
||||
logLevel: 4,
|
||||
errorReporting: 'console'
|
||||
};
|
||||
less.functions = {
|
||||
add: function(a, b) {
|
||||
return new(less.tree.Dimension)(a.value + b.value);
|
||||
},
|
||||
increment: function(a) {
|
||||
return new(less.tree.Dimension)(a.value + 1);
|
||||
},
|
||||
_color: function(str) {
|
||||
if (str.value === 'evil red') {
|
||||
return new(less.tree.Color)('600');
|
||||
}
|
||||
}
|
||||
};
|
||||
7
node_modules/less/test/browser/runner-main-spec.js
generated
vendored
Normal file
7
node_modules/less/test/browser/runner-main-spec.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
console.warn('start spec');
|
||||
describe('less.js main tests', function() {
|
||||
testLessEqualsInDocument();
|
||||
it('the global environment', function() {
|
||||
expect(window.require).to.be.undefined;
|
||||
});
|
||||
});
|
||||
5
node_modules/less/test/browser/runner-modify-vars-options.js
generated
vendored
Normal file
5
node_modules/less/test/browser/runner-modify-vars-options.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/* exported less */
|
||||
var less = {
|
||||
logLevel: 4,
|
||||
errorReporting: 'console'
|
||||
};
|
||||
33
node_modules/less/test/browser/runner-modify-vars-spec.js
generated
vendored
Normal file
33
node_modules/less/test/browser/runner-modify-vars-spec.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
var alreadyRun = false;
|
||||
|
||||
describe('less.js modify vars', function () {
|
||||
beforeEach(function (done) {
|
||||
// simulating "setUp" or "beforeAll" method
|
||||
if (alreadyRun) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
alreadyRun = true;
|
||||
|
||||
less.pageLoadFinished
|
||||
.then(function () {
|
||||
less.modifyVars({
|
||||
var1: 'green',
|
||||
var2: 'purple',
|
||||
scale: 20
|
||||
}).then(function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
testLessEqualsInDocument();
|
||||
it('Should log only 2 XHR requests', function (done) {
|
||||
var xhrLogMessages = logMessages.filter(function (item) {
|
||||
return (/XHR: Getting '/).test(item);
|
||||
});
|
||||
expect(xhrLogMessages.length).to.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
4
node_modules/less/test/browser/runner-no-js-errors-options.js
generated
vendored
Normal file
4
node_modules/less/test/browser/runner-no-js-errors-options.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
var less = {logLevel: 4};
|
||||
|
||||
less.strictUnits = true;
|
||||
less.javascriptEnabled = false;
|
||||
3
node_modules/less/test/browser/runner-no-js-errors-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-no-js-errors-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js javascript disabled error tests', function() {
|
||||
testLessErrorsInDocument();
|
||||
});
|
||||
3
node_modules/less/test/browser/runner-postProcessorPlugin-options.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-postProcessorPlugin-options.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: 'console',
|
||||
plugins: [postProcessorPlugin]};
|
||||
3
node_modules/less/test/browser/runner-postProcessorPlugin.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-postProcessorPlugin.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js postProcessor Plugin', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
3
node_modules/less/test/browser/runner-preProcessorPlugin-options.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-preProcessorPlugin-options.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: 'console',
|
||||
plugins: [preProcessorPlugin]};
|
||||
3
node_modules/less/test/browser/runner-preProcessorPlugin.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-preProcessorPlugin.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js preProcessor Plugin', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
3
node_modules/less/test/browser/runner-production-options.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-production-options.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var less = {logLevel: 1,
|
||||
errorReporting: 'console'};
|
||||
less.env = 'production';
|
||||
5
node_modules/less/test/browser/runner-production-spec.js
generated
vendored
Normal file
5
node_modules/less/test/browser/runner-production-spec.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
describe('less.js production behaviour', function() {
|
||||
it('doesn\'t log any messages', function() {
|
||||
expect(logMessages.length).to.equal(0);
|
||||
});
|
||||
});
|
||||
3
node_modules/less/test/browser/runner-relative-urls-options.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-relative-urls-options.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: 'console'};
|
||||
less.relativeUrls = true;
|
||||
3
node_modules/less/test/browser/runner-relative-urls-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-relative-urls-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js browser test - relative url\'s', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
3
node_modules/less/test/browser/runner-rewrite-urls-options.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-rewrite-urls-options.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: 'console'};
|
||||
less.rewriteUrls = 'all';
|
||||
3
node_modules/less/test/browser/runner-rewrite-urls-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-rewrite-urls-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js browser test - rewrite urls', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
3
node_modules/less/test/browser/runner-rootpath-options.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-rootpath-options.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: 'console'};
|
||||
less.rootpath = 'https://localhost/';
|
||||
4
node_modules/less/test/browser/runner-rootpath-relative-options.js
generated
vendored
Normal file
4
node_modules/less/test/browser/runner-rootpath-relative-options.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: 'console'};
|
||||
less.rootpath = 'https://www.github.com/cloudhead/less.js/';
|
||||
less.relativeUrls = true;
|
||||
3
node_modules/less/test/browser/runner-rootpath-relative-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-rootpath-relative-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js browser test - rootpath and relative urls', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
4
node_modules/less/test/browser/runner-rootpath-rewrite-urls-options.js
generated
vendored
Normal file
4
node_modules/less/test/browser/runner-rootpath-rewrite-urls-options.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
var less = {logLevel: 4,
|
||||
errorReporting: 'console'};
|
||||
less.rootpath = 'https://www.github.com/cloudhead/less.js/';
|
||||
less.rewriteUrls = 'all';
|
||||
3
node_modules/less/test/browser/runner-rootpath-rewrite-urls-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-rootpath-rewrite-urls-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js browser test - rootpath and rewrite urls', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
3
node_modules/less/test/browser/runner-rootpath-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-rootpath-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js browser test - rootpath url\'s', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
5
node_modules/less/test/browser/runner-strict-units-options.js
generated
vendored
Normal file
5
node_modules/less/test/browser/runner-strict-units-options.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
var less = {
|
||||
logLevel: 4,
|
||||
errorReporting: 'console',
|
||||
strictMath: true,
|
||||
strictUnits: true };
|
||||
3
node_modules/less/test/browser/runner-strict-units-spec.js
generated
vendored
Normal file
3
node_modules/less/test/browser/runner-strict-units-spec.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('less.js strict units tests', function() {
|
||||
testLessEqualsInDocument();
|
||||
});
|
||||
307
node_modules/less/test/index.js
generated
vendored
Normal file
307
node_modules/less/test/index.js
generated
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
// Mock needle for HTTP requests BEFORE any other requires
|
||||
const Module = require('module');
|
||||
const originalRequire = Module.prototype.require;
|
||||
Module.prototype.require = function(id) {
|
||||
if (id === 'needle') {
|
||||
return {
|
||||
get: function(url, options, callback) {
|
||||
|
||||
// Handle CDN requests
|
||||
if (url.includes('cdn.jsdelivr.net')) {
|
||||
if (url.includes('selectors.less')) {
|
||||
setTimeout(() => {
|
||||
callback(null, { statusCode: 200 }, fs.readFileSync(path.join(__dirname, '../../test-data/tests-unit/selectors/selectors.less'), 'utf8'));
|
||||
}, 10);
|
||||
return;
|
||||
}
|
||||
if (url.includes('media.less')) {
|
||||
setTimeout(() => {
|
||||
callback(null, { statusCode: 200 }, fs.readFileSync(path.join(__dirname, '../../test-data/tests-unit/media/media.less'), 'utf8'));
|
||||
}, 10);
|
||||
return;
|
||||
}
|
||||
if (url.includes('empty.less')) {
|
||||
setTimeout(() => {
|
||||
callback(null, { statusCode: 200 }, fs.readFileSync(path.join(__dirname, '../../test-data/tests-unit/empty/empty.less'), 'utf8'));
|
||||
}, 10);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle redirect test - simulate needle's automatic redirect handling
|
||||
if (url.includes('example.com/redirect.less')) {
|
||||
setTimeout(() => {
|
||||
// Simulate the final response after needle automatically follows the redirect
|
||||
callback(null, { statusCode: 200 }, 'h1 { color: blue; }');
|
||||
}, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.includes('example.com/target.less')) {
|
||||
setTimeout(() => {
|
||||
callback(null, { statusCode: 200 }, 'h1 { color: blue; }');
|
||||
}, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
// Default error for unmocked URLs
|
||||
setTimeout(() => {
|
||||
callback(new Error('Unmocked URL: ' + url), null, null);
|
||||
}, 10);
|
||||
}
|
||||
};
|
||||
}
|
||||
return originalRequire.apply(this, arguments);
|
||||
};
|
||||
|
||||
// Now load other modules after mocking is set up
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
lessTest = require('./less-test'),
|
||||
stylize = require('../lib/less-node/lessc-helper').stylize;
|
||||
|
||||
// Parse command line arguments for test filtering
|
||||
var args = process.argv.slice(2);
|
||||
var testFilter = args.length > 0 ? args[0] : null;
|
||||
|
||||
// Create the test runner with the filter
|
||||
var lessTester = lessTest(testFilter);
|
||||
|
||||
// HTTP mocking is now handled by needle mocking above
|
||||
|
||||
// Test HTTP redirect functionality
|
||||
function testHttpRedirects() {
|
||||
const less = require('../lib/less-node').default;
|
||||
|
||||
console.log('🧪 Testing HTTP redirect functionality...');
|
||||
|
||||
const redirectTest = `
|
||||
@import "https://example.com/redirect.less";
|
||||
|
||||
h1 { color: red; }
|
||||
`;
|
||||
|
||||
return less.render(redirectTest, {
|
||||
filename: 'test-redirect.less'
|
||||
}).then(result => {
|
||||
console.log('✅ HTTP redirect test SUCCESS:');
|
||||
console.log(result.css);
|
||||
|
||||
// Check if both imported and local content are present
|
||||
if (result.css.includes('color: blue') && result.css.includes('color: red')) {
|
||||
console.log('🎉 HTTP redirect test PASSED - both imported and local content found');
|
||||
return true;
|
||||
} else {
|
||||
console.log('❌ HTTP redirect test FAILED - missing expected content');
|
||||
return false;
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log('❌ HTTP redirect test ERROR:');
|
||||
console.log(err.message);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Test import-remote functionality
|
||||
function testImportRemote() {
|
||||
const less = require('../lib/less-node').default;
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
console.log('🧪 Testing import-remote functionality...');
|
||||
|
||||
const testFile = path.join(__dirname, '../../test-data/tests-unit/import/import-remote.less');
|
||||
const expectedFile = path.join(__dirname, '../../test-data/tests-unit/import/import-remote.css');
|
||||
|
||||
const content = fs.readFileSync(testFile, 'utf8');
|
||||
const expected = fs.readFileSync(expectedFile, 'utf8');
|
||||
|
||||
return less.render(content, {
|
||||
filename: testFile
|
||||
}).then(result => {
|
||||
console.log('✅ Import-remote test SUCCESS:');
|
||||
console.log('Expected:', expected.trim());
|
||||
console.log('Actual:', result.css.trim());
|
||||
|
||||
if (result.css.trim() === expected.trim()) {
|
||||
console.log('🎉 Import-remote test PASSED - CDN imports and variable resolution working');
|
||||
return true;
|
||||
} else {
|
||||
console.log('❌ Import-remote test FAILED - output mismatch');
|
||||
return false;
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log('❌ Import-remote test ERROR:');
|
||||
console.log(err.message);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n' + stylize('Less', 'underline') + '\n');
|
||||
|
||||
if (testFilter) {
|
||||
console.log('Running tests matching: ' + testFilter + '\n');
|
||||
}
|
||||
|
||||
// Glob patterns for main test runs (excluding problematic tests that will run separately)
|
||||
var globPatterns = [
|
||||
'tests-config/*/*.less',
|
||||
'tests-unit/*/*.less',
|
||||
// Debug tests have nested subdirectories (comments/, mediaquery/, all/)
|
||||
'tests-config/debug/*/linenumbers-*.less',
|
||||
'!tests-config/sourcemaps/**/*.less', // Exclude sourcemaps (need special handling)
|
||||
'!tests-config/sourcemaps-empty/*', // Exclude sourcemaps-empty (need special handling)
|
||||
'!tests-config/sourcemaps-disable-annotation/*', // Exclude sourcemaps-disable-annotation (need special handling)
|
||||
'!tests-config/sourcemaps-variable-selector/*', // Exclude sourcemaps-variable-selector (need special handling)
|
||||
'!tests-config/globalVars/*', // Exclude globalVars (need JSON config handling)
|
||||
'!tests-config/modifyVars/*', // Exclude modifyVars (need JSON config handling)
|
||||
'!tests-config/js-type-errors/*', // Exclude js-type-errors (need special test function)
|
||||
'!tests-config/no-js-errors/*', // Exclude no-js-errors (need special test function)
|
||||
'!tests-unit/import/import-remote.less', // Exclude import-remote (tested separately in isolation)
|
||||
|
||||
// HTTP import tests are now included since we have needle mocking
|
||||
];
|
||||
|
||||
var testMap = [
|
||||
// Main test runs using glob patterns (cosmiconfig handles configs)
|
||||
{
|
||||
patterns: globPatterns
|
||||
},
|
||||
|
||||
// Error tests
|
||||
{
|
||||
patterns: ['tests-error/eval/*.less'],
|
||||
verifyFunction: lessTester.testErrors
|
||||
},
|
||||
{
|
||||
patterns: ['tests-error/parse/*.less'],
|
||||
verifyFunction: lessTester.testErrors
|
||||
},
|
||||
|
||||
// Special test cases with specific handling
|
||||
{
|
||||
patterns: ['tests-config/js-type-errors/*.less'],
|
||||
verifyFunction: lessTester.testTypeErrors
|
||||
},
|
||||
{
|
||||
patterns: ['tests-config/no-js-errors/*.less'],
|
||||
verifyFunction: lessTester.testErrors
|
||||
},
|
||||
|
||||
// Sourcemap tests with special handling
|
||||
{
|
||||
patterns: [
|
||||
'tests-config/sourcemaps/**/*.less',
|
||||
'tests-config/sourcemaps-url/**/*.less',
|
||||
'tests-config/sourcemaps-rootpath/**/*.less',
|
||||
'tests-config/sourcemaps-basepath/**/*.less',
|
||||
'tests-config/sourcemaps-include-source/**/*.less'
|
||||
],
|
||||
verifyFunction: lessTester.testSourcemap,
|
||||
getFilename: function(filename, type, baseFolder) {
|
||||
if (type === 'vars') {
|
||||
return path.join(baseFolder, filename) + '.json';
|
||||
}
|
||||
// Extract just the filename (without directory) for the JSON file
|
||||
var jsonFilename = path.basename(filename);
|
||||
// For sourcemap type, return path relative to test directory
|
||||
if (type === 'sourcemap') {
|
||||
return path.join('test/sourcemaps', jsonFilename) + '.json';
|
||||
}
|
||||
return path.join('test/sourcemaps', jsonFilename) + '.json';
|
||||
}
|
||||
},
|
||||
{
|
||||
patterns: ['tests-config/sourcemaps-empty/*.less'],
|
||||
verifyFunction: lessTester.testEmptySourcemap
|
||||
},
|
||||
{
|
||||
patterns: ['tests-config/sourcemaps-disable-annotation/*.less'],
|
||||
verifyFunction: lessTester.testSourcemapWithoutUrlAnnotation
|
||||
},
|
||||
{
|
||||
patterns: ['tests-config/sourcemaps-variable-selector/*.less'],
|
||||
verifyFunction: lessTester.testSourcemapWithVariableInSelector
|
||||
},
|
||||
|
||||
// Import tests with JSON configs
|
||||
{
|
||||
patterns: ['tests-config/globalVars/*.less'],
|
||||
lessOptions: {
|
||||
globalVars: function(file) {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const basename = path.basename(file, '.less');
|
||||
const jsonPath = path.join(path.dirname(file), basename + '.json');
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
patterns: ['tests-config/modifyVars/*.less'],
|
||||
lessOptions: {
|
||||
modifyVars: function(file) {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const basename = path.basename(file, '.less');
|
||||
const jsonPath = path.join(path.dirname(file), basename + '.json');
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
// Note: needle mocking is set up globally at the top of the file
|
||||
|
||||
testMap.forEach(function(testConfig) {
|
||||
// For glob patterns, pass lessOptions as the first parameter and patterns as the second
|
||||
if (testConfig.patterns) {
|
||||
lessTester.runTestSet(
|
||||
testConfig.lessOptions || {}, // First param: options (including lessOptions)
|
||||
testConfig.patterns, // Second param: patterns
|
||||
testConfig.verifyFunction || null, // Third param: verifyFunction
|
||||
testConfig.nameModifier || null, // Fourth param: nameModifier
|
||||
testConfig.doReplacements || null, // Fifth param: doReplacements
|
||||
testConfig.getFilename || null // Sixth param: getFilename
|
||||
);
|
||||
} else {
|
||||
// Legacy format for non-glob tests
|
||||
var args = [
|
||||
testConfig.options || {}, // First param: options
|
||||
testConfig.foldername, // Second param: foldername
|
||||
testConfig.verifyFunction || null, // Third param: verifyFunction
|
||||
testConfig.nameModifier || null, // Fourth param: nameModifier
|
||||
testConfig.doReplacements || null, // Fifth param: doReplacements
|
||||
testConfig.getFilename || null // Sixth param: getFilename
|
||||
];
|
||||
lessTester.runTestSet.apply(lessTester, args);
|
||||
}
|
||||
});
|
||||
|
||||
// Special synchronous tests
|
||||
lessTester.testSyncronous({syncImport: true}, 'tests-unit/import/import');
|
||||
lessTester.testSyncronous({syncImport: true}, 'tests-config/math-strict/css');
|
||||
|
||||
lessTester.testNoOptions();
|
||||
lessTester.testDisablePluginRule();
|
||||
lessTester.testJSImport();
|
||||
lessTester.finished();
|
||||
|
||||
|
||||
// Test HTTP redirect functionality
|
||||
console.log('\nTesting HTTP redirect functionality...');
|
||||
testHttpRedirects();
|
||||
console.log('HTTP redirect test completed');
|
||||
|
||||
// Test import-remote functionality in isolation
|
||||
console.log('\nTesting import-remote functionality...');
|
||||
testImportRemote();
|
||||
console.log('Import-remote test completed');
|
||||
984
node_modules/less/test/less-test.js
generated
vendored
Normal file
984
node_modules/less/test/less-test.js
generated
vendored
Normal file
@@ -0,0 +1,984 @@
|
||||
/* jshint latedef: nofunc */
|
||||
var semver = require('semver');
|
||||
var logger = require('../lib/less/logger').default;
|
||||
var { cosmiconfigSync } = require('cosmiconfig');
|
||||
var glob = require('glob');
|
||||
|
||||
var isVerbose = process.env.npm_config_loglevel !== 'concise';
|
||||
logger.addListener({
|
||||
info(msg) {
|
||||
if (isVerbose) {
|
||||
process.stdout.write(msg + '\n');
|
||||
}
|
||||
},
|
||||
warn(msg) {
|
||||
process.stdout.write(msg + '\n');
|
||||
},
|
||||
error(msg) {
|
||||
process.stdout.write(msg + '\n');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = function(testFilter) {
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
clone = require('copy-anything').copy;
|
||||
|
||||
var less = require('../');
|
||||
|
||||
var stylize = require('../lib/less-node/lessc-helper').stylize;
|
||||
|
||||
var globals = Object.keys(global);
|
||||
|
||||
var oneTestOnly = testFilter || process.argv[2],
|
||||
isFinished = false;
|
||||
|
||||
var testFolder = path.dirname(require.resolve('@less/test-data'));
|
||||
var lessFolder = testFolder;
|
||||
|
||||
// Define String.prototype.endsWith if it doesn't exist (in older versions of node)
|
||||
// This is required by the testSourceMap function below
|
||||
if (typeof String.prototype.endsWith !== 'function') {
|
||||
String.prototype.endsWith = function (str) {
|
||||
return this.slice(-str.length) === str;
|
||||
}
|
||||
}
|
||||
|
||||
var queueList = [],
|
||||
queueRunning = false;
|
||||
function queue(func) {
|
||||
if (queueRunning) {
|
||||
// console.log("adding to queue");
|
||||
queueList.push(func);
|
||||
} else {
|
||||
// console.log("first in queue - starting");
|
||||
queueRunning = true;
|
||||
func();
|
||||
}
|
||||
}
|
||||
function release() {
|
||||
if (queueList.length) {
|
||||
// console.log("running next in queue");
|
||||
var func = queueList.shift();
|
||||
setTimeout(func, 0);
|
||||
} else {
|
||||
// console.log("stopping queue");
|
||||
queueRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
var totalTests = 0,
|
||||
failedTests = 0,
|
||||
passedTests = 0,
|
||||
finishTimer = setInterval(endTest, 500);
|
||||
|
||||
less.functions.functionRegistry.addMultiple({
|
||||
add: function (a, b) {
|
||||
return new(less.tree.Dimension)(a.value + b.value);
|
||||
},
|
||||
increment: function (a) {
|
||||
return new(less.tree.Dimension)(a.value + 1);
|
||||
},
|
||||
_color: function (str) {
|
||||
if (str.value === 'evil red') { return new(less.tree.Color)('600'); }
|
||||
}
|
||||
});
|
||||
|
||||
function validateSourcemapMappings(sourcemap, lessFile, compiledCSS) {
|
||||
// Validate sourcemap mappings using SourceMapConsumer
|
||||
var SourceMapConsumer = require('source-map').SourceMapConsumer;
|
||||
// sourcemap can be either a string or already parsed object
|
||||
var sourceMapObj = typeof sourcemap === 'string' ? JSON.parse(sourcemap) : sourcemap;
|
||||
var consumer = new SourceMapConsumer(sourceMapObj);
|
||||
|
||||
// Read the LESS source file
|
||||
var lessSource = fs.readFileSync(lessFile, 'utf8');
|
||||
var lessLines = lessSource.split('\n');
|
||||
|
||||
// Use the compiled CSS (remove sourcemap annotation for validation)
|
||||
var cssSource = compiledCSS.replace(/\/\*# sourceMappingURL=.*\*\/\s*$/, '').trim();
|
||||
var cssLines = cssSource.split('\n');
|
||||
|
||||
var errors = [];
|
||||
var validatedMappings = 0;
|
||||
|
||||
// Validate mappings for each line in the CSS
|
||||
for (var cssLine = 1; cssLine <= cssLines.length; cssLine++) {
|
||||
var cssLineContent = cssLines[cssLine - 1];
|
||||
// Skip empty lines
|
||||
if (!cssLineContent.trim()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check mapping for the start of this CSS line
|
||||
var mapping = consumer.originalPositionFor({
|
||||
line: cssLine,
|
||||
column: 0
|
||||
});
|
||||
|
||||
if (mapping.source) {
|
||||
validatedMappings++;
|
||||
|
||||
// Verify the source file exists in the sourcemap
|
||||
if (!sourceMapObj.sources || sourceMapObj.sources.indexOf(mapping.source) === -1) {
|
||||
errors.push('Line ' + cssLine + ': mapped to source "' + mapping.source + '" which is not in sources array');
|
||||
}
|
||||
|
||||
// Verify the line number is valid
|
||||
if (mapping.line && mapping.line > 0) {
|
||||
// If we can find the source file, validate the line exists
|
||||
var sourceIndex = sourceMapObj.sources.indexOf(mapping.source);
|
||||
if (sourceIndex >= 0 && sourceMapObj.sourcesContent && sourceMapObj.sourcesContent[sourceIndex] !== undefined && sourceMapObj.sourcesContent[sourceIndex] !== null) {
|
||||
var sourceContent = sourceMapObj.sourcesContent[sourceIndex];
|
||||
// Ensure sourceContent is a string (it should be, but be defensive)
|
||||
if (typeof sourceContent !== 'string') {
|
||||
sourceContent = String(sourceContent);
|
||||
}
|
||||
// Split by newline - handle both \n and \r\n
|
||||
var sourceLines = sourceContent.split(/\r?\n/);
|
||||
if (mapping.line > sourceLines.length) {
|
||||
errors.push('Line ' + cssLine + ': mapped to line ' + mapping.line + ' in "' + mapping.source + '" but source only has ' + sourceLines.length + ' lines');
|
||||
}
|
||||
} else if (sourceIndex >= 0) {
|
||||
// Source content not embedded, try to validate against the actual file if it matches
|
||||
// This is a best-effort validation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate that all sources in the sourcemap are valid
|
||||
if (sourceMapObj.sources) {
|
||||
sourceMapObj.sources.forEach(function(source, index) {
|
||||
if (sourceMapObj.sourcesContent && sourceMapObj.sourcesContent[index]) {
|
||||
// Source content is embedded, validate it's not empty
|
||||
if (!sourceMapObj.sourcesContent[index].trim()) {
|
||||
errors.push('Source "' + source + '" has empty content');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (consumer.destroy && typeof consumer.destroy === 'function') {
|
||||
consumer.destroy();
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors: errors,
|
||||
mappingsValidated: validatedMappings
|
||||
};
|
||||
}
|
||||
|
||||
function testSourcemap(name, err, compiledLess, doReplacements, sourcemap, baseFolder, getFilename) {
|
||||
if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
return;
|
||||
}
|
||||
// Check the sourceMappingURL at the bottom of the file
|
||||
// Default expected URL is name + '.css.map', but can be overridden by sourceMapURL option
|
||||
var sourceMappingPrefix = '/*# sourceMappingURL=',
|
||||
sourceMappingSuffix = ' */';
|
||||
var indexOfSourceMappingPrefix = compiledLess.indexOf(sourceMappingPrefix);
|
||||
if (indexOfSourceMappingPrefix === -1) {
|
||||
fail('ERROR: sourceMappingURL was not found in ' + baseFolder + '/' + name + '.css.');
|
||||
return;
|
||||
}
|
||||
|
||||
var startOfSourceMappingValue = indexOfSourceMappingPrefix + sourceMappingPrefix.length,
|
||||
indexOfSuffix = compiledLess.indexOf(sourceMappingSuffix, startOfSourceMappingValue),
|
||||
actualSourceMapURL = compiledLess.substring(startOfSourceMappingValue, indexOfSuffix === -1 ? compiledLess.length : indexOfSuffix).trim();
|
||||
|
||||
// For tests with custom sourceMapURL, we just verify it exists and is non-empty
|
||||
// The actual value will be validated by comparing the sourcemap JSON
|
||||
if (!actualSourceMapURL) {
|
||||
fail('ERROR: sourceMappingURL is empty in ' + baseFolder + '/' + name + '.css.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Use getFilename if available (for sourcemap tests with subdirectories)
|
||||
var jsonPath;
|
||||
if (getFilename && typeof getFilename === 'function') {
|
||||
jsonPath = getFilename(name, 'sourcemap', baseFolder);
|
||||
} else {
|
||||
// Fallback: extract just the filename for sourcemap JSON files
|
||||
var jsonFilename = path.basename(name);
|
||||
jsonPath = path.join('test/sourcemaps', jsonFilename) + '.json';
|
||||
}
|
||||
fs.readFile(jsonPath, 'utf8', function (e, expectedSourcemap) {
|
||||
process.stdout.write('- ' + path.join(baseFolder, name) + ': ');
|
||||
if (e) {
|
||||
fail('ERROR: Could not read expected sourcemap file: ' + jsonPath + ' - ' + e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply doReplacements to the expected sourcemap to handle {path} placeholders
|
||||
// This normalizes absolute paths that differ between environments
|
||||
// For sourcemaps, we need to ensure {path} uses forward slashes to avoid breaking JSON
|
||||
// (backslashes in JSON strings need escaping, and sourcemaps should use forward slashes anyway)
|
||||
var replacementPath = path.join(path.dirname(path.join(baseFolder, name) + '.less'), '/');
|
||||
// Normalize to forward slashes for sourcemap JSON (web-compatible)
|
||||
replacementPath = replacementPath.replace(/\\/g, '/');
|
||||
// Replace {path} with normalized forward-slash path BEFORE calling doReplacements
|
||||
// This ensures the JSON is always valid and uses web-compatible paths
|
||||
expectedSourcemap = expectedSourcemap.replace(/\{path\}/g, replacementPath);
|
||||
// Also handle other placeholders that might be in the sourcemap (but {path} is already done)
|
||||
expectedSourcemap = doReplacements(expectedSourcemap, baseFolder, path.join(baseFolder, name) + '.less');
|
||||
|
||||
// Normalize paths in sourcemap JSON to use forward slashes (web-compatible)
|
||||
// We need to parse the JSON, normalize the file property, then stringify for comparison
|
||||
// This avoids breaking escape sequences like \n in the JSON string
|
||||
function normalizeSourcemapPaths(sm) {
|
||||
try {
|
||||
var parsed = typeof sm === 'string' ? JSON.parse(sm) : sm;
|
||||
if (parsed.file) {
|
||||
parsed.file = parsed.file.replace(/\\/g, '/');
|
||||
}
|
||||
// Also normalize paths in sources array
|
||||
if (parsed.sources && Array.isArray(parsed.sources)) {
|
||||
parsed.sources = parsed.sources.map(function(src) {
|
||||
return src.replace(/\\/g, '/');
|
||||
});
|
||||
}
|
||||
return JSON.stringify(parsed, null, 0);
|
||||
} catch (parseErr) {
|
||||
// If parsing fails, return original (shouldn't happen)
|
||||
return sm;
|
||||
}
|
||||
}
|
||||
|
||||
var normalizedSourcemap = normalizeSourcemapPaths(sourcemap);
|
||||
var normalizedExpected = normalizeSourcemapPaths(expectedSourcemap);
|
||||
|
||||
if (normalizedSourcemap === normalizedExpected) {
|
||||
// Validate the sourcemap mappings are correct
|
||||
// Find the actual LESS file - it might be in a subdirectory
|
||||
var nameParts = name.split('/');
|
||||
var lessFileName = nameParts[nameParts.length - 1];
|
||||
var lessFileDir = nameParts.length > 1 ? nameParts.slice(0, -1).join('/') : '';
|
||||
var lessFile = path.join(lessFolder, lessFileDir, lessFileName) + '.less';
|
||||
|
||||
// Only validate if the LESS file exists
|
||||
if (fs.existsSync(lessFile)) {
|
||||
try {
|
||||
// Parse the sourcemap once for validation (avoid re-parsing)
|
||||
// Use the original sourcemap string, not the normalized one
|
||||
var sourceMapObjForValidation = typeof sourcemap === 'string' ? JSON.parse(sourcemap) : sourcemap;
|
||||
var validation = validateSourcemapMappings(sourceMapObjForValidation, lessFile, compiledLess);
|
||||
if (!validation.valid) {
|
||||
fail('ERROR: Sourcemap validation failed:\n' + validation.errors.join('\n'));
|
||||
return;
|
||||
}
|
||||
if (isVerbose && validation.mappingsValidated > 0) {
|
||||
process.stdout.write(' (validated ' + validation.mappingsValidated + ' mappings)');
|
||||
}
|
||||
} catch (validationErr) {
|
||||
if (isVerbose) {
|
||||
process.stdout.write(' (validation error: ' + validationErr.message + ')');
|
||||
}
|
||||
// Don't fail the test if validation has an error, just log it
|
||||
}
|
||||
}
|
||||
|
||||
ok('OK');
|
||||
} else if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
if (isVerbose) {
|
||||
process.stdout.write('\n');
|
||||
process.stdout.write(err.stack + '\n');
|
||||
}
|
||||
} else {
|
||||
difference('FAIL', normalizedExpected, normalizedSourcemap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testSourcemapWithoutUrlAnnotation(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
|
||||
if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
return;
|
||||
}
|
||||
// This matches with strings that end($) with source mapping url annotation.
|
||||
var sourceMapRegExp = /\/\*# sourceMappingURL=.+\.css\.map \*\/$/;
|
||||
if (sourceMapRegExp.test(compiledLess)) {
|
||||
fail('ERROR: sourceMappingURL found in ' + baseFolder + '/' + name + '.css.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Even if annotation is not necessary, the map file should be there.
|
||||
fs.readFile(path.join('test/', name) + '.json', 'utf8', function (e, expectedSourcemap) {
|
||||
process.stdout.write('- ' + path.join(baseFolder, name) + ': ');
|
||||
if (sourcemap === expectedSourcemap) {
|
||||
ok('OK');
|
||||
} else if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
if (isVerbose) {
|
||||
process.stdout.write('\n');
|
||||
process.stdout.write(err.stack + '\n');
|
||||
}
|
||||
} else {
|
||||
difference('FAIL', expectedSourcemap, sourcemap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testEmptySourcemap(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
|
||||
process.stdout.write('- ' + path.join(baseFolder, name) + ': ');
|
||||
if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
} else {
|
||||
var expectedSourcemap = undefined;
|
||||
if ( compiledLess !== '' ) {
|
||||
difference('\nCompiledLess must be empty', '', compiledLess);
|
||||
|
||||
} else if (sourcemap !== expectedSourcemap) {
|
||||
fail('Sourcemap must be undefined');
|
||||
} else {
|
||||
ok('OK');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testSourcemapWithVariableInSelector(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
|
||||
if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
return;
|
||||
}
|
||||
|
||||
// Even if annotation is not necessary, the map file should be there.
|
||||
fs.readFile(path.join('test/', name) + '.json', 'utf8', function (e, expectedSourcemap) {
|
||||
process.stdout.write('- ' + path.join(baseFolder, name) + ': ');
|
||||
if (sourcemap === expectedSourcemap) {
|
||||
ok('OK');
|
||||
} else if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
if (isVerbose) {
|
||||
process.stdout.write('\n');
|
||||
process.stdout.write(err.stack + '\n');
|
||||
}
|
||||
} else {
|
||||
difference('FAIL', expectedSourcemap, sourcemap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testImports(name, err, compiledLess, doReplacements, sourcemap, baseFolder, imports) {
|
||||
if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
return;
|
||||
}
|
||||
|
||||
function stringify(str) {
|
||||
return JSON.stringify(imports, null, ' ')
|
||||
}
|
||||
|
||||
/** Imports are not sorted */
|
||||
const importsString = stringify(imports.sort())
|
||||
|
||||
fs.readFile(path.join(lessFolder, name) + '.json', 'utf8', function (e, expectedImports) {
|
||||
if (e) {
|
||||
fail('ERROR: ' + (e && e.message));
|
||||
return;
|
||||
}
|
||||
process.stdout.write('- ' + path.join(baseFolder, name) + ': ');
|
||||
expectedImports = stringify(JSON.parse(expectedImports).sort());
|
||||
expectedImports = globalReplacements(expectedImports, baseFolder);
|
||||
|
||||
if (expectedImports === importsString) {
|
||||
ok('OK');
|
||||
} else if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
if (isVerbose) {
|
||||
process.stdout.write('\n');
|
||||
process.stdout.write(err.stack + '\n');
|
||||
}
|
||||
} else {
|
||||
difference('FAIL', expectedImports, importsString);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testErrors(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
|
||||
fs.readFile(path.join(baseFolder, name) + '.txt', 'utf8', function (e, expectedErr) {
|
||||
process.stdout.write('- ' + path.join(baseFolder, name) + ': ');
|
||||
expectedErr = doReplacements(expectedErr, baseFolder, err && err.filename);
|
||||
if (!err) {
|
||||
if (compiledLess) {
|
||||
fail('No Error', 'red');
|
||||
} else {
|
||||
fail('No Error, No Output');
|
||||
}
|
||||
} else {
|
||||
var errMessage = err.toString();
|
||||
if (errMessage === expectedErr) {
|
||||
ok('OK');
|
||||
} else {
|
||||
difference('FAIL', expectedErr, errMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// To fix ci fail about error format change in upstream v8 project
|
||||
// https://github.com/v8/v8/commit/c0fd89c3c089e888c4f4e8582e56db7066fa779b
|
||||
// Node 16.9.0+ include this change via https://github.com/nodejs/node/pull/39947
|
||||
function testTypeErrors(name, err, compiledLess, doReplacements, sourcemap, baseFolder) {
|
||||
const fileSuffix = semver.gte(process.version, 'v16.9.0') ? '-2.txt' : '.txt';
|
||||
fs.readFile(path.join(baseFolder, name) + fileSuffix, 'utf8', function (e, expectedErr) {
|
||||
process.stdout.write('- ' + path.join(baseFolder, name) + ': ');
|
||||
expectedErr = doReplacements(expectedErr, baseFolder, err && err.filename);
|
||||
if (!err) {
|
||||
if (compiledLess) {
|
||||
fail('No Error', 'red');
|
||||
} else {
|
||||
fail('No Error, No Output');
|
||||
}
|
||||
} else {
|
||||
var errMessage = err.toString();
|
||||
if (errMessage === expectedErr) {
|
||||
ok('OK');
|
||||
} else {
|
||||
difference('FAIL', expectedErr, errMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// https://github.com/less/less.js/issues/3112
|
||||
function testJSImport() {
|
||||
process.stdout.write('- Testing root function registry');
|
||||
less.functions.functionRegistry.add('ext', function() {
|
||||
return new less.tree.Anonymous('file');
|
||||
});
|
||||
var expected = '@charset "utf-8";\n';
|
||||
toCSS({}, path.join(lessFolder, 'tests-config', 'root-registry', 'root.less'), function(error, output) {
|
||||
if (error) {
|
||||
return fail('ERROR: ' + error);
|
||||
}
|
||||
if (output.css === expected) {
|
||||
return ok('OK');
|
||||
}
|
||||
difference('FAIL', expected, output.css);
|
||||
});
|
||||
}
|
||||
|
||||
function globalReplacements(input, directory, filename) {
|
||||
var path = require('path');
|
||||
var p = filename ? path.join(path.dirname(filename), '/') : directory;
|
||||
|
||||
// For debug tests in subdirectories (comments/, mediaquery/, all/),
|
||||
// the import/ directory and main linenumbers.less file are at the parent debug/ level, not in the subdirectory
|
||||
var isDebugSubdirectory = false;
|
||||
var debugParentPath = null;
|
||||
|
||||
if (directory) {
|
||||
// Normalize directory path separators for matching
|
||||
var normalizedDir = directory.replace(/\\/g, '/');
|
||||
// Check if we're in a debug subdirectory
|
||||
if (normalizedDir.includes('/debug/') && (normalizedDir.includes('/comments/') || normalizedDir.includes('/mediaquery/') || normalizedDir.includes('/all/'))) {
|
||||
isDebugSubdirectory = true;
|
||||
// Extract the debug/ directory path (parent of the subdirectory)
|
||||
// Match everything up to and including /debug/ (works with both absolute and relative paths)
|
||||
var debugMatch = normalizedDir.match(/(.+\/debug)\//);
|
||||
if (debugMatch) {
|
||||
debugParentPath = debugMatch[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDebugSubdirectory && debugParentPath) {
|
||||
// For {path} placeholder, use the parent debug/ directory
|
||||
// Convert back to native path format
|
||||
p = debugParentPath.replace(/\//g, path.sep) + path.sep;
|
||||
}
|
||||
|
||||
var pathimport;
|
||||
if (isDebugSubdirectory && debugParentPath) {
|
||||
pathimport = path.join(debugParentPath.replace(/\//g, path.sep), 'import') + path.sep;
|
||||
} else {
|
||||
pathimport = path.join(directory + 'import/');
|
||||
}
|
||||
|
||||
var pathesc = p.replace(/[.:/\\]/g, function(a) { return '\\' + (a == '\\' ? '\/' : a); }),
|
||||
pathimportesc = pathimport.replace(/[.:/\\]/g, function(a) { return '\\' + (a == '\\' ? '\/' : a); });
|
||||
|
||||
return input.replace(/\{path\}/g, p)
|
||||
.replace(/\{node\}/g, '')
|
||||
.replace(/\{\/node\}/g, '')
|
||||
.replace(/\{pathhref\}/g, '')
|
||||
.replace(/\{404status\}/g, '')
|
||||
.replace(/\{nodepath\}/g, path.join(process.cwd(), 'node_modules', '/'))
|
||||
.replace(/\{pathrel\}/g, path.join(path.relative(lessFolder, p), '/'))
|
||||
.replace(/\{pathesc\}/g, pathesc)
|
||||
.replace(/\{pathimport\}/g, pathimport)
|
||||
.replace(/\{pathimportesc\}/g, pathimportesc)
|
||||
.replace(/\r\n/g, '\n');
|
||||
}
|
||||
|
||||
function checkGlobalLeaks() {
|
||||
return Object.keys(global).filter(function(v) {
|
||||
return globals.indexOf(v) < 0;
|
||||
});
|
||||
}
|
||||
|
||||
function testSyncronous(options, filenameNoExtension) {
|
||||
if (oneTestOnly && ('Test Sync ' + filenameNoExtension) !== oneTestOnly) {
|
||||
return;
|
||||
}
|
||||
totalTests++;
|
||||
queue(function() {
|
||||
var isSync = true;
|
||||
toCSS(options, path.join(lessFolder, filenameNoExtension + '.less'), function (err, result) {
|
||||
process.stdout.write('- Test Sync ' + filenameNoExtension + ': ');
|
||||
|
||||
if (isSync) {
|
||||
ok('OK');
|
||||
} else {
|
||||
fail('Not Sync');
|
||||
}
|
||||
release();
|
||||
});
|
||||
isSync = false;
|
||||
});
|
||||
}
|
||||
|
||||
function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
|
||||
// Handle case where first parameter is glob patterns (no options object)
|
||||
if (Array.isArray(options)) {
|
||||
// First parameter is glob patterns, no options object
|
||||
foldername = options;
|
||||
options = {};
|
||||
} else if (typeof options === 'string') {
|
||||
// First parameter is foldername (no options object)
|
||||
foldername = options;
|
||||
options = {};
|
||||
} else {
|
||||
options = options ? clone(options) : {};
|
||||
}
|
||||
runTestSetInternal(lessFolder, options, foldername, verifyFunction, nameModifier, doReplacements, getFilename);
|
||||
}
|
||||
|
||||
function runTestSetNormalOnly(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
|
||||
runTestSetInternal(lessFolder, options, foldername, verifyFunction, nameModifier, doReplacements, getFilename);
|
||||
}
|
||||
|
||||
function runTestSetInternal(baseFolder, opts, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
|
||||
foldername = foldername || '';
|
||||
|
||||
var originalOptions = opts || {};
|
||||
|
||||
if (!doReplacements) {
|
||||
doReplacements = globalReplacements;
|
||||
}
|
||||
|
||||
// Handle glob patterns with exclusions
|
||||
if (Array.isArray(foldername)) {
|
||||
var patterns = foldername;
|
||||
var includePatterns = [];
|
||||
var excludePatterns = [];
|
||||
|
||||
|
||||
patterns.forEach(function(pattern) {
|
||||
if (pattern.startsWith('!')) {
|
||||
excludePatterns.push(pattern.substring(1));
|
||||
} else {
|
||||
includePatterns.push(pattern);
|
||||
}
|
||||
});
|
||||
|
||||
// Use glob to find all matching files, excluding the excluded patterns
|
||||
var allFiles = [];
|
||||
includePatterns.forEach(function(pattern) {
|
||||
var files = glob.sync(pattern, {
|
||||
cwd: baseFolder,
|
||||
absolute: true,
|
||||
ignore: excludePatterns
|
||||
});
|
||||
|
||||
allFiles = allFiles.concat(files);
|
||||
});
|
||||
|
||||
// Note: needle mocking is set up globally in index.js
|
||||
|
||||
// Process each .less file found
|
||||
allFiles.forEach(function(filePath) {
|
||||
if (/\.less$/.test(filePath)) {
|
||||
var file = path.basename(filePath);
|
||||
// For glob patterns, we need to construct the relative path differently
|
||||
// The filePath is absolute, so we need to get the path relative to the test-data directory
|
||||
var relativePath = path.relative(baseFolder, path.dirname(filePath)) + '/';
|
||||
|
||||
// Only process files that have corresponding .css files (these are the actual tests)
|
||||
var cssPath = path.join(path.dirname(filePath), path.basename(file, '.less') + '.css');
|
||||
if (fs.existsSync(cssPath)) {
|
||||
// Process this file using the existing logic
|
||||
processFileWithInfo({
|
||||
file: file,
|
||||
fullPath: filePath,
|
||||
relativePath: relativePath
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function processFileWithInfo(fileInfo) {
|
||||
var file = fileInfo.file;
|
||||
var fullPath = fileInfo.fullPath;
|
||||
var relativePath = fileInfo.relativePath;
|
||||
|
||||
// Load config for this specific file using cosmiconfig
|
||||
var configResult = cosmiconfigSync('styles').search(path.dirname(fullPath));
|
||||
|
||||
// Deep clone the original options to prevent Less from modifying shared objects
|
||||
var options = JSON.parse(JSON.stringify(originalOptions || {}));
|
||||
|
||||
if (configResult && configResult.config && configResult.config.language && configResult.config.language.less) {
|
||||
// Deep clone and merge the language.less settings with the original options
|
||||
var lessConfig = JSON.parse(JSON.stringify(configResult.config.language.less));
|
||||
Object.keys(lessConfig).forEach(function(key) {
|
||||
options[key] = lessConfig[key];
|
||||
});
|
||||
}
|
||||
|
||||
// Merge any lessOptions from the testMap (for dynamic options like getVars functions)
|
||||
if (originalOptions && originalOptions.lessOptions) {
|
||||
Object.keys(originalOptions.lessOptions).forEach(function(key) {
|
||||
var value = originalOptions.lessOptions[key];
|
||||
if (typeof value === 'function') {
|
||||
// For functions, call them with the file path
|
||||
var result = value(fullPath);
|
||||
options[key] = result;
|
||||
} else {
|
||||
// For static values, use them directly
|
||||
options[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Don't pass stylize to less.render as it's not a valid option
|
||||
|
||||
var name = getBasename(file, relativePath);
|
||||
|
||||
|
||||
if (oneTestOnly && typeof oneTestOnly === 'string' && !name.includes(oneTestOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
totalTests++;
|
||||
|
||||
if (options.sourceMap && !options.sourceMap.sourceMapFileInline) {
|
||||
// Set test infrastructure defaults only if not already set by styles.config.cjs
|
||||
// Less.js core (parse-tree.js) will handle normalization of:
|
||||
// - sourceMapBasepath (defaults to input file's directory)
|
||||
// - sourceMapInputFilename (defaults to options.filename)
|
||||
// - sourceMapFilename (derived from sourceMapOutputFilename or input filename)
|
||||
// - sourceMapOutputFilename (derived from input filename if not set)
|
||||
if (!options.sourceMap.sourceMapOutputFilename) {
|
||||
// Needed for sourcemap file name in JSON output
|
||||
options.sourceMap.sourceMapOutputFilename = name + '.css';
|
||||
}
|
||||
if (!options.sourceMap.sourceMapRootpath) {
|
||||
// Test-specific default for consistent test output paths
|
||||
options.sourceMap.sourceMapRootpath = 'testweb/';
|
||||
}
|
||||
}
|
||||
|
||||
options.getVars = function(file) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(getFilename(getBasename(file, relativePath), 'vars', baseFolder), 'utf8'));
|
||||
}
|
||||
catch (e) {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
var doubleCallCheck = false;
|
||||
queue(function() {
|
||||
toCSS(options, fullPath, function (err, result) {
|
||||
|
||||
if (doubleCallCheck) {
|
||||
totalTests++;
|
||||
fail('less is calling back twice');
|
||||
process.stdout.write(doubleCallCheck + '\n');
|
||||
process.stdout.write((new Error()).stack + '\n');
|
||||
return;
|
||||
}
|
||||
doubleCallCheck = (new Error()).stack;
|
||||
|
||||
/**
|
||||
* @todo - refactor so the result object is sent to the verify function
|
||||
*/
|
||||
if (verifyFunction) {
|
||||
var verificationResult = verifyFunction(
|
||||
name, err, result && result.css, doReplacements, result && result.map, baseFolder, result && result.imports, getFilename
|
||||
);
|
||||
release();
|
||||
return verificationResult;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
fail('ERROR: ' + (err && err.message));
|
||||
if (isVerbose) {
|
||||
process.stdout.write('\n');
|
||||
if (err.stack) {
|
||||
process.stdout.write(err.stack + '\n');
|
||||
} else {
|
||||
// this sometimes happen - show the whole error object
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
release();
|
||||
return;
|
||||
}
|
||||
var css_name = name;
|
||||
if (nameModifier) { css_name = nameModifier(name); }
|
||||
|
||||
// Check if we're using the new co-located structure (tests-unit/ or tests-config/) or the old separated structure
|
||||
var cssPath;
|
||||
if (relativePath.startsWith('tests-unit/') || relativePath.startsWith('tests-config/')) {
|
||||
// New co-located structure: CSS file is in the same directory as LESS file
|
||||
cssPath = path.join(path.dirname(fullPath), path.basename(file, '.less') + '.css');
|
||||
} else {
|
||||
// Old separated structure: CSS file is in separate css/ folder
|
||||
// Windows compatibility: css_name may already contain path separators
|
||||
// Use path.join with empty string to let path.join handle normalization
|
||||
cssPath = path.join(testFolder, css_name) + '.css';
|
||||
}
|
||||
|
||||
// For the new structure, we need to handle replacements differently
|
||||
var replacementPath;
|
||||
if (relativePath.startsWith('tests-unit/') || relativePath.startsWith('tests-config/')) {
|
||||
replacementPath = path.dirname(fullPath);
|
||||
// Ensure replacementPath ends with a path separator for consistent matching
|
||||
if (!replacementPath.endsWith(path.sep)) {
|
||||
replacementPath += path.sep;
|
||||
}
|
||||
} else {
|
||||
replacementPath = path.join(baseFolder, relativePath);
|
||||
}
|
||||
|
||||
var testName = fullPath.replace(/\.less$/, '');
|
||||
process.stdout.write('- ' + testName + ': ');
|
||||
|
||||
|
||||
var css = fs.readFileSync(cssPath, 'utf8');
|
||||
css = css && doReplacements(css, replacementPath);
|
||||
if (result.css === css) { ok('OK'); }
|
||||
else {
|
||||
difference('FAIL', css, result.css);
|
||||
}
|
||||
|
||||
release();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getBasename(file, relativePath) {
|
||||
var basePath = relativePath || foldername;
|
||||
// Ensure basePath ends with a slash for proper path construction
|
||||
if (basePath.charAt(basePath.length - 1) !== '/') {
|
||||
basePath = basePath + '/';
|
||||
}
|
||||
return basePath + path.basename(file, '.less');
|
||||
}
|
||||
|
||||
|
||||
// This function is only called for non-glob patterns now
|
||||
// For glob patterns, we use the glob library in the calling code
|
||||
var dirPath = path.join(baseFolder, foldername);
|
||||
var items = fs.readdirSync(dirPath);
|
||||
|
||||
items.forEach(function(item) {
|
||||
if (/\.less$/.test(item)) {
|
||||
processFileWithInfo({
|
||||
file: item,
|
||||
fullPath: path.join(dirPath, item),
|
||||
relativePath: foldername
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function diff(left, right) {
|
||||
// Configure chalk to always show colors
|
||||
var chalk = require('chalk');
|
||||
chalk.level = 3; // Force colors on
|
||||
|
||||
// Use jest-diff for much clearer output like Vitest
|
||||
var diffResult = require('jest-diff').diffStringsUnified(left || '', right || '', {
|
||||
expand: false,
|
||||
includeChangeCounts: true,
|
||||
contextLines: 1,
|
||||
aColor: chalk.red,
|
||||
bColor: chalk.green,
|
||||
changeColor: chalk.inverse,
|
||||
commonColor: chalk.dim
|
||||
});
|
||||
|
||||
// jest-diff returns a string with ANSI colors, so we can output it directly
|
||||
process.stdout.write(diffResult + '\n');
|
||||
}
|
||||
|
||||
function fail(msg) {
|
||||
process.stdout.write(stylize(msg, 'red') + '\n');
|
||||
failedTests++;
|
||||
endTest();
|
||||
}
|
||||
|
||||
function difference(msg, left, right) {
|
||||
process.stdout.write(stylize(msg, 'yellow') + '\n');
|
||||
failedTests++;
|
||||
|
||||
// Only show the diff, not the full text
|
||||
process.stdout.write(stylize('Diff:', 'yellow') + '\n');
|
||||
|
||||
diff(left || '', right || '');
|
||||
endTest();
|
||||
}
|
||||
|
||||
function ok(msg) {
|
||||
process.stdout.write(stylize(msg, 'green') + '\n');
|
||||
passedTests++;
|
||||
endTest();
|
||||
}
|
||||
|
||||
function finished() {
|
||||
isFinished = true;
|
||||
endTest();
|
||||
}
|
||||
|
||||
function endTest() {
|
||||
if (isFinished && ((failedTests + passedTests) >= totalTests)) {
|
||||
clearInterval(finishTimer);
|
||||
var leaked = checkGlobalLeaks();
|
||||
process.stdout.write('\n');
|
||||
if (failedTests > 0) {
|
||||
process.stdout.write(failedTests + stylize(' Failed', 'red') + ', ' + passedTests + ' passed\n');
|
||||
} else {
|
||||
process.stdout.write(stylize('All Passed ', 'green') + passedTests + ' run\n');
|
||||
}
|
||||
if (leaked.length > 0) {
|
||||
process.stdout.write('\n');
|
||||
process.stdout.write(stylize('Global leak detected: ', 'red') + leaked.join(', ') + '\n');
|
||||
}
|
||||
|
||||
if (leaked.length || failedTests) {
|
||||
process.on('exit', function() { process.reallyExit(1); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function contains(fullArray, obj) {
|
||||
for (var i = 0; i < fullArray.length; i++) {
|
||||
if (fullArray[i] === obj) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {string} filePath
|
||||
* @param {Function} callback
|
||||
*/
|
||||
function toCSS(options, filePath, callback) {
|
||||
// Deep clone options to prevent modifying the original, but preserve functions
|
||||
var originalOptions = options || {};
|
||||
options = JSON.parse(JSON.stringify(originalOptions));
|
||||
|
||||
// Restore functions that were lost in JSON serialization
|
||||
if (originalOptions.getVars) {
|
||||
options.getVars = originalOptions.getVars;
|
||||
}
|
||||
var str = fs.readFileSync(filePath, 'utf8'), addPath = path.dirname(filePath);
|
||||
|
||||
// Initialize paths array if it doesn't exist
|
||||
if (typeof options.paths !== 'string') {
|
||||
options.paths = options.paths || [];
|
||||
} else {
|
||||
options.paths = [options.paths];
|
||||
}
|
||||
|
||||
// Add the current directory to paths if not already present
|
||||
if (!contains(options.paths, addPath)) {
|
||||
options.paths.push(addPath);
|
||||
}
|
||||
|
||||
// Resolve all paths relative to the test file's directory
|
||||
options.paths = options.paths.map(searchPath => {
|
||||
if (path.isAbsolute(searchPath)) {
|
||||
return searchPath;
|
||||
}
|
||||
// Resolve relative to the test file's directory
|
||||
return path.resolve(path.dirname(filePath), searchPath);
|
||||
})
|
||||
|
||||
options.filename = path.resolve(process.cwd(), filePath);
|
||||
options.optimization = options.optimization || 0;
|
||||
|
||||
// Note: globalVars and modifyVars are now handled via styles.config.cjs or lessOptions
|
||||
if (options.plugin) {
|
||||
var Plugin = require(path.resolve(process.cwd(), options.plugin));
|
||||
options.plugins = [Plugin];
|
||||
}
|
||||
less.render(str, options, callback);
|
||||
}
|
||||
|
||||
function testNoOptions() {
|
||||
if (oneTestOnly && 'Integration' !== oneTestOnly) {
|
||||
return;
|
||||
}
|
||||
totalTests++;
|
||||
try {
|
||||
process.stdout.write('- Integration - creating parser without options: ');
|
||||
less.render('');
|
||||
} catch (e) {
|
||||
fail(stylize('FAIL\n', 'red'));
|
||||
return;
|
||||
}
|
||||
ok(stylize('OK\n', 'green'));
|
||||
}
|
||||
|
||||
// HTTP redirect testing is now handled directly in test/index.js
|
||||
|
||||
function testDisablePluginRule() {
|
||||
less.render(
|
||||
'@plugin "../../plugin/some_plugin";',
|
||||
{disablePluginRule: true},
|
||||
function(err) {
|
||||
// TODO: Need a better way of identifing exactly which error is thrown. Checking
|
||||
// text like this tends to be rather brittle.
|
||||
const EXPECTED = '@plugin statements are not allowed when disablePluginRule is set to true';
|
||||
if (!err || String(err).indexOf(EXPECTED) < 0) {
|
||||
fail('ERROR: Expected "' + EXPECTED + '" error');
|
||||
return;
|
||||
}
|
||||
ok(stylize('OK\n', 'green'));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
runTestSet: runTestSet,
|
||||
runTestSetNormalOnly: runTestSetNormalOnly,
|
||||
testSyncronous: testSyncronous,
|
||||
testErrors: testErrors,
|
||||
testTypeErrors: testTypeErrors,
|
||||
testSourcemap: testSourcemap,
|
||||
testSourcemapWithoutUrlAnnotation: testSourcemapWithoutUrlAnnotation,
|
||||
testSourcemapWithVariableInSelector: testSourcemapWithVariableInSelector,
|
||||
testImports: testImports,
|
||||
testEmptySourcemap: testEmptySourcemap,
|
||||
testNoOptions: testNoOptions,
|
||||
testDisablePluginRule: testDisablePluginRule,
|
||||
testJSImport: testJSImport,
|
||||
finished: finished
|
||||
};
|
||||
};
|
||||
210
node_modules/less/test/mocha-playwright/runner.js
generated
vendored
Normal file
210
node_modules/less/test/mocha-playwright/runner.js
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const util = require('util');
|
||||
const { chromium } = require('playwright');
|
||||
const TIMEOUT_MILLISECONDS = 60000;
|
||||
|
||||
function initMocha(reporter) {
|
||||
|
||||
console.log = (console => {
|
||||
const log = console.log.bind(console);
|
||||
return (...args) => args.length ? log(...args) : log('');
|
||||
})(console);
|
||||
|
||||
function shimMochaInstance(m) {
|
||||
|
||||
const originalReporter = m.reporter.bind(m);
|
||||
let reporterIsChanged = false;
|
||||
|
||||
m.reporter = (...args) => {
|
||||
reporterIsChanged = true;
|
||||
originalReporter(...args);
|
||||
};
|
||||
|
||||
const run = m.run.bind(m);
|
||||
|
||||
m.run = () => {
|
||||
const all = [], pending = [], failures = [], passes = [];
|
||||
|
||||
function error(err) {
|
||||
if (!err) return {};
|
||||
|
||||
let res = {};
|
||||
Object.getOwnPropertyNames(err).forEach(key => res[key] = err[key]);
|
||||
return res;
|
||||
}
|
||||
|
||||
function clean(test) {
|
||||
return {
|
||||
title: test.title,
|
||||
fullTitle: test.fullTitle(),
|
||||
duration: test.duration,
|
||||
err: error(test.err)
|
||||
};
|
||||
}
|
||||
|
||||
function result(stats) {
|
||||
return {
|
||||
result: {
|
||||
stats: {
|
||||
tests: all.length,
|
||||
passes: passes.length,
|
||||
pending: pending.length,
|
||||
failures: failures.length,
|
||||
start: stats.start.toISOString(),
|
||||
end: stats.end.toISOString(),
|
||||
duration: stats.duration
|
||||
},
|
||||
tests: all.map(clean),
|
||||
pending: pending.map(clean),
|
||||
failures: failures.map(clean),
|
||||
passes: passes.map(clean)
|
||||
},
|
||||
coverage: window.__coverage__
|
||||
};
|
||||
}
|
||||
|
||||
function setResult() {
|
||||
!window.__mochaResult__ && (window.__mochaResult__ = result(this.stats));
|
||||
}
|
||||
|
||||
!reporterIsChanged && m.setup({
|
||||
reporter: Mocha.reporters[reporter] || Mocha.reporters.spec
|
||||
});
|
||||
|
||||
const runner = run(() => setTimeout(() => setResult.call(runner), 0))
|
||||
.on('pass', test => { passes.push(test); all.push(test); })
|
||||
.on('fail', test => { failures.push(test); all.push(test); })
|
||||
.on('pending', test => { pending.push(test); all.push(test); })
|
||||
.on('end', setResult);
|
||||
|
||||
return runner;
|
||||
};
|
||||
}
|
||||
|
||||
function shimMochaProcess(M) {
|
||||
// Mocha needs a process.stdout.write in order to change the cursor position.
|
||||
!M.process && (M.process = {});
|
||||
!M.process.stdout && (M.process.stdout = {});
|
||||
|
||||
M.process.stdout.write = data => console.log('stdout:', data);
|
||||
M.reporters.Base.useColors = true;
|
||||
M.reporters.none = function None(runner) {
|
||||
M.reporters.Base.call(this, runner);
|
||||
};
|
||||
}
|
||||
|
||||
Object.defineProperty(window, 'mocha', {
|
||||
get: function() { return undefined },
|
||||
set: function(m) {
|
||||
shimMochaInstance(m);
|
||||
delete window.mocha;
|
||||
window.mocha = m
|
||||
},
|
||||
configurable: true
|
||||
})
|
||||
|
||||
Object.defineProperty(window, 'Mocha', {
|
||||
get: function() { return undefined },
|
||||
set: function(m) {
|
||||
shimMochaProcess(m);
|
||||
delete window.Mocha;
|
||||
window.Mocha = m;
|
||||
},
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
function configureViewport(width, height, page) {
|
||||
if (!width && !height) return page;
|
||||
|
||||
let viewport = page.viewport();
|
||||
width && (viewport.width = width);
|
||||
height && (viewport.height = height);
|
||||
|
||||
return page.setViewport(viewport).then(() => page);
|
||||
}
|
||||
|
||||
function handleConsole(msg) {
|
||||
const args = msg.args() || [];
|
||||
|
||||
Promise.all(args.map(a => a.jsonValue().catch(error => {
|
||||
console.warn('Failed to retrieve JSON value from argument:', error);
|
||||
return '';
|
||||
})))
|
||||
.then(args => {
|
||||
// process stdout stub
|
||||
let isStdout = args[0] === 'stdout:';
|
||||
isStdout && (args = args.slice(1));
|
||||
|
||||
let msg = util.format(...args);
|
||||
!isStdout && msg && (msg += '\n');
|
||||
process.stdout.write(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function prepareUrl(filePath) {
|
||||
if (/^[a-zA-Z]+:\/\//.test(filePath)) {
|
||||
// path is URL
|
||||
return filePath;
|
||||
}
|
||||
|
||||
// local path
|
||||
let resolvedPath = path.resolve(filePath);
|
||||
return `file://${resolvedPath}`;
|
||||
}
|
||||
|
||||
exports.runner = function ({ file, reporter, timeout, width, height, args, executablePath, visible, polling }) {
|
||||
return new Promise(resolve => {
|
||||
|
||||
// validate options
|
||||
if (!file) {
|
||||
throw new Error('Test page path is required.');
|
||||
}
|
||||
|
||||
args = [].concat(args || []).map(arg => '--' + arg);
|
||||
!timeout && (timeout = TIMEOUT_MILLISECONDS);
|
||||
/^\d+$/.test(polling) && (polling = parseInt(polling));
|
||||
|
||||
const url = prepareUrl(file);
|
||||
|
||||
const options = {
|
||||
ignoreHTTPSErrors: true,
|
||||
headless: !visible,
|
||||
executablePath,
|
||||
args
|
||||
};
|
||||
|
||||
const result = chromium.launch(options)
|
||||
.then(browser => browser.newContext()
|
||||
.then(context => context.newPage()
|
||||
.then(page => {
|
||||
if (width || height) {
|
||||
return page.setViewportSize({ width: width || 800, height: height || 600 }).then(() => page);
|
||||
}
|
||||
return page;
|
||||
})
|
||||
.then(page => {
|
||||
page.on('console', handleConsole);
|
||||
page.on('dialog', dialog => dialog.dismiss());
|
||||
page.on('pageerror', err => console.error(err));
|
||||
|
||||
return page.addInitScript(initMocha, reporter)
|
||||
.then(() => page.goto(url))
|
||||
.then(() => page.waitForFunction(() => window.__mochaResult__, { timeout, polling }))
|
||||
.then(() => page.evaluate(() => window.__mochaResult__))
|
||||
.then(result => {
|
||||
if (!result) {
|
||||
throw new Error('Mocha results not found after waiting. The tests may not have run correctly.');
|
||||
}
|
||||
// Close browser before resolving result
|
||||
return browser.close().then(() => result);
|
||||
});
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
resolve(result);
|
||||
});
|
||||
};
|
||||
28
node_modules/less/test/modify-vars.js
generated
vendored
Normal file
28
node_modules/less/test/modify-vars.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
var less;
|
||||
|
||||
// Dist fallback for NPM-installed Less (for plugins that do testing)
|
||||
try {
|
||||
less = require('../tmp/less.cjs.js');
|
||||
}
|
||||
catch (e) {
|
||||
less = require('../dist/less.cjs.js');
|
||||
}
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var input = fs.readFileSync('./test/less/modifyVars/extended.less', 'utf8');
|
||||
var expectedCss = fs.readFileSync('./test/css/modifyVars/extended.css', 'utf8');
|
||||
var options = {
|
||||
modifyVars: JSON.parse(fs.readFileSync('./test/less/modifyVars/extended.json', 'utf8'))
|
||||
};
|
||||
|
||||
less.render(input, options, function (err, result) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
if (result.css === expectedCss) {
|
||||
console.log('PASS');
|
||||
} else {
|
||||
console.log('FAIL');
|
||||
}
|
||||
});
|
||||
19
node_modules/less/test/plugins/filemanager/index.js
generated
vendored
Normal file
19
node_modules/less/test/plugins/filemanager/index.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
(function(exports) {
|
||||
var plugin = function(less) {
|
||||
var FileManager = less.FileManager, TestFileManager = new FileManager();
|
||||
function TestFileManager() { }
|
||||
TestFileManager.loadFile = function (filename, currentDirectory, options, environment, callback) {
|
||||
if (filename.match(/.*\.test$/)) {
|
||||
return less.environment.fileManagers[0].loadFile('colors.test', currentDirectory, options, environment, callback);
|
||||
}
|
||||
return less.environment.fileManagers[0].loadFile(filename, currentDirectory, options, environment, callback);
|
||||
};
|
||||
|
||||
return TestFileManager;
|
||||
};
|
||||
|
||||
exports.install = function(less, pluginManager) {
|
||||
less.environment.addFileManager(new plugin(less));
|
||||
};
|
||||
|
||||
})(typeof exports === 'undefined' ? this['AddFilePlugin'] = {} : exports);
|
||||
14
node_modules/less/test/plugins/postprocess/index.js
generated
vendored
Normal file
14
node_modules/less/test/plugins/postprocess/index.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
(function(exports) {
|
||||
var postProcessor = function() {};
|
||||
|
||||
postProcessor.prototype = {
|
||||
process: function (css) {
|
||||
return 'hr {height:50px;}\n' + css;
|
||||
}
|
||||
};
|
||||
|
||||
exports.install = function(less, pluginManager) {
|
||||
pluginManager.addPostProcessor( new postProcessor());
|
||||
};
|
||||
|
||||
})(typeof exports === 'undefined' ? this['postProcessorPlugin'] = {} : exports);
|
||||
19
node_modules/less/test/plugins/preprocess/index.js
generated
vendored
Normal file
19
node_modules/less/test/plugins/preprocess/index.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
(function(exports) {
|
||||
var preProcessor = function() {};
|
||||
|
||||
preProcessor.prototype = {
|
||||
process : function (src, extra) {
|
||||
var injected = '@color: red;\n';
|
||||
var ignored = extra.imports.contentsIgnoredChars;
|
||||
var fileInfo = extra.fileInfo;
|
||||
ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0;
|
||||
ignored[fileInfo.filename] += injected.length;
|
||||
return injected + src;
|
||||
}
|
||||
};
|
||||
|
||||
exports.install = function(less, pluginManager) {
|
||||
pluginManager.addPreProcessor( new preProcessor() );
|
||||
};
|
||||
|
||||
})(typeof exports === 'undefined' ? this['preProcessorPlugin'] = {} : exports);
|
||||
24
node_modules/less/test/plugins/visitor/index.js
generated
vendored
Normal file
24
node_modules/less/test/plugins/visitor/index.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
(function(exports) {
|
||||
var RemoveProperty = function(less) {
|
||||
this._visitor = new less.visitors.Visitor(this);
|
||||
};
|
||||
|
||||
RemoveProperty.prototype = {
|
||||
isReplacing: true,
|
||||
run: function (root) {
|
||||
return this._visitor.visit(root);
|
||||
},
|
||||
visitDeclaration: function (ruleNode, visitArgs) {
|
||||
if (ruleNode.name != '-some-aribitrary-property') {
|
||||
return ruleNode;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.install = function(less, pluginManager) {
|
||||
pluginManager.addVisitor( new RemoveProperty(less));
|
||||
};
|
||||
|
||||
})(typeof exports === 'undefined' ? this['VisitorPlugin'] = {} : exports);
|
||||
1
node_modules/less/test/sourcemaps-disable-annotation/basic.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps-disable-annotation/basic.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["testweb/sourcemaps-disable-annotation/basic.less"],"names":[],"mappings":"AAAA;;EAEE,YAAA","file":"sourcemaps-disable-annotation/basic.css"}
|
||||
1
node_modules/less/test/sourcemaps-variable-selector/basic.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps-variable-selector/basic.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["testweb/sourcemaps-variable-selector/basic.less"],"names":[],"mappings":"AAEC;EACG,eAAA","file":"sourcemaps-variable-selector/basic.css"}
|
||||
1
node_modules/less/test/sourcemaps/basic.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps/basic.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["testweb/sourcemaps/basic.less","testweb/sourcemaps/imported.css"],"names":[],"mappings":"AAMA;EACE,YAAA;EAJA,UAAA;EAWA,iBAAA;EALA,WAAA;EACA,iBAAA;;AAJF,EASE;AATF,EASM;EACF,gBAAA;;AACA,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;EAGA,UAAA;;AALN;AAAI;AAUJ;EATE,iBAAA;;AADF,EAEE;AAFE,EAEF;AAFF,EAEM;AAFF,EAEE;AAQN,OARE;AAQF,OARM;EACF,gBAAA;;AACA,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFJ;AAEE,EAFF,GAEI,KAFA;AAEF,EAFF,GAEI,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFJ;AAEE,EAFE,GAEA,KAFA;AAEF,EAFE,GAEA,KAFA;AAQN,OARE,GAQF,UARE;AAQF,OARE,GAEI,KAFJ;AAQF,OARE,GAQF,UARM;AAQN,OARE,GAEI,KAFA;AAEF,EAFF,GAQF,UARE;AAEE,EAFF,GAQF,UARM;AAQN,OARM,GAQN,UARE;AAQF,OARM,GAEA,KAFJ;AAQF,OARM,GAQN,UARM;AAQN,OARM,GAEA,KAFA;AAEF,EAFE,GAQN,UARE;AAEE,EAFE,GAQN,UARM;EAGA,UAAA;;AAKN;EACE,WAAA;;ACxBF;AACA;AACA;AACA;AACA;AACA;AACA","file":"sourcemaps/basic.css"}
|
||||
1
node_modules/less/test/sourcemaps/comprehensive.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps/comprehensive.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["comprehensive.less"],"names":[],"mappings":"AAoBA;EACE,aAAA;EACA,mBAAA;;AAFF,UAIE;EACE,YAAA;EACA,eAAA;;AANJ,UAIE,QAIE;EACE,iBAAA;EACA,mBAAA;;AAVN,UAcE;EACE,mBAAA;EACA,aAAA;;AAhBJ,UAcE,SAIE;EACE,SAAA;EACA,gBAAA;;AAMN;EACE,OAAO,qBAAP;EACA,QAAQ,iBAAR;EACA,YAAA;;AAIF;EACE,cAAA;EACA,mBAAA;EACA,yCAAA;;AAIF;EAlDE,mBAAA;EACA,2BAAA;EACA,wBAAA;EAIA,yCAAA;EA+CA,aAAA;EACA,iBAAA;;AAIF,QAA0B;EACxB;IACE,aAAA;;EADF,UAGE;IACE,eAAA;;;AAKN;EACE;IACE,aAAA;IACA,uBAAuB,cAAvB;IACA,SAAA;;;AAKJ;AAMA;EALE,kBAAA;EACA,YAAA;EACA,eAAA;;AAGF;EAEE,mBAAA;EACA,YAAA;;AAIF,WACE;EACE,gBAAA;;AAFJ,WACE,GAGE;EACE,qBAAA;;AALN,WACE,GAGE,GAGE;EACE,qBAAA;;AAEA,WATN,GAGE,GAGE,EAGG;EACC,cAAA;;AAGF,WAbN,GAGE,GAGE,EAOG;EACC,cAAA;;AAYT;EACC,cAAA;;AAIF,OACE,QACE,QACE;EACE,cAAA","file":"{path}comprehensive.css"}
|
||||
1
node_modules/less/test/sourcemaps/custom-props.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps/custom-props.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["testweb/sourcemaps/custom-props.less"],"names":[],"mappings":"AAEA;EACC,uBAHO,UAGP;EACA,OAAO,eAAP;EACA,sBALO,UAKP","file":"sourcemaps/custom-props.css"}
|
||||
17
node_modules/less/test/sourcemaps/index.html
generated
vendored
Normal file
17
node_modules/less/test/sourcemaps/index.html
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<link type="text/css" rel="stylesheet" media="all" href="import.css">
|
||||
<link type="text/css" rel="stylesheet" media="all" href="basic.css">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div id="import-test">id import-test</div>
|
||||
<div id="import">id import-test</div>
|
||||
<div class="imported inline">class imported inline</div>
|
||||
<div id="mixin">class mixin</div>
|
||||
<div class="a">class a</div>
|
||||
<div class="b">class b</div>
|
||||
<div class="b">class b<div class="c">class c</div></div>
|
||||
<div class="a">class a<div class="d">class d</div></div>
|
||||
<div class="extend">class extend<div class="c">class c</div></div>
|
||||
</body>
|
||||
</html>
|
||||
1
node_modules/less/test/sourcemaps/sourcemaps-basepath.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps/sourcemaps-basepath.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["testweb/sourcemaps-basepath.less"],"names":[],"mappings":"AAEA;EACE,eAAA;EACA,gBAAA;;AAGF;EACE,iBAAA","file":"tests-config/sourcemaps-basepath/sourcemaps-basepath.css"}
|
||||
1
node_modules/less/test/sourcemaps/sourcemaps-include-source.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps/sourcemaps-include-source.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["testweb/sourcemaps-include-source.less"],"names":[],"mappings":"AAGA;EACE,mBAAA;EACA,YAAA;EACA,kBAAA;;AAGF;EACE,mBAAA","file":"tests-config/sourcemaps-include-source/sourcemaps-include-source.css","sourcesContent":["@primary: #007bff;\n@secondary: #6c757d;\n\n.button {\n background: @primary;\n color: white;\n padding: 10px 20px;\n}\n\n.secondary {\n background: @secondary;\n}\n\n"]}
|
||||
1
node_modules/less/test/sourcemaps/sourcemaps-rootpath.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps/sourcemaps-rootpath.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["https://example.com/less/sourcemaps-rootpath.less"],"names":[],"mappings":"AAEA;EACE,aAAA;EACA,YAAA;;AAGF;EACE,WAAA","file":"tests-config/sourcemaps-rootpath/sourcemaps-rootpath.css"}
|
||||
1
node_modules/less/test/sourcemaps/sourcemaps-url.json
generated
vendored
Normal file
1
node_modules/less/test/sourcemaps/sourcemaps-url.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["testweb/sourcemaps-url.less"],"names":[],"mappings":"AAEA;EACE,UAAA;EACA,gBAAA;;AAGF;EACE,YAAA","file":"tests-config/sourcemaps-url/sourcemaps-url.css"}
|
||||
17
node_modules/less/test/test-es6.ts
generated
vendored
Normal file
17
node_modules/less/test/test-es6.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// https://github.com/less/less.js/issues/3533
|
||||
console.log('Testing ES6 imports...')
|
||||
|
||||
import less from '..';
|
||||
const lessRender = less.render;
|
||||
|
||||
// then I call lessRender on something
|
||||
lessRender(`
|
||||
body {
|
||||
a: 1;
|
||||
b: 2;
|
||||
c: 30;
|
||||
d: 4;
|
||||
}`, {sourceMap: {}}, function(error: any, output: any) {
|
||||
if (error)
|
||||
console.error(error)
|
||||
})
|
||||
Reference in New Issue
Block a user