@amazon-devices/shopify__react-native-performance-lists-profiler 1.1.1758683737

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +7 -0
  2. package/README.kepler.md +331 -0
  3. package/README.md +7 -0
  4. package/ReactNativePerformanceListsProfiler.podspec +30 -0
  5. package/SystemBundles/1b881d5412b1fc3466fe9ebb1f1c33915d19056d122263f1ba0356a8c71c31ca.bundle +10666 -0
  6. package/SystemBundles/1b881d5412b1fc3466fe9ebb1f1c33915d19056d122263f1ba0356a8c71c31ca.map +1 -0
  7. package/SystemModules/amzn__shopify__react-native-performance-lists-profiler-1.modules.txt +26 -0
  8. package/SystemModules/amzn__shopify__react-native-performance-lists-profiler-1.private.modules.txt +96 -0
  9. package/SystemModules/keplerscript-system-bundle-config.json +7 -0
  10. package/THIRD_PARTY_NOTICES.txt +472 -0
  11. package/android/build.gradle +59 -0
  12. package/android/src/main/AndroidManifest.xml +3 -0
  13. package/android/src/main/kotlin/com/shopify/reactnativeperformancelistsprofiler/BlankAreaView.kt +150 -0
  14. package/android/src/main/kotlin/com/shopify/reactnativeperformancelistsprofiler/FlashListPerformanceViewManager.kt +49 -0
  15. package/android/src/main/kotlin/com/shopify/reactnativeperformancelistsprofiler/FlatListPerformanceViewManager.kt +47 -0
  16. package/android/src/main/kotlin/com/shopify/reactnativeperformancelistsprofiler/ReactNativePerformanceListsProfilerPackage.kt +19 -0
  17. package/dist/FlashListPerformanceView.d.ts +14 -0
  18. package/dist/FlashListPerformanceView.d.ts.map +1 -0
  19. package/dist/FlashListPerformanceView.js +33 -0
  20. package/dist/FlashListPerformanceView.js.map +1 -0
  21. package/dist/FlashListPerformanceView.types.d.ts +21 -0
  22. package/dist/FlashListPerformanceView.types.d.ts.map +1 -0
  23. package/dist/FlashListPerformanceView.types.js +3 -0
  24. package/dist/FlashListPerformanceView.types.js.map +1 -0
  25. package/dist/FlashListPerformanceViewNativeComponent.d.ts +4 -0
  26. package/dist/FlashListPerformanceViewNativeComponent.d.ts.map +1 -0
  27. package/dist/FlashListPerformanceViewNativeComponent.js +7 -0
  28. package/dist/FlashListPerformanceViewNativeComponent.js.map +1 -0
  29. package/dist/FlashListPerformanceViewNativeComponent.kepler.d.ts +5 -0
  30. package/dist/FlashListPerformanceViewNativeComponent.kepler.d.ts.map +1 -0
  31. package/dist/FlashListPerformanceViewNativeComponent.kepler.js +35 -0
  32. package/dist/FlashListPerformanceViewNativeComponent.kepler.js.map +1 -0
  33. package/dist/FlatListPerformanceView.d.ts +15 -0
  34. package/dist/FlatListPerformanceView.d.ts.map +1 -0
  35. package/dist/FlatListPerformanceView.js +38 -0
  36. package/dist/FlatListPerformanceView.js.map +1 -0
  37. package/dist/FlatListPerformanceView.types.d.ts +19 -0
  38. package/dist/FlatListPerformanceView.types.d.ts.map +1 -0
  39. package/dist/FlatListPerformanceView.types.js +10 -0
  40. package/dist/FlatListPerformanceView.types.js.map +1 -0
  41. package/dist/FlatListPerformanceViewNativeComponent.d.ts +4 -0
  42. package/dist/FlatListPerformanceViewNativeComponent.d.ts.map +1 -0
  43. package/dist/FlatListPerformanceViewNativeComponent.js +7 -0
  44. package/dist/FlatListPerformanceViewNativeComponent.js.map +1 -0
  45. package/dist/FlatListPerformanceViewNativeComponent.kepler.d.ts +5 -0
  46. package/dist/FlatListPerformanceViewNativeComponent.kepler.d.ts.map +1 -0
  47. package/dist/FlatListPerformanceViewNativeComponent.kepler.js +35 -0
  48. package/dist/FlatListPerformanceViewNativeComponent.kepler.js.map +1 -0
  49. package/dist/ListsProfiler.d.ts +9 -0
  50. package/dist/ListsProfiler.d.ts.map +1 -0
  51. package/dist/ListsProfiler.js +54 -0
  52. package/dist/ListsProfiler.js.map +1 -0
  53. package/dist/ListsProfilerContext.d.ts +9 -0
  54. package/dist/ListsProfilerContext.d.ts.map +1 -0
  55. package/dist/ListsProfilerContext.js +11 -0
  56. package/dist/ListsProfilerContext.js.map +1 -0
  57. package/dist/ListsProfilerModule.d.ts +6 -0
  58. package/dist/ListsProfilerModule.d.ts.map +1 -0
  59. package/dist/ListsProfilerModule.js +14 -0
  60. package/dist/ListsProfilerModule.js.map +1 -0
  61. package/dist/ListsProfilerProps.d.ts +19 -0
  62. package/dist/ListsProfilerProps.d.ts.map +1 -0
  63. package/dist/ListsProfilerProps.js +3 -0
  64. package/dist/ListsProfilerProps.js.map +1 -0
  65. package/dist/__tests__/FlashListPerformanceView.test.d.ts +2 -0
  66. package/dist/__tests__/FlashListPerformanceView.test.d.ts.map +1 -0
  67. package/dist/__tests__/FlashListPerformanceView.test.js +53 -0
  68. package/dist/__tests__/FlashListPerformanceView.test.js.map +1 -0
  69. package/dist/__tests__/FlatListPerformanceView.test.d.ts +2 -0
  70. package/dist/__tests__/FlatListPerformanceView.test.d.ts.map +1 -0
  71. package/dist/__tests__/FlatListPerformanceView.test.js +59 -0
  72. package/dist/__tests__/FlatListPerformanceView.test.js.map +1 -0
  73. package/dist/__tests__/ListProfiler.test.d.ts +2 -0
  74. package/dist/__tests__/ListProfiler.test.d.ts.map +1 -0
  75. package/dist/__tests__/ListProfiler.test.js +53 -0
  76. package/dist/__tests__/ListProfiler.test.js.map +1 -0
  77. package/dist/index.d.ts +4 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +13 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/tsconfig.tsbuildinfo +1 -0
  82. package/ios/ReactNativePerformanceListsProfiler.xcodeproj/project.pbxproj +3 -0
  83. package/ios/Sources/BlankAreaView.swift +111 -0
  84. package/ios/Sources/FlashListPerformanceViewManager.m +9 -0
  85. package/ios/Sources/FlashListPerformanceViewManager.swift +23 -0
  86. package/ios/Sources/FlatListPerformanceViewManager.m +9 -0
  87. package/ios/Sources/FlatListPerformanceViewManager.swift +18 -0
  88. package/ios/Sources/ReactNativePerfomanceListsProfilerUmbrella.h +8 -0
  89. package/ios/Tests/ReactNativePerformanceListsProfilerTests.swift +5 -0
  90. package/kepler-compatibility.json +8 -0
  91. package/kepler-transformed-package-info.json +3 -0
  92. package/package.json +1 -0
  93. package/src/FlashListPerformanceView.tsx +44 -0
  94. package/src/FlashListPerformanceView.types.ts +23 -0
  95. package/src/FlashListPerformanceViewNativeComponent.kepler.ts +38 -0
  96. package/src/FlashListPerformanceViewNativeComponent.ts +7 -0
  97. package/src/FlatListPerformanceView.tsx +61 -0
  98. package/src/FlatListPerformanceView.types.ts +28 -0
  99. package/src/FlatListPerformanceViewNativeComponent.kepler.tsx +38 -0
  100. package/src/FlatListPerformanceViewNativeComponent.tsx +7 -0
  101. package/src/ListsProfiler.tsx +67 -0
  102. package/src/ListsProfilerContext.tsx +13 -0
  103. package/src/ListsProfilerModule.ts +25 -0
  104. package/src/ListsProfilerProps.ts +18 -0
  105. package/src/__tests__/FlashListPerformanceView.test.tsx +71 -0
  106. package/src/__tests__/FlatListPerformanceView.test.tsx +77 -0
  107. package/src/__tests__/ListProfiler.test.tsx +60 -0
  108. package/src/__tests__/setupJest.js +5 -0
  109. package/src/index.ts +3 -0
