Skip to content

Commit 23eec74

Browse files
SimenBcpojer
authored andcommitted
[WIP] Remove usage of retainLines (jestjs#5594)
* Remove usage of `retainLines` * update changelog * Move callsite to jest-util, add sourcemap support * This is a type * Remove unused function moved to jest-util * Fix lint * Minor clean `up * Feedback updates * fix flow violations and minimize diff * add todo * use sourcemaps in buffered console as well * fix stupid typo * Add unit tests for get_callsite * Fix tests * move changelog entry
1 parent 6ab04b7 commit 23eec74

File tree

17 files changed

+189
-26
lines changed

17 files changed

+189
-26
lines changed

.babelrc

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@
88
"transform-async-to-generator",
99
"transform-strict-mode",
1010
["transform-es2015-modules-commonjs", {"allowTopLevelThis": true}]
11-
],
12-
"retainLines": true
11+
]
1312
}

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
* `[jest-runtime]` Provide `require.main` property set to module with test suite
66
([#5618](https://github.com/facebook/jest/pull/5618))
7+
8+
### Fixes
9+
10+
* `[babel-jest]` Remove `retainLines` argument to babel.
11+
([#5594](https://github.com/facebook/jest/pull/5594))
12+
13+
### Chore & Maintenance
14+
715
* `[docs]` Add note about Node version support
816
([#5622](https://github.com/facebook/jest/pull/5622))
917
* `[docs]` Update to use yarn

integration-tests/__tests__/__snapshots__/failures.test.js.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ exports[`works with async failures 1`] = `
118118
+ \\"foo\\": \\"bar\\",
119119
}
120120
121-
at ../../packages/expect/build/index.js:145:57
121+
at ../../packages/expect/build/index.js:104:76
122122
123123
"
124124
`;

integration-tests/__tests__/location_in_results.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ it('adds correct location info when provided with flag', () => {
2828
const assertions = result.testResults[0].assertionResults;
2929
expect(result.success).toBe(true);
3030
expect(result.numTotalTests).toBe(2);
31-
expect(assertions[0].location).toEqual({column: 1, line: 9});
32-
expect(assertions[1].location).toEqual({column: 3, line: 14});
31+
expect(assertions[0].location).toEqual({column: 1, line: 10});
32+
expect(assertions[1].location).toEqual({column: 2, line: 15});
3333
});

integration-tests/location-in-results/__tests__/test.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
7-
'use strict';
7+
// This file is missing 'use strict' to force babel into doing something
8+
// as we have `transform-strict-mode`
89

910
it('no ancestors', () => {
1011
expect(true).toBeTruthy();

packages/babel-jest/src/index.js

-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ const createTransformer = (options: any): Transformer => {
7474
options = Object.assign({}, options, {
7575
plugins: (options && options.plugins) || [],
7676
presets: ((options && options.presets) || []).concat([jestPreset]),
77-
retainLines: true,
7877
sourceMaps: 'both',
7978
});
8079
delete options.cacheDirectory;

packages/jest-jasmine2/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"license": "MIT",
99
"main": "build/index.js",
1010
"dependencies": {
11-
"callsites": "^2.0.0",
1211
"chalk": "^2.0.1",
1312
"co": "^4.6.0",
1413
"expect": "^22.4.0",
@@ -18,6 +17,7 @@
1817
"jest-matcher-utils": "^22.4.0",
1918
"jest-message-util": "^22.4.0",
2019
"jest-snapshot": "^22.4.0",
20+
"jest-util": "^22.4.0",
2121
"source-map-support": "^0.5.0"
2222
},
2323
"devDependencies": {

packages/jest-jasmine2/src/index.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import type {TestResult} from 'types/TestResult';
1515
import type Runtime from 'jest-runtime';
1616

1717
import path from 'path';
18-
import fs from 'fs';
19-
import callsites from 'callsites';
18+
import fs from 'graceful-fs';
19+
import {getCallsite} from 'jest-util';
2020
import JasmineReporter from './reporter';
2121
import {install as jasmineAsyncInstall} from './jasmine_async';
2222

@@ -51,7 +51,7 @@ async function jasmine2(
5151
if (config.testLocationInResults === true) {
5252
const originalIt = environment.global.it;
5353
environment.global.it = (...args) => {
54-
const stack = callsites()[1];
54+
const stack = getCallsite(1, runtime.getSourceMaps());
5555
const it = originalIt(...args);
5656

5757
it.result.__callsite = stack;
@@ -125,12 +125,13 @@ async function jasmine2(
125125
environment: 'node',
126126
handleUncaughtExceptions: false,
127127
retrieveSourceMap: source => {
128-
if (runtime._sourceMapRegistry[source]) {
128+
const sourceMaps = runtime.getSourceMaps();
129+
const sourceMapSource = sourceMaps && sourceMaps[source];
130+
131+
if (sourceMapSource) {
129132
try {
130133
return {
131-
map: JSON.parse(
132-
fs.readFileSync(runtime._sourceMapRegistry[source]),
133-
),
134+
map: JSON.parse(fs.readFileSync(sourceMapSource)),
134135
url: source,
135136
};
136137
} catch (e) {}

packages/jest-runner/src/run_test.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,21 @@ async function runTestInternal(
7474
RuntimeClass,
7575
>);
7676

77+
let runtime = undefined;
78+
7779
const consoleOut = globalConfig.useStderr ? process.stderr : process.stdout;
7880
const consoleFormatter = (type, message) =>
7981
getConsoleOutput(
8082
config.cwd,
8183
!!globalConfig.verbose,
8284
// 4 = the console call is buried 4 stack frames deep
83-
BufferedConsole.write([], type, message, 4),
85+
BufferedConsole.write(
86+
[],
87+
type,
88+
message,
89+
4,
90+
runtime && runtime.getSourceMaps(),
91+
),
8492
);
8593

8694
let testConsole;
@@ -90,7 +98,7 @@ async function runTestInternal(
9098
} else if (globalConfig.verbose) {
9199
testConsole = new Console(consoleOut, process.stderr, consoleFormatter);
92100
} else {
93-
testConsole = new BufferedConsole();
101+
testConsole = new BufferedConsole(() => runtime && runtime.getSourceMaps());
94102
}
95103

96104
const environment = new TestEnvironment(config, {console: testConsole});
@@ -101,7 +109,7 @@ async function runTestInternal(
101109
const cacheFS = {[path]: testSource};
102110
setGlobal(environment.global, 'console', testConsole);
103111

104-
const runtime = new Runtime(config, environment, resolver, cacheFS, {
112+
runtime = new Runtime(config, environment, resolver, cacheFS, {
105113
collectCoverage: globalConfig.collectCoverage,
106114
collectCoverageFrom: globalConfig.collectCoverageFrom,
107115
collectCoverageOnlyFrom: globalConfig.collectCoverageOnlyFrom,

packages/jest-runtime/src/index.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {Context} from 'types/Context';
1515
import type {Jest, LocalModuleRequire} from 'types/Jest';
1616
import type {ModuleMap} from 'jest-haste-map';
1717
import type {MockFunctionMetadata, ModuleMocker} from 'types/Mock';
18+
import type {SourceMapRegistry} from 'types/SourceMaps';
1819

1920
import path from 'path';
2021
import HasteMap from 'jest-haste-map';
@@ -100,7 +101,7 @@ class Runtime {
100101
_shouldAutoMock: boolean;
101102
_shouldMockModuleCache: BooleanObject;
102103
_shouldUnmockTransitiveDependenciesCache: BooleanObject;
103-
_sourceMapRegistry: {[key: string]: string, __proto__: null};
104+
_sourceMapRegistry: SourceMapRegistry;
104105
_scriptTransformer: ScriptTransformer;
105106
_transitiveShouldMock: BooleanObject;
106107
_unmockList: ?RegExp;
@@ -449,6 +450,10 @@ class Runtime {
449450
}, {});
450451
}
451452

453+
getSourceMaps(): SourceMapRegistry {
454+
return this._sourceMapRegistry;
455+
}
456+
452457
setMock(
453458
from: string,
454459
moduleName: string,

packages/jest-util/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"graceful-fs": "^4.1.11",
1414
"is-ci": "^1.0.10",
1515
"jest-message-util": "^22.4.0",
16-
"mkdirp": "^0.5.1"
16+
"mkdirp": "^0.5.1",
17+
"source-map": "^0.6.0"
1718
},
1819
"devDependencies": {
1920
"jest-mock": "^22.2.0"

packages/jest-util/src/__tests__/buffered_console.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ describe('CustomConsole', () => {
1919
.join('\n');
2020

2121
beforeEach(() => {
22-
_console = new BufferedConsole();
22+
_console = new BufferedConsole(() => null);
2323
});
2424

2525
describe('assert', () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import fs from 'fs';
2+
import SourceMap from 'source-map';
3+
import getCallsite from '../get_callsite';
4+
5+
jest.mock('fs');
6+
7+
describe('getCallsite', () => {
8+
test('without source map', () => {
9+
const site = getCallsite(0);
10+
11+
expect(site.getFileName()).toEqual(__filename);
12+
expect(site.getColumnNumber()).toEqual(expect.any(Number));
13+
expect(site.getLineNumber()).toEqual(expect.any(Number));
14+
expect(fs.readFileSync).not.toHaveBeenCalled();
15+
});
16+
17+
test('ignores errors when fs throws', () => {
18+
fs.readFileSync.mockImplementation(() => {
19+
throw new Error('Mock error');
20+
});
21+
22+
const site = getCallsite(0, {[__filename]: 'mockedSourceMapFile'});
23+
24+
expect(site.getFileName()).toEqual(__filename);
25+
expect(site.getColumnNumber()).toEqual(expect.any(Number));
26+
expect(site.getLineNumber()).toEqual(expect.any(Number));
27+
expect(fs.readFileSync).toHaveBeenCalledWith('mockedSourceMapFile', 'utf8');
28+
});
29+
30+
test('reads source map file to determine line and column', () => {
31+
fs.readFileSync.mockImplementation(() => 'file data');
32+
33+
const sourceMapColumn = 1;
34+
const sourceMapLine = 2;
35+
SourceMap.SourceMapConsumer = class {
36+
originalPositionFor(params) {
37+
expect(params).toMatchObject({
38+
column: expect.any(Number),
39+
line: expect.any(Number),
40+
});
41+
42+
return {
43+
column: sourceMapColumn,
44+
line: sourceMapLine,
45+
};
46+
}
47+
};
48+
49+
const site = getCallsite(0, {[__filename]: 'mockedSourceMapFile'});
50+
51+
expect(site.getFileName()).toEqual(__filename);
52+
expect(site.getColumnNumber()).toEqual(sourceMapColumn);
53+
expect(site.getLineNumber()).toEqual(sourceMapLine);
54+
expect(fs.readFileSync).toHaveBeenCalledWith('mockedSourceMapFile', 'utf8');
55+
});
56+
});

packages/jest-util/src/buffered_console.js

+14-5
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,28 @@ import type {
1515
LogTimers,
1616
} from 'types/Console';
1717

18+
import type {SourceMapRegistry} from 'types/SourceMaps';
19+
1820
import assert from 'assert';
1921
import {Console} from 'console';
2022
import {format} from 'util';
2123
import chalk from 'chalk';
22-
import callsites from 'callsites';
24+
import getCallsite from './get_callsite';
2325

2426
export default class BufferedConsole extends Console {
2527
_buffer: ConsoleBuffer;
2628
_counters: LogCounters;
2729
_timers: LogTimers;
2830
_groupDepth: number;
31+
_getSourceMaps: () => ?SourceMapRegistry;
2932

30-
constructor() {
33+
constructor(getSourceMaps: () => ?SourceMapRegistry) {
3134
const buffer = [];
32-
super({write: message => BufferedConsole.write(buffer, 'log', message)});
35+
super({
36+
write: message =>
37+
BufferedConsole.write(buffer, 'log', message, null, getSourceMaps()),
38+
});
39+
this._getSourceMaps = getSourceMaps;
3340
this._buffer = buffer;
3441
this._counters = {};
3542
this._timers = {};
@@ -41,9 +48,10 @@ export default class BufferedConsole extends Console {
4148
type: LogType,
4249
message: LogMessage,
4350
level: ?number,
51+
sourceMaps: ?SourceMapRegistry,
4452
) {
45-
const call = callsites()[level != null ? level : 2];
46-
const origin = call.getFileName() + ':' + call.getLineNumber();
53+
const callsite = getCallsite(level != null ? level : 2, sourceMaps);
54+
const origin = callsite.getFileName() + ':' + callsite.getLineNumber();
4755

4856
buffer.push({
4957
message,
@@ -60,6 +68,7 @@ export default class BufferedConsole extends Console {
6068
type,
6169
' '.repeat(this._groupDepth) + message,
6270
3,
71+
this._getSourceMaps(),
6372
);
6473
}
6574

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
import type {SourceMapRegistry} from 'types/SourceMaps';
11+
12+
import fs from 'graceful-fs';
13+
import callsites from 'callsites';
14+
import {SourceMapConsumer} from 'source-map';
15+
16+
// Copied from https://github.com/rexxars/sourcemap-decorate-callsites/blob/5b9735a156964973a75dc62fd2c7f0c1975458e8/lib/index.js#L113-L158
17+
const addSourceMapConsumer = (callsite, consumer) => {
18+
const getLineNumber = callsite.getLineNumber;
19+
const getColumnNumber = callsite.getColumnNumber;
20+
let position = null;
21+
22+
function getPosition() {
23+
if (!position) {
24+
position = consumer.originalPositionFor({
25+
column: getColumnNumber.call(callsite),
26+
line: getLineNumber.call(callsite),
27+
});
28+
}
29+
30+
return position;
31+
}
32+
33+
Object.defineProperties(callsite, {
34+
getColumnNumber: {
35+
value() {
36+
return getPosition().column || getColumnNumber.call(callsite);
37+
},
38+
writable: false,
39+
},
40+
getLineNumber: {
41+
value() {
42+
return getPosition().line || getLineNumber.call(callsite);
43+
},
44+
writable: false,
45+
},
46+
});
47+
};
48+
49+
export default (level: number, sourceMaps: ?SourceMapRegistry) => {
50+
const levelAfterThisCall = level + 1;
51+
const stack = callsites()[levelAfterThisCall];
52+
const sourceMapFileName = sourceMaps && sourceMaps[stack.getFileName()];
53+
54+
if (sourceMapFileName) {
55+
try {
56+
const sourceMap = fs.readFileSync(sourceMapFileName, 'utf8');
57+
addSourceMapConsumer(stack, new SourceMapConsumer(sourceMap));
58+
} catch (e) {
59+
// ignore
60+
}
61+
}
62+
63+
return stack;
64+
};

packages/jest-util/src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import getConsoleOutput from './get_console_output';
1919
import installCommonGlobals from './install_common_globals';
2020
import NullConsole from './null_console';
2121
import isInteractive from './is_interative';
22+
import getCallsite from './get_callsite';
2223
import setGlobal from './set_global';
2324
import deepCyclicCopy from './deep_cyclic_copy';
2425

@@ -41,6 +42,7 @@ module.exports = {
4142
createDirectory,
4243
deepCyclicCopy,
4344
formatTestResults,
45+
getCallsite,
4446
getConsoleOutput,
4547
getFailedSnapshotTests,
4648
installCommonGlobals,

0 commit comments

Comments
 (0)