jsmin.sourcemap.test.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Load in dependencies
  2. var assert = require('assert'),
  3. fs = require('fs'),
  4. sourcemap = require('source-map'),
  5. charProps = require('char-props'),
  6. jsmin = require('../'),
  7. SourceMapConsumer = sourcemap.SourceMapConsumer,
  8. testFilesDir = __dirname + '/test_files';
  9. function minifySingle() {
  10. before(function () {
  11. // Read in the src file
  12. var params = this.params,
  13. src = params.src,
  14. singleSrc = fs.readFileSync(testFilesDir + '/' + src, 'utf8');
  15. // Save to the code namespace
  16. this.input = [{'src': src, 'code': singleSrc}];
  17. this.result = jsmin({'code': singleSrc, 'src': src, 'dest': params.dest});
  18. });
  19. }
  20. function minifyMulti() {
  21. before(function () {
  22. // Localize the src
  23. var params = this.params,
  24. src = params.src;
  25. // Read in the src files
  26. var srcFiles = src.map(function (filepath) {
  27. var fileSrc = fs.readFileSync(testFilesDir + '/' + filepath, 'utf8'),
  28. retObj = {
  29. 'code': fileSrc,
  30. 'src': filepath
  31. };
  32. return retObj;
  33. });
  34. // Save relevant info
  35. this.input = srcFiles;
  36. this.result = jsmin({'input': srcFiles, 'dest': params.dest});
  37. });
  38. }
  39. function assertMatchesC() {
  40. it('matches its C-minified counterpart', function () {
  41. var params = this.params,
  42. expectedCode = fs.readFileSync(__dirname + '/expected_files/' + params.dest, 'utf8');
  43. assert.strictEqual(
  44. this.result.code,
  45. expectedCode,
  46. 'Minified ' + JSON.stringify(params.src) + ' does not match ' + params.dest
  47. );
  48. });
  49. }
  50. function mapAgainstSource() {
  51. before(function () {
  52. // Iterate over the input
  53. var srcPropMap = {};
  54. this.input.forEach(function (item) {
  55. srcPropMap[item.src] = charProps(item.code);
  56. });
  57. // Generate a consumer and charProps lookups
  58. var result = this.result;
  59. this.srcConsumer = new SourceMapConsumer(result.sourcemap);
  60. this.actualProps = charProps(result.code);
  61. this.srcPropMap = srcPropMap;
  62. });
  63. }
  64. function assertAllPositionsMatch() {
  65. it('matches at all positions', function () {
  66. // Iterate over each of the characters
  67. var breaks = this.expectedBreaks || [],
  68. result = this.result,
  69. actualCode = result.code,
  70. actualProps = this.actualProps,
  71. i = 0,
  72. len = actualCode.length;
  73. for (; i < len; i++) {
  74. // Look up the position of our index
  75. var actualPosition = {
  76. 'line': actualProps.lineAt(i) + 1,
  77. 'column': actualProps.columnAt(i)
  78. };
  79. // Grab the position of the item and its fil
  80. var srcPosition = this.srcConsumer.originalPositionFor(actualPosition),
  81. srcFile = srcPosition.source;
  82. // If we have a source file and we are not at a break spot
  83. // TODO: Actually figure out `breaks`
  84. var atBreakSpot = breaks.indexOf(i) > -1;
  85. if (srcFile && !atBreakSpot) {
  86. // Grab the srcProps for it
  87. var srcProps = this.srcPropMap[srcFile];
  88. // Lookup the character at the src positions
  89. var srcLine = srcPosition.line - 1,
  90. srcCol = srcPosition.column,
  91. srcChar = srcProps.charAt({
  92. 'line': srcLine,
  93. 'column': srcCol
  94. });
  95. // Assert that the actual and expected characters are equal
  96. var actualChar = actualCode.charAt(i);
  97. // DEV: Nuking character comparison for break location so we can find it via error message
  98. // assert.strictEqual(actualChar, srcChar, 'The sourcemapped character at index ' + i + ' does not match its original character at line ' + srcLine + ', column ' + srcCol + '.');
  99. assert(actualChar === srcChar, 'The sourcemapped character at index ' + i + ' does not match its original character at line ' + srcLine + ', column ' + srcCol + '.');
  100. }
  101. }
  102. });
  103. }
  104. function isDebuggable() {
  105. if (process.env.TEST_DEBUG) {
  106. before(function () {
  107. try { fs.mkdirSync(__dirname + '/actual_files'); } catch (e) {}
  108. fs.writeFileSync(__dirname + '/actual_files/debug.min.js', this.result.code, 'utf8');
  109. fs.writeFileSync(__dirname + '/actual_files/debug.min.map', this.result.sourcemap, 'utf8');
  110. });
  111. }
  112. }
  113. describe('A single file', function () {
  114. before(function jQueryPaths () {
  115. this.params = {'src': '1.js', 'dest': 'single.js'};
  116. });
  117. describe('minified and sourcemapped (single)', function () {
  118. minifySingle();
  119. isDebuggable();
  120. assertMatchesC();
  121. describe('mapped against its source', function () {
  122. mapAgainstSource();
  123. assertAllPositionsMatch();
  124. });
  125. });
  126. });
  127. describe('jQuery', function () {
  128. before(function jQueryPaths () {
  129. this.params = {'src': 'jquery.js', 'dest': 'jquery.min.js'};
  130. });
  131. describe('minified and sourcemapped (single)', function () {
  132. minifySingle();
  133. isDebuggable();
  134. assertMatchesC();
  135. });
  136. });
  137. describe('Multiple files', function () {
  138. before(function multiPaths () {
  139. this.params = {'src': ['1.js', '2.js', '3.js'], 'dest': 'multi.js'};
  140. this.expectedBreaks = [52, 70];
  141. });
  142. describe('minified and sourcemapped (multi)', function () {
  143. minifyMulti();
  144. isDebuggable();
  145. assertMatchesC();
  146. describe('mapped against its source', function () {
  147. mapAgainstSource();
  148. assertAllPositionsMatch();
  149. });
  150. });
  151. });
  152. describe('Multiple nested files', function () {
  153. before(function () {
  154. this.params = {
  155. 'src': [
  156. 'nested.js',
  157. 'nested/controllers/controller1.js',
  158. 'nested/controllers/controller2.js',
  159. 'nested/models/model1.js'
  160. ],
  161. 'dest': 'nested.min.js'
  162. };
  163. this.expectedBreaks = [1, 43, 88, 100];
  164. });
  165. describe('minified and sourcemapped (multi)', function () {
  166. minifyMulti();
  167. isDebuggable();
  168. assertMatchesC();
  169. describe('mapped against its source', function () {
  170. mapAgainstSource();
  171. assertAllPositionsMatch();
  172. });
  173. });
  174. });
  175. describe('Multiple files containing "use strict"', function () {
  176. before(function () {
  177. this.params = {
  178. 'src': [
  179. 'strict1.js',
  180. 'strict2.js'
  181. ],
  182. 'dest': 'strict.min.js'
  183. };
  184. this.expectedBreaks = [36];
  185. });
  186. describe('minified and sourcemapped (multi)', function () {
  187. minifyMulti();
  188. isDebuggable();
  189. // DEV: This is not the actual C output. The C one doesn't contain line breaks which can break concatenated scripts.
  190. assertMatchesC();
  191. describe('mapped against its source', function () {
  192. mapAgainstSource();
  193. assertAllPositionsMatch();
  194. });
  195. });
  196. });
  197. describe('Multiple files containing "use strict" 2', function () {
  198. before(function () {
  199. this.params = {
  200. 'src': [
  201. 'strict3.js',
  202. 'strict4.js'
  203. ],
  204. 'dest': 'strict2.min.js'
  205. };
  206. this.expectedBreaks = [135];
  207. });
  208. describe('minified and sourcemapped (multi)', function () {
  209. minifyMulti();
  210. isDebuggable();
  211. // DEV: This is not the actual C output. The C one doesn't contain line breaks which can break concatenated scripts.
  212. assertMatchesC();
  213. describe('mapped against its source', function () {
  214. mapAgainstSource();
  215. assertAllPositionsMatch();
  216. });
  217. });
  218. });