Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions lib/promise/capture_local_err.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

/** @param {Function} constructorOpt Passed to Error.captureStackTrace (omit this frame from stacks). */
function captureStackHolder(constructorOpt) {
const holder = {};
// Bun's Error.prepareStackTrace requires an Error instance. A plain object
// works in V8, but throws "First argument must be an Error object" there.
const holder = new Error();
Error.captureStackTrace(holder, constructorOpt);
return holder;
}
Expand All @@ -12,7 +14,7 @@ function captureStackHolder(constructorOpt) {
* callback error instance and its MySQL fields.
*
* @param {Error} err
* @param {{ stack?: string }} holder
* @param {Error} holder
*/
function applyCapturedStack(err, holder) {
const stack = holder && holder.stack;
Expand Down
50 changes: 50 additions & 0 deletions test/unit/test-capture-local-err.test.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, it, strict } from 'poku';
import captureLocalErr from '../../lib/promise/capture_local_err.js';

const { captureStackHolder, applyCapturedStack } = captureLocalErr;

await describe('capture_local_err', async () => {
await it('should capture on an Error so Bun prepareStackTrace can format it', () => {
const original = Error.prepareStackTrace;
let seenErr: Error | undefined;
Error.prepareStackTrace = (err, traces) => {
seenErr = err;
if (!(err instanceof Error)) {
throw new TypeError('First argument must be an Error object failed');
}
return original ? original.call(Error, err, traces) : String(err.stack);
};
try {
const holder = captureStackHolder(captureStackHolder);
strict.ok(holder instanceof Error, 'holder should be an Error instance');
const stack = holder.stack ?? '';
strict.equal(typeof holder.stack, 'string');
strict.ok(stack.length > 0);
strict.ok(seenErr instanceof Error);
} finally {
Error.prepareStackTrace = original;
}
});

await it('should keep the callback error identity and rewrite its stack', () => {
function captureHere() {
return captureStackHolder(captureHere);
}
const holder = captureHere();
const err = new Error('ER_PARSE_ERROR: syntax error') as Error & {
code?: string;
};
err.code = 'ER_PARSE_ERROR';
applyCapturedStack(err, holder);
strict.equal(err.code, 'ER_PARSE_ERROR');
const stack = err.stack ?? '';
strict.ok(
stack.startsWith('Error: ER_PARSE_ERROR: syntax error'),
`unexpected stack:\n${stack}`
);
strict.ok(
stack.includes('test-capture-local-err.test.mts'),
`expected this test file in the rewritten stack:\n${stack}`
);
});
});
Loading