Skip to content

Commit 712464f

Browse files
authored
Make it idempotent to capturePromise (#400)
* Make it idempotent to capturePromise Add uncapturePromise function in order to cancel patch in tests. fix #398 * Move Move cleanup after the assertion To ensure it's executed after the test will execute. * Change setup process for process_p.test.js To assure variables reference to original `then` and `catch` function.
1 parent 781e1a2 commit 712464f

File tree

3 files changed

+61
-21
lines changed

3 files changed

+61
-21
lines changed

packages/core/lib/patchers/promise_p.js

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,29 @@
99

1010
const contextUtils = require('../context_utils');
1111

12+
const originalThen = Symbol('original then');
13+
const originalCatch = Symbol('original catch');
14+
1215
function patchPromise(Promise) {
1316
const then = Promise.prototype.then;
14-
Promise.prototype.then = function(onFulfilled, onRejected) {
15-
if (contextUtils.isAutomaticMode()
16-
&& tryGetCurrentSegment()
17-
) {
18-
const ns = contextUtils.getNamespace();
19-
20-
onFulfilled = onFulfilled && ns.bind(onFulfilled);
21-
onRejected = onRejected && ns.bind(onRejected);
22-
}
23-
24-
return then.call(this, onFulfilled, onRejected);
25-
};
17+
if (!then[originalThen]) {
18+
Promise.prototype.then = function(onFulfilled, onRejected) {
19+
if (contextUtils.isAutomaticMode()
20+
&& tryGetCurrentSegment()
21+
) {
22+
const ns = contextUtils.getNamespace();
23+
24+
onFulfilled = onFulfilled && ns.bind(onFulfilled);
25+
onRejected = onRejected && ns.bind(onRejected);
26+
}
27+
28+
return then.call(this, onFulfilled, onRejected);
29+
};
30+
Promise.prototype.then[originalThen] = then;
31+
}
2632

2733
const origCatch = Promise.prototype.catch;
28-
if (origCatch) {
34+
if (origCatch && !origCatch[originalCatch]) {
2935
Promise.prototype.catch = function (onRejected) {
3036
if (contextUtils.isAutomaticMode()
3137
&& tryGetCurrentSegment()
@@ -37,6 +43,18 @@ function patchPromise(Promise) {
3743

3844
return origCatch.call(this, onRejected);
3945
};
46+
Promise.prototype.catch[originalCatch] = origCatch;
47+
}
48+
}
49+
50+
function unpatchPromise(Promise) {
51+
const then = Promise.prototype.then;
52+
if (then[originalThen]) {
53+
Promise.prototype.then = then[originalThen];
54+
}
55+
const origCatch = Promise.prototype.catch;
56+
if (origCatch && origCatch[originalCatch]) {
57+
Promise.prototype.catch = origCatch[originalCatch];
4058
}
4159
}
4260

@@ -52,6 +70,11 @@ function capturePromise() {
5270
patchPromise(Promise);
5371
}
5472

73+
function uncapturePromise() {
74+
unpatchPromise(Promise);
75+
}
76+
5577
capturePromise.patchThirdPartyPromise = patchPromise;
5678

5779
module.exports.capturePromise = capturePromise;
80+
module.exports.uncapturePromise = uncapturePromise;

packages/core/test/integration/segment_maintained_across_shared_promise.test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ var server = http
3737
// setTimeout so the assertion isn't caught by the promise
3838
setTimeout(function() {
3939
assert.equal(segment.id, retrievedSegment.id);
40+
// Cancel the patch because it doesn't affect other tests
41+
require('../../lib/patchers/promise_p').uncapturePromise();
4042
});
4143
});
4244
});

packages/core/test/unit/patchers/promise_p.test.js

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
const expect = require('chai').expect;
22
const sinon = require('sinon');
33

4-
const { capturePromise } = require('../../../lib/patchers/promise_p');
4+
const { capturePromise, uncapturePromise } = require('../../../lib/patchers/promise_p');
55
const contextUtils = require('../../../lib/context_utils');
66

7-
const origThen = Promise.prototype.then;
8-
const origCatch = Promise.prototype.catch;
9-
7+
let origThen;
8+
let origCatch;
109
let getNamespaceStub;
1110
let isAutomaticModeStub;
1211
let getSegmentStub;
@@ -26,14 +25,16 @@ beforeEach(() => {
2625

2726
beforeEach(() => {
2827
sinon.restore();
29-
Promise.prototype.then = origThen;
30-
Promise.prototype.catch = origCatch;
28+
uncapturePromise();
29+
origThen = Promise.prototype.then;
30+
origCatch = Promise.prototype.catch;
3131
});
3232

3333
after(() => {
3434
sinon.restore();
35-
Promise.prototype.then = origThen;
36-
Promise.prototype.catch = origCatch;
35+
uncapturePromise();
36+
origThen = Promise.prototype.then;
37+
origCatch = Promise.prototype.catch;
3738
});
3839

3940
function verifyBindings (segment, isAutomaticMode, onFulfilled, onRejected) {
@@ -125,6 +126,20 @@ describe('capturePromise', () => {
125126
});
126127
createTests(true);
127128
});
129+
130+
it('should be idempotent', async () => {
131+
capturePromise();
132+
const thenFirst = Promise.prototype.then;
133+
const catchFirst = Promise.prototype.catch;
134+
capturePromise();
135+
const thenSecond = Promise.prototype.then;
136+
const catchSecond = Promise.prototype.catch;
137+
capturePromise();
138+
expect(Promise.prototype.then).to.equal(thenFirst);
139+
expect(Promise.prototype.catch).to.equal(catchFirst);
140+
expect(Promise.prototype.then).to.equal(thenSecond);
141+
expect(Promise.prototype.catch).to.equal(catchSecond);
142+
});
128143
});
129144

130145
describe('capturePromise.patchThirdPartyPromise', () => {

0 commit comments

Comments
 (0)