Skip to content
Merged
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
2 changes: 2 additions & 0 deletions packages/javascript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"build": "vite build",
"stats": "size-limit > stats.txt",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest",
"lint": "eslint --fix \"src/**/*.{js,ts}\""
},
Expand All @@ -43,6 +44,7 @@
},
"devDependencies": {
"@hawk.so/types": "0.5.8",
"@vitest/coverage-v8": "^4.0.18",
"jsdom": "^28.0.0",
"vite": "^7.3.1",
"vite-plugin-dts": "^4.2.4",
Expand Down
181 changes: 0 additions & 181 deletions packages/javascript/tests/before-send.test.ts

This file was deleted.

95 changes: 95 additions & 0 deletions packages/javascript/tests/catcher.addons.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { BreadcrumbManager } from '../src/addons/breadcrumbs';
import { wait, createTransport, getLastPayload, createCatcher } from './catcher.helpers';

const mockParse = vi.hoisted(() => vi.fn().mockResolvedValue([]));
vi.mock('../src/modules/stackParser', () => ({
default: class { parse = mockParse; },
}));

describe('Catcher', () => {
beforeEach(() => {
localStorage.clear();
mockParse.mockResolvedValue([]);
(BreadcrumbManager as any).instance = null;
});

// ── Environment addons ────────────────────────────────────────────────────
//
// Browser-specific data collected from window (URL, GET params, debug info).
describe('environment addons', () => {
it('should include GET parameters when the URL has a query string', async () => {
vi.stubGlobal('location', {
...window.location,
search: '?foo=bar&baz=qux',
href: 'http://localhost/?foo=bar&baz=qux',
});

const { sendSpy, transport } = createTransport();

createCatcher(transport).send(new Error('e'));
await wait();

expect(getLastPayload(sendSpy).addons.get).toEqual({ foo: 'bar', baz: 'qux' });

vi.unstubAllGlobals();
});

it('should include raw error data in debug mode', async () => {
const { sendSpy, transport } = createTransport();
const error = new Error('debug error');

createCatcher(transport, { debug: true }).send(error);
await wait();

expect(getLastPayload(sendSpy).addons.RAW_EVENT_DATA).toMatchObject({
name: 'Error',
message: 'debug error',
stack: expect.any(String),
});
});

it('should not include raw error data for string errors even in debug mode', async () => {
const { sendSpy, transport } = createTransport();

createCatcher(transport, { debug: true }).send('string reason');
await wait();

expect(getLastPayload(sendSpy).addons.RAW_EVENT_DATA).toBeUndefined();
});
});

// ── Integration addons ────────────────────────────────────────────────────
//
// Framework integrations (Vue, Nuxt, etc.) attach extra addons when
// reporting errors via captureError(). These are merged into the payload
// alongside the standard browser addons.
describe('integration addons via captureError()', () => {
it('should merge integration-specific addons', async () => {
const { sendSpy, transport } = createTransport();

createCatcher(transport).captureError(new Error('e'), {
vue: { component: '<App />', props: {}, lifecycle: 'mounted' },
});
await wait();

expect(getLastPayload(sendSpy).addons).toMatchObject({
vue: { component: '<App />', props: {}, lifecycle: 'mounted' },
});
});

it('should preserve standard browser addons when integration addons are merged', async () => {
const { sendSpy, transport } = createTransport();

createCatcher(transport).captureError(new Error('e'), {
vue: { component: '<Foo />', props: {}, lifecycle: 'mounted' },
});
await wait();

const addons = getLastPayload(sendSpy).addons;

expect(addons.userAgent).toBeDefined();
expect(addons.url).toBeDefined();
});
});
});
Loading