• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3if (!process.features.inspector) return;
4
5const common = require('../common');
6const assert = require('assert');
7const { dirname } = require('path');
8const fs = require('fs');
9const path = require('path');
10const { spawnSync } = require('child_process');
11
12const tmpdir = require('../common/tmpdir');
13tmpdir.refresh();
14
15let dirc = 0;
16function nextdir() {
17  return process.env.NODE_V8_COVERAGE ||
18    path.join(tmpdir.path, `source_map_${++dirc}`);
19}
20
21// Outputs source maps when event loop is drained, with no async logic.
22{
23  const coverageDirectory = nextdir();
24  const output = spawnSync(process.execPath, [
25    require.resolve('../fixtures/source-map/basic')
26  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
27  if (output.status !== 0) {
28    console.log(output.stderr.toString());
29  }
30  assert.strictEqual(output.status, 0);
31  assert.strictEqual(output.stderr.toString(), '');
32  const sourceMap = getSourceMapFromCache('basic.js', coverageDirectory);
33  assert.strictEqual(sourceMap.url, 'https://ci.nodejs.org/418');
34}
35
36// Outputs source maps when process.kill(process.pid, "SIGINT"); exits process.
37{
38  const coverageDirectory = nextdir();
39  const output = spawnSync(process.execPath, [
40    require.resolve('../fixtures/source-map/sigint')
41  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
42  if (!common.isWindows) {
43    if (output.signal !== 'SIGINT') {
44      console.log(output.stderr.toString());
45    }
46    assert.strictEqual(output.signal, 'SIGINT');
47  }
48  assert.strictEqual(output.stderr.toString(), '');
49  const sourceMap = getSourceMapFromCache('sigint.js', coverageDirectory);
50  assert.strictEqual(sourceMap.url, 'https://ci.nodejs.org/402');
51}
52
53// Outputs source maps when source-file calls process.exit(1).
54{
55  const coverageDirectory = nextdir();
56  const output = spawnSync(process.execPath, [
57    require.resolve('../fixtures/source-map/exit-1')
58  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
59  assert.strictEqual(output.stderr.toString(), '');
60  const sourceMap = getSourceMapFromCache('exit-1.js', coverageDirectory);
61  assert.strictEqual(sourceMap.url, 'https://ci.nodejs.org/404');
62}
63
64// Outputs source-maps for esm module.
65{
66  const coverageDirectory = nextdir();
67  const output = spawnSync(process.execPath, [
68    '--no-warnings',
69    require.resolve('../fixtures/source-map/esm-basic.mjs')
70  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
71  assert.strictEqual(output.stderr.toString(), '');
72  const sourceMap = getSourceMapFromCache('esm-basic.mjs', coverageDirectory);
73  assert.strictEqual(sourceMap.url, 'https://ci.nodejs.org/405');
74}
75
76// Loads source-maps with relative path from .map file on disk.
77{
78  const coverageDirectory = nextdir();
79  const output = spawnSync(process.execPath, [
80    require.resolve('../fixtures/source-map/disk-relative-path')
81  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
82  assert.strictEqual(output.status, 0);
83  assert.strictEqual(output.stderr.toString(), '');
84  const sourceMap = getSourceMapFromCache(
85    'disk-relative-path.js',
86    coverageDirectory
87  );
88  // Source-map should have been loaded from disk and sources should have been
89  // rewritten, such that they're absolute paths.
90  assert.strictEqual(
91    dirname(
92      `file://${require.resolve('../fixtures/source-map/disk-relative-path')}`),
93    dirname(sourceMap.data.sources[0])
94  );
95}
96
97// Loads source-maps from inline data URL.
98{
99  const coverageDirectory = nextdir();
100  const output = spawnSync(process.execPath, [
101    require.resolve('../fixtures/source-map/inline-base64.js')
102  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
103  assert.strictEqual(output.status, 0);
104  assert.strictEqual(output.stderr.toString(), '');
105  const sourceMap = getSourceMapFromCache(
106    'inline-base64.js',
107    coverageDirectory
108  );
109  // base64 JSON should have been decoded, and paths to sources should have
110  // been rewritten such that they're absolute:
111  assert.strictEqual(
112    dirname(
113      `file://${require.resolve('../fixtures/source-map/inline-base64')}`),
114    dirname(sourceMap.data.sources[0])
115  );
116}
117
118// base64 encoding error does not crash application.
119{
120  const coverageDirectory = nextdir();
121  const output = spawnSync(process.execPath, [
122    require.resolve('../fixtures/source-map/inline-base64-type-error.js')
123  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
124  assert.strictEqual(output.status, 0);
125  assert.strictEqual(output.stderr.toString(), '');
126  const sourceMap = getSourceMapFromCache(
127    'inline-base64-type-error.js',
128    coverageDirectory
129  );
130
131  assert.strictEqual(sourceMap.data, null);
132}
133
134// JSON error does not crash application.
135{
136  const coverageDirectory = nextdir();
137  const output = spawnSync(process.execPath, [
138    require.resolve('../fixtures/source-map/inline-base64-json-error.js')
139  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
140  assert.strictEqual(output.status, 0);
141  assert.strictEqual(output.stderr.toString(), '');
142  const sourceMap = getSourceMapFromCache(
143    'inline-base64-json-error.js',
144    coverageDirectory
145  );
146
147  assert.strictEqual(sourceMap.data, null);
148}
149
150// Does not apply source-map to stack trace if --experimental-modules
151// is not set.
152{
153  const output = spawnSync(process.execPath, [
154    require.resolve('../fixtures/source-map/uglify-throw.js')
155  ]);
156  assert.strictEqual(
157    output.stderr.toString().match(/->.*uglify-throw-original\.js:5:9/),
158    null
159  );
160  assert.strictEqual(
161    output.stderr.toString().match(/->.*uglify-throw-original\.js:9:3/),
162    null
163  );
164}
165
166// Applies source-maps generated by uglifyjs to stack trace.
167{
168  const output = spawnSync(process.execPath, [
169    '--enable-source-maps',
170    require.resolve('../fixtures/source-map/uglify-throw.js')
171  ]);
172  assert.ok(
173    output.stderr.toString().match(/->.*uglify-throw-original\.js:5:9/)
174  );
175  assert.ok(
176    output.stderr.toString().match(/->.*uglify-throw-original\.js:9:3/)
177  );
178}
179
180// Applies source-maps generated by tsc to stack trace.
181{
182  const output = spawnSync(process.execPath, [
183    '--enable-source-maps',
184    require.resolve('../fixtures/source-map/typescript-throw.js')
185  ]);
186  assert.ok(output.stderr.toString().match(/->.*typescript-throw\.ts:18:11/));
187  assert.ok(output.stderr.toString().match(/->.*typescript-throw\.ts:24:1/));
188}
189
190// Applies source-maps generated by babel to stack trace.
191{
192  const output = spawnSync(process.execPath, [
193    '--enable-source-maps',
194    require.resolve('../fixtures/source-map/babel-throw.js')
195  ]);
196  assert.ok(
197    output.stderr.toString().match(/->.*babel-throw-original\.js:18:31/)
198  );
199}
200
201// Applies source-maps generated by nyc to stack trace.
202{
203  const output = spawnSync(process.execPath, [
204    '--enable-source-maps',
205    require.resolve('../fixtures/source-map/istanbul-throw.js')
206  ]);
207  assert.ok(
208    output.stderr.toString().match(/->.*istanbul-throw-original\.js:5:9/)
209  );
210  assert.ok(
211    output.stderr.toString().match(/->.*istanbul-throw-original\.js:9:3/)
212  );
213}
214
215// Applies source-maps in esm modules to stack trace.
216{
217  const output = spawnSync(process.execPath, [
218    '--enable-source-maps',
219    require.resolve('../fixtures/source-map/babel-esm.mjs')
220  ]);
221  assert.ok(
222    output.stderr.toString().match(/->.*babel-esm-original\.mjs:9:29/)
223  );
224}
225
226// Does not persist url parameter if source-map has been parsed.
227{
228  const coverageDirectory = nextdir();
229  spawnSync(process.execPath, [
230    require.resolve('../fixtures/source-map/inline-base64.js')
231  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
232  const sourceMap = getSourceMapFromCache(
233    'inline-base64.js',
234    coverageDirectory
235  );
236  assert.strictEqual(sourceMap.url, null);
237}
238
239// Persists line lengths for in-memory representation of source file.
240{
241  const coverageDirectory = nextdir();
242  spawnSync(process.execPath, [
243    require.resolve('../fixtures/source-map/istanbul-throw.js')
244  ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } });
245  const sourceMap = getSourceMapFromCache(
246    'istanbul-throw.js',
247    coverageDirectory
248  );
249  if (common.isWindows) {
250    assert.deepStrictEqual(sourceMap.lineLengths, [1086, 31, 185, 649, 0]);
251  } else {
252    assert.deepStrictEqual(sourceMap.lineLengths, [1085, 30, 184, 648, 0]);
253  }
254}
255
256// trace.length === 0 .
257{
258  const output = spawnSync(process.execPath, [
259    '--enable-source-maps',
260    require.resolve('../fixtures/source-map/emptyStackError.js')
261  ]);
262
263  assert.ok(
264    output.stderr.toString().match('emptyStackError')
265  );
266}
267
268function getSourceMapFromCache(fixtureFile, coverageDirectory) {
269  const jsonFiles = fs.readdirSync(coverageDirectory);
270  for (const jsonFile of jsonFiles) {
271    let maybeSourceMapCache;
272    try {
273      maybeSourceMapCache = require(
274        path.join(coverageDirectory, jsonFile)
275      )['source-map-cache'] || {};
276    } catch (err) {
277      console.warn(err);
278      maybeSourceMapCache = {};
279    }
280    const keys = Object.keys(maybeSourceMapCache);
281    for (const key of keys) {
282      if (key.includes(fixtureFile)) {
283        return maybeSourceMapCache[key];
284      }
285    }
286  }
287}
288