diff --git a/static/app/components/modals/sudoModal.spec.tsx b/static/app/components/modals/sudoModal.spec.tsx index f0efd7dba4e0ea..01d00a2f82bb5d 100644 --- a/static/app/components/modals/sudoModal.spec.tsx +++ b/static/app/components/modals/sudoModal.spec.tsx @@ -1,6 +1,5 @@ import {OrganizationFixture} from 'sentry-fixture/organization'; -import {initializeOrg} from 'sentry-test/initializeOrg'; import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary'; import ConfigStore from 'sentry/stores/configStore'; @@ -63,7 +62,6 @@ describe('Sudo Modal', () => { }); it('can delete an org with sudo flow', async () => { - const {routerProps} = initializeOrg({router: {params: {}}}); setHasPasswordAuth(true); const successCb = jest.fn(); @@ -76,11 +74,7 @@ describe('Sudo Modal', () => { error: errorCb, }); - render( - -
placeholder content
-
- ); + render(); // Should have Modal + input expect(await screen.findByRole('dialog')).toBeInTheDocument(); @@ -137,17 +131,12 @@ describe('Sudo Modal', () => { }); it('shows button to redirect if user does not have password auth', async () => { - const {routerProps} = initializeOrg({router: {params: {}}}); setHasPasswordAuth(false); // Should return w/ `sudoRequired` and trigger the modal to open new MockApiClient().request('/organizations/org-slug/', {method: 'DELETE'}); - render( - -
placeholder content
-
- ); + render(); // Should have Modal + input expect(await screen.findByRole('dialog')).toBeInTheDocument(); diff --git a/static/app/routes.tsx b/static/app/routes.tsx index 408a7655b6c042..a28de60b9a300f 100644 --- a/static/app/routes.tsx +++ b/static/app/routes.tsx @@ -3151,7 +3151,6 @@ function buildRoutes(): RouteObject[] { { path: '/', component: errorHandler(App), - deprecatedRouteProps: true, children: [ rootRoutes, authV2Routes, diff --git a/static/app/views/app/index.spec.tsx b/static/app/views/app/index.spec.tsx index 6222a67a5ebb6b..03cb17d26c546a 100644 --- a/static/app/views/app/index.spec.tsx +++ b/static/app/views/app/index.spec.tsx @@ -1,7 +1,6 @@ import {InstallWizardFixture} from 'sentry-fixture/installWizard'; import {OrganizationFixture} from 'sentry-fixture/organization'; -import {initializeOrg} from 'sentry-test/initializeOrg'; import {act, render, screen, waitFor} from 'sentry-test/reactTestingLibrary'; import AlertStore from 'sentry/stores/alertStore'; @@ -20,9 +19,23 @@ function HookWrapper(props: any) { ); } +function PlaceholderContent() { + return
placeholder content
; +} + +const defaultRouterConfig = { + location: {pathname: '/organizations/org-slug/'}, + children: [ + { + index: true, + element: , + }, + ], + route: '/organizations/:orgSlug/', +}; + describe('App', () => { const configState = ConfigStore.getState(); - const {routerProps} = initializeOrg(); beforeEach(() => { const organization = OrganizationFixture(); @@ -68,11 +81,7 @@ describe('App', () => { }); it('renders', async () => { - render( - -
placeholder content
-
- ); + render(, {initialRouterConfig: defaultRouterConfig}); await waitFor(() => OrganizationsStore.getAll().length === 1); expect(screen.getByText('placeholder content')).toBeInTheDocument(); @@ -83,11 +92,7 @@ describe('App', () => { const user = ConfigStore.get('user'); user.flags.newsletter_consent_prompt = true; - render( - -
placeholder content
-
- ); + render(, {initialRouterConfig: defaultRouterConfig}); await waitFor(() => OrganizationsStore.getAll().length === 1); @@ -113,11 +118,7 @@ describe('App', () => { }, }); - render( - -
placeholder content
-
- ); + render(, {initialRouterConfig: defaultRouterConfig}); await waitFor(() => OrganizationsStore.getAll().length === 1); @@ -135,11 +136,7 @@ describe('App', () => { agreements: ['standard', 'partner_presence'], }); HookStore.add('component:partnership-agreement', () => ); - render( - -
placeholder content
-
- ); + render(, {initialRouterConfig: defaultRouterConfig}); await waitFor(() => OrganizationsStore.getAll().length === 1); expect(HookStore.get('component:partnership-agreement')).toHaveLength(1); @@ -149,11 +146,7 @@ describe('App', () => { it('does not render PartnerAgreement for non-partnered orgs', async () => { ConfigStore.set('partnershipAgreementPrompt', null); HookStore.add('component:partnership-agreement', () => ); - render( - -
placeholder content
-
- ); + render(, {initialRouterConfig: defaultRouterConfig}); await waitFor(() => OrganizationsStore.getAll().length === 1); expect(screen.getByText('placeholder content')).toBeInTheDocument(); @@ -172,11 +165,7 @@ describe('App', () => { }, }); - render( - -
placeholder content
-
- ); + render(, {initialRouterConfig: defaultRouterConfig}); await waitFor(() => OrganizationsStore.getAll().length === 1); @@ -191,11 +180,7 @@ describe('App', () => { ConfigStore.set('needsUpgrade', true); ConfigStore.set('isSelfHosted', false); - render( - -
placeholder content
-
- ); + render(, {initialRouterConfig: defaultRouterConfig}); await waitFor(() => OrganizationsStore.getAll().length === 1); expect(screen.getByText('placeholder content')).toBeInTheDocument(); @@ -204,13 +189,23 @@ describe('App', () => { it('redirects to sentryUrl on invalid org slug', async () => { const {sentryUrl} = ConfigStore.get('links'); - render( - -
placeholder content
-
- ); + // Avoid mounting OrganizationContextProvider and related preloads which + // would issue org-specific requests for the invalid slug + ConfigStore.set('shouldPreloadData', false); + render(, { + initialRouterConfig: { + location: {pathname: '/organizations/albertos%2fapples/'}, + route: '/organizations/:orgId/', + children: [ + { + index: true, + element: , + }, + ], + }, + }); - await waitFor(() => OrganizationsStore.getAll().length === 1); + await waitFor(() => expect(testableWindowLocation.replace).toHaveBeenCalled()); expect(screen.queryByText('placeholder content')).not.toBeInTheDocument(); expect(sentryUrl).toBe('https://sentry.io'); expect(testableWindowLocation.replace).toHaveBeenCalledWith('https://sentry.io'); @@ -234,11 +229,7 @@ describe('App', () => { const restore = ConfigStore.get('isSelfHosted'); ConfigStore.set('isSelfHosted', true); - render( - -
placeholder content
-
- ); + render(, {initialRouterConfig: defaultRouterConfig}); act(() => ConfigStore.set('isSelfHosted', restore)); await waitFor(() => OrganizationsStore.getAll().length === 1); diff --git a/static/app/views/app/index.tsx b/static/app/views/app/index.tsx index f4c7a1294a7501..1f6ed5da10292a 100644 --- a/static/app/views/app/index.tsx +++ b/static/app/views/app/index.tsx @@ -1,4 +1,5 @@ import {lazy, Suspense, useCallback, useEffect, useRef} from 'react'; +import {Outlet} from 'react-router-dom'; import styled from '@emotion/styled'; import { @@ -22,7 +23,6 @@ import GuideStore from 'sentry/stores/guideStore'; import HookStore from 'sentry/stores/hookStore'; import OrganizationsStore from 'sentry/stores/organizationsStore'; import {useLegacyStore} from 'sentry/stores/useLegacyStore'; -import type {RouteComponentProps} from 'sentry/types/legacyReactRouter'; import {DemoToursProvider} from 'sentry/utils/demoMode/demoTours'; import isValidOrgSlug from 'sentry/utils/isValidOrgSlug'; import {onRenderCallback, Profiler} from 'sentry/utils/performanceForSentry'; @@ -33,6 +33,7 @@ import {useColorscheme} from 'sentry/utils/useColorscheme'; import {GlobalFeedbackForm} from 'sentry/utils/useFeedbackForm'; import {useHotkeys} from 'sentry/utils/useHotkeys'; import {useLocation} from 'sentry/utils/useLocation'; +import {useParams} from 'sentry/utils/useParams'; import {useUser} from 'sentry/utils/useUser'; import {AsyncSDKIntegrationContextProvider} from 'sentry/views/app/asyncSDKIntegrationProvider'; import LastKnownRouteContextProvider from 'sentry/views/lastKnownRouteContextProvider'; @@ -41,10 +42,6 @@ import RouteAnalyticsContextProvider from 'sentry/views/routeAnalyticsContextPro import ExplorerPanel from 'sentry/views/seerExplorer/explorerPanel'; import {useExplorerPanel} from 'sentry/views/seerExplorer/useExplorerPanel'; -type Props = { - children: React.ReactNode; -} & RouteComponentProps<{orgId?: string}>; - const InstallWizard = lazy(() => import('sentry/views/admin/installWizard')); const NewsletterConsent = lazy(() => import('sentry/views/newsletterConsent')); const BeaconConsent = lazy(() => import('sentry/views/beaconConsent')); @@ -52,7 +49,7 @@ const BeaconConsent = lazy(() => import('sentry/views/beaconConsent')); /** * App is the root level container for all uathenticated routes. */ -function App({children, params}: Props) { +function App() { useColorscheme(); const api = useApi(); @@ -125,7 +122,7 @@ function App({children, params}: Props) { }, [api, config.isSelfHosted]); const {sentryUrl} = ConfigStore.get('links'); - const {orgId} = params; + const {orgId} = useParams<{orgId?: string}>(); const isOrgSlugValid = orgId ? isValidOrgSlug(orgId) : true; useEffect(() => { @@ -243,7 +240,7 @@ function App({children, params}: Props) { return null; } - return children; + return ; } const renderOrganizationContextProvider = useCallback(