diff --git a/api/src/api/context.ts b/api/src/api/context.ts index ac5aff2cdd..fee5f30e49 100644 --- a/api/src/api/context.ts +++ b/api/src/api/context.ts @@ -78,12 +78,16 @@ export class ContextAPI { * * @param context context to be active during function execution * @param fn function to execute in a context + * @param thisArg optional receiver to be used for calling fn + * @param args optional arguments forwarded to fn */ - public with ReturnType>( + public with ReturnType>( context: Context, - fn: T - ): ReturnType { - return this._getContextManager().with(context, fn); + fn: F, + thisArg?: ThisParameterType, + ...args: A + ): ReturnType { + return this._getContextManager().with(context, fn, thisArg, ...args); } /** diff --git a/api/src/context-base/NoopContextManager.ts b/api/src/context-base/NoopContextManager.ts index cb7fdd0de6..54589a0624 100644 --- a/api/src/context-base/NoopContextManager.ts +++ b/api/src/context-base/NoopContextManager.ts @@ -22,11 +22,13 @@ export class NoopContextManager implements types.ContextManager { return ROOT_CONTEXT; } - with ReturnType>( + with ReturnType>( _context: types.Context, - fn: T - ): ReturnType { - return fn(); + fn: F, + thisArg?: ThisParameterType, + ...args: A + ): ReturnType { + return fn.call(thisArg, ...args); } bind(target: T, _context?: types.Context): T { diff --git a/api/src/context-base/types.ts b/api/src/context-base/types.ts index 20922441a7..af7a1ee15d 100644 --- a/api/src/context-base/types.ts +++ b/api/src/context-base/types.ts @@ -50,11 +50,15 @@ export interface ContextManager { * Run the fn callback with object set as the current active context * @param context Any object to set as the current active context * @param fn A callback to be immediately run within a specific context + * @param thisArg optional receiver to be used for calling fn + * @param args optional arguments forwarded to fn */ - with ReturnType>( + with ReturnType>( context: Context, - fn: T - ): ReturnType; + fn: F, + thisArg?: ThisParameterType, + ...args: A + ): ReturnType; /** * Bind an object as the current context (or a specific one) diff --git a/api/test/api/api.test.ts b/api/test/api/api.test.ts index bb15fb02e9..b3e7728095 100644 --- a/api/test/api/api.test.ts +++ b/api/test/api/api.test.ts @@ -41,6 +41,26 @@ describe('API', () => { assert.strictEqual(typeof tracer, 'object'); }); + describe('Context', () => { + it('with should forward this, arguments and return value', () => { + function fnWithThis(this: string, a: string, b: number): string { + assert.strictEqual(this, 'that'); + assert.strictEqual(arguments.length, 2); + assert.strictEqual(a, 'one'); + assert.strictEqual(b, 2); + return 'done'; + } + + const res = context.with(ROOT_CONTEXT, fnWithThis, 'that', 'one', 2); + assert.strictEqual(res, 'done'); + + assert.strictEqual( + context.with(ROOT_CONTEXT, () => 3.14), + 3.14 + ); + }); + }); + describe('GlobalTracerProvider', () => { const spanContext = { traceId: 'd4cda95b652f4a1592b449d5929fda1b', diff --git a/api/test/context-base/NoopContextManager.test.ts b/api/test/context-base/NoopContextManager.test.ts index 61f9ae7355..5528735adc 100644 --- a/api/test/context-base/NoopContextManager.test.ts +++ b/api/test/context-base/NoopContextManager.test.ts @@ -70,6 +70,30 @@ describe('NoopContextManager', () => { return done(); }); }); + + it('should forward this, arguments and return value', () => { + function fnWithThis(this: string, a: string, b: number): string { + assert.strictEqual(this, 'that'); + assert.strictEqual(arguments.length, 2); + assert.strictEqual(a, 'one'); + assert.strictEqual(b, 2); + return 'done'; + } + + const res = contextManager.with( + ROOT_CONTEXT, + fnWithThis, + 'that', + 'one', + 2 + ); + assert.strictEqual(res, 'done'); + + assert.strictEqual( + contextManager.with(ROOT_CONTEXT, () => 3.14), + 3.14 + ); + }); }); describe('.active()', () => {