diff --git a/editor/src/components/canvas/controls/comment-indicator.tsx b/editor/src/components/canvas/controls/comment-indicator.tsx index 4bbd39680faf..0fb4eb6db0ea 100644 --- a/editor/src/components/canvas/controls/comment-indicator.tsx +++ b/editor/src/components/canvas/controls/comment-indicator.tsx @@ -321,7 +321,7 @@ const CommentIndicator = React.memo(({ thread }: CommentIndicatorProps) => { return } if (isOnAnotherRoute && remixLocationRoute != null && remixState != null) { - remixState.navigate(remixLocationRoute) + void remixState.navigate(remixLocationRoute) } cancelHover() dispatch([ diff --git a/editor/src/components/canvas/multiplayer-presence.tsx b/editor/src/components/canvas/multiplayer-presence.tsx index 7a8261c85cb1..badc6f19122e 100644 --- a/editor/src/components/canvas/multiplayer-presence.tsx +++ b/editor/src/components/canvas/multiplayer-presence.tsx @@ -395,7 +395,7 @@ const FollowingOverlay = React.memo(() => { const sceneState = remixNavigationState[presence.remix.scene] if (sceneState != null && presence.remix.locationRoute != null) { setActiveRemixScene(EP.fromString(presence.remix.scene)) - sceneState.navigate(presence.remix.locationRoute) + void sceneState.navigate(presence.remix.locationRoute) actions.push( showToast( notice( diff --git a/editor/src/components/canvas/remix/remix-rendering.spec.browser2.tsx b/editor/src/components/canvas/remix/remix-rendering.spec.browser2.tsx index d5b8ad652ea1..ae31523c13ce 100644 --- a/editor/src/components/canvas/remix/remix-rendering.spec.browser2.tsx +++ b/editor/src/components/canvas/remix/remix-rendering.spec.browser2.tsx @@ -1,4 +1,4 @@ -import { within } from '@testing-library/react' +import { getByText, waitFor, within } from '@testing-library/react' import * as EP from '../../../core/shared/element-path' import type { WindowPoint } from '../../../core/shared/math-utils' import { windowPoint } from '../../../core/shared/math-utils' @@ -10,7 +10,7 @@ import { } from '../../../sample-projects/sample-project-utils.test-utils' import type { Modifiers } from '../../../utils/modifiers' import { emptyModifiers, cmdModifier } from '../../../utils/modifiers' -import { selectComponentsForTest } from '../../../utils/utils.test-utils' +import { selectComponentsForTest, wait } from '../../../utils/utils.test-utils' import { runDOMWalker, selectComponents, @@ -1320,10 +1320,14 @@ describe('Remix navigation', () => { ) for (let i = 1; i < 7; i++) { + // eslint-disable-next-line no-await-in-loop await clickRemixLink(renderResult) - expect( - renderResult.renderedDOM.queryAllByText(`post id: ${i}`).filter(filterOutMenuLabels), - ).toHaveLength(1) + // eslint-disable-next-line no-await-in-loop + await waitFor(() => { + expect( + renderResult.renderedDOM.queryAllByText(`post id: ${i}`).filter(filterOutMenuLabels), + ).toHaveLength(1) + }) } }) @@ -1337,26 +1341,36 @@ describe('Remix navigation', () => { expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual(RemixIndexPathLabel) await clickRemixLink(renderResult) - - expect( - renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), - ).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + await waitFor(() => { + expect( + renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), + ).toHaveLength(1) + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + }) await navigateWithRemixSceneLabelButton(renderResult, pathToRemixScene, 'back') - - expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual(RemixIndexPathLabel) + await waitFor(() => { + expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual( + RemixIndexPathLabel, + ) + }) await navigateWithRemixSceneLabelButton(renderResult, pathToRemixScene, 'forward') - expect( - renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), - ).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + await waitFor(() => { + expect( + renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), + ).toHaveLength(1) + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + }) await navigateWithRemixSceneLabelButton(renderResult, pathToRemixScene, 'home') - expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual(RemixIndexPathLabel) + await waitFor(() => { + expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual( + RemixIndexPathLabel, + ) + }) }) it('can navigate with the scene label nav buttons, in edit mode', async () => { @@ -1369,33 +1383,50 @@ describe('Remix navigation', () => { await clickRemixLink(renderResult) - expect( - renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), - ).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') - + await waitFor(() => { + expect( + renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), + ).toHaveLength(1) + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + }) await switchToEditMode(renderResult) + await waitFor(() => { + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + }) + // check that switching modes doesn't change the navigation state - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + // expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') expect( renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), ).toHaveLength(1) await navigateWithRemixSceneLabelButton(renderResult, pathToRemixScene, 'back') - expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual(RemixIndexPathLabel) + await waitFor(() => { + expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual( + RemixIndexPathLabel, + ) + }) await navigateWithRemixSceneLabelButton(renderResult, pathToRemixScene, 'forward') - expect( - renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), - ).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + + await waitFor(() => { + expect( + renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), + ).toHaveLength(1) + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual('/about') + }) await navigateWithRemixSceneLabelButton(renderResult, pathToRemixScene, 'home') - expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual(RemixIndexPathLabel) + + await waitFor(() => { + expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene)).toEqual( + RemixIndexPathLabel, + ) + }) }) it('navigating in one Remix scene does not affect the navigation state in the other', async () => { @@ -1409,16 +1440,21 @@ describe('Remix navigation', () => { expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene2)).toEqual(RemixIndexPathLabel) await clickRemixLink(renderResult) - const remixScene1 = renderResult.renderedDOM.getByTestId(Remix1TestId) - expect( - within(remixScene1).queryAllByText(AboutTextContent).filter(filterOutMenuLabels), - ).toHaveLength(1) - const remixScene2 = renderResult.renderedDOM.getByTestId(Remix2TestId) - expect(within(remixScene2).queryAllByText(RootTextContent)).toHaveLength(1) + await waitFor(() => { + const remixScene1 = renderResult.renderedDOM.getByTestId(Remix1TestId) + expect( + within(remixScene1).queryAllByText(AboutTextContent).filter(filterOutMenuLabels), + ).toHaveLength(1) - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene1)).toEqual('/about') - expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene2)).toEqual(RemixIndexPathLabel) + const remixScene2 = renderResult.renderedDOM.getByTestId(Remix2TestId) + expect(within(remixScene2).queryAllByText(RootTextContent)).toHaveLength(1) + + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene1)).toEqual('/about') + expect(getPathInRemixSceneLabel(renderResult, pathToRemixScene2)).toEqual( + RemixIndexPathLabel, + ) + }) }) }) @@ -1431,25 +1467,33 @@ describe('Remix navigation', () => { await clickRemixLink(renderResult) - expect( - renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), - ).toHaveLength(1) - expect(getPathInRemixNavigationBar(renderResult)).toEqual('/about') + await waitFor(() => { + expect( + renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), + ).toHaveLength(1) + expect(getPathInRemixNavigationBar(renderResult)).toEqual('/about') + }) await navigateWithRemixNavigationBarButton(renderResult, 'back') - expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) - expect(getPathInRemixNavigationBar(renderResult)).toEqual(RemixIndexPathLabel) + await waitFor(() => { + expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) + expect(getPathInRemixNavigationBar(renderResult)).toEqual(RemixIndexPathLabel) + }) await navigateWithRemixNavigationBarButton(renderResult, 'forward') - expect( - renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), - ).toHaveLength(1) - expect(getPathInRemixNavigationBar(renderResult)).toEqual('/about') + await waitFor(() => { + expect( + renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), + ).toHaveLength(1) + expect(getPathInRemixNavigationBar(renderResult)).toEqual('/about') + }) await navigateWithRemixNavigationBarButton(renderResult, 'home') - expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) - expect(getPathInRemixNavigationBar(renderResult)).toEqual(RemixIndexPathLabel) + await waitFor(() => { + expect(renderResult.renderedDOM.queryAllByText(RootTextContent)).toHaveLength(1) + expect(getPathInRemixNavigationBar(renderResult)).toEqual(RemixIndexPathLabel) + }) }) it('can navigate inside multiple Remix scenes, using the nav bar in the canvas toolbar', async () => { @@ -1459,16 +1503,18 @@ describe('Remix navigation', () => { expect(getPathInRemixNavigationBar(renderResult)).toEqual(RemixIndexPathLabel) await clickRemixLink(renderResult) - - expect( - renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), - ).toHaveLength(1) - expect(getPathInRemixNavigationBar(renderResult)).toEqual('/about') - + await waitFor(() => { + expect( + renderResult.renderedDOM.queryAllByText(AboutTextContent).filter(filterOutMenuLabels), + ).toHaveLength(1) + expect(getPathInRemixNavigationBar(renderResult)).toEqual('/about') + }) const remixScene2 = renderResult.renderedDOM.getByTestId(Remix2TestId) - await mouseClickAtPoint(remixScene2, { x: 10, y: 10 }) - expect(getPathInRemixNavigationBar(renderResult)).toEqual(RemixIndexPathLabel) + await mouseClickAtPoint(remixScene2, { x: 10, y: 10 }) + await waitFor(() => { + expect(getPathInRemixNavigationBar(renderResult)).toEqual(RemixIndexPathLabel) + }) }) }) }) @@ -2331,13 +2377,17 @@ async function clickLinkWithTestId(editor: EditorRenderResult, testId: string) { } async function clickRemixLink(editor: EditorRenderResult) { + await wait(10) await clickLinkWithTestId(editor, 'remix-link') await editor.getDispatchFollowUpActionsFinished() + await wait(10) } async function clickPostLink(editor: EditorRenderResult) { + await wait(10) await clickLinkWithTestId(editor, 'post-link') await editor.getDispatchFollowUpActionsFinished() + await wait(10) } async function navigateWithRemixSceneLabelButton( @@ -2345,6 +2395,7 @@ async function navigateWithRemixSceneLabelButton( pathToRemixScene: ElementPath, button: RemixSceneLabelButtonType, ) { + await wait(10) await mouseClickAtPoint( renderResult.renderedDOM.getByTestId(RemixSceneLabelButtonTestId(pathToRemixScene, button)), { @@ -2353,6 +2404,7 @@ async function navigateWithRemixSceneLabelButton( }, ) await renderResult.getDispatchFollowUpActionsFinished() + await wait(10) } const getPathInRemixSceneLabel = ( @@ -2364,6 +2416,7 @@ async function navigateWithRemixNavigationBarButton( renderResult: EditorRenderResult, button: RemixSceneLabelButtonType, ) { + await wait(10) await mouseClickAtPoint( renderResult.renderedDOM.getByTestId(RemixNavigationBarButtonTestId(button)), { @@ -2372,6 +2425,7 @@ async function navigateWithRemixNavigationBarButton( }, ) await renderResult.getDispatchFollowUpActionsFinished() + await wait(10) } const getPathInRemixNavigationBar = (renderResult: EditorRenderResult) => diff --git a/editor/src/components/canvas/remix/utopia-remix-root-component.tsx b/editor/src/components/canvas/remix/utopia-remix-root-component.tsx index c62843e372e5..7fcc94bf8813 100644 --- a/editor/src/components/canvas/remix/utopia-remix-root-component.tsx +++ b/editor/src/components/canvas/remix/utopia-remix-root-component.tsx @@ -18,15 +18,16 @@ import { AlwaysFalse, usePubSubAtomReadOnly } from '../../../core/shared/atom-wi import { CreateRemixDerivedDataRefsGLOBAL } from '../../editor/store/remix-derived-data' import { patchRoutesWithContext } from '../../../third-party/remix/create-remix-stub' import type { AppLoadContext } from '@remix-run/server-runtime' +import { wait } from '../../../utils/utils.test-utils' type RouteModule = RouteModules[keyof RouteModules] type RouterType = ReturnType interface RemixNavigationContext { - forward: () => void - back: () => void - home: () => void - navigate: (loc: string) => void + forward: () => Promise + back: () => Promise + home: () => Promise + navigate: (loc: string) => Promise location: Location entries: Array } @@ -258,10 +259,10 @@ export const UtopiaRemixRootComponent = (props: UtopiaRemixRootComponentProps) = return { ...current, [EP.toString(basePath)]: { - forward: () => void innerRouter.navigate(1), - back: () => void innerRouter.navigate(-1), - home: () => void innerRouter.navigate('/'), - navigate: (loc: string) => void innerRouter.navigate(loc), + forward: () => innerRouter.navigate(1), + back: () => innerRouter.navigate(-1), + home: () => innerRouter.navigate('/'), + navigate: (loc: string) => innerRouter.navigate(loc), location: location, entries: updatedEntries, }, diff --git a/editor/src/components/editor/remix-navigation-bar.tsx b/editor/src/components/editor/remix-navigation-bar.tsx index 7354dfda242d..57b198abe55e 100644 --- a/editor/src/components/editor/remix-navigation-bar.tsx +++ b/editor/src/components/editor/remix-navigation-bar.tsx @@ -31,15 +31,15 @@ export const RemixNavigationBar = React.memo(() => { ) const forward = React.useCallback( - () => navigationControls[EP.toString(activeRemixScene)]?.forward(), + () => void navigationControls[EP.toString(activeRemixScene)]?.forward(), [activeRemixScene, navigationControls], ) const back = React.useCallback( - () => navigationControls[EP.toString(activeRemixScene)]?.back(), + () => void navigationControls[EP.toString(activeRemixScene)]?.back(), [activeRemixScene, navigationControls], ) const home = React.useCallback( - () => navigationControls[EP.toString(activeRemixScene)]?.home(), + () => void navigationControls[EP.toString(activeRemixScene)]?.home(), [activeRemixScene, navigationControls], ) diff --git a/editor/src/components/inspector/sections/comment-section.tsx b/editor/src/components/inspector/sections/comment-section.tsx index 87c86cbe8fe8..b605324f1e33 100644 --- a/editor/src/components/inspector/sections/comment-section.tsx +++ b/editor/src/components/inspector/sections/comment-section.tsx @@ -198,7 +198,7 @@ const ThreadPreview = React.memo(({ thread }: ThreadPreviewProps) => { if (remixState == null) { return } - remixState.navigate(remixLocationRoute) + void remixState.navigate(remixLocationRoute) } let actions: EditorAction[] = [...openCommentThreadActions(thread.id, commentScene)]