@@ -0,0 +1,61 @@
1
+ import React, {useRef, useContext, useCallback} from 'react';
2
+
3
+ import {ListsProfilerContext} from './ListsProfilerContext';
4
+ import {FlatListPerformanceViewNativeComponent} from './FlatListPerformanceViewNativeComponent';
5
+ import {OnBlankAreaEvent, OnInteractiveEvent} from './FlatListPerformanceView.types';
6
+ import ListsProfilerProps from './ListsProfilerProps';
7
+ // @amznmod_react - Add import for the turbomodule
8
+ import ListsProfilerModule from './ListsProfilerModule';
9
+
10
+ interface FlatListPerformanceViewProps {
11
+ /**
12
+ * Name of the list. Used for distinguishing between lists in the `ListsProfiler`.
13
+ */
14
+ listName: string;
15
+ children: JSX.Element;
16
+ }
17
+
18
+ /**
19
+ * Wrap your `FlatList` with this component.
20
+ */
21
+ const FlatListPerformanceView = ({
22
+ children,
23
+ listName,
24
+ onInteractive = () => {},
25
+ onBlankArea = () => {},
26
+ }: FlatListPerformanceViewProps & ListsProfilerProps) => {
27
+ const time = useRef(Date.now()).current;
28
+ const listsProfilerController = useContext(ListsProfilerContext);
29
+ const onInteractiveCallback = useCallback(
30
+ ({nativeEvent}: OnInteractiveEvent) => {
31
+ const tti = nativeEvent.timestamp - time;
32
+ onInteractive(tti, listName);
33
+ listsProfilerController.onInteractive(tti, listName);
34
+ },
35
+ [listsProfilerController, onInteractive, listName, time],
36
+ );
37
+ const onBlankAreaCallback = useCallback(
38
+ ({nativeEvent}: OnBlankAreaEvent) => {
39
+ onBlankArea(nativeEvent.offsetStart, nativeEvent.offsetEnd, listName);
40
+ listsProfilerController.onBlankArea(nativeEvent.offsetStart, nativeEvent.offsetEnd, listName);
41
+ },
42
+ [onBlankArea, listsProfilerController, listName],
43
+ );
44
+ return (
45
+ <FlatListPerformanceViewNativeComponent
46
+ onInteractive={onInteractiveCallback}
47
+ onBlankAreaEvent={onBlankAreaCallback}
48
+ >
49
+ {/* @amznmod_react - Extend the list's onScroll with a call to the TM */}
50
+ {React.cloneElement(children, {
51
+ onScroll: () => {
52
+ if (children?.props?.onScroll) {
53
+ children.props.onScroll();
54
+ }
55
+ ListsProfilerModule?.invokeCallback();
56
+ },
57
+ })}
58
+ </FlatListPerformanceViewNativeComponent>
59
+ );
60
+ };
61
+ export default FlatListPerformanceView;
@@ -0,0 +1,28 @@
1
+ /*
2
+ * Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ *
4
+ * PROPRIETARY/CONFIDENTIAL
5
+ *
6
+ * Use is subject to license terms.
7
+ */
8
+
9
+ export interface OnInteractiveEvent {
10
+ nativeEvent: {
11
+ timestamp: number;
12
+ };
13
+ }
14
+
15
+ export interface OnBlankAreaEvent {
16
+ nativeEvent: {
17
+ offsetStart: number;
18
+ offsetEnd: number;
19
+ };
20
+ }
21
+
22
+ type OnInteractiveHandler = (event: OnInteractiveEvent) => void;
23
+ type OnBlankAreaEventHandler = (event: OnBlankAreaEvent) => void;
24
+
25
+ export interface FlatListPerformanceViewNativeComponentProps {
26
+ onInteractive: OnInteractiveHandler;
27
+ onBlankAreaEvent: OnBlankAreaEventHandler;
28
+ }
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ *
4
+ * PROPRIETARY/CONFIDENTIAL
5
+ *
6
+ * Use is subject to license terms.
7
+ */
8
+
9
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
10
+ // @ts-ignore For some reason this is unknown
11
+ import register from 'react-native/Libraries/Utilities/registerGeneratedViewConfig';
12
+ import { HostComponent } from 'react-native';
13
+
14
+ import { FlatListPerformanceViewNativeComponentProps } from './FlatListPerformanceView.types';
15
+
16
+ const FlatListPerformanceView = 'AmazonFlatListPerformanceView';
17
+
18
+ register(FlatListPerformanceView, {
19
+ uiViewClassName: FlatListPerformanceView,
20
+ bubblingEventTypes: {
21
+ topOnInteractive: {
22
+ phasedRegistrationNames: {
23
+ bubbled: 'onInteractive',
24
+ captured: 'onInteractiveCapture',
25
+ },
26
+ },
27
+ topOnBlankAreaEvent: {
28
+ phasedRegistrationNames: {
29
+ bubbled: 'onBlankAreaEvent',
30
+ captured: 'onBlankAreaEventCapture',
31
+ },
32
+ },
33
+ },
34
+ });
35
+
36
+ const FlatListPerformanceViewNativeComponent =
37
+ (FlatListPerformanceView as unknown) as HostComponent<FlatListPerformanceViewNativeComponentProps>;
38
+ export { FlatListPerformanceViewNativeComponent };
@@ -0,0 +1,7 @@
1
+ import {requireNativeComponent} from 'react-native';
2
+
3
+ import {FlatListPerformanceViewNativeComponentProps} from './FlatListPerformanceView.types';
4
+
5
+ const FlatListPerformanceViewNativeComponent =
6
+ requireNativeComponent<FlatListPerformanceViewNativeComponentProps>('FlatListPerformanceView');
7
+ export {FlatListPerformanceViewNativeComponent};
@@ -0,0 +1,67 @@
1
+ import React, {useCallback} from 'react';
2
+ import {Flipper, addPlugin} from 'react-native-flipper';
3
+
4
+ import {ListsProfilerContextProvider} from './ListsProfilerContext';
5
+ import ListsProfilerProps from './ListsProfilerProps';
6
+
7
+ const bootstrapPlugin = (): Promise<Flipper.FlipperConnection> => {
8
+ return new Promise(resolve => {
9
+ addPlugin({
10
+ getId: () => '@shopify/react-native-performance',
11
+ onConnect: connection => {
12
+ return resolve(connection);
13
+ },
14
+ onDisconnect: () => {},
15
+ runInBackground: () => true,
16
+ });
17
+ });
18
+ };
19
+
20
+ /**
21
+ * Wrap your app with this component to get events from all the lists wrapped with their performance view.
22
+ * For example, `FlatList` must be wrapped in the `FlatListPerformanceView`.
23
+ */
24
+ const ListsProfiler = ({onInteractive = () => {}, onBlankArea = () => {}, children}: ListsProfilerProps) => {
25
+ let connection: Flipper.FlipperConnection | undefined;
26
+ bootstrapPlugin()
27
+ .then(conn => {
28
+ connection = conn;
29
+ })
30
+ .catch(error => {
31
+ throw error;
32
+ });
33
+
34
+ const onInteractiveCallback = useCallback(
35
+ (TTI: number, listName: string) => {
36
+ onInteractive(TTI, listName);
37
+ connection?.send('newListTTIData', {
38
+ TTI,
39
+ listName,
40
+ });
41
+ },
42
+ [connection, onInteractive],
43
+ );
44
+ const onBlankAreaCallback = useCallback(
45
+ (offsetStart: number, offsetEnd: number, listName: string) => {
46
+ onBlankArea(offsetStart, offsetEnd, listName);
47
+ const blankArea = Math.max(Math.max(offsetStart, offsetEnd), 0);
48
+ connection?.send('newBlankData', {
49
+ offset: blankArea,
50
+ listName,
51
+ });
52
+ },
53
+ [connection, onBlankArea],
54
+ );
55
+ return (
56
+ <ListsProfilerContextProvider
57
+ value={{
58
+ onInteractive: onInteractiveCallback,
59
+ onBlankArea: onBlankAreaCallback,
60
+ }}
61
+ >
62
+ {children}
63
+ </ListsProfilerContextProvider>
64
+ );
65
+ };
66
+
67
+ export default ListsProfiler;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+
3
+ interface ListsProfilerController {
4
+ onInteractive: (TTI: number, listName: string) => void;
5
+ onBlankArea: (offsetStart: number, offsetEnd: number, listName: string) => void;
6
+ }
7
+
8
+ export const ListsProfilerContext = React.createContext<ListsProfilerController>({
9
+ onInteractive: () => {},
10
+ onBlankArea: () => {},
11
+ });
12
+
13
+ export const ListsProfilerContextProvider = ListsProfilerContext.Provider;
@@ -0,0 +1,25 @@
1
+ import type {KeplerTurboModule} from '@amazon-devices/keplerscript-turbomodule-api';
2
+ import {TurboModuleRegistry} from '@amazon-devices/keplerscript-turbomodule-api';
3
+
4
+ interface Spec extends KeplerTurboModule {
5
+ invokeCallback: () => void;
6
+ }
7
+
8
+ const nativeModule = TurboModuleRegistry.get<Spec>('AmazonReactNativePerformanceListsProfilerModule') as Spec;
9
+
10
+ interface ListsProfilerModule {
11
+ invokeCallback: () => void;
12
+ }
13
+
14
+ const module: ListsProfilerModule = {
15
+ invokeCallback() {
16
+ if (!nativeModule) {
17
+ throw new Error(
18
+ 'Lists profiler module not found in NativeModules. Chances are you\'re in a test environment, but the mocks have not been setup correctly');
19
+ }
20
+
21
+ nativeModule.invokeCallback();
22
+ },
23
+ };
24
+
25
+ export default module;
@@ -0,0 +1,18 @@
1
+ interface ListsProfilerProps {
2
+ /**
3
+ * Triggered when a list wrapped in a list performance view becomes interactive.
4
+ * @param TTI: Reported time-to-interactive
5
+ * @param listName - Name of the list that triggered the event defined in the list performance view
6
+ */
7
+ onInteractive?: (TTI: number, listName: string) => void;
8
+ /**
9
+ * Triggered when a list wrapped in a list performance view is scrolled and reports a blank area.
10
+ * @param offsetStart - Offset at the beginning of the list (top when the list is vertical)
11
+ * @param offsetEnd - Offset at the end of the list (bottom when the list is vertical)
12
+ * @param listName - Name of the list that triggered the event defined in the list performance view
13
+ */
14
+ onBlankArea?: (offsetStart: number, offsetEnd: number, listName: string) => void;
15
+ children: JSX.Element;
16
+ }
17
+
18
+ export default ListsProfilerProps;
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import { render, fireEvent } from '@testing-library/react-native';
3
+ import { Text } from 'react-native';
4
+ import FlashListPerformanceView from '../FlashListPerformanceView';
5
+ import { ListsProfilerContextProvider } from '../ListsProfilerContext';
6
+ import 'jest-extended';
7
+
8
+ jest.mock('../FlashListPerformanceViewNativeComponent', () => {
9
+ const RN = require('react-native');
10
+
11
+ return {
12
+ FlashListPerformanceViewNativeComponent: ({ onInteractive, onBlankAreaEvent, children }: any) => (
13
+ <RN.View>
14
+ <RN.TouchableOpacity testID="interactive" onPress={onInteractive}>
15
+ <RN.Text>Interactive Event</RN.Text>
16
+ </RN.TouchableOpacity>
17
+ <RN.TouchableOpacity testID="blankArea" onPress={onBlankAreaEvent}>
18
+ <RN.Text>Blank Area Event</RN.Text>
19
+ </RN.TouchableOpacity>
20
+ {children}
21
+ </RN.View>
22
+ ),
23
+ };
24
+ });
25
+
26
+ describe('FlashListPerformanceView', () => {
27
+ let mockListsProfilerController: any;
28
+
29
+ beforeEach(() => {
30
+ mockListsProfilerController = {
31
+ onInteractive: jest.fn(),
32
+ onBlankArea: jest.fn(),
33
+ };
34
+ });
35
+
36
+ const wrapper = ({ children }: { children: React.ReactElement }) => (
37
+ <ListsProfilerContextProvider value={mockListsProfilerController}>
38
+ {children}
39
+ </ListsProfilerContextProvider>
40
+ );
41
+
42
+ it('calls listsProfilerController.onInteractive on interactive event', () => {
43
+ const { getByTestId } = render(
44
+ <FlashListPerformanceView listName="TestList">
45
+ <Text>Child</Text>
46
+ </FlashListPerformanceView>,
47
+ { wrapper }
48
+ );
49
+
50
+ fireEvent.press(getByTestId('interactive'), {
51
+ nativeEvent: { timestamp: Date.now() },
52
+ });
53
+
54
+ expect(mockListsProfilerController.onInteractive).toHaveBeenCalledWith(expect.any(Number), 'TestList');
55
+ });
56
+
57
+ it('calls listsProfilerController.onBlankArea on blank area event', () => {
58
+ const { getByTestId } = render(
59
+ <FlashListPerformanceView listName="TestList">
60
+ <Text>Child</Text>
61
+ </FlashListPerformanceView>,
62
+ { wrapper }
63
+ );
64
+
65
+ fireEvent.press(getByTestId('blankArea'), {
66
+ nativeEvent: { offsetStart: 100, offsetEnd: 200 },
67
+ });
68
+
69
+ expect(mockListsProfilerController.onBlankArea).toHaveBeenCalledWith(100, 200, 'TestList');
70
+ });
71
+ });
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import { render, fireEvent } from '@testing-library/react-native';
3
+ import { Text } from 'react-native';
4
+ import FlatListPerformanceView from '../FlatListPerformanceView';
5
+ import { ListsProfilerContextProvider } from '../ListsProfilerContext';
6
+ import 'jest-extended';
7
+
8
+ jest.mock('../FlatListPerformanceViewNativeComponent', () => {
9
+ const RN = require('react-native');
10
+
11
+ return {
12
+ FlatListPerformanceViewNativeComponent: ({ onInteractive, onBlankAreaEvent, children }: any) => (
13
+ <RN.View>
14
+ <RN.TouchableOpacity testID="interactive" onPress={onInteractive}>
15
+ <RN.Text>Interactive Event</RN.Text>
16
+ </RN.TouchableOpacity>
17
+ <RN.TouchableOpacity testID="blankArea" onPress={onBlankAreaEvent}>
18
+ <RN.Text>Blank Area Event</RN.Text>
19
+ </RN.TouchableOpacity>
20
+ {children}
21
+ </RN.View>
22
+ ),
23
+ };
24
+ });
25
+
26
+ describe('FlatListPerformanceView', () => {
27
+ let mockOnInteractive: jest.Mock;
28
+ let mockOnBlankArea: jest.Mock;
29
+ let mockListsProfilerController: any;
30
+
31
+ beforeEach(() => {
32
+ mockOnInteractive = jest.fn();
33
+ mockOnBlankArea = jest.fn();
34
+ mockListsProfilerController = {
35
+ onInteractive: jest.fn(),
36
+ onBlankArea: jest.fn(),
37
+ };
38
+ });
39
+
40
+ const wrapper = ({ children }: { children: React.ReactElement }) => (
41
+ <ListsProfilerContextProvider value={mockListsProfilerController}>
42
+ {children}
43
+ </ListsProfilerContextProvider>
44
+ );
45
+
46
+ it('calls onInteractive and listsProfilerController.onInteractive on interactive event', () => {
47
+ const { getByTestId } = render(
48
+ <FlatListPerformanceView listName="TestList" onInteractive={mockOnInteractive}>
49
+ <Text>Child</Text>
50
+ </FlatListPerformanceView>,
51
+ { wrapper }
52
+ );
53
+
54
+ fireEvent.press(getByTestId('interactive'), {
55
+ nativeEvent: { timestamp: Date.now() },
56
+ });
57
+
58
+ expect(mockOnInteractive).toHaveBeenCalledWith(expect.any(Number), 'TestList');
59
+ expect(mockListsProfilerController.onInteractive).toHaveBeenCalledWith(expect.any(Number), 'TestList');
60
+ });
61
+
62
+ it('calls onBlankArea and listsProfilerController.onBlankArea on blank area event', () => {
63
+ const { getByTestId } = render(
64
+ <FlatListPerformanceView listName="TestList" onBlankArea={mockOnBlankArea}>
65
+ <Text>Child</Text>
66
+ </FlatListPerformanceView>,
67
+ { wrapper }
68
+ );
69
+
70
+ fireEvent.press(getByTestId('blankArea'), {
71
+ nativeEvent: { offsetStart: 100, offsetEnd: 200 },
72
+ });
73
+
74
+ expect(mockOnBlankArea).toHaveBeenCalledWith(100, 200, 'TestList');
75
+ expect(mockListsProfilerController.onBlankArea).toHaveBeenCalledWith(100, 200, 'TestList');
76
+ });
77
+ });
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ import { renderHook } from '@testing-library/react-hooks';
3
+ import ListsProfiler from '../ListsProfiler';
4
+ import { ListsProfilerContext } from '../ListsProfilerContext';
5
+
6
+ jest.mock('react-native-flipper', () => ({
7
+ addPlugin: jest.fn(),
8
+ }));
9
+
10
+ describe('ListsProfiler', () => {
11
+ let mockOnInteractive: jest.Mock;
12
+ let mockOnBlankArea: jest.Mock;
13
+ let mockConnection: { send: jest.Mock };
14
+
15
+ beforeEach(() => {
16
+ mockOnInteractive = jest.fn();
17
+ mockOnBlankArea = jest.fn();
18
+ mockConnection = {
19
+ send: jest.fn(),
20
+ };
21
+
22
+ (require('react-native-flipper').addPlugin as jest.Mock).mockImplementation(({ onConnect }: { onConnect: (connection: any) => void }) => {
23
+ onConnect(mockConnection);
24
+ });
25
+ });
26
+
27
+ it('calls Flipper addPlugin on mount', () => {
28
+ const wrapper = ({children}: {children: React.ReactElement}) => (
29
+ <ListsProfiler onInteractive={mockOnInteractive} onBlankArea={mockOnBlankArea}>{children}</ListsProfiler>
30
+ );
31
+
32
+ renderHook(() => React.useContext(ListsProfilerContext), { wrapper });
33
+
34
+ expect(require('react-native-flipper').addPlugin).toHaveBeenCalledTimes(1);
35
+ });
36
+
37
+ it('invokes onInteractive callback', () => {
38
+ const wrapper = ({children}: {children: React.ReactElement}) => (
39
+ <ListsProfiler onInteractive={mockOnInteractive} onBlankArea={mockOnBlankArea}>{children}</ListsProfiler>
40
+ );
41
+ const { result } = renderHook(() => React.useContext(ListsProfilerContext), { wrapper });
42
+
43
+ result.current.onInteractive(2000, 'TestList');
44
+
45
+ expect(mockOnInteractive).toHaveBeenCalledWith(2000, 'TestList');
46
+ });
47
+
48
+ it('invokes onBlankArea callback', () => {
49
+ const wrapper = ({children}: {children: React.ReactElement}) => (
50
+ <ListsProfiler onInteractive={mockOnInteractive} onBlankArea={mockOnBlankArea}>{children}</ListsProfiler>
51
+ );
52
+
53
+ const { result } = renderHook(() => React.useContext(ListsProfilerContext), { wrapper });
54
+
55
+ result.current.onBlankArea(100, 200, 'TestList');
56
+
57
+ expect(mockOnBlankArea).toHaveBeenCalledWith(100, 200, 'TestList');
58
+ });
59
+ });
60
+
@@ -0,0 +1,5 @@
1
+ jest.mock('@amazon-devices/keplerscript-turbomodule-api', () => ({
2
+ TurboModuleRegistry: {
3
+ get: jest.fn(),
4
+ },
5
+ }));
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export {default as FlatListPerformanceView} from './FlatListPerformanceView';
2
+ export {default as FlashListPerformanceView} from './FlashListPerformanceView';
3
+ export {default as ListsProfiler} from './ListsProfiler';