Skip to content

Commit 03bb5a8

Browse files
committed
add tests for source-mapped locations and heavy errors
1 parent 5c86ae3 commit 03bb5a8

1 file changed

Lines changed: 147 additions & 0 deletions

File tree

tests/formatters/ConsoleFormatter.test.ts

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,3 +673,150 @@ describe('ConsoleFormatter', () => {
673673
});
674674
});
675675
});
676+
677+
describe('ConsoleFormatter - Source Map & Heavy Error Tests', () => {
678+
679+
it('includes top frame location in JSON detailed output', async () => {
680+
const mockFrame = {
681+
name: 'myFunction',
682+
uiSourceCode: {
683+
uiLocation: (line: number, column: number) => ({
684+
uiSourceCode: { url: () => 'http://example.com/app.js' },
685+
lineNumber: line,
686+
columnNumber: column,
687+
linkText: () => 'app.js:10:5',
688+
}),
689+
},
690+
line: 9,
691+
column: 4,
692+
};
693+
694+
const mockStackTrace = {
695+
syncFragment: { frames: [mockFrame] },
696+
asyncFragments: [],
697+
} as unknown as DevTools.StackTrace.StackTrace.StackTrace;
698+
699+
const mockError = {
700+
message: 'Something went wrong',
701+
stackTrace: mockStackTrace,
702+
cause: undefined,
703+
} as unknown as SymbolizedError;
704+
705+
const uncaughtError = new UncaughtError({} as Protocol.Runtime.ExceptionDetails, 'target-1');
706+
707+
const formatter = await ConsoleFormatter.from(uncaughtError, {
708+
id: 42,
709+
resolvedStackTraceForTesting: mockStackTrace,
710+
resolvedCauseForTesting: mockError,
711+
});
712+
713+
const json = formatter.toJSONDetailed();
714+
assert.deepStrictEqual((json as any).location, {
715+
url: 'http://example.com/app.js',
716+
lineNumber: 10,
717+
columnNumber: 5,
718+
});
719+
});
720+
721+
it('handles heavy/nested errors with cause chain', async () => {
722+
const innerFrame = { line: 5, column: 1, url: 'lib.js', name: 'inner' };
723+
const outerFrame = { line: 10, column: 2, url: 'app.js', name: 'outer' };
724+
725+
const innerError = SymbolizedError.createForTesting(
726+
'Inner error',
727+
{ syncFragment: { frames: [innerFrame] }, asyncFragments: [] } as any,
728+
);
729+
730+
const outerError = SymbolizedError.createForTesting(
731+
'Outer error',
732+
{ syncFragment: { frames: [outerFrame] }, asyncFragments: [] } as any,
733+
innerError,
734+
);
735+
736+
const uncaughtError = new UncaughtError({} as Protocol.Runtime.ExceptionDetails, 'heavy-1');
737+
738+
const formatter = await ConsoleFormatter.from(uncaughtError, {
739+
id: 99,
740+
resolvedCauseForTesting: outerError,
741+
resolvedStackTraceForTesting: outerError.stackTrace as any,
742+
});
743+
744+
const detailed = formatter.toStringDetailed();
745+
assert.ok(detailed.includes('Outer error'));
746+
assert.ok(detailed.includes('Caused by: Inner error'));
747+
assert.ok(detailed.includes('inner'));
748+
assert.ok(detailed.includes('outer'));
749+
});
750+
751+
it('handles async fragments correctly', async () => {
752+
const syncFrame = { name: 'syncFunc', line: 1, column: 1, url: 'sync.js' };
753+
const asyncFrame = { name: 'asyncFunc', line: 5, column: 2, url: 'async.js' };
754+
755+
const stackTrace = {
756+
syncFragment: { frames: [syncFrame] },
757+
asyncFragments: [{ description: 'asyncTask', frames: [asyncFrame] }],
758+
} as unknown as DevTools.StackTrace.StackTrace.StackTrace;
759+
760+
const error = SymbolizedError.createForTesting(
761+
'Async error',
762+
stackTrace,
763+
);
764+
765+
const uncaughtError = new UncaughtError({} as Protocol.Runtime.ExceptionDetails, 'async-1');
766+
767+
const formatter = await ConsoleFormatter.from(uncaughtError, {
768+
id: 100,
769+
resolvedCauseForTesting: error,
770+
resolvedStackTraceForTesting: stackTrace,
771+
});
772+
773+
const detailed = formatter.toStringDetailed();
774+
assert.ok(detailed.includes('--- asyncTask'));
775+
assert.ok(detailed.includes('asyncFunc'));
776+
});
777+
778+
it('includes correct top frame location even when all others ignored', async () => {
779+
const ignoredFrame = { name: 'ignored', line: 1, column: 1, url: 'ignore.js' };
780+
const topFrame = {
781+
name: 'topFrame',
782+
line: 10,
783+
column: 2,
784+
uiSourceCode: {
785+
uiLocation: (line: number, column: number) => ({
786+
uiSourceCode: { url: () => 'top.js' },
787+
lineNumber: line,
788+
columnNumber: column,
789+
linkText: () => 'top.js:11:3',
790+
}),
791+
},
792+
};
793+
794+
const stackTrace = {
795+
syncFragment: { frames: [ignoredFrame as any, topFrame as any] },
796+
asyncFragments: [],
797+
} as unknown as DevTools.StackTrace.StackTrace.StackTrace;
798+
799+
const error = SymbolizedError.createForTesting(
800+
'Test error',
801+
stackTrace,
802+
);
803+
804+
const uncaughtError = new UncaughtError({} as Protocol.Runtime.ExceptionDetails, 'ignore-test');
805+
806+
const formatter = await ConsoleFormatter.from(uncaughtError, {
807+
id: 101,
808+
resolvedStackTraceForTesting: stackTrace,
809+
resolvedCauseForTesting: error,
810+
isIgnoredForTesting: frame => frame.url === 'ignore.js',
811+
});
812+
813+
const json = formatter.toJSONDetailed();
814+
assert.deepStrictEqual((json as any).location, {
815+
url: 'top.js',
816+
lineNumber: 11,
817+
columnNumber: 3,
818+
});
819+
});
820+
821+
});
822+

0 commit comments

Comments
 (0)