Skip to content

Commit a0b7a89

Browse files
authored
Merge pull request #167 from codex-team/test/catcher
Catcher covered with tests
2 parents d1f0b3d + 7c822b0 commit a0b7a89

15 files changed

+1137
-183
lines changed

packages/javascript/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"build": "vite build",
2222
"stats": "size-limit > stats.txt",
2323
"test": "vitest run",
24+
"test:coverage": "vitest run --coverage",
2425
"test:watch": "vitest",
2526
"lint": "eslint --fix \"src/**/*.{js,ts}\""
2627
},
@@ -43,6 +44,7 @@
4344
},
4445
"devDependencies": {
4546
"@hawk.so/types": "0.5.8",
47+
"@vitest/coverage-v8": "^4.0.18",
4648
"jsdom": "^28.0.0",
4749
"vite": "^7.3.1",
4850
"vite-plugin-dts": "^4.2.4",

packages/javascript/tests/before-send.test.ts

Lines changed: 0 additions & 181 deletions
This file was deleted.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { describe, it, expect, vi, beforeEach } from 'vitest';
2+
import { BreadcrumbManager } from '../src/addons/breadcrumbs';
3+
import { wait, createTransport, getLastPayload, createCatcher } from './catcher.helpers';
4+
5+
const mockParse = vi.hoisted(() => vi.fn().mockResolvedValue([]));
6+
vi.mock('../src/modules/stackParser', () => ({
7+
default: class { parse = mockParse; },
8+
}));
9+
10+
describe('Catcher', () => {
11+
beforeEach(() => {
12+
localStorage.clear();
13+
mockParse.mockResolvedValue([]);
14+
(BreadcrumbManager as any).instance = null;
15+
});
16+
17+
// ── Environment addons ────────────────────────────────────────────────────
18+
//
19+
// Browser-specific data collected from window (URL, GET params, debug info).
20+
describe('environment addons', () => {
21+
it('should include GET parameters when the URL has a query string', async () => {
22+
vi.stubGlobal('location', {
23+
...window.location,
24+
search: '?foo=bar&baz=qux',
25+
href: 'http://localhost/?foo=bar&baz=qux',
26+
});
27+
28+
const { sendSpy, transport } = createTransport();
29+
30+
createCatcher(transport).send(new Error('e'));
31+
await wait();
32+
33+
expect(getLastPayload(sendSpy).addons.get).toEqual({ foo: 'bar', baz: 'qux' });
34+
35+
vi.unstubAllGlobals();
36+
});
37+
38+
it('should include raw error data in debug mode', async () => {
39+
const { sendSpy, transport } = createTransport();
40+
const error = new Error('debug error');
41+
42+
createCatcher(transport, { debug: true }).send(error);
43+
await wait();
44+
45+
expect(getLastPayload(sendSpy).addons.RAW_EVENT_DATA).toMatchObject({
46+
name: 'Error',
47+
message: 'debug error',
48+
stack: expect.any(String),
49+
});
50+
});
51+
52+
it('should not include raw error data for string errors even in debug mode', async () => {
53+
const { sendSpy, transport } = createTransport();
54+
55+
createCatcher(transport, { debug: true }).send('string reason');
56+
await wait();
57+
58+
expect(getLastPayload(sendSpy).addons.RAW_EVENT_DATA).toBeUndefined();
59+
});
60+
});
61+
62+
// ── Integration addons ────────────────────────────────────────────────────
63+
//
64+
// Framework integrations (Vue, Nuxt, etc.) attach extra addons when
65+
// reporting errors via captureError(). These are merged into the payload
66+
// alongside the standard browser addons.
67+
describe('integration addons via captureError()', () => {
68+
it('should merge integration-specific addons', async () => {
69+
const { sendSpy, transport } = createTransport();
70+
71+
createCatcher(transport).captureError(new Error('e'), {
72+
vue: { component: '<App />', props: {}, lifecycle: 'mounted' },
73+
});
74+
await wait();
75+
76+
expect(getLastPayload(sendSpy).addons).toMatchObject({
77+
vue: { component: '<App />', props: {}, lifecycle: 'mounted' },
78+
});
79+
});
80+
81+
it('should preserve standard browser addons when integration addons are merged', async () => {
82+
const { sendSpy, transport } = createTransport();
83+
84+
createCatcher(transport).captureError(new Error('e'), {
85+
vue: { component: '<Foo />', props: {}, lifecycle: 'mounted' },
86+
});
87+
await wait();
88+
89+
const addons = getLastPayload(sendSpy).addons;
90+
91+
expect(addons.userAgent).toBeDefined();
92+
expect(addons.url).toBeDefined();
93+
});
94+
});
95+
});

0 commit comments

Comments
 (0)