diff --git a/desktop/app/src/__tests__/deeplink.node.tsx b/desktop/app/src/__tests__/deeplink.node.tsx
index 3e8c3d884..3df509039 100644
--- a/desktop/app/src/__tests__/deeplink.node.tsx
+++ b/desktop/app/src/__tests__/deeplink.node.tsx
@@ -97,4 +97,54 @@ test('Will throw error on invalid deeplinks', async () => {
expect(() =>
handleDeeplink(undefined as any, logger, `flipper://test`),
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown deeplink"`);
+
+ expect(logger.track).toHaveBeenCalledTimes(2);
+ expect(logger.track).toHaveBeenLastCalledWith('usage', 'deeplink', {
+ query: 'flipper://test',
+ state: 'ERROR',
+ errorMessage: 'Unknown deeplink',
+ });
+});
+
+test('Will throw error on invalid protocol', async () => {
+ const logger: Logger = {
+ track: jest.fn(),
+ } as any;
+
+ expect(() =>
+ handleDeeplink(undefined as any, logger, `notflipper://test`),
+ ).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown deeplink"`);
+
+ expect(logger.track).toHaveBeenCalledTimes(2);
+ expect(logger.track).toHaveBeenLastCalledWith('usage', 'deeplink', {
+ query: 'notflipper://test',
+ state: 'ERROR',
+ errorMessage: 'Unknown deeplink',
+ });
+});
+
+test('Will track deeplinks', async () => {
+ const definition = new _SandyPluginDefinition(
+ TestUtils.createMockPluginDetails(),
+ {
+ plugin: () => {},
+ Component() {
+ return
{'world'}
;
+ },
+ },
+ );
+ const {store, logger} = await renderMockFlipperWithPlugin(definition);
+ logger.track = jest.fn();
+
+ await handleDeeplink(
+ store,
+ logger,
+ 'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe',
+ );
+
+ expect(logger.track).toHaveBeenCalledWith('usage', 'deeplink', {
+ query:
+ 'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe',
+ state: 'INIT',
+ });
});
diff --git a/desktop/app/src/deeplink.tsx b/desktop/app/src/deeplink.tsx
index c66b7d047..99e752db2 100644
--- a/desktop/app/src/deeplink.tsx
+++ b/desktop/app/src/deeplink.tsx
@@ -21,6 +21,22 @@ import {Dialog} from 'flipper-plugin';
import {handleOpenPluginDeeplink} from './dispatcher/handleOpenPluginDeeplink';
import {message} from 'antd';
+type DeeplinkInteraction = {
+ state: 'INIT' | 'ERROR';
+ errorMessage?: string;
+};
+
+function track(
+ logger: Logger,
+ query: string,
+ interaction: DeeplinkInteraction,
+) {
+ logger.track('usage', 'deeplink', {
+ ...interaction,
+ query,
+ });
+}
+
const UNKNOWN = 'Unknown deeplink';
/**
* Handle a flipper:// deeplink. Will throw if the URL pattern couldn't be recognised
@@ -30,9 +46,21 @@ export async function handleDeeplink(
logger: Logger,
query: string,
): Promise {
- const uri = new URL(query);
- if (uri.protocol !== 'flipper:') {
+ const trackInteraction = track.bind(null, logger, query);
+ const unknownError = () => {
+ trackInteraction({
+ state: 'ERROR',
+ errorMessage: UNKNOWN,
+ });
throw new Error(UNKNOWN);
+ };
+ const uri = new URL(query);
+
+ trackInteraction({
+ state: 'INIT',
+ });
+ if (uri.protocol !== 'flipper:') {
+ throw unknownError();
}
if (uri.href.startsWith('flipper://open-plugin')) {
return handleOpenPluginDeeplink(store, query);
@@ -57,7 +85,7 @@ export async function handleDeeplink(
handle.close();
});
}
- throw new Error(UNKNOWN);
+ throw unknownError();
} else if (uri.pathname.match(/^\/*support-form\/*$/)) {
const formParam = uri.searchParams.get('form');
const grp = deeplinkFormParamToGroups(formParam);
@@ -65,7 +93,7 @@ export async function handleDeeplink(
grp.handleSupportFormDeeplinks(store);
return;
}
- throw new Error(UNKNOWN);
+ throw unknownError();
} else if (uri.pathname.match(/^\/*login\/*$/)) {
const token = uri.searchParams.get('token');
store.dispatch(setPastedToken(token ?? undefined));
@@ -93,7 +121,7 @@ export async function handleDeeplink(
);
return;
} else {
- throw new Error(UNKNOWN);
+ throw unknownError();
}
}