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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- ref: Remove v5 prefix from react navigation instrumentation to support v6 #1768

## 3.0.3

- Fix: Set Java 8 for source and target compatibility if not using AGP >= 4.2.x (#1763)
Expand Down
2 changes: 2 additions & 0 deletions src/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ export { TouchEventBoundary, withTouchEventBoundary } from "./touchevents";
export {
ReactNativeTracing,
ReactNavigationV4Instrumentation,
// eslint-disable-next-line deprecation/deprecation
ReactNavigationV5Instrumentation,
ReactNavigationInstrumentation,
RoutingInstrumentation,
ReactNavigationTransactionContext,
} from "./tracing";
Expand Down
6 changes: 5 additions & 1 deletion src/js/tracing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ export {
RoutingInstrumentationInstance,
} from "./routingInstrumentation";

export { ReactNavigationV5Instrumentation } from "./reactnavigationv5";
export {
ReactNavigationInstrumentation,
// eslint-disable-next-line deprecation/deprecation
ReactNavigationV5Instrumentation,
} from "./reactnavigation";
export { ReactNavigationV4Instrumentation } from "./reactnavigationv4";
export {
ReactNavigationCurrentRoute,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@ import {
} from "./routingInstrumentation";
import { ReactNavigationTransactionContext } from "./types";

export interface NavigationRouteV5 {
export interface NavigationRoute {
name: string;
key: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
params?: Record<string, any>;
}

interface NavigationContainerV5 {
interface NavigationContainer {
addListener: (type: string, listener: () => void) => void;
getCurrentRoute: () => NavigationRouteV5;
getCurrentRoute: () => NavigationRoute;
}

interface ReactNavigationV5Options {
interface ReactNavigationOptions {
/**
* The time the transaction will wait for route to mount before it is discarded.
*/
routeChangeTimeoutMs: number;
}

const defaultOptions: ReactNavigationV5Options = {
const defaultOptions: ReactNavigationOptions = {
routeChangeTimeoutMs: 1000,
};

Expand All @@ -39,22 +39,22 @@ const defaultOptions: ReactNavigationV5Options = {
* - `_onStateChange` is then called AFTER the state change happens due to a dispatch and sets the route context onto the active transaction.
* - If `_onStateChange` isn't called within `STATE_CHANGE_TIMEOUT_DURATION` of the dispatch, then the transaction is not sampled and finished.
*/
export class ReactNavigationV5Instrumentation extends RoutingInstrumentation {
export class ReactNavigationInstrumentation extends RoutingInstrumentation {
public static instrumentationName: string = "react-navigation-v5";

private _navigationContainer: NavigationContainerV5 | null = null;
private _navigationContainer: NavigationContainer | null = null;

private readonly _maxRecentRouteLen: number = 200;

private _latestRoute?: NavigationRouteV5;
private _latestRoute?: NavigationRoute;
private _latestTransaction?: TransactionType;
private _initialStateHandled: boolean = false;
private _stateChangeTimeout?: number | undefined;
private _recentRouteKeys: string[] = [];

private _options: ReactNavigationV5Options;
private _options: ReactNavigationOptions;

public constructor(options: Partial<ReactNavigationV5Options> = {}) {
public constructor(options: Partial<ReactNavigationOptions> = {}) {
super();

this._options = {
Expand Down Expand Up @@ -147,9 +147,7 @@ export class ReactNavigationV5Instrumentation extends RoutingInstrumentation {
* and gets the route information from there, @see _onStateChange
*/
private _onDispatch(): void {
this._latestTransaction = this.onRouteWillChange(
BLANK_TRANSACTION_CONTEXT_V5
);
this._latestTransaction = this.onRouteWillChange(BLANK_TRANSACTION_CONTEXT);

this._stateChangeTimeout = setTimeout(
this._discardLatestTransaction.bind(this),
Expand Down Expand Up @@ -179,7 +177,7 @@ export class ReactNavigationV5Instrumentation extends RoutingInstrumentation {
this._latestTransaction &&
(!previousRoute || previousRoute.key !== route.key)
) {
const originalContext = this._latestTransaction.toContext() as typeof BLANK_TRANSACTION_CONTEXT_V5;
const originalContext = this._latestTransaction.toContext() as typeof BLANK_TRANSACTION_CONTEXT;
const routeHasBeenSeen = this._recentRouteKeys.includes(route.key);

const updatedContext: ReactNavigationTransactionContext = {
Expand Down Expand Up @@ -263,12 +261,18 @@ export class ReactNavigationV5Instrumentation extends RoutingInstrumentation {
}
}

export const BLANK_TRANSACTION_CONTEXT_V5 = {
/**
* Backwards compatibility alias for ReactNavigationInstrumentation
* @deprecated Use ReactNavigationInstrumentation
*/
export const ReactNavigationV5Instrumentation = ReactNavigationInstrumentation;

export const BLANK_TRANSACTION_CONTEXT = {
name: "Route Change",
op: "navigation",
tags: {
"routing.instrumentation":
ReactNavigationV5Instrumentation.instrumentationName,
ReactNavigationInstrumentation.instrumentationName,
},
data: {},
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,31 @@ import { Transaction } from "@sentry/tracing";
import { getGlobalObject } from "@sentry/utils";

import {
BLANK_TRANSACTION_CONTEXT_V5,
NavigationRouteV5,
ReactNavigationV5Instrumentation,
} from "../../src/js/tracing/reactnavigationv5";
BLANK_TRANSACTION_CONTEXT,
NavigationRoute,
ReactNavigationInstrumentation,
} from "../../src/js/tracing/reactnavigation";

const dummyRoute = {
name: "Route",
key: "0",
};

class MockNavigationContainer {
currentRoute: NavigationRouteV5 = dummyRoute;
currentRoute: NavigationRoute = dummyRoute;
listeners: Record<string, (e: any) => void> = {};
addListener: any = jest.fn(
(eventType: string, listener: (e: any) => void): void => {
this.listeners[eventType] = listener;
}
);
getCurrentRoute(): NavigationRouteV5 {
getCurrentRoute(): NavigationRoute {
return this.currentRoute;
}
}

const getMockTransaction = () => {
const transaction = new Transaction(BLANK_TRANSACTION_CONTEXT_V5);
const transaction = new Transaction(BLANK_TRANSACTION_CONTEXT);

// Assume it's sampled
transaction.sampled = true;
Expand All @@ -45,9 +45,9 @@ afterEach(() => {
jest.resetAllMocks();
});

describe("ReactNavigationV5Instrumentation", () => {
describe("ReactNavigationInstrumentation", () => {
test("transaction set on initialize", () => {
const instrumentation = new ReactNavigationV5Instrumentation();
const instrumentation = new ReactNavigationInstrumentation();

const mockTransaction = getMockTransaction();
const tracingListener = jest.fn(() => mockTransaction);
Expand All @@ -66,7 +66,7 @@ describe("ReactNavigationV5Instrumentation", () => {

expect(mockTransaction.name).toBe(dummyRoute.name);
expect(mockTransaction.tags).toStrictEqual({
...BLANK_TRANSACTION_CONTEXT_V5.tags,
...BLANK_TRANSACTION_CONTEXT.tags,
"routing.route.name": dummyRoute.name,
});
expect(mockTransaction.data).toStrictEqual({
Expand All @@ -81,7 +81,7 @@ describe("ReactNavigationV5Instrumentation", () => {
});

test("transaction sent on navigation", async () => {
const instrumentation = new ReactNavigationV5Instrumentation();
const instrumentation = new ReactNavigationInstrumentation();

// Need a dummy transaction as the instrumentation will start a transaction right away when the first navigation container is attached.
const mockTransactionDummy = getMockTransaction();
Expand Down Expand Up @@ -121,7 +121,7 @@ describe("ReactNavigationV5Instrumentation", () => {

expect(mockTransaction.name).toBe(route.name);
expect(mockTransaction.tags).toStrictEqual({
...BLANK_TRANSACTION_CONTEXT_V5.tags,
...BLANK_TRANSACTION_CONTEXT.tags,
"routing.route.name": route.name,
});
expect(mockTransaction.data).toStrictEqual({
Expand All @@ -144,7 +144,7 @@ describe("ReactNavigationV5Instrumentation", () => {
});

test("transaction context changed with beforeNavigate", async () => {
const instrumentation = new ReactNavigationV5Instrumentation();
const instrumentation = new ReactNavigationInstrumentation();

// Need a dummy transaction as the instrumentation will start a transaction right away when the first navigation container is attached.
const mockTransactionDummy = getMockTransaction();
Expand Down Expand Up @@ -194,7 +194,7 @@ describe("ReactNavigationV5Instrumentation", () => {
});

test("transaction not sent on a cancelled navigation", async () => {
const instrumentation = new ReactNavigationV5Instrumentation();
const instrumentation = new ReactNavigationInstrumentation();

// Need a dummy transaction as the instrumentation will start a transaction right away when the first navigation container is attached.
const mockTransactionDummy = getMockTransaction();
Expand Down Expand Up @@ -224,10 +224,10 @@ describe("ReactNavigationV5Instrumentation", () => {
setTimeout(() => {
expect(mockTransaction.sampled).toBe(false);
expect(mockTransaction.name).toStrictEqual(
BLANK_TRANSACTION_CONTEXT_V5.name
BLANK_TRANSACTION_CONTEXT.name
);
expect(mockTransaction.tags).toStrictEqual(
BLANK_TRANSACTION_CONTEXT_V5.tags
BLANK_TRANSACTION_CONTEXT.tags
);
expect(mockTransaction.data).toStrictEqual({});
resolve();
Expand All @@ -237,7 +237,7 @@ describe("ReactNavigationV5Instrumentation", () => {

describe("navigation container registration", () => {
test("registers navigation container object ref", () => {
const instrumentation = new ReactNavigationV5Instrumentation();
const instrumentation = new ReactNavigationInstrumentation();
const mockNavigationContainer = new MockNavigationContainer();
instrumentation.registerNavigationContainer({
current: mockNavigationContainer,
Expand All @@ -260,7 +260,7 @@ describe("ReactNavigationV5Instrumentation", () => {
});

test("registers navigation container direct ref", () => {
const instrumentation = new ReactNavigationV5Instrumentation();
const instrumentation = new ReactNavigationInstrumentation();
const mockNavigationContainer = new MockNavigationContainer();
instrumentation.registerNavigationContainer(mockNavigationContainer);

Expand All @@ -283,7 +283,7 @@ describe("ReactNavigationV5Instrumentation", () => {
test("does not register navigation container if there is an existing one", () => {
_global.__sentry_rn_v5_registered = true;

const instrumentation = new ReactNavigationV5Instrumentation();
const instrumentation = new ReactNavigationInstrumentation();
const mockNavigationContainer = new MockNavigationContainer();
instrumentation.registerNavigationContainer({
current: mockNavigationContainer,
Expand All @@ -298,7 +298,7 @@ describe("ReactNavigationV5Instrumentation", () => {
});

test("works if routing instrumentation registration is after navigation registration", async () => {
const instrumentation = new ReactNavigationV5Instrumentation();
const instrumentation = new ReactNavigationInstrumentation();

const mockNavigationContainer = new MockNavigationContainer();
instrumentation.registerNavigationContainer(mockNavigationContainer);
Expand All @@ -321,7 +321,7 @@ describe("ReactNavigationV5Instrumentation", () => {

describe("options", () => {
test("waits until routeChangeTimeoutMs", async () => {
const instrumentation = new ReactNavigationV5Instrumentation({
const instrumentation = new ReactNavigationInstrumentation({
routeChangeTimeoutMs: 200,
});

Expand Down Expand Up @@ -351,7 +351,7 @@ describe("ReactNavigationV5Instrumentation", () => {
});

test("discards if after routeChangeTimeoutMs", async () => {
const instrumentation = new ReactNavigationV5Instrumentation({
const instrumentation = new ReactNavigationInstrumentation({
routeChangeTimeoutMs: 200,
});

Expand Down