Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions static/app/components/modals/sudoModal.spec.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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();
Expand All @@ -76,11 +74,7 @@ describe('Sudo Modal', () => {
error: errorCb,
});

render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />);

// Should have Modal + input
expect(await screen.findByRole('dialog')).toBeInTheDocument();
Expand Down Expand Up @@ -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(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />);

// Should have Modal + input
expect(await screen.findByRole('dialog')).toBeInTheDocument();
Expand Down
1 change: 0 additions & 1 deletion static/app/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3151,7 +3151,6 @@ function buildRoutes(): RouteObject[] {
{
path: '/',
component: errorHandler(App),
deprecatedRouteProps: true,
children: [
rootRoutes,
authV2Routes,
Expand Down
87 changes: 39 additions & 48 deletions static/app/views/app/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -20,9 +19,23 @@ function HookWrapper(props: any) {
);
}

function PlaceholderContent() {
return <div>placeholder content</div>;
}

const defaultRouterConfig = {
location: {pathname: '/organizations/org-slug/'},
children: [
{
index: true,
element: <PlaceholderContent />,
},
],
route: '/organizations/:orgSlug/',
};

describe('App', () => {
const configState = ConfigStore.getState();
const {routerProps} = initializeOrg();

beforeEach(() => {
const organization = OrganizationFixture();
Expand Down Expand Up @@ -68,11 +81,7 @@ describe('App', () => {
});

it('renders', async () => {
render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />, {initialRouterConfig: defaultRouterConfig});

await waitFor(() => OrganizationsStore.getAll().length === 1);
expect(screen.getByText('placeholder content')).toBeInTheDocument();
Expand All @@ -83,11 +92,7 @@ describe('App', () => {
const user = ConfigStore.get('user');
user.flags.newsletter_consent_prompt = true;

render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />, {initialRouterConfig: defaultRouterConfig});

await waitFor(() => OrganizationsStore.getAll().length === 1);

Expand All @@ -113,11 +118,7 @@ describe('App', () => {
},
});

render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />, {initialRouterConfig: defaultRouterConfig});

await waitFor(() => OrganizationsStore.getAll().length === 1);

Expand All @@ -135,11 +136,7 @@ describe('App', () => {
agreements: ['standard', 'partner_presence'],
});
HookStore.add('component:partnership-agreement', () => <HookWrapper key={0} />);
render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />, {initialRouterConfig: defaultRouterConfig});

await waitFor(() => OrganizationsStore.getAll().length === 1);
expect(HookStore.get('component:partnership-agreement')).toHaveLength(1);
Expand All @@ -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', () => <HookWrapper key={0} />);
render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />, {initialRouterConfig: defaultRouterConfig});

await waitFor(() => OrganizationsStore.getAll().length === 1);
expect(screen.getByText('placeholder content')).toBeInTheDocument();
Expand All @@ -172,11 +165,7 @@ describe('App', () => {
},
});

render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />, {initialRouterConfig: defaultRouterConfig});

await waitFor(() => OrganizationsStore.getAll().length === 1);

Expand All @@ -191,11 +180,7 @@ describe('App', () => {
ConfigStore.set('needsUpgrade', true);
ConfigStore.set('isSelfHosted', false);

render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />, {initialRouterConfig: defaultRouterConfig});

await waitFor(() => OrganizationsStore.getAll().length === 1);
expect(screen.getByText('placeholder content')).toBeInTheDocument();
Expand All @@ -204,13 +189,23 @@ describe('App', () => {

it('redirects to sentryUrl on invalid org slug', async () => {
const {sentryUrl} = ConfigStore.get('links');
render(
<App {...routerProps} params={{orgId: 'albertos%2fapples'}}>
<div>placeholder content</div>
</App>
);
// Avoid mounting OrganizationContextProvider and related preloads which
// would issue org-specific requests for the invalid slug
ConfigStore.set('shouldPreloadData', false);
render(<App />, {
initialRouterConfig: {
location: {pathname: '/organizations/albertos%2fapples/'},
route: '/organizations/:orgId/',
children: [
{
index: true,
element: <PlaceholderContent />,
},
],
},
});

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');
Expand All @@ -234,11 +229,7 @@ describe('App', () => {
const restore = ConfigStore.get('isSelfHosted');
ConfigStore.set('isSelfHosted', true);

render(
<App {...routerProps}>
<div>placeholder content</div>
</App>
);
render(<App />, {initialRouterConfig: defaultRouterConfig});
act(() => ConfigStore.set('isSelfHosted', restore));

await waitFor(() => OrganizationsStore.getAll().length === 1);
Expand Down
13 changes: 5 additions & 8 deletions static/app/views/app/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {lazy, Suspense, useCallback, useEffect, useRef} from 'react';
import {Outlet} from 'react-router-dom';
import styled from '@emotion/styled';

import {
Expand All @@ -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';
Expand All @@ -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';
Expand All @@ -41,18 +42,14 @@ 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'));

/**
* App is the root level container for all uathenticated routes.
*/
function App({children, params}: Props) {
function App() {
useColorscheme();

const api = useApi();
Expand Down Expand Up @@ -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(() => {
Expand Down Expand Up @@ -243,7 +240,7 @@ function App({children, params}: Props) {
return null;
}

return children;
return <Outlet />;
}

const renderOrganizationContextProvider = useCallback(
Expand Down
Loading