diff --git a/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/init.js b/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/init.js new file mode 100644 index 000000000000..99ffd9f0ab31 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/init.js @@ -0,0 +1,8 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + attachStacktrace: true, +}); diff --git a/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/subject.js b/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/subject.js new file mode 100644 index 000000000000..cf462c59a2fb --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/subject.js @@ -0,0 +1 @@ +Sentry.captureMessage('foo'); diff --git a/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/test.ts b/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/test.ts new file mode 100644 index 000000000000..0e769cca73fe --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/public-api/captureMessage/simple_message_attachStackTrace/test.ts @@ -0,0 +1,28 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/core'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../utils/helpers'; + +sentryTest( + 'captures a simple message string with stack trace if `attachStackTrace` is `true`', + async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.message).toBe('foo'); + expect(eventData.level).toBe('info'); + expect(eventData.exception?.values?.[0]).toEqual({ + mechanism: { + handled: true, + type: 'generic', + synthetic: true, + }, + stacktrace: { + frames: expect.arrayContaining([expect.any(Object), expect.any(Object)]), + }, + value: 'foo', + }); + }, +); diff --git a/packages/browser/src/eventbuilder.ts b/packages/browser/src/eventbuilder.ts index 7f7539f5cf5f..ce34be0de707 100644 --- a/packages/browser/src/eventbuilder.ts +++ b/packages/browser/src/eventbuilder.ts @@ -347,6 +347,7 @@ function eventFromString( values: [{ value: message, stacktrace: { frames } }], }; } + addExceptionMechanism(event, { synthetic: true }); } if (isParameterizedString(message)) { diff --git a/packages/browser/test/eventbuilder.test.ts b/packages/browser/test/eventbuilder.test.ts index 31112abbfc7e..f9949800ee94 100644 --- a/packages/browser/test/eventbuilder.test.ts +++ b/packages/browser/test/eventbuilder.test.ts @@ -5,7 +5,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { defaultStackParser } from '../src'; -import { eventFromUnknownInput, extractMessage, extractType } from '../src/eventbuilder'; +import { eventFromMessage, eventFromUnknownInput, extractMessage, extractType } from '../src/eventbuilder'; vi.mock('@sentry/core', async requireActual => { return { @@ -231,3 +231,33 @@ describe('extractName', () => { expect(name).toBeUndefined(); }); }); + +describe('eventFromMessage ', () => { + it('creates an event from a string message', async () => { + const event = await eventFromMessage(defaultStackParser, 'Test message'); + expect(event).toEqual({ + level: 'info', + message: 'Test message', + }); + }); + + it('creates an event with a synthetic stack trace if attachStacktrace is true', async () => { + const syntheticException = new Error('Test message'); + const event = await eventFromMessage(defaultStackParser, 'Test message', 'info', { syntheticException }, true); + expect(event.exception?.values?.[0]).toEqual( + expect.objectContaining({ + mechanism: { handled: true, synthetic: true, type: 'generic' }, + stacktrace: { + frames: expect.arrayContaining([expect.any(Object), expect.any(Object)]), + }, + value: 'Test message', + }), + ); + }); + + it("doesn't add a synthetic stack trace if attachStacktrace is false, even if one is passed-", async () => { + const syntheticException = new Error('Test message'); + const event = await eventFromMessage(defaultStackParser, 'Test message', 'info', { syntheticException }, false); + expect(event.exception).toBeUndefined(); + }); +});