diff --git a/CHANGELOG.md b/CHANGELOG.md index 6acbd3b103..b860dc239d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Add `lastEventId` method to the API ([#2675](https://github.com/getsentry/sentry-react-native/pull/2675)) +### Fix + +- `Sentry.startTransaction` doesn't require `op` ([#2691](https://github.com/getsentry/sentry-react-native/pull/2691)) + ### Dependencies - Bump Cocoa SDK from v7.31.2 to v7.31.3 ([#2647](https://github.com/getsentry/sentry-react-native/pull/2647)) diff --git a/src/js/measurements.ts b/src/js/measurements.ts index 242d7b3add..709a9122a0 100644 --- a/src/js/measurements.ts +++ b/src/js/measurements.ts @@ -1,9 +1,11 @@ import { getCurrentHub, getMainCarrier, Hub } from '@sentry/core'; import { Transaction } from '@sentry/tracing'; -import { CustomSamplingContext, TransactionContext } from '@sentry/types'; +import { CustomSamplingContext, Span, SpanContext, TransactionContext } from '@sentry/types'; import { ReactNativeTracing } from './tracing'; +const SPAN_OP_DEFAULT = 'default'; + /** * Adds React Native's extensions. Needs to be called after @sentry/tracing's extension methods are added */ @@ -28,7 +30,7 @@ export function _addTracingExtensions(): void { } } -type StartTransactionFunction = ( +export type StartTransactionFunction = ( this: Hub, transactionContext: TransactionContext, customSamplingContext?: CustomSamplingContext @@ -48,10 +50,25 @@ const _patchStartTransaction = ( transactionContext: TransactionContext, customSamplingContext?: CustomSamplingContext ): Transaction { + // Native SDKs require op to be set - for JS Relay sets `default` + if (!transactionContext.op) { + transactionContext.op = SPAN_OP_DEFAULT; + } + const transaction: Transaction = originalStartTransaction.apply(this, [ transactionContext, customSamplingContext, ]); + const originalStartChild: Transaction['startChild'] = transaction.startChild.bind(transaction); + transaction.startChild = ( + spanContext?: Pick>, + ): Span => { + return originalStartChild({ + ...spanContext, + // Native SDKs require op to be set + op: spanContext?.op || SPAN_OP_DEFAULT, + }); + }; const reactNativeTracing = getCurrentHub().getIntegration( ReactNativeTracing diff --git a/test/measurements.test.ts b/test/measurements.test.ts new file mode 100644 index 0000000000..cbe6ac8d5a --- /dev/null +++ b/test/measurements.test.ts @@ -0,0 +1,56 @@ +import { Carrier, getCurrentHub, getMainCarrier } from '@sentry/core'; +import { Transaction } from '@sentry/tracing'; +import { Hub } from '@sentry/types'; + +import { _addTracingExtensions, StartTransactionFunction } from '../src/js/measurements'; + +describe('Tracing extensions', () => { + let hub: Hub; + let carrier: Carrier; + let startTransaction: StartTransactionFunction | undefined; + + beforeEach(() => { + _addTracingExtensions(); + hub = getCurrentHub(); + carrier = getMainCarrier(); + startTransaction = carrier.__SENTRY__?.extensions?.startTransaction as StartTransactionFunction | undefined; + }); + + test('transaction has default op', async () => { + const transaction: Transaction = startTransaction?.apply(hub, [{}]); + + expect(transaction).toEqual(expect.objectContaining({ op: 'default' })); + }); + + test('transaction does not overwrite custom op', async () => { + const transaction: Transaction = startTransaction?.apply(hub, [{ op: 'custom' }]); + + expect(transaction).toEqual(expect.objectContaining({ op: 'custom' })); + }); + + test('transaction start span creates default op', async () => { + const transaction: Transaction = startTransaction?.apply(hub, [{ op: 'custom' }]); + const span = transaction?.startChild(); + + expect(span).toEqual(expect.objectContaining({ op: 'default' })); + }); + + test('transaction start span keeps custom op', async () => { + const transaction: Transaction = startTransaction?.apply(hub, [{ op: 'custom' }]); + const span = transaction?.startChild({ op: 'custom' }); + + expect(span).toEqual(expect.objectContaining({ op: 'custom' })); + }); + + test('transaction start span passes correct values to the child', async () => { + const transaction: Transaction = startTransaction?.apply(hub, [{ op: 'custom' }]); + const span = transaction?.startChild({ op: 'custom' }); + + expect(span).toEqual(expect.objectContaining({ + transaction, + parentSpanId: transaction.spanId, + sampled: transaction.sampled, + traceId: transaction.traceId, + })); + }); +});