diff --git a/src/components/ScreenWrapper/index.js b/src/components/ScreenWrapper/index.js
index bd277ffa1ab8..432139353c56 100644
--- a/src/components/ScreenWrapper/index.js
+++ b/src/components/ScreenWrapper/index.js
@@ -39,16 +39,32 @@ const ScreenWrapper = React.forwardRef(
shouldDismissKeyboardBeforeClose,
onEntryTransitionEnd,
testID,
+
+ /**
+ * The navigation prop is passed by the navigator. It is used to trigger the onEntryTransitionEnd callback
+ * when the screen transition ends.
+ *
+ * This is required because transitionEnd event doesn't trigger in the testing environment.
+ */
+ navigation: navigationProp,
},
ref,
) => {
+ /**
+ * We are only passing navigation as prop from
+ * ReportScreenWrapper -> ReportScreen -> ScreenWrapper
+ *
+ * so in other places where ScreenWrapper is used, we need to
+ * fallback to useNavigation.
+ */
+ const navigationFallback = useNavigation();
+ const navigation = navigationProp || navigationFallback;
const {windowHeight, isSmallScreenWidth} = useWindowDimensions();
const {initialHeight} = useInitialDimensions();
const styles = useThemeStyles();
const keyboardState = useKeyboardState();
const {isDevelopment} = useEnvironment();
const {isOffline} = useNetwork();
- const navigation = useNavigation();
const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false);
const maxHeight = shouldEnableMaxHeight ? windowHeight : undefined;
const minHeight = shouldEnableMinHeight && !Browser.isSafari() ? initialHeight : undefined;
diff --git a/src/libs/Navigation/AppNavigator/ReportScreenWrapper.tsx b/src/libs/Navigation/AppNavigator/ReportScreenWrapper.tsx
index 20922fd785ce..f3295aadb888 100644
--- a/src/libs/Navigation/AppNavigator/ReportScreenWrapper.tsx
+++ b/src/libs/Navigation/AppNavigator/ReportScreenWrapper.tsx
@@ -12,8 +12,11 @@ function ReportScreenWrapper({route, navigation}: ReportScreenWrapperProps) {
// until the reportID is loaded and set in the route param
return (
<>
- {/* @ts-expect-error Error will be resolved after ReportScreen migration to TypeScript */}
-
+
{
PusherHelper.teardown();
});
+/**
+ * This is a helper function to create a mock for the addListener function of the react-navigation library.
+ * The reason we need this is because we need to trigger the transitionEnd event in our tests to simulate
+ * the transitionEnd event that is triggered when the screen transition animation is completed.
+ *
+ * P.S: This can't be moved to a utils file because Jest wants any external function to stay in the scope.
+ *
+ * @returns {Object} An object with two functions: triggerTransitionEnd and addListener
+ */
+const createAddListenerMock = () => {
+ const transitionEndListeners = [];
+ const triggerTransitionEnd = () => {
+ transitionEndListeners.forEach((transitionEndListener) => transitionEndListener());
+ };
+
+ const addListener = jest.fn().mockImplementation((listener, callback) => {
+ if (listener === 'transitionEnd') {
+ transitionEndListeners.push(callback);
+ }
+ return () => {
+ _.filter(transitionEndListeners, (cb) => cb !== callback);
+ };
+ });
+
+ return {triggerTransitionEnd, addListener};
+};
+
function ReportScreenWrapper(args) {
return (
);
@@ -125,7 +154,19 @@ function ReportScreenWrapper(args) {
const runs = CONST.PERFORMANCE_TESTS.RUNS;
test('[ReportScreen] should render ReportScreen with composer interactions', () => {
+ const {triggerTransitionEnd, addListener} = createAddListenerMock();
const scenario = async () => {
+ /**
+ * First make sure ReportScreen is mounted, so that we can trigger
+ * the transitionEnd event manually.
+ *
+ * If we don't do that, then the transitionEnd event will be triggered
+ * before the ReportScreen is mounted, and the test will fail.
+ */
+ await screen.findByTestId('ReportScreen');
+
+ await act(triggerTransitionEnd);
+
// Query for the report list
await screen.findByTestId('report-actions-list');
@@ -158,6 +199,8 @@ test('[ReportScreen] should render ReportScreen with composer interactions', ()
const reportActions = ReportTestUtils.getMockedReportActionsMap(1000);
const mockRoute = {params: {reportID: '1'}};
+ const navigation = {addListener};
+
return waitForBatchedUpdates()
.then(() =>
Onyx.multiSet({
@@ -172,11 +215,31 @@ test('[ReportScreen] should render ReportScreen with composer interactions', ()
},
}),
)
- .then(() => measurePerformance(, {scenario, runs}));
+ .then(() =>
+ measurePerformance(
+ ,
+ {scenario, runs},
+ ),
+ );
});
test('[ReportScreen] should press of the report item', () => {
+ const {triggerTransitionEnd, addListener} = createAddListenerMock();
const scenario = async () => {
+ /**
+ * First make sure ReportScreen is mounted, so that we can trigger
+ * the transitionEnd event manually.
+ *
+ * If we don't do that, then the transitionEnd event will be triggered
+ * before the ReportScreen is mounted, and the test will fail.
+ */
+ await screen.findByTestId('ReportScreen');
+
+ await act(triggerTransitionEnd);
+
// Query for the report list
await screen.findByTestId('report-actions-list');
@@ -201,6 +264,8 @@ test('[ReportScreen] should press of the report item', () => {
const reportActions = ReportTestUtils.getMockedReportActionsMap(1000);
const mockRoute = {params: {reportID: '2'}};
+ const navigation = {addListener};
+
return waitForBatchedUpdates()
.then(() =>
Onyx.multiSet({
@@ -215,5 +280,13 @@ test('[ReportScreen] should press of the report item', () => {
},
}),
)
- .then(() => measurePerformance(, {scenario, runs}));
+ .then(() =>
+ measurePerformance(
+ ,
+ {scenario, runs},
+ ),
+ );
});