diff --git a/workers/javascript/src/index.ts b/workers/javascript/src/index.ts index 84fae857..9a9966bc 100644 --- a/workers/javascript/src/index.ts +++ b/workers/javascript/src/index.ts @@ -210,6 +210,16 @@ export default class JavascriptEventWorker extends EventWorker { bias: SourceMapConsumer.LEAST_UPPER_BOUND, }); + /** + * source-map-js returns nulls when the generated position is not in the map. + * Assigning them would wipe the catcher coordinates and set sourceCode to []. + * + * Fixes bug: https://github.com/codex-team/hawk.workers/issues/600 + */ + if (!originalLocation.source) { + return stackFrame; + } + /** * Source code lines */ diff --git a/workers/javascript/tests/index.test.ts b/workers/javascript/tests/index.test.ts index 531826e8..8849b8e8 100644 --- a/workers/javascript/tests/index.test.ts +++ b/workers/javascript/tests/index.test.ts @@ -281,6 +281,56 @@ describe('JavaScript event worker', () => { await worker.finish(); }); + it('should keep the original frame when the source map has no mapping', async () => { + /** + * Arrange + */ + const worker = new JavascriptEventWorker(); + + jest.spyOn(worker, 'addTask'); + jest.spyOn(JavascriptEventWorker.prototype as any, 'loadSourceMapFile') + .mockResolvedValue(sourceMapFileContent); + await worker.start(); + + const workerEvent = createEventMock({ withBacktrace: true }); + const originalFrame = { + file: 'file:///main.js', + line: 9999, + column: 1, + function: 'handler', + }; + + /** + * Copy the frame so a mutation inside the worker cannot hide a failed lookup + */ + workerEvent.payload.backtrace = [ { ...originalFrame } ]; + + const release = createReleaseMock({ + projectId: workerEvent.projectId, + release: workerEvent.payload.release, + }); + + await db.collection('releases').insertOne(release); + + /** + * Act + */ + await worker.handle(workerEvent); + + /** + * Assert + */ + expect(worker.addTask).toHaveBeenCalledWith( + WorkerNames.GROUPER, + expect.objectContaining({ + payload: expect.objectContaining({ + backtrace: [ originalFrame ], + }), + }) + ); + await worker.finish(); + }); + it('should use cache while processing source maps', async () => { /** * Arrange