common.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. var logMessages = [];
  2. window.less = window.less || {};
  3. var logLevel_debug = 4,
  4. logLevel_info = 3,
  5. logLevel_warn = 2,
  6. logLevel_error = 1;
  7. // The amount of logging in the javascript console.
  8. // 3 - Debug, information and errors
  9. // 2 - Information and errors
  10. // 1 - Errors
  11. // 0 - None
  12. // Defaults to 2
  13. less.loggers = [
  14. {
  15. debug: function(msg) {
  16. if (less.options.logLevel >= logLevel_debug) {
  17. logMessages.push(msg);
  18. }
  19. },
  20. info: function(msg) {
  21. if (less.options.logLevel >= logLevel_info) {
  22. logMessages.push(msg);
  23. }
  24. },
  25. warn: function(msg) {
  26. if (less.options.logLevel >= logLevel_warn) {
  27. logMessages.push(msg);
  28. }
  29. },
  30. error: function(msg) {
  31. if (less.options.logLevel >= logLevel_error) {
  32. logMessages.push(msg);
  33. }
  34. }
  35. }
  36. ];
  37. testLessEqualsInDocument = function () {
  38. testLessInDocument(testSheet);
  39. };
  40. testLessErrorsInDocument = function (isConsole) {
  41. testLessInDocument(isConsole ? testErrorSheetConsole : testErrorSheet);
  42. };
  43. testLessInDocument = function (testFunc) {
  44. var links = document.getElementsByTagName('link'),
  45. typePattern = /^text\/(x-)?less$/;
  46. for (var i = 0; i < links.length; i++) {
  47. if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
  48. (links[i].type.match(typePattern)))) {
  49. testFunc(links[i]);
  50. }
  51. }
  52. };
  53. ieFormat = function(text) {
  54. var styleNode = document.createElement('style');
  55. styleNode.setAttribute('type', 'text/css');
  56. var headNode = document.getElementsByTagName('head')[0];
  57. headNode.appendChild(styleNode);
  58. try {
  59. if (styleNode.styleSheet) {
  60. styleNode.styleSheet.cssText = text;
  61. } else {
  62. styleNode.innerText = text;
  63. }
  64. } catch (e) {
  65. throw new Error('Couldn\'t reassign styleSheet.cssText.');
  66. }
  67. var transformedText = styleNode.styleSheet ? styleNode.styleSheet.cssText : styleNode.innerText;
  68. headNode.removeChild(styleNode);
  69. return transformedText;
  70. };
  71. testSheet = function (sheet) {
  72. it(sheet.id + ' should match the expected output', function (done) {
  73. var lessOutputId = sheet.id.replace('original-', ''),
  74. expectedOutputId = 'expected-' + lessOutputId,
  75. lessOutputObj,
  76. lessOutput,
  77. expectedOutputHref = document.getElementById(expectedOutputId).href,
  78. expectedOutput = loadFile(expectedOutputHref);
  79. // Browser spec generates less on the fly, so we need to loose control
  80. less.pageLoadFinished
  81. .then(function () {
  82. lessOutputObj = document.getElementById(lessOutputId);
  83. lessOutput = lessOutputObj.styleSheet ? lessOutputObj.styleSheet.cssText :
  84. (lessOutputObj.innerText || lessOutputObj.innerHTML);
  85. expectedOutput
  86. .then(function (text) {
  87. if (window.navigator.userAgent.indexOf('MSIE') >= 0 ||
  88. window.navigator.userAgent.indexOf('Trident/') >= 0) {
  89. text = ieFormat(text);
  90. }
  91. expect(lessOutput).to.equal(text);
  92. done();
  93. })
  94. .catch(function(err) {
  95. done(err);
  96. });
  97. })
  98. .catch(function(err) {
  99. done(err);
  100. });
  101. });
  102. };
  103. // TODO: do it cleaner - the same way as in css
  104. function extractId(href) {
  105. return href.replace(/^[a-z-]+:\/+?[^\/]+/i, '') // Remove protocol & domain
  106. .replace(/^\//, '') // Remove root /
  107. .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension
  108. .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
  109. .replace(/\./g, ':'); // Replace dots with colons(for valid id)
  110. }
  111. waitFor = function (waitFunc) {
  112. return new Promise(function (resolve) {
  113. var timeoutId = setInterval(function () {
  114. if (waitFunc()) {
  115. clearInterval(timeoutId);
  116. resolve();
  117. }
  118. }, 5);
  119. });
  120. };
  121. testErrorSheet = function (sheet) {
  122. it(sheet.id + ' should match an error', function (done) {
  123. var lessHref = sheet.href,
  124. id = 'less-error-message:' + extractId(lessHref),
  125. errorHref = lessHref.replace(/.less$/, '.txt'),
  126. errorFile = loadFile(errorHref),
  127. actualErrorElement,
  128. actualErrorMsg;
  129. // Less.js sets 10ms timer in order to add error message on top of page.
  130. waitFor(function () {
  131. actualErrorElement = document.getElementById(id);
  132. return actualErrorElement !== null;
  133. }).then(function () {
  134. var innerText = (actualErrorElement.innerHTML
  135. .replace(/<h3>|<\/?p>|<a href="[^"]*">|<\/a>|<ul>|<\/?pre( class="?[^">]*"?)?>|<\/li>|<\/?label>/ig, '')
  136. .replace(/<\/h3>/ig, ' ')
  137. .replace(/<li>|<\/ul>|<br>/ig, '\n'))
  138. .replace(/&amp;/ig, '&')
  139. // for IE8
  140. .replace(/\r\n/g, '\n')
  141. .replace(/\. \nin/, '. in');
  142. actualErrorMsg = innerText
  143. .replace(/\n\d+/g, function (lineNo) {
  144. return lineNo + ' ';
  145. })
  146. .replace(/\n\s*in /g, ' in ')
  147. .replace(/\n{2,}/g, '\n')
  148. .replace(/\nStack Trace\n[\s\S]*/i, '')
  149. .replace(/\n$/, '')
  150. .trim();
  151. errorFile
  152. .then(function (errorTxt) {
  153. errorTxt = errorTxt
  154. .replace(/\{path\}/g, '')
  155. .replace(/\{pathrel\}/g, '')
  156. .replace(/\{pathhref\}/g, 'http://localhost:8081/test/less/errors/')
  157. .replace(/\{404status\}/g, ' (404)')
  158. .replace(/\{node\}[\s\S]*\{\/node\}/g, '')
  159. .replace(/\n$/, '')
  160. .trim();
  161. expect(actualErrorMsg).to.equal(errorTxt);
  162. if (errorTxt == actualErrorMsg) {
  163. actualErrorElement.style.display = 'none';
  164. }
  165. done();
  166. })
  167. .catch(function (err) {
  168. done(err);
  169. });
  170. });
  171. });
  172. };
  173. testErrorSheetConsole = function (sheet) {
  174. it(sheet.id + ' should match an error', function (done) {
  175. var lessHref = sheet.href,
  176. id = sheet.id.replace(/^original-less:/, 'less-error-message:'),
  177. errorHref = lessHref.replace(/.less$/, '.txt'),
  178. errorFile = loadFile(errorHref),
  179. actualErrorElement = document.getElementById(id),
  180. actualErrorMsg = logMessages[logMessages.length - 1]
  181. .replace(/\nStack Trace\n[\s\S]*/, '');
  182. describe('the error', function () {
  183. expect(actualErrorElement).to.be.null;
  184. });
  185. errorFile
  186. .then(function (errorTxt) {
  187. errorTxt
  188. .replace(/\{path\}/g, '')
  189. .replace(/\{pathrel\}/g, '')
  190. .replace(/\{pathhref\}/g, 'http://localhost:8081/browser/less/')
  191. .replace(/\{404status\}/g, ' (404)')
  192. .replace(/\{node\}.*\{\/node\}/g, '')
  193. .trim();
  194. expect(actualErrorMsg).to.equal(errorTxt);
  195. done();
  196. });
  197. });
  198. };
  199. loadFile = function (href) {
  200. return new Promise(function (resolve, reject) {
  201. var request = new XMLHttpRequest();
  202. request.open('GET', href, true);
  203. request.onreadystatechange = function () {
  204. if (request.readyState == 4) {
  205. resolve(request.responseText.replace(/\r/g, ''));
  206. }
  207. };
  208. request.send(null);
  209. });
  210. };