diff --git a/static/app/components/acl/featureDisabledModal.spec.tsx b/static/app/components/acl/featureDisabledModal.spec.tsx index 3a16b0ee393a..176c9531a789 100644 --- a/static/app/components/acl/featureDisabledModal.spec.tsx +++ b/static/app/components/acl/featureDisabledModal.spec.tsx @@ -1,4 +1,4 @@ -import type {ComponentProps, PropsWithChildren} from 'react'; +import type {PropsWithChildren} from 'react'; import styled from '@emotion/styled'; import {render, screen} from 'sentry-test/reactTestingLibrary'; @@ -8,9 +8,14 @@ import {FeatureDisabledModal} from 'sentry/components/acl/featureDisabledModal'; describe('FeatureTourModal', () => { const onCloseModal = jest.fn(); const styledWrapper = styled((c: PropsWithChildren) => c.children); - const renderComponent = ( - props: Partial> = {} - ) => + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders', () => { + const featureName = 'Custom Feature'; + const features = ['organization:custom-feature']; + render( { Header={() => Header} closeModal={onCloseModal} CloseButton={() => } - featureName="Default Feature" - features="organization:test-feature" - {...props} + featureName={featureName} + features={features} /> ); - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('renders', () => { - const featureName = 'Custom Feature'; - const features = ['organization:custom-feature']; - - renderComponent({ - featureName, - features, - }); - expect( screen.getByText('This feature is not enabled on your Sentry installation.') ).toBeInTheDocument(); diff --git a/static/app/components/charts/optionSelector.spec.tsx b/static/app/components/charts/optionSelector.spec.tsx index b6e04ae7d063..f61db2df0be6 100644 --- a/static/app/components/charts/optionSelector.spec.tsx +++ b/static/app/components/charts/optionSelector.spec.tsx @@ -36,12 +36,8 @@ describe('Charts > OptionSelector (Multiple)', () => { ); } - const renderComponent = () => { - return render(); - }; - it('renders yAxisOptions with yAxisValue selected', async () => { - renderComponent(); + render(); expect(await screen.findByRole('option', {name: 'count()'})).toHaveAttribute( 'aria-selected', 'true' @@ -57,7 +53,7 @@ describe('Charts > OptionSelector (Multiple)', () => { }); it('calls onChange prop with new checkbox option state', async () => { - renderComponent(); + render(); await userEvent.click(screen.getByRole('option', {name: 'count()'})); expect(onChangeStub).toHaveBeenCalledWith(['failure_count()']); onChangeStub.mockClear(); @@ -79,7 +75,7 @@ describe('Charts > OptionSelector (Multiple)', () => { }); it('does not uncheck options when clicked if only one option is currently selected', async () => { - renderComponent(); + render(); await userEvent.click(screen.getByRole('option', {name: 'count()'})); expect(onChangeStub).toHaveBeenCalledWith(['failure_count()']); await userEvent.click(screen.getByRole('option', {name: 'failure_count()'})); @@ -87,7 +83,7 @@ describe('Charts > OptionSelector (Multiple)', () => { }); it('only allows up to 3 options to be checked at one time', async () => { - renderComponent(); + render(); await userEvent.click(screen.getByRole('option', {name: 'count_unique(user)'})); expect(onChangeStub).toHaveBeenCalledWith([ 'count()', diff --git a/static/app/components/commandPalette/ui/featureFlagCommandPaletteActions.spec.tsx b/static/app/components/commandPalette/ui/featureFlagCommandPaletteActions.spec.tsx index fff7cd3086c7..5a6f32ffd004 100644 --- a/static/app/components/commandPalette/ui/featureFlagCommandPaletteActions.spec.tsx +++ b/static/app/components/commandPalette/ui/featureFlagCommandPaletteActions.spec.tsx @@ -36,15 +36,14 @@ function SlotOutlets() { ); } -function renderFeatureFlagActions(organization = OrganizationFixture()) { - render( +function ExampleFeatureFlagActions() { + return ( - , - {organization} + ); } @@ -74,7 +73,7 @@ describe('FeatureFlagCommandPaletteActions', () => { it('toggles an existing feature flag without reloading', async () => { const organization = OrganizationFixture({features: ['enabled-feature']}); - renderFeatureFlagActions(organization); + render(, {organization}); await openCommandPalette(); await userEvent.type( @@ -96,7 +95,7 @@ describe('FeatureFlagCommandPaletteActions', () => { it('keeps a disabled feature flag in the list after returning to it', async () => { const organization = OrganizationFixture({features: ['enabled-feature']}); - renderFeatureFlagActions(organization); + render(, {organization}); await openCommandPalette(); await userEvent.type( @@ -131,7 +130,7 @@ describe('FeatureFlagCommandPaletteActions', () => { it('adds a new enabled feature flag from the modal', async () => { const organization = OrganizationFixture({features: []}); - renderFeatureFlagActions(organization); + render(, {organization}); await openCommandPalette(); await userEvent.type( diff --git a/static/app/components/core/avatar/avatarList.spec.tsx b/static/app/components/core/avatar/avatarList.spec.tsx index 9ab1dc10df8b..9e3d130f9c8e 100644 --- a/static/app/components/core/avatar/avatarList.spec.tsx +++ b/static/app/components/core/avatar/avatarList.spec.tsx @@ -5,16 +5,6 @@ import {render, screen} from 'sentry-test/reactTestingLibrary'; import {AvatarList} from '@sentry/scraps/avatar'; -function renderComponent({ - users, - teams, -}: { - users: React.ComponentProps['users']; - teams?: React.ComponentProps['teams']; -}) { - return render(); -} - describe('AvatarList', () => { const user = UserFixture(); const team = TeamFixture(); @@ -25,7 +15,7 @@ describe('AvatarList', () => { {...user, id: '2', name: 'BC'}, ]; - renderComponent({users}); + render(); expect(screen.getByText('A')).toBeInTheDocument(); expect(screen.getByText('B')).toBeInTheDocument(); expect(screen.queryByTestId('avatarList-collapsedavatars')).not.toBeInTheDocument(); @@ -41,7 +31,7 @@ describe('AvatarList', () => { {...user, id: '6', name: 'FG'}, ]; - renderComponent({users}); + render(); expect(screen.getByText(users[0]!.name.charAt(0))).toBeInTheDocument(); expect(screen.getByText(users[1]!.name.charAt(0))).toBeInTheDocument(); expect(screen.getByText(users[2]!.name.charAt(0))).toBeInTheDocument(); @@ -62,7 +52,7 @@ describe('AvatarList', () => { {...user, id: '7', name: 'GH'}, ]; - renderComponent({users}); + render(); expect(screen.getByText(users[0]!.name.charAt(0))).toBeInTheDocument(); expect(screen.getByText(users[1]!.name.charAt(0))).toBeInTheDocument(); expect(screen.getByText(users[2]!.name.charAt(0))).toBeInTheDocument(); @@ -82,7 +72,7 @@ describe('AvatarList', () => { {...team, id: '2', name: 'B', slug: 'B', type: 'team'}, ]; - renderComponent({users, teams}); + render(); expect(screen.getByText('A')).toBeInTheDocument(); expect(screen.getByText('B')).toBeInTheDocument(); expect(screen.getByText('C')).toBeInTheDocument(); @@ -96,7 +86,7 @@ describe('AvatarList', () => { {...team, id: '2', name: 'B', slug: 'B', type: 'team'}, ]; - renderComponent({users: [], teams}); + render(); expect(screen.getByText('A')).toBeInTheDocument(); expect(screen.getByText('B')).toBeInTheDocument(); expect(screen.queryByTestId('avatarList-collapsedavatars')).not.toBeInTheDocument(); diff --git a/static/app/components/events/attachmentViewers/logFileViewer.spec.tsx b/static/app/components/events/attachmentViewers/logFileViewer.spec.tsx index 51a8bc3b7132..753f4ff9b9b0 100644 --- a/static/app/components/events/attachmentViewers/logFileViewer.spec.tsx +++ b/static/app/components/events/attachmentViewers/logFileViewer.spec.tsx @@ -19,8 +19,8 @@ describe('LogFileViewer', () => { }); const attachmentUrl = `/api/0/projects/${organization.id}/${project.slug}/events/${event.id}/attachments/${attachment.id}/?download`; - function renderViewer() { - render( + function ExampleLogFileViewer() { + return ( { ]); fetchMock.route(attachmentUrl, fetchMock.Response(bytes)); - renderViewer(); + render(); expect(await screen.findByText('A中')).toBeInTheDocument(); expect(fetchMock).toHaveBeenCalledWith( @@ -61,7 +61,7 @@ describe('LogFileViewer', () => { it('renders an error when the attachment cannot be downloaded', async () => { fetchMock.route(attachmentUrl, '', {status: 404}); - renderViewer(); + render(); expect(await screen.findByText('Failed to download attachment.')).toBeInTheDocument(); }); diff --git a/static/app/components/events/breadcrumbs/breadcrumbsDrawer.spec.tsx b/static/app/components/events/breadcrumbs/breadcrumbsDrawer.spec.tsx index 1b8aef335430..6d354d91bbb9 100644 --- a/static/app/components/events/breadcrumbs/breadcrumbsDrawer.spec.tsx +++ b/static/app/components/events/breadcrumbs/breadcrumbsDrawer.spec.tsx @@ -7,7 +7,7 @@ import { } from 'sentry/components/events/breadcrumbs/testUtils'; import {mockElementSize} from 'sentry/utils/fixtures/virtualization'; -async function renderBreadcrumbDrawer() { +async function openBreadcrumbDrawer() { mockElementSize({width: 0, height: 30}); render(); await userEvent.click(screen.getByRole('button', {name: 'View 2 more'})); @@ -16,7 +16,7 @@ async function renderBreadcrumbDrawer() { describe('BreadcrumbsDrawer', () => { it('renders the drawer as expected', async () => { - const drawerScreen = await renderBreadcrumbDrawer(); + const drawerScreen = await openBreadcrumbDrawer(); expect( within(drawerScreen).getByRole('button', {name: 'Close Drawer'}) ).toBeInTheDocument(); @@ -60,7 +60,7 @@ describe('BreadcrumbsDrawer', () => { }); it('allows search to affect displayed crumbs', async () => { - const drawerScreen = await renderBreadcrumbDrawer(); + const drawerScreen = await openBreadcrumbDrawer(); const [warningCrumb, logCrumb] = MOCK_BREADCRUMBS; expect(within(drawerScreen).getByText(warningCrumb.category)).toBeInTheDocument(); @@ -76,7 +76,7 @@ describe('BreadcrumbsDrawer', () => { }); it('allows type filter to affect displayed crumbs', async () => { - const drawerScreen = await renderBreadcrumbDrawer(); + const drawerScreen = await openBreadcrumbDrawer(); const queryCrumb = MOCK_BREADCRUMBS[3]; const requestCrumb = MOCK_BREADCRUMBS[2]; @@ -95,7 +95,7 @@ describe('BreadcrumbsDrawer', () => { }); it('allows level spofilter to affect displayed crumbs', async () => { - const drawerScreen = await renderBreadcrumbDrawer(); + const drawerScreen = await openBreadcrumbDrawer(); const [warningCrumb, logCrumb] = MOCK_BREADCRUMBS; @@ -112,7 +112,7 @@ describe('BreadcrumbsDrawer', () => { }); it('allows sort dropdown to affect displayed crumbs', async () => { - const drawerScreen = await renderBreadcrumbDrawer(); + const drawerScreen = await openBreadcrumbDrawer(); const [warningCrumb, logCrumb] = MOCK_BREADCRUMBS; @@ -145,7 +145,7 @@ describe('BreadcrumbsDrawer', () => { }); it('allows time display dropdown to change all displayed crumbs', async () => { - const drawerScreen = await renderBreadcrumbDrawer(); + const drawerScreen = await openBreadcrumbDrawer(); expect( within(drawerScreen).getAllByText('May 21, 2019 6:00:48.760 PM UTC') ).toHaveLength(MOCK_BREADCRUMBS.length); diff --git a/static/app/components/events/featureFlags/eventFeatureFlagDrawer.spec.tsx b/static/app/components/events/featureFlags/eventFeatureFlagDrawer.spec.tsx index 7252b2c6de93..58e9586dff88 100644 --- a/static/app/components/events/featureFlags/eventFeatureFlagDrawer.spec.tsx +++ b/static/app/components/events/featureFlags/eventFeatureFlagDrawer.spec.tsx @@ -11,7 +11,7 @@ import { import {mockElementSize} from 'sentry/utils/fixtures/virtualization'; import {GroupDataContextProvider} from 'sentry/views/issueDetails/groupDataContext'; -async function renderFlagDrawer() { +async function openFlagDrawer() { mockElementSize({width: 0, height: 30}); render( { }); }); it('renders the drawer as expected', async () => { - const drawerScreen = await renderFlagDrawer(); + const drawerScreen = await openFlagDrawer(); expect( within(drawerScreen).getByRole('button', {name: 'Close Drawer'}) ).toBeInTheDocument(); @@ -73,7 +73,7 @@ describe('FeatureFlagDrawer', () => { }); it('allows search to affect displayed flags', async () => { - const drawerScreen = await renderFlagDrawer(); + const drawerScreen = await openFlagDrawer(); const [webVitalsFlag, enableReplay] = MOCK_FLAGS.filter(f => f.result); expect(within(drawerScreen).getByText(webVitalsFlag!.flag)).toBeInTheDocument(); @@ -89,7 +89,7 @@ describe('FeatureFlagDrawer', () => { }); it('allows sort dropdown to affect displayed flags', async () => { - const drawerScreen = await renderFlagDrawer(); + const drawerScreen = await openFlagDrawer(); const [webVitalsFlag, enableReplay] = MOCK_FLAGS.filter(f => f.result); diff --git a/static/app/components/loading/loadingContainer.spec.tsx b/static/app/components/loading/loadingContainer.spec.tsx index 3b0bbbae8cc0..68d089622e13 100644 --- a/static/app/components/loading/loadingContainer.spec.tsx +++ b/static/app/components/loading/loadingContainer.spec.tsx @@ -3,8 +3,8 @@ import {render, screen} from 'sentry-test/reactTestingLibrary'; import type {LoadingContainerProps} from 'sentry/components/loading/loadingContainer'; import {LoadingContainer} from 'sentry/components/loading/loadingContainer'; -function renderComponent(props: LoadingContainerProps = {}) { - return render( +function ExampleLoadingContainer(props: LoadingContainerProps) { + return (
hello!
@@ -13,13 +13,13 @@ function renderComponent(props: LoadingContainerProps = {}) { describe('LoadingContainer', () => { it('handles normal state', () => { - renderComponent(); + render(); expect(screen.getByText('hello!')).toBeInTheDocument(); expect(() => screen.getByTestId('loading-indicator')).toThrow(); }); it('handles loading state', () => { - const {rerender} = renderComponent({isLoading: true}); + const {rerender} = render(); expect(screen.getByText('hello!')).toBeInTheDocument(); expect(screen.getByTestId('loading-indicator')).toBeInTheDocument(); rerender(); @@ -28,7 +28,7 @@ describe('LoadingContainer', () => { }); it('handles reloading state', () => { - const {rerender} = renderComponent({isReloading: true}); + const {rerender} = render(); expect(screen.getByText('hello!')).toBeInTheDocument(); expect(screen.getByTestId('loading-indicator')).toBeInTheDocument(); rerender(); diff --git a/static/app/components/modals/teamAccessRequestModal.spec.tsx b/static/app/components/modals/teamAccessRequestModal.spec.tsx index 24fbe6cc722e..7e2b14257442 100644 --- a/static/app/components/modals/teamAccessRequestModal.spec.tsx +++ b/static/app/components/modals/teamAccessRequestModal.spec.tsx @@ -32,10 +32,6 @@ describe('TeamAccessRequestModal', () => { api: new MockApiClient(), }; - function renderComponent() { - return render(); - } - beforeEach(() => { MockApiClient.clearMockResponses(); createMock = MockApiClient.addMockResponse({ @@ -45,7 +41,7 @@ describe('TeamAccessRequestModal', () => { }); it('renders', () => { - const {container} = renderComponent(); + const {container} = render(); expect(container).toHaveTextContent( `You do not have permission to add members to the #${teamId} team, but we will send a request to your organization admins for approval.` @@ -53,14 +49,14 @@ describe('TeamAccessRequestModal', () => { }); it('creates access request on continue', async () => { - renderComponent(); + render(); await userEvent.click(screen.getByRole('button', {name: 'Continue'})); expect(createMock).toHaveBeenCalled(); }); it('closes modal on cancel', async () => { - renderComponent(); + render(); await userEvent.click(screen.getByRole('button', {name: 'Cancel'})); expect(createMock).not.toHaveBeenCalled(); diff --git a/static/app/components/onboarding/createSampleEventButton.spec.tsx b/static/app/components/onboarding/createSampleEventButton.spec.tsx index f8719fa62dbf..caf840842843 100644 --- a/static/app/components/onboarding/createSampleEventButton.spec.tsx +++ b/static/app/components/onboarding/createSampleEventButton.spec.tsx @@ -15,17 +15,14 @@ describe('CreateSampleEventButton', () => { const groupID = '123'; const createSampleText = 'Create a sample event'; - function renderComponent() { - return render( + function ExampleCreateSampleEventButton() { + return ( {createSampleText} - , - { - organization: org, - } + ); } @@ -34,7 +31,7 @@ describe('CreateSampleEventButton', () => { }); it('creates a sample event', async () => { - const {router} = renderComponent(); + const {router} = render(, {organization: org}); MockApiClient.addMockResponse({ url: `/projects/${org.slug}/${project.slug}/create-sample/`, method: 'POST', @@ -63,7 +60,7 @@ describe('CreateSampleEventButton', () => { }); it('fires the legacy view sample event when hasScmOnboarding is not set', async () => { - renderComponent(); + render(, {organization: org}); MockApiClient.addMockResponse({ url: `/projects/${org.slug}/${project.slug}/create-sample/`, method: 'POST', @@ -129,7 +126,7 @@ describe('CreateSampleEventButton', () => { it('waits for the latest event to be processed', async () => { jest.useFakeTimers(); - const {router} = renderComponent(); + const {router} = render(, {organization: org}); const createRequest = MockApiClient.addMockResponse({ url: `/projects/${org.slug}/${project.slug}/create-sample/`, method: 'POST', diff --git a/static/app/components/onboarding/scm/scmMessagingProviderRow/action.spec.tsx b/static/app/components/onboarding/scm/scmMessagingProviderRow/action.spec.tsx index a13cf88a23bc..b2f2bf746856 100644 --- a/static/app/components/onboarding/scm/scmMessagingProviderRow/action.spec.tsx +++ b/static/app/components/onboarding/scm/scmMessagingProviderRow/action.spec.tsx @@ -22,11 +22,11 @@ const permissionLimitedSlack: ScmMessagingResolvedProvider = { status: 'permission-limited', }; -function renderActions( - visualState: RowVisualState, - overrides: Partial> = {} -) { - return render( +function ExampleRowActions({ + visualState, + ...overrides +}: {visualState: RowVisualState} & Partial>) { + return ( { describe.each(['loading', 'installing'])('%s state', visualState => { it('shows a spinner', () => { - renderActions(visualState); + render(); expect(screen.getByTestId('loading-indicator')).toBeInTheDocument(); }); }); describe('installable state', () => { it('renders an enabled Connect button', () => { - renderActions('installable'); + render(); expect(screen.getByRole('button', {name: /Connect Slack/})).toBeEnabled(); }); }); @@ -61,14 +61,19 @@ describe('RowActions', () => { ['permission-limited', permissionLimitedSlack], ])('%s state', (visualState, resolvedProvider) => { it('renders a disabled Connect button', () => { - renderActions(visualState, {resolvedProvider}); + render( + + ); expect(screen.getByRole('button', {name: /Connect/})).toBeDisabled(); }); }); describe('choose-destination state', () => { it('renders the Choose destination button', () => { - renderActions('choose-destination'); + render(); expect( screen.getByRole('button', {name: /Choose destination for Slack/}) ).toBeInTheDocument(); @@ -77,7 +82,7 @@ describe('RowActions', () => { describe('configured state', () => { it('renders Edit and Remove buttons', () => { - renderActions('configured'); + render(); expect(screen.getByRole('button', {name: /Edit/})).toBeInTheDocument(); expect(screen.getByRole('button', {name: /Remove/})).toBeInTheDocument(); @@ -86,7 +91,7 @@ describe('RowActions', () => { describe('removing state', () => { it('renders Cancel and Remove buttons', () => { - renderActions('removing'); + render(); expect(screen.getByRole('button', {name: /Cancel/})).toBeInTheDocument(); expect(screen.getByRole('button', {name: 'Remove'})).toBeInTheDocument(); @@ -97,7 +102,7 @@ describe('RowActions', () => { '%s state', visualState => { it('renders nothing', () => { - const {container} = renderActions(visualState); + const {container} = render(); expect(container).toBeEmptyDOMElement(); }); } diff --git a/static/app/components/onboarding/scm/scmProjectDetailsCore.spec.tsx b/static/app/components/onboarding/scm/scmProjectDetailsCore.spec.tsx index 954c2a64dfd6..562669fdbec0 100644 --- a/static/app/components/onboarding/scm/scmProjectDetailsCore.spec.tsx +++ b/static/app/components/onboarding/scm/scmProjectDetailsCore.spec.tsx @@ -6,31 +6,32 @@ import {ScmProjectDetailsCore} from './scmProjectDetailsCore'; type CoreProps = React.ComponentProps; -function renderCore(overrides: Partial = {}) { - const props: CoreProps = { - projectName: 'my-project', - onProjectNameChange: jest.fn(), - onProjectNameBlur: jest.fn(), - teamSlug: 'my-team', - onTeamChange: jest.fn(), - isOrgMemberWithNoAccess: false, - ...overrides, - }; - - render(, {organization: OrganizationFixture()}); - return props; +function ExampleScmProjectDetailsCore(overrides: Partial) { + return ( + + ); } describe('ScmProjectDetailsCore', () => { it('labels the project name and team fields', () => { - renderCore(); + render(, {organization: OrganizationFixture()}); expect(screen.getByRole('textbox', {name: 'Project name'})).toHaveValue('my-project'); expect(screen.getByRole('textbox', {name: 'Team'})).toBeInTheDocument(); }); it('hides the team selector for a no-access member', () => { - renderCore({isOrgMemberWithNoAccess: true}); + render(, { + organization: OrganizationFixture(), + }); expect(screen.getByRole('textbox', {name: 'Project name'})).toBeInTheDocument(); expect(screen.queryByRole('textbox', {name: 'Team'})).not.toBeInTheDocument(); diff --git a/static/app/components/replays/table/replayTableHeader.spec.tsx b/static/app/components/replays/table/replayTableHeader.spec.tsx index 874573994ed0..b0dd0671aad4 100644 --- a/static/app/components/replays/table/replayTableHeader.spec.tsx +++ b/static/app/components/replays/table/replayTableHeader.spec.tsx @@ -39,8 +39,8 @@ function baseListCheckboxState(overrides: Partial) { }; } -function renderWithOrganization() { - render( +function ExampleReplayTableHeader() { + return ( - , - {organization: OrganizationFixture()} + ); } @@ -64,7 +63,7 @@ describe('ReplayTableHeader', () => { baseListCheckboxState({isAnySelected: false, selectedIds: []}) ); - renderWithOrganization(); + render(, {organization: OrganizationFixture()}); expect(screen.queryByTestId('replay-bulk-viewed-actions')).not.toBeInTheDocument(); expect(screen.queryByTestId('delete-replays')).not.toBeInTheDocument(); @@ -80,7 +79,7 @@ describe('ReplayTableHeader', () => { }) ); - renderWithOrganization(); + render(, {organization: OrganizationFixture()}); expect(screen.queryByTestId('replay-bulk-viewed-actions')).not.toBeInTheDocument(); expect(screen.getByTestId('delete-replays')).toBeInTheDocument(); @@ -96,7 +95,7 @@ describe('ReplayTableHeader', () => { }) ); - renderWithOrganization(); + render(, {organization: OrganizationFixture()}); expect(screen.getByTestId('replay-bulk-viewed-actions')).toBeInTheDocument(); expect(screen.getByTestId('delete-replays')).toBeInTheDocument(); diff --git a/static/app/components/resultGrid.spec.tsx b/static/app/components/resultGrid.spec.tsx index f85411be1627..ee996a6948b9 100644 --- a/static/app/components/resultGrid.spec.tsx +++ b/static/app/components/resultGrid.spec.tsx @@ -19,10 +19,10 @@ describe('ResultGrid', () => { ); } - function renderBasicGrid( - extraProps: Partial> = {} + function ExampleBasicResultGrid( + extraProps: Partial> ) { - return render( + return ( { headers: {Link: makeLinkHeader()}, }); - renderBasicGrid(); + render(); expect(await screen.findByText('alpha')).toBeInTheDocument(); expect(screen.getByText('beta')).toBeInTheDocument(); @@ -63,7 +63,7 @@ describe('ResultGrid', () => { headers: {Link: makeLinkHeader()}, }); - const {router} = renderBasicGrid(); + const {router} = render(); await userEvent.type(await screen.findByPlaceholderText('Search'), 'hello'); await userEvent.click(screen.getByRole('button', {name: 'Search'})); @@ -81,7 +81,7 @@ describe('ResultGrid', () => { headers: {Link: makeLinkHeader()}, }); - const {router} = renderBasicGrid(); + const {router} = render(); await screen.findByTestId('pagination'); @@ -103,9 +103,11 @@ describe('ResultGrid', () => { headers: {Link: makeLinkHeader()}, }); - const {router} = renderBasicGrid({ - filters: {status: {name: 'Status', options: [['active', 'Active']]}}, - }); + const {router} = render( + + ); await screen.findByTestId('pagination'); await userEvent.click(screen.getByRole('button', {name: /Status/})); @@ -127,7 +129,7 @@ describe('ResultGrid', () => { cancel: () => {}, }); - renderBasicGrid(); + render(); const alert = await screen.findByText('Something bad happened :/'); expect(alert).toBeInTheDocument(); diff --git a/static/app/components/seer/markdown/embeds/components/chart.spec.tsx b/static/app/components/seer/markdown/embeds/components/chart.spec.tsx index 96ac96c20005..9efd2bfbbd0d 100644 --- a/static/app/components/seer/markdown/embeds/components/chart.spec.tsx +++ b/static/app/components/seer/markdown/embeds/components/chart.spec.tsx @@ -10,9 +10,8 @@ jest.mock('sentry/components/charts/baseChart', () => ({ BaseChart: jest.fn(() => null), })); -function renderChart(body: Record) { - const raw = `{% chart %}${JSON.stringify(body)}{% /chart %}`; - render(); +function ExampleChartEmbed({body}: {body: Record}) { + return ; } describe('Chart embed', () => { @@ -23,23 +22,27 @@ describe('Chart embed', () => { it.each(['line', 'area', 'bar'] as const)( 'renders a Dashboard %s time-series visualization', visualization => { - renderChart({ - title: 'Error volume', - subtitle: 'Last three hours', - visualization, - x_axis: 'time', - y_axis_unit: 'number', - series: [ - { - label: 'Errors', - data: [ - {x: '2026-07-30T14:00:00Z', y: 15}, - {x: '2026-07-30T12:00:00Z', y: 12}, - {x: '2026-07-30T13:00:00Z', y: 18}, + render( + + ); expect(screen.getByText('Error volume')).toBeInTheDocument(); expect(screen.getByText('Last three hours')).toBeInTheDocument(); @@ -68,20 +71,24 @@ describe('Chart embed', () => { ); it('renders category bars with the Dashboard categorical visualization', () => { - renderChart({ - title: 'Errors by status', - visualization: 'bar', - x_axis: 'category', - series: [ - { - label: 'Errors', - data: [ - {x: 200, y: 12}, - {x: 500, y: 4}, + render( + + ); const props = jest.mocked(BaseChart).mock.calls.at(-1)![0]; expect(props.renderer).toBe('canvas'); @@ -105,21 +112,25 @@ describe('Chart embed', () => { ] as const)( 'uses Dashboard formatting for %s values', (unit, inputValue, chartValue, expected) => { - renderChart({ - title: 'Metric', - visualization: 'line', - x_axis: 'time', - y_axis_unit: unit, - series: [ - { - label: 'Metric', - data: [ - {x: '2026-07-30T12:00:00Z', y: inputValue}, - {x: '2026-07-30T13:00:00Z', y: inputValue}, + render( + + ); const props = jest.mocked(BaseChart).mock.calls.at(-1)![0]; const formatter = ( @@ -136,51 +147,67 @@ describe('Chart embed', () => { it.each(['not-a-timestamp', 1_785_405_600])( 'does not render invalid time-axis value %s', value => { - renderChart({ - title: 'Error volume', - x_axis: 'time', - series: [{label: 'Errors', data: [{x: value, y: 12}]}], - }); + render( + + ); expect(screen.queryByTestId('seer-chart-embed')).not.toBeInTheDocument(); } ); it.each(['line', 'area'])('does not render a category %s chart', visualization => { - renderChart({ - title: 'Invalid', - visualization, - x_axis: 'category', - series: [{label: 'Errors', data: [{x: '500', y: 12}]}], - }); + render( + + ); expect(screen.queryByTestId('seer-chart-embed')).not.toBeInTheDocument(); }); it.each(['heatmap', 'wheel'])('does not render removed %s charts', visualization => { - renderChart({ - title: 'Invalid', - visualization, - x_axis: 'category', - series: [{label: 'Errors', data: [{x: '500', y: 12}]}], - }); + render( + + ); expect(screen.queryByTestId('seer-chart-embed')).not.toBeInTheDocument(); }); it('renders the legacy series name field', () => { - renderChart({ - title: 'Legacy chart', - series: [ - { - name: 'Errors', - data: [ - {x: '2026-07-30T12:00:00Z', y: 12}, - {x: '2026-07-30T13:00:00Z', y: 18}, + render( + + ); expect(screen.getByTestId('seer-chart-embed')).toBeInTheDocument(); }); diff --git a/static/app/components/seer/markdown/embeds/components/errorsQuery.spec.tsx b/static/app/components/seer/markdown/embeds/components/errorsQuery.spec.tsx index 53a2d3ac51ab..1d394905c63c 100644 --- a/static/app/components/seer/markdown/embeds/components/errorsQuery.spec.tsx +++ b/static/app/components/seer/markdown/embeds/components/errorsQuery.spec.tsx @@ -12,7 +12,7 @@ const SERIES = [ [1_700_003_600, [{count: 8}]], ]; -function renderEmbed({ +function ExampleErrorsQueryEmbed({ data, level = 'block', }: { @@ -20,7 +20,7 @@ function renderEmbed({ level?: 'block' | 'inline'; }) { const tag = `{% errorsQuery %}${JSON.stringify(data)}{% /errorsQuery %}`; - return render(); + return ; } describe('errors query embed', () => { @@ -41,16 +41,18 @@ describe('errors query embed', () => { body: {data: SERIES}, }); - renderEmbed({ - data: { - mode: 'samples', - query: 'event.type:error', - fields: ['title', 'project', 'timestamp'], - sort: '-timestamp', - statsPeriod: '24h', - title: 'Recent errors', - }, - }); + render( + + ); expect(await screen.findByText('Error 1')).toBeInTheDocument(); expect(screen.getByText('Error 5')).toBeInTheDocument(); @@ -116,17 +118,19 @@ describe('errors query embed', () => { body: {data: SERIES}, }); - renderEmbed({ - data: { - mode: 'aggregate', - query: '', - fields: ['title', 'project', 'count_unique(user)'], - sort: '-count_unique_user', - statsPeriod: '1h', - yAxes: ['count()'], - title: 'Errors by title', - }, - }); + render( + + ); expect(await screen.findByText('TypeError')).toBeInTheDocument(); expect(screen.getByText('1,234')).toBeInTheDocument(); @@ -161,16 +165,18 @@ describe('errors query embed', () => { body: {data: SERIES}, }); - renderEmbed({ - data: { - mode: 'aggregate', - query: 'event.type:error', - fields: ['title', 'project', 'count()'], - sort: '-count', - statsPeriod: '24h', - title: 'Errors by title', - }, - }); + render( + + ); expect(await screen.findByTestId('seer-chart-content')).toBeInTheDocument(); @@ -205,15 +211,17 @@ describe('errors query embed', () => { body: {data: SERIES}, }); - renderEmbed({ - data: { - mode: 'aggregate', - query: 'event.type:error', - fields: ['count()'], - statsPeriod: '1h', - title: 'Error count', - }, - }); + render( + + ); expect(await screen.findByTestId('seer-chart-content')).toBeInTheDocument(); expect(screen.getAllByLabelText('event.type:error').length).toBeGreaterThan(0); @@ -247,13 +255,15 @@ describe('errors query embed', () => { body: {data: SERIES}, }); - const {router} = renderEmbed({ - data: { - mode: 'samples', - query: 'event.type:error', - fields: ['title', 'project', 'timestamp'], - }, - }); + const {router} = render( + + ); expect(await screen.findByText('Error 1')).toBeInTheDocument(); @@ -287,12 +297,9 @@ describe('errors query embed', () => { body: {data: []}, }); - renderEmbed({ - // No `mode`, so this also pins the schema default. `errorsQuery` shipped - // before the mode existed, and samples is what it used to do. - data: {query: 'is:unresolved'}, - level: 'inline', - }); + // No `mode`, so this also pins the schema default. `errorsQuery` shipped + // before the mode existed, and samples is what it used to do. + render(); expect(screen.getByRole('link', {name: 'Error search'})).toBeInTheDocument(); expect(request).not.toHaveBeenCalled(); diff --git a/static/app/components/seer/markdown/embeds/components/logsQuery.spec.tsx b/static/app/components/seer/markdown/embeds/components/logsQuery.spec.tsx index 5519b56bc416..2374811ab34e 100644 --- a/static/app/components/seer/markdown/embeds/components/logsQuery.spec.tsx +++ b/static/app/components/seer/markdown/embeds/components/logsQuery.spec.tsx @@ -20,9 +20,9 @@ const TIME_SERIES = [ }, ]; -function renderEmbed(data: Record) { +function ExampleLogsQueryEmbed({data}: {data: Record}) { const tag = `{% logsQuery %}${JSON.stringify(data)}{% /logsQuery %}`; - return render(); + return ; } describe('logs query embed', () => { @@ -54,7 +54,11 @@ describe('logs query embed', () => { }, }); - renderEmbed({query: 'severity:error', mode: 'samples', statsPeriod: '24h'}); + render( + + ); expect(await screen.findByText('Connection refused')).toBeInTheDocument(); expect(await screen.findByTestId('seer-chart-content')).toBeInTheDocument(); @@ -98,13 +102,17 @@ describe('logs query embed', () => { body: {data: [{severity: 'error', 'count(message)': 42}]}, }); - renderEmbed({ - query: '', - mode: 'aggregate', - groupBy: ['severity'], - yAxes: ['count(message)'], - statsPeriod: '7d', - }); + render( + + ); expect(await screen.findByText('error')).toBeInTheDocument(); @@ -131,14 +139,18 @@ describe('logs query embed', () => { body: {data: [{severity: 'error', 'count(message)': 42}]}, }); - renderEmbed({ - query: '', - mode: 'aggregate', - groupBy: ['severity'], - yAxes: ['count(message)'], - sort: 'severity', - statsPeriod: '7d', - }); + render( + + ); expect(await screen.findByText('error')).toBeInTheDocument(); @@ -169,7 +181,11 @@ describe('logs query embed', () => { body: {data: []}, }); - renderEmbed({query: 'severity:error', mode: 'samples', statsPeriod: '24h'}); + render( + + ); expect(await screen.findByTestId('seer-chart-content')).toBeInTheDocument(); @@ -195,12 +211,16 @@ describe('logs query embed', () => { // The logs dataset rejects an orderby that names no selected column, so // the default `-timestamp` cannot survive a field list without it. - renderEmbed({ - query: 'severity:error', - mode: 'samples', - fields: ['message'], - statsPeriod: '24h', - }); + render( + + ); expect(await screen.findByText('Connection refused')).toBeInTheDocument(); @@ -225,12 +245,16 @@ describe('logs query embed', () => { body: {data: [{timestamp: '2026-08-27T12:00:00Z', message: 'Retrying'}]}, }); - renderEmbed({ - query: '', - mode: 'samples', - sort: '-span.duration', - statsPeriod: '24h', - }); + render( + + ); expect(await screen.findByText('Retrying')).toBeInTheDocument(); @@ -252,7 +276,9 @@ describe('logs query embed', () => { body: {data: []}, }); - renderEmbed({query: '', mode: 'aggregate', statsPeriod: '24h'}); + render( + + ); expect(await screen.findByTestId('seer-chart-content')).toBeInTheDocument(); expect(screen.queryByRole('table')).not.toBeInTheDocument(); diff --git a/static/app/components/seer/markdown/embeds/components/metricsQuery.spec.tsx b/static/app/components/seer/markdown/embeds/components/metricsQuery.spec.tsx index f09fee7fdc89..43918d9fdcef 100644 --- a/static/app/components/seer/markdown/embeds/components/metricsQuery.spec.tsx +++ b/static/app/components/seer/markdown/embeds/components/metricsQuery.spec.tsx @@ -28,7 +28,7 @@ const TIME_SERIES = [ }, ]; -function renderEmbed({ +function ExampleMetricsQueryEmbed({ data, level = 'block', }: { @@ -36,15 +36,17 @@ function renderEmbed({ level?: 'block' | 'inline'; }) { const tag = `{% metricsQuery %}${JSON.stringify(data)}{% /metricsQuery %}`; - return render(); + return ; } describe('metrics query embed', () => { it('qualifies a bare y-axis with the metric it measures', () => { - renderEmbed({ - data: {...METRIC, mode: 'aggregate', query: '', yAxes: ['p95(value)']}, - level: 'inline', - }); + render( + + ); // Seer emits `p95(value)`; Explore only decodes the qualified spelling, and // refuses a query that charts nothing. @@ -57,10 +59,12 @@ describe('metrics query embed', () => { }); it('falls back to the default aggregate for the metric type', () => { - renderEmbed({ - data: {...METRIC, mode: 'aggregate', query: ''}, - level: 'inline', - }); + render( + + ); // `distribution` defaults to `sum`, not a blanket `sum(value)`. const href = screen @@ -85,16 +89,18 @@ describe('metrics query embed', () => { }, }); - renderEmbed({ - data: { - ...METRIC, - mode: 'aggregate', - query: 'release:1.0', - groupBy: ['service.name'], - yAxes: ['p95(value)'], - statsPeriod: '24h', - }, - }); + render( + + ); expect(await screen.findByTestId('seer-chart-content')).toBeInTheDocument(); expect(await screen.findByText('checkout')).toBeInTheDocument(); @@ -140,9 +146,11 @@ describe('metrics query embed', () => { body: {data: []}, }); - renderEmbed({ - data: {...METRIC, mode: 'aggregate', query: '', yAxes: ['p95(value)']}, - }); + render( + + ); expect(await screen.findByTestId('seer-chart-content')).toBeInTheDocument(); expect(screen.queryByRole('table')).not.toBeInTheDocument(); @@ -159,7 +167,11 @@ describe('metrics query embed', () => { body: {data: [{id: '1', 'metric.value': 42, timestamp: '2026-08-27T12:00:00Z'}]}, }); - renderEmbed({data: {...METRIC, mode: 'samples', query: 'release:1.0'}}); + render( + + ); await waitFor(() => { expect(table).toHaveBeenCalledWith( diff --git a/static/app/components/seer/markdown/embeds/components/release.spec.tsx b/static/app/components/seer/markdown/embeds/components/release.spec.tsx index 3010f69a041e..b72ffab87d6b 100644 --- a/static/app/components/seer/markdown/embeds/components/release.spec.tsx +++ b/static/app/components/seer/markdown/embeds/components/release.spec.tsx @@ -10,9 +10,9 @@ import {SeerMarkdown} from 'sentry/components/seer/markdown'; const version = 'frontend@65318d61d370'; const projectId = 4383603; -function renderReleaseEmbed(level: 'block' | 'inline' = 'block') { +function ExampleReleaseEmbed({level = 'block'}: {level?: 'block' | 'inline'}) { const tag = `{% release %}${JSON.stringify({version, projectId})}{% /release %}`; - return render(); + return ; } describe('release embed', () => { @@ -48,7 +48,7 @@ describe('release embed', () => { ], }); - renderReleaseEmbed(); + render(); expect(await screen.findByText('New Issues')).toBeInTheDocument(); expect(screen.getByText('3')).toBeInTheDocument(); @@ -97,7 +97,7 @@ describe('release embed', () => { body: [], }); - renderReleaseEmbed(); + render(); expect(await screen.findByText('2 commits')).toBeInTheDocument(); expect(screen.queryByText('2 commits by 0 authors')).not.toBeInTheDocument(); @@ -113,7 +113,7 @@ describe('release embed', () => { body: [], }); - renderReleaseEmbed('inline'); + render(); expect(screen.getByRole('link', {name: /Release:/})).toBeInTheDocument(); expect(releaseRequest).not.toHaveBeenCalled(); diff --git a/static/app/components/seer/projectTable/seerProjectTable.spec.tsx b/static/app/components/seer/projectTable/seerProjectTable.spec.tsx index 6fa0dee9b09d..16146fdb813b 100644 --- a/static/app/components/seer/projectTable/seerProjectTable.spec.tsx +++ b/static/app/components/seer/projectTable/seerProjectTable.spec.tsx @@ -91,12 +91,11 @@ describe('SeerProjectTable', () => { jest.restoreAllMocks(); }); - function renderTable(renderOrganization = organization) { - render( + function ExampleSeerProjectTable() { + return ( - , - {organization: renderOrganization} + ); } @@ -108,7 +107,7 @@ describe('SeerProjectTable', () => { }); const errorSpy = jest.spyOn(indicators, 'addErrorMessage'); - renderTable(); + render(, {organization}); // The agent dropdown renders its current value, "Seer". await userEvent.click(await screen.findByText('Seer')); @@ -152,7 +151,7 @@ describe('SeerProjectTable', () => { }); const errorSpy = jest.spyOn(indicators, 'addErrorMessage'); - renderTable(); + render(, {organization}); await userEvent.click(await screen.findByText('Seer')); await userEvent.click( @@ -177,7 +176,7 @@ describe('SeerProjectTable', () => { }); const errorSpy = jest.spyOn(indicators, 'addErrorMessage'); - renderTable(); + render(, {organization}); await userEvent.click(await screen.findByText('Seer')); await userEvent.click( @@ -190,7 +189,9 @@ describe('SeerProjectTable', () => { }); it('disables adding a project without organization write access', async () => { - renderTable(OrganizationFixture({slug: organization.slug, access: []})); + render(, { + organization: OrganizationFixture({slug: organization.slug, access: []}), + }); expect(await screen.findByRole('button', {name: 'Add Project'})).toBeDisabled(); }); diff --git a/static/app/components/stackTrace/stackTrace.spec.tsx b/static/app/components/stackTrace/stackTrace.spec.tsx index 76d45e5addc7..071168dfe43d 100644 --- a/static/app/components/stackTrace/stackTrace.spec.tsx +++ b/static/app/components/stackTrace/stackTrace.spec.tsx @@ -1,4 +1,4 @@ -import type {ComponentProps} from 'react'; +import {useMemo, type ComponentProps} from 'react'; import {DataScrubbingRelayPiiConfigFixture} from 'sentry-fixture/dataScrubbingRelayPiiConfig'; import {EventFixture} from 'sentry-fixture/event'; import {EventEntryStacktraceFixture} from 'sentry-fixture/eventEntryStacktrace'; @@ -85,10 +85,10 @@ function TestStackTraceProvider({ ); } -function renderStackTrace() { - const {event, stacktrace} = makeStackTraceData(); +function ExampleStackTrace() { + const {event, stacktrace} = useMemo(() => makeStackTraceData(), []); - render( + return ( @@ -116,7 +116,7 @@ describe('Core StackTrace', () => { }); it('switches between app and full stack views', async () => { - renderStackTrace(); + render(); expect(screen.getAllByTestId('core-stacktrace-frame-row')).toHaveLength(4); @@ -127,7 +127,7 @@ describe('Core StackTrace', () => { }); it('toggles frame ordering', async () => { - renderStackTrace(); + render(); expect(screen.getAllByTestId('core-stacktrace-frame-title')[0]).toHaveTextContent( 'raven/scripts/runner.py' @@ -142,7 +142,7 @@ describe('Core StackTrace', () => { }); it('supports raw stack trace view', async () => { - renderStackTrace(); + render(); await userEvent.click(screen.getByRole('button', {name: 'Display options'})); await userEvent.click(await screen.findByRole('option', {name: 'Raw Stack Trace'})); @@ -192,7 +192,7 @@ describe('Core StackTrace', () => { }); it('toggles frame expansion', async () => { - renderStackTrace(); + render(); expect(screen.getByTestId('core-stacktrace-frame-context')).toBeInTheDocument(); @@ -217,7 +217,7 @@ describe('Core StackTrace', () => { }); it('toggles frame expansion when clicking the right trailing area', async () => { - renderStackTrace(); + render(); const firstTrailingArea = screen.getAllByTestId('core-stacktrace-frame-trailing')[0]!; @@ -248,7 +248,7 @@ describe('Core StackTrace', () => { }); it('shows and hides collapsed system frames', async () => { - renderStackTrace(); + render(); const toggleButton = screen.getByRole('button', {name: 'Show 1 more frame'}); @@ -259,14 +259,14 @@ describe('Core StackTrace', () => { }); it('renders frame badges for in-app frames only', async () => { - renderStackTrace(); + render(); expect((await screen.findAllByText('In App')).length).toBeGreaterThan(0); expect(screen.queryByText('System')).not.toBeInTheDocument(); }); it('renders captured python frame variables', async () => { - renderStackTrace(); + render(); expect(await screen.findByText('args')).toBeInTheDocument(); expect(screen.getByText('dsn')).toBeInTheDocument(); @@ -374,7 +374,7 @@ describe('Core StackTrace', () => { }); it('renders lead hint when non-app frame leads to app frame', async () => { - renderStackTrace(); + render(); expect(await screen.findByText('Called from:')).toBeInTheDocument(); }); diff --git a/static/app/components/timeRangeSelector/index.spec.tsx b/static/app/components/timeRangeSelector/index.spec.tsx index 342763ff2f4c..9a79873b2713 100644 --- a/static/app/components/timeRangeSelector/index.spec.tsx +++ b/static/app/components/timeRangeSelector/index.spec.tsx @@ -1,3 +1,4 @@ +import type {ComponentProps} from 'react'; import {ConfigFixture} from 'sentry-fixture/config'; import {OrganizationFixture} from 'sentry-fixture/organization'; import {UserFixture} from 'sentry-fixture/user'; @@ -12,14 +13,12 @@ const organization = OrganizationFixture({features: ['open-membership']}); describe('TimeRangeSelector', () => { const onChange = jest.fn(); - function getComponent(props = {}) { + function ExampleTimeRangeSelector( + props: Partial> + ) { return ; } - function renderComponent(props = {}) { - return render(getComponent(props)); - } - beforeEach(() => { ConfigStore.loadInitialData( ConfigFixture({ @@ -32,7 +31,7 @@ describe('TimeRangeSelector', () => { }); it('renders when given relative period', async () => { - renderComponent({relative: '9d'}); + render(); expect(await screen.findByRole('button', {name: '9D'})).toBeInTheDocument(); }); @@ -46,7 +45,7 @@ describe('TimeRangeSelector', () => { }); it('hides relative options', async () => { - renderComponent({showRelative: false, start: '0', end: '0'}); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); @@ -63,7 +62,7 @@ describe('TimeRangeSelector', () => { }); it('hides absolute selector', async () => { - renderComponent({showAbsolute: false}); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); @@ -73,7 +72,7 @@ describe('TimeRangeSelector', () => { }); it('can select an absolute date range', async () => { - renderComponent(); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); await userEvent.click(screen.getByRole('option', {name: 'Absolute date'})); @@ -104,7 +103,7 @@ describe('TimeRangeSelector', () => { }); it('can select an absolute range with utc enabled', async () => { - renderComponent({utc: true}); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); await userEvent.click(screen.getByRole('option', {name: 'Absolute date'})); @@ -136,7 +135,7 @@ describe('TimeRangeSelector', () => { }); it('keeps time inputs focused while interacting with them', async () => { - renderComponent(); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); await userEvent.click(screen.getByRole('option', {name: 'Absolute date'})); @@ -151,7 +150,7 @@ describe('TimeRangeSelector', () => { }); it('switches from relative to absolute and then toggling UTC (starting with UTC)', async () => { - renderComponent({relative: '7d', utc: true}); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); await userEvent.click(screen.getByRole('option', {name: 'Absolute date'})); @@ -173,7 +172,7 @@ describe('TimeRangeSelector', () => { }); it('switches from relative to absolute and then toggling UTC (starting with non-UTC)', async () => { - renderComponent({relative: '7d', utc: false}); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); await userEvent.click(screen.getByRole('option', {name: 'Absolute date'})); @@ -194,12 +193,14 @@ describe('TimeRangeSelector', () => { }); it('uses the default absolute date', async () => { - renderComponent({ - defaultAbsolute: { - start: new Date('2017-10-10T00:00:00.000Z'), - end: new Date('2017-10-17T23:59:59.000Z'), - }, - }); + render( + + ); await userEvent.click(screen.getByRole('button', {expanded: false})); await userEvent.click(screen.getByRole('option', {name: 'Absolute date'})); @@ -210,7 +211,7 @@ describe('TimeRangeSelector', () => { }); it('can select arbitrary relative time ranges', async () => { - renderComponent(); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); @@ -247,7 +248,7 @@ describe('TimeRangeSelector', () => { }); it('respects maxPickableDays for defaults', async () => { - renderComponent({maxPickableDays: 30}); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); @@ -255,7 +256,7 @@ describe('TimeRangeSelector', () => { }); it('respects maxPickableDays for arbitrary time ranges', async () => { - renderComponent({maxPickableDays: 30}); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); @@ -283,7 +284,7 @@ describe('TimeRangeSelector', () => { }); it('cannot select arbitrary relative time ranges with disallowArbitraryRelativeRanges', async () => { - renderComponent({disallowArbitraryRelativeRanges: true}); + render(); await userEvent.click(screen.getByRole('button', {expanded: false})); diff --git a/static/app/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar.spec.tsx b/static/app/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar.spec.tsx index b613fc92cf44..74b3a11d3f14 100644 --- a/static/app/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar.spec.tsx +++ b/static/app/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar.spec.tsx @@ -1,4 +1,3 @@ -import type {ComponentProps} from 'react'; import {WidgetQueryFixture} from 'sentry-fixture/widgetQuery'; import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary'; @@ -14,17 +13,6 @@ interface MockedTagValue extends Pick< 'key' | 'value' | 'name' | 'count' | 'firstSeen' | 'lastSeen' > {} -function renderWithProvider({ - widgetQuery, - onSearch, - onClose, -}: ComponentProps) { - return render( - , - {} - ); -} - function mockSpanTags({ type, mockedTags, @@ -111,11 +99,13 @@ describe('SpansSearchBar', () => { ], }); - renderWithProvider({ - widgetQuery: WidgetQueryFixture({conditions: 'span.op:function'}), - onSearch: jest.fn(), - onClose: jest.fn(), - }); + render( + + ); await screen.findByLabelText('span.op:function'); }); @@ -123,11 +113,13 @@ describe('SpansSearchBar', () => { it.isKnownFlake('calls onSearch with the correct query', async () => { const onSearch = jest.fn(); - renderWithProvider({ - widgetQuery: WidgetQueryFixture({conditions: ''}), - onSearch, - onClose: jest.fn(), - }); + render( + + ); const searchInput = await screen.findByRole('combobox', { name: 'Add a search term', @@ -148,11 +140,13 @@ describe('SpansSearchBar', () => { it.isKnownFlake('triggers onClose when the query changes', async () => { const onClose = jest.fn(); - renderWithProvider({ - widgetQuery: WidgetQueryFixture({conditions: ''}), - onSearch: jest.fn(), - onClose, - }); + render( + + ); const searchInput = await screen.findByRole('combobox', { name: 'Add a search term', diff --git a/static/app/views/dashboards/widgetBuilder/components/widgetPreview.spec.tsx b/static/app/views/dashboards/widgetBuilder/components/widgetPreview.spec.tsx index 226fb0e0342b..133590e34b52 100644 --- a/static/app/views/dashboards/widgetBuilder/components/widgetPreview.spec.tsx +++ b/static/app/views/dashboards/widgetBuilder/components/widgetPreview.spec.tsx @@ -20,32 +20,40 @@ describe('WidgetPreview', () => { filters: {}, }; - function renderPreview( - previewStatus: Parameters[0]['previewStatus'] - ) { - render( + const renderOptions = { + organization: OrganizationFixture(), + additionalWrapper: WidgetBuilderProvider, + initialRouterConfig: { + location: {pathname: DASHBOARD_WIDGET_BUILDER_PATHNAME}, + }, + }; + + function ExampleWidgetPreview({ + previewStatus, + }: { + previewStatus: Parameters[0]['previewStatus']; + }) { + return ( , - { - organization: OrganizationFixture(), - additionalWrapper: WidgetBuilderProvider, - initialRouterConfig: { - location: {pathname: DASHBOARD_WIDGET_BUILDER_PATHNAME}, - }, - } + /> ); } it('renders a loading state when the preview status is loading', () => { - renderPreview({status: 'loading'}); + render(, renderOptions); expect(screen.getByTestId('loading-placeholder')).toBeInTheDocument(); }); it('renders the error message when the preview status is invalid', () => { - renderPreview({status: 'invalid', message: 'This widget is broken.'}); + render( + , + renderOptions + ); expect(screen.getByText('This widget is broken.')).toBeInTheDocument(); }); }); diff --git a/static/app/views/dashboards/widgetBuilder/components/xAxisSelector.spec.tsx b/static/app/views/dashboards/widgetBuilder/components/xAxisSelector.spec.tsx index 80b1f100e55e..10a4e71d2682 100644 --- a/static/app/views/dashboards/widgetBuilder/components/xAxisSelector.spec.tsx +++ b/static/app/views/dashboards/widgetBuilder/components/xAxisSelector.spec.tsx @@ -38,8 +38,15 @@ describe('WidgetBuilderXAxisSelector', () => { }); }); - function renderSelector() { - return render(, { + it('fetches attributes from the server while typing', async () => { + const searchAttributesMock = MockApiClient.addMockResponse({ + url: ATTRIBUTES_URL, + method: 'GET', + body: [cappedAttribute, genAiAttribute], + match: [MockApiClient.matchQuery({substringMatch: 'gen_ai'})], + }); + + render(, { organization, additionalWrapper: WidgetBuilderProvider, initialRouterConfig: { @@ -53,17 +60,6 @@ describe('WidgetBuilderXAxisSelector', () => { route: DASHBOARD_WIDGET_BUILDER_ROUTE, }, }); - } - - it('fetches attributes from the server while typing', async () => { - const searchAttributesMock = MockApiClient.addMockResponse({ - url: ATTRIBUTES_URL, - method: 'GET', - body: [cappedAttribute, genAiAttribute], - match: [MockApiClient.matchQuery({substringMatch: 'gen_ai'})], - }); - - renderSelector(); expect(await screen.findByText('X-Axis')).toBeInTheDocument(); diff --git a/static/app/views/discover/table/cellAction.spec.tsx b/static/app/views/discover/table/cellAction.spec.tsx index 5e2c8be0b722..124c71f97e75 100644 --- a/static/app/views/discover/table/cellAction.spec.tsx +++ b/static/app/views/discover/table/cellAction.spec.tsx @@ -32,7 +32,7 @@ const defaultData: TableDataRow = { id: '42', }; -function renderComponent({ +function ExampleCellAction({ eventView, handleCellAction = jest.fn(), columnIndex = 0, @@ -52,7 +52,7 @@ function renderComponent({ pin?: React.ReactNode; triggerType?: ActionTriggerType; }) { - return render( + return ( CellAction', () => { describe('hover menu button', () => { it('shows no menu by default', () => { - renderComponent({eventView: view}); + render(); expect(screen.getByRole('button', {name: 'Actions'})).toBeInTheDocument(); }); }); describe('opening the menu', () => { it('toggles the menu on click', async () => { - renderComponent({eventView: view}); + render(); await openMenu(); expect( screen.getByRole('menuitemradio', {name: 'Add to filter'}) @@ -124,7 +124,7 @@ describe('Discover -> CellAction', () => { }); it('add button appends condition', async () => { - renderComponent({eventView: view, handleCellAction}); + render(); await openMenu(); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Add to filter'})); @@ -132,7 +132,7 @@ describe('Discover -> CellAction', () => { }); it('exclude button adds condition', async () => { - renderComponent({eventView: view, handleCellAction}); + render(); await openMenu(); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Exclude from filter'}) @@ -147,7 +147,9 @@ describe('Discover -> CellAction', () => { query: {...location.query, query: '!transaction:nope'}, }) ); - renderComponent({eventView: excludeView, handleCellAction}); + render( + + ); await openMenu(); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Exclude from filter'}) @@ -157,7 +159,13 @@ describe('Discover -> CellAction', () => { }); it('go to release button goes to release health page', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 3}); + render( + + ); await openMenu(); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Go to release'})); @@ -168,7 +176,13 @@ describe('Discover -> CellAction', () => { }); it('greater than button adds condition', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 2}); + render( + + ); await openMenu(); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Show values greater than'}) @@ -181,7 +195,13 @@ describe('Discover -> CellAction', () => { }); it('less than button adds condition', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 2}); + render( + + ); await openMenu(); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Show values less than'}) @@ -283,12 +303,14 @@ describe('Discover -> CellAction', () => { }); it('error.handled with null adds condition', async () => { - renderComponent({ - eventView: view, - handleCellAction, - columnIndex: 7, - data: defaultData, - }); + render( + + ); await openMenu(); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Add to filter'})); @@ -296,12 +318,14 @@ describe('Discover -> CellAction', () => { }); it('error.type with array values adds condition', async () => { - renderComponent({ - eventView: view, - handleCellAction, - columnIndex: 8, - data: defaultData, - }); + render( + + ); await openMenu(); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Add to filter'})); @@ -314,16 +338,18 @@ describe('Discover -> CellAction', () => { }); it('error.handled with 0 adds condition', async () => { - renderComponent({ - eventView: view, - handleCellAction, - columnIndex: 7, - data: { - ...defaultData, - // @ts-expect-error TODO: Fix this type - 'error.handled': ['0'], - }, - }); + render( + + ); await openMenu(); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Add to filter'})); @@ -331,7 +357,7 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for string cells', async () => { - renderComponent({eventView: view, handleCellAction}); + render(); await openMenu(); expect( @@ -359,16 +385,18 @@ describe('Discover -> CellAction', () => { column: {kind: 'field', field: 'tags[my.tags,array]'}, width: undefined, }; - renderComponent({ - eventView: view, - handleCellAction, - column: arrayColumn, - data: { - ...defaultData, - // @ts-expect-error TODO: Fix this type - 'tags[my.tags,array]': ['foo', 'bar'], - }, - }); + render( + + ); await openMenu(); expect( @@ -394,16 +422,18 @@ describe('Discover -> CellAction', () => { column: {kind: 'field', field: 'tags[my.tags,array]'}, width: undefined, }; - renderComponent({ - eventView: view, - handleCellAction, - column: arrayColumn, - data: { - ...defaultData, - // @ts-expect-error TODO: Fix this type - 'tags[my.tags,array]': null, - }, - }); + render( + + ); await openMenu(); expect( @@ -415,7 +445,13 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for string cells with null values', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 4}); + render( + + ); await openMenu(); expect( @@ -427,7 +463,13 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for number cells', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 1}); + render( + + ); await openMenu(); expect( @@ -445,7 +487,13 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for date cells', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 2}); + render( + + ); await openMenu(); expect( @@ -463,7 +511,13 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for release cells', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 3}); + render( + + ); await openMenu(); expect( @@ -472,13 +526,15 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for empty release cells', async () => { - renderComponent({ - eventView: view, - handleCellAction, - columnIndex: 3, - // @ts-expect-error TODO: Fix this type - data: {...defaultData, release: null}, - }); + render( + + ); await openMenu(); expect( @@ -487,7 +543,13 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for measurement cells', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 5}); + render( + + ); await openMenu(); expect( @@ -505,16 +567,18 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for empty measurement cells', async () => { - renderComponent({ - eventView: view, - handleCellAction, - columnIndex: 5, - data: { - ...defaultData, - // @ts-expect-error TODO: Fix this type - 'measurements.fcp': null, - }, - }); + render( + + ); await openMenu(); expect( @@ -532,7 +596,13 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for numeric function cells', async () => { - renderComponent({eventView: view, handleCellAction, columnIndex: 6}); + render( + + ); await openMenu(); expect( @@ -544,37 +614,43 @@ describe('Discover -> CellAction', () => { }); it('show appropriate actions for empty numeric function cells', () => { - renderComponent({ - eventView: view, - handleCellAction, - columnIndex: 6, - data: { - ...defaultData, - // @ts-expect-error TODO: Fix this type - 'percentile(measurements.fcp, 0.5)': null, - }, - }); + render( + + ); expect(screen.queryByRole('button', {name: 'Actions'})).not.toBeInTheDocument(); }); }); describe('pin prop', () => { it('renders the pin element with the bold hover trigger', () => { - renderComponent({ - eventView: view, - triggerType: ActionTriggerType.BOLD_HOVER, - pin: , - }); + render( + pin me} + /> + ); expect(screen.getByRole('button', {name: 'pin me'})).toBeInTheDocument(); }); it('renders the pin element with the ellipsis trigger', () => { - renderComponent({ - eventView: view, - triggerType: ActionTriggerType.ELLIPSIS, - pin: , - }); + render( + pin me} + /> + ); expect(screen.getByRole('button', {name: 'pin me'})).toBeInTheDocument(); }); diff --git a/static/app/views/discover/table/tableView.spec.tsx b/static/app/views/discover/table/tableView.spec.tsx index 2cfa644208b9..5d0c798fb1f7 100644 --- a/static/app/views/discover/table/tableView.spec.tsx +++ b/static/app/views/discover/table/tableView.spec.tsx @@ -54,12 +54,26 @@ describe('TableView > CellActions', () => { const eventView = EventView.fromLocation(location); - function renderComponent( - tableData: TableData, - view: EventView, - queryDataset = SavedQueryDatasets.TRANSACTIONS - ) { - return render( + const renderOptions = { + organization, + initialRouterConfig: { + location: { + pathname: location.pathname, + query: locationQuery, + }, + }, + }; + + function ExampleTableView({ + tableData, + view, + queryDataset = SavedQueryDatasets.TRANSACTIONS, + }: { + tableData: TableData; + view: EventView; + queryDataset?: SavedQueryDatasets; + }) { + return ( CellActions', () => { showTags={false} title="" queryDataset={queryDataset} - />, - { - organization, - initialRouterConfig: { - location: { - pathname: location.pathname, - query: locationQuery, - }, - }, - } + /> ); } @@ -142,7 +147,7 @@ describe('TableView > CellActions', () => { it('updates sort order on equation fields', () => { const view = eventView.clone(); - renderComponent(rows, view); + render(, renderOptions); const equationCell = screen.getByRole('columnheader', {name: 'count() + 100'}); const sortLink = within(equationCell).getByRole('link'); @@ -155,7 +160,7 @@ describe('TableView > CellActions', () => { it('updates sort order on non-equation fields', () => { const view = eventView.clone(); - renderComponent(rows, view); + render(, renderOptions); const transactionCell = screen.getByRole('columnheader', {name: 'transaction'}); const sortLink = within(transactionCell).getByRole('link'); @@ -169,7 +174,10 @@ describe('TableView > CellActions', () => { it('handles add cell action on null value', async () => { rows.data[0]!.title = null as any; - const {router} = renderComponent(rows, eventView); + const {router} = render( + , + renderOptions + ); await openContextMenu(1); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Add to filter'})); @@ -190,7 +198,10 @@ describe('TableView > CellActions', () => { const view = eventView.clone(); view.query = 'tag:value has:title'; - const {router} = renderComponent(rows, view); + const {router} = render( + , + renderOptions + ); await openContextMenu(1); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Add to filter'})); @@ -210,7 +221,10 @@ describe('TableView > CellActions', () => { const view = eventView.clone(); view.query = 'tag:value !title:nope'; - const {router} = renderComponent(rows, view); + const {router} = render( + , + renderOptions + ); await openContextMenu(1); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Add to filter'})); @@ -277,7 +291,10 @@ describe('TableView > CellActions', () => { }); it('handles exclude cell action on string value', async () => { - const {router} = renderComponent(rows, eventView); + const {router} = render( + , + renderOptions + ); await openContextMenu(1); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Exclude from filter'}) @@ -299,7 +316,10 @@ describe('TableView > CellActions', () => { const view = eventView.clone(); view.query = 'tag:value title:nope'; - const {router} = renderComponent(rows, view); + const {router} = render( + , + renderOptions + ); await openContextMenu(1); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Exclude from filter'}) @@ -320,7 +340,10 @@ describe('TableView > CellActions', () => { it('handles exclude cell action on null value', async () => { rows.data[0]!.title = null as any; - const {router} = renderComponent(rows, eventView); + const {router} = render( + , + renderOptions + ); await openContextMenu(1); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Exclude from filter'}) @@ -343,7 +366,10 @@ describe('TableView > CellActions', () => { const view = eventView.clone(); view.query = 'tag:value !has:title'; - const {router} = renderComponent(rows, view); + const {router} = render( + , + renderOptions + ); await openContextMenu(1); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Exclude from filter'}) @@ -362,7 +388,10 @@ describe('TableView > CellActions', () => { }); it('handles greater than cell action on number value', async () => { - const {router} = renderComponent(rows, eventView); + const {router} = render( + , + renderOptions + ); await openContextMenu(3); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Show values greater than'}) @@ -381,7 +410,10 @@ describe('TableView > CellActions', () => { }); it('handles less than cell action on number value', async () => { - const {router} = renderComponent(rows, eventView); + const {router} = render( + , + renderOptions + ); await openContextMenu(3); await userEvent.click( screen.getByRole('menuitemradio', {name: 'Show values less than'}) @@ -402,7 +434,7 @@ describe('TableView > CellActions', () => { it('renders transaction summary link', () => { rows.data[0]!.project = 'project-slug'; - renderComponent(rows, eventView); + render(, renderOptions); const firstRow = screen.getAllByRole('row')[1]!; const link = within(firstRow).getByTestId('tableView-transaction-link'); @@ -508,7 +540,14 @@ describe('TableView > CellActions', () => { 'project.name': 'project-slug', }; - renderComponent(rows, view, SavedQueryDatasets.ERRORS); + render( + , + renderOptions + ); const firstRow = screen.getAllByRole('row')[1]!; const link = within(firstRow).getByTestId('view-event'); @@ -520,7 +559,10 @@ describe('TableView > CellActions', () => { }); it('handles go to release', async () => { - const {router} = renderComponent(rows, eventView); + const {router} = render( + , + renderOptions + ); await openContextMenu(5); await userEvent.click(screen.getByRole('menuitemradio', {name: 'Go to release'})); @@ -541,7 +583,7 @@ describe('TableView > CellActions', () => { it('has title on integer value greater than 999', () => { rows.data[0]!['count()'] = 1000; - renderComponent(rows, eventView); + render(, renderOptions); const firstRow = screen.getAllByRole('row')[1]!; const emptyValueCell = within(firstRow).getAllByRole('cell')[3]!; diff --git a/static/app/views/explore/components/chart/droppedDataBand/droppedDataTooltip.spec.tsx b/static/app/views/explore/components/chart/droppedDataBand/droppedDataTooltip.spec.tsx index c40e20573b57..92a27ca6e254 100644 --- a/static/app/views/explore/components/chart/droppedDataBand/droppedDataTooltip.spec.tsx +++ b/static/app/views/explore/components/chart/droppedDataBand/droppedDataTooltip.spec.tsx @@ -9,37 +9,45 @@ import {groupIntoBuckets} from 'sentry/views/explore/components/chart/droppedDat const START = Date.UTC(2024, 0, 12, 15, 0); const END = Date.UTC(2024, 0, 12, 15, 5); -function renderTooltip(dropped: Annotation[], accepted: Annotation[] = []) { +function ExampleDroppedDataTooltip({ + dropped, + accepted = [], +}: { + dropped: Annotation[]; + accepted?: Annotation[]; +}) { const [bucket] = groupIntoBuckets(dropped, accepted); - render(); + return ; } describe('DroppedDataTooltip', () => { it('shows the drop ratio, a row per outcome, and the time range', () => { - renderTooltip( - [ - AnnotationFixture({ - start: START, - end: END, - outcome: 'rate_limited', - eventCount: 40_000, - }), - AnnotationFixture({ - start: START, - end: END, - outcome: 'invalid', - eventCount: 20_000, - }), - ], - [ - AnnotationFixture({ - start: START, - end: END, - outcome: 'accepted', - eventCount: 180_000, - }), - ] + render( + ); expect(screen.getByText('Total Dropped')).toBeInTheDocument(); @@ -55,9 +63,11 @@ describe('DroppedDataTooltip', () => { }); it('shows <0.01% for a drop ratio at or below 0.01%', () => { - renderTooltip( - [AnnotationFixture({start: START, end: END, eventCount: 1})], - [AnnotationFixture({start: START, end: END, eventCount: 9_999})] + render( + ); expect(screen.getByText('<0.01%')).toBeInTheDocument(); @@ -65,37 +75,49 @@ describe('DroppedDataTooltip', () => { }); it('reads a drop with no accepted volume as the whole bucket', () => { - renderTooltip([AnnotationFixture({start: START, end: END, eventCount: 10})]); + render( + + ); expect(screen.getByText('100%')).toBeInTheDocument(); expect(screen.getByText('/10')).toBeInTheDocument(); }); it('labels an unintentional client discard as an SDK drop', () => { - renderTooltip([ - AnnotationFixture({ - start: START, - end: END, - outcome: 'client_discard', - reason: 'queue_overflow', - eventCount: 10, - }), - ]); + render( + + ); expect(screen.getByText('SDK Data Dropped')).toBeInTheDocument(); }); it('shares one byte unit between the payload row numbers', () => { - renderTooltip( - [AnnotationFixture({start: START, end: END, eventCount: 10, byteSize: 26e9})], - [ - AnnotationFixture({ - start: START, - end: END, - eventCount: 90, - byteSize: 224e9, - }), - ] + render( + ); expect(screen.getByText('Payloads Rejected')).toBeInTheDocument(); @@ -104,20 +126,28 @@ describe('DroppedDataTooltip', () => { }); it('omits the payload row for datasets without a byte category', () => { - renderTooltip([AnnotationFixture({start: START, end: END, eventCount: 10})]); + render( + + ); expect(screen.queryByText('Payloads Rejected')).not.toBeInTheDocument(); }); it('falls back to a generic label for an unknown outcome', () => { - renderTooltip([ - AnnotationFixture({ - start: START, - end: END, - outcome: 'something_new', - eventCount: 10, - }), - ]); + render( + + ); expect(screen.getByText('Other Rejected')).toBeInTheDocument(); }); diff --git a/static/app/views/explore/components/exports/exploreExportModal.spec.tsx b/static/app/views/explore/components/exports/exploreExportModal.spec.tsx index c7a6bc9a0c95..82b7e693b564 100644 --- a/static/app/views/explore/components/exports/exploreExportModal.spec.tsx +++ b/static/app/views/explore/components/exports/exploreExportModal.spec.tsx @@ -51,8 +51,14 @@ function makeConfig( }; } -function renderModal(config: TraceItemExportConfig, onCancel = jest.fn()) { - render( +function ExampleExploreExportModal({ + config, + onCancel = jest.fn(), +}: { + config: TraceItemExportConfig; + onCancel?: () => void; +}) { + return ( , - {organization} + /> ); } @@ -74,7 +79,9 @@ describe('ExploreExportModal', () => { it('calls onCancel and closeModal when Cancel is clicked', async () => { const onCancel = jest.fn(); - renderModal(makeConfig(), onCancel); + render(, { + organization, + }); await userEvent.click(screen.getByRole('button', {name: 'Cancel'})); @@ -90,7 +97,7 @@ describe('ExploreExportModal', () => { body: {id: 721}, }); - renderModal(config); + render(, {organization}); await userEvent.click(screen.getByRole('button', {name: 'Export'})); @@ -112,7 +119,7 @@ describe('ExploreExportModal', () => { }); it("disables the Format radios and selects JSONL when the 'All Columns' switch is on", async () => { - renderModal(makeConfig()); + render(, {organization}); await userEvent.click(await screen.findByRole('checkbox', {name: 'All Columns?'})); @@ -130,7 +137,7 @@ describe('ExploreExportModal', () => { body: {id: 721}, }); - renderModal(config); + render(, {organization}); await userEvent.click(await screen.findByRole('checkbox', {name: 'All Columns?'})); await userEvent.click(screen.getByRole('button', {name: 'Export'})); @@ -165,7 +172,7 @@ describe('ExploreExportModal', () => { body: {id: 721}, }); - renderModal(config); + render(, {organization}); await userEvent.click(screen.getByRole('button', {name: 'Number of rows'})); await userEvent.click(await screen.findByRole('option', {name: /\(All\)$/})); @@ -209,7 +216,7 @@ describe('ExploreExportModal', () => { body: {id: 721}, }); - renderModal(config); + render(, {organization}); await userEvent.click(screen.getByRole('button', {name: 'Number of rows'})); await userEvent.click(await screen.findByRole('option', {name: /\(All\)$/})); @@ -235,7 +242,7 @@ describe('ExploreExportModal', () => { body: {id: 721}, }); - renderModal(config); + render(, {organization}); await userEvent.click(screen.getByRole('button', {name: 'Export'})); @@ -256,7 +263,10 @@ describe('ExploreExportModal', () => { }); it('hides the All Columns switch when not supported', async () => { - renderModal(makeConfig({supportsAllColumns: false})); + render( + , + {organization} + ); expect(await screen.findByRole('button', {name: 'Export'})).toBeInTheDocument(); expect( @@ -265,7 +275,12 @@ describe('ExploreExportModal', () => { }); it('hides the Format radios when only one format is available', async () => { - renderModal(makeConfig({supportsAllColumns: false, availableFormats: ['csv']})); + render( + , + {organization} + ); expect(await screen.findByRole('button', {name: 'Export'})).toBeInTheDocument(); expect(screen.queryByRole('radio', {name: 'CSV'})).not.toBeInTheDocument(); diff --git a/static/app/views/explore/components/exports/exploreExportModalButton.spec.tsx b/static/app/views/explore/components/exports/exploreExportModalButton.spec.tsx index c47ae4508584..c80017095654 100644 --- a/static/app/views/explore/components/exports/exploreExportModalButton.spec.tsx +++ b/static/app/views/explore/components/exports/exploreExportModalButton.spec.tsx @@ -36,25 +36,20 @@ function makeConfig(): ExploreExportConfig { }; } -function renderButton( - props: Partial> = {} +function ExampleExploreExportModalButton( + props: Partial> ) { - const onOpen = jest.fn(); - const onClose = jest.fn(); - render( + return ( , - {organization} + /> ); - renderGlobalModal(); - return {onOpen, onClose}; } describe('ExploreExportModalButton', () => { @@ -63,7 +58,9 @@ describe('ExploreExportModalButton', () => { }); it('opens the modal and fires onOpen when clicked', async () => { - const {onOpen} = renderButton(); + const onOpen = jest.fn(); + render(, {organization}); + renderGlobalModal(); await userEvent.click(screen.getByRole('button', {name: 'Export'})); @@ -72,7 +69,9 @@ describe('ExploreExportModalButton', () => { }); it('fires onClose with escape_key when closed via Escape', async () => { - const {onClose} = renderButton(); + const onClose = jest.fn(); + render(, {organization}); + renderGlobalModal(); await userEvent.click(screen.getByRole('button', {name: 'Export'})); expect(await screen.findByRole('dialog')).toBeInTheDocument(); @@ -85,7 +84,9 @@ describe('ExploreExportModalButton', () => { }); it('fires onClose once with cancel_button when the Cancel button is clicked', async () => { - const {onClose} = renderButton(); + const onClose = jest.fn(); + render(, {organization}); + renderGlobalModal(); await userEvent.click(screen.getByRole('button', {name: 'Export'})); await userEvent.click(await screen.findByRole('button', {name: 'Cancel'})); @@ -97,7 +98,8 @@ describe('ExploreExportModalButton', () => { }); it('disables the button with a tooltip when data is empty', async () => { - renderButton({isDataEmpty: true}); + render(, {organization}); + renderGlobalModal(); const button = screen.getByRole('button', {name: 'Export'}); expect(button).toBeDisabled(); diff --git a/static/app/views/issueDetails/actions/resolutionReason.spec.tsx b/static/app/views/issueDetails/actions/resolutionReason.spec.tsx index a5891d61cee6..c656888a7058 100644 --- a/static/app/views/issueDetails/actions/resolutionReason.spec.tsx +++ b/static/app/views/issueDetails/actions/resolutionReason.spec.tsx @@ -34,26 +34,30 @@ const activity = { user: actor, } satisfies GroupActivity; -function renderReason({ +const organization = OrganizationFixture(); + +function ExampleResolutionReason({ activities = [activity], statusDetails, }: { statusDetails: ResolvedStatusDetails; activities?: GroupActivity[]; }) { - return render( + return ( , - {organization: OrganizationFixture()} + /> ); } describe('ResolutionReason', () => { it('shows the resolving pull request and canonical release for activity', () => { - const {container} = renderReason({statusDetails: {actor, inRelease: release}}); + const {container} = render( + , + {organization} + ); expect(container).toHaveTextContent( 'David Cramer resolved via #1234 released in 1.2.3' @@ -65,30 +69,36 @@ describe('ResolutionReason', () => { }); it('shows an exact release without a pull request for activity', () => { - const {container} = renderReason({ - activities: [ - { - ...activity, - data: {version: 'frontend@1.2.3'}, - }, - ], - statusDetails: {actor, inRelease: release}, - }); + const {container} = render( + , + {organization} + ); expect(container).toHaveTextContent('David Cramer resolved in 1.2.3'); expect(screen.queryByRole('link', {name: '#1234'})).not.toBeInTheDocument(); }); it('shows the first release that will contain the resolution for activity', () => { - const {container} = renderReason({ - activities: [ - { - ...activity, - data: {current_release_version: 'backend@1.0.0'}, - }, - ], - statusDetails: {actor, inNextRelease: true}, - }); + const {container} = render( + , + {organization} + ); expect(container).toHaveTextContent( 'David Cramer resolved starting with a release after 1.0.0' @@ -96,10 +106,13 @@ describe('ResolutionReason', () => { }); it('shows an upcoming release without a known current release for activity', () => { - const {container} = renderReason({ - activities: [], - statusDetails: {actor, inNextRelease: true}, - }); + const {container} = render( + , + {organization} + ); expect(container).toHaveTextContent( 'David Cramer set this to resolve in the upcoming release' @@ -108,18 +121,21 @@ describe('ResolutionReason', () => { it('shows the resolving commit for activity', () => { const commit = CommitFixture({repository}); - const {container} = renderReason({ - activities: [ - { - type: GroupActivityType.SET_RESOLVED_IN_COMMIT, - id: 'resolved-in-commit-1', - dateCreated: '2020-01-01T00:00:00', - data: {commit}, - user: actor, - }, - ], - statusDetails: {inCommit: {commit: commit.id}}, - }); + const {container} = render( + , + {organization} + ); expect(container).toHaveTextContent('David Cramer resolved via f7f395d'); expect(screen.getByRole('link', {name: /f7f395d/})).toHaveAttribute( @@ -130,18 +146,21 @@ describe('ResolutionReason', () => { it('prefers the pull request associated with a resolving commit', () => { const commit = CommitFixture({pullRequest, repository}); - const {container} = renderReason({ - activities: [ - { - type: GroupActivityType.SET_RESOLVED_IN_COMMIT, - id: 'resolved-in-commit-1', - dateCreated: '2020-01-01T00:00:00', - data: {commit}, - user: actor, - }, - ], - statusDetails: {inCommit: {commit: commit.id}}, - }); + const {container} = render( + , + {organization} + ); expect(container).toHaveTextContent('David Cramer resolved via #1234'); expect(screen.getByRole('link', {name: '#1234'})).toHaveAttribute( diff --git a/static/app/views/issueDetails/eventList.spec.tsx b/static/app/views/issueDetails/eventList.spec.tsx index a1717fe469c9..c4ca74242443 100644 --- a/static/app/views/issueDetails/eventList.spec.tsx +++ b/static/app/views/issueDetails/eventList.spec.tsx @@ -76,14 +76,8 @@ describe('EventList', () => { }); }); - function renderAllEvents() { - render(, { - initialRouterConfig, - }); - } - it('renders the list using a discover event query', async () => { - renderAllEvents(); + render(, {initialRouterConfig}); const {result} = renderHook(() => useEventColumns(group, organization)); expect(await screen.findByText('All Events')).toBeInTheDocument(); diff --git a/static/app/views/navigation/topBarActions.spec.tsx b/static/app/views/navigation/topBarActions.spec.tsx index f708413d6585..bb436ac76879 100644 --- a/static/app/views/navigation/topBarActions.spec.tsx +++ b/static/app/views/navigation/topBarActions.spec.tsx @@ -10,25 +10,27 @@ import {AskSeerButton} from 'sentry/views/seerExplorer/components/askSeerButton' const theme = ThemeFixture(); -function renderActions(width = 0) { - jest.spyOn(Element.prototype, 'clientWidth', 'get').mockReturnValue(width); - - return render( +function ExampleTopBarActions() { + return ( - , - {organization: OrganizationFixture()} + ); } +function mockContainerWidth(width: number) { + jest.spyOn(Element.prototype, 'clientWidth', 'get').mockReturnValue(width); +} + describe('top bar actions', () => { afterEach(() => { jest.restoreAllMocks(); }); it('shows tooltips for icon-only actions', async () => { - renderActions(); + mockContainerWidth(0); + render(, {organization: OrganizationFixture()}); const searchButton = screen.getByRole('button', {name: 'Command Palette'}); const askSeerButton = screen.getByRole('button', {name: 'Ask Seer'}); @@ -43,7 +45,8 @@ describe('top bar actions', () => { }); it('keeps Command Palette compact and exposes the Ask Seer shortcut in its tooltip at sm', async () => { - renderActions(Number.parseFloat(theme.container.sm)); + mockContainerWidth(Number.parseFloat(theme.container.sm)); + render(, {organization: OrganizationFixture()}); const askSeerButton = screen.getByRole('button', {name: 'Ask Seer'}); expect(screen.getByRole('button', {name: 'Command Palette'})).toBeInTheDocument(); diff --git a/static/app/views/performance/transactionSummary/transactionThresholdButton.spec.tsx b/static/app/views/performance/transactionSummary/transactionThresholdButton.spec.tsx index 9bf22b0b7497..359392f096c9 100644 --- a/static/app/views/performance/transactionSummary/transactionThresholdButton.spec.tsx +++ b/static/app/views/performance/transactionSummary/transactionThresholdButton.spec.tsx @@ -15,12 +15,16 @@ import type {Organization} from 'sentry/types/organization'; import {EventView} from 'sentry/utils/discover/eventView'; import {TransactionThresholdButton} from 'sentry/views/performance/transactionSummary/transactionThresholdButton'; -function renderComponent( - eventView: EventView, - organization: Organization, - onChangeThreshold: () => void -) { - return render( +function ExampleTransactionThresholdButton({ + eventView, + organization, + onChangeThreshold, +}: { + eventView: EventView; + onChangeThreshold: () => void; + organization: Organization; +}) { + return ( { metric: 'duration', }, }); - renderComponent(eventView, organization, onChangeThreshold); + render( + + ); const button = screen.getByRole('button'); await waitFor(() => expect(button).toBeEnabled()); @@ -97,7 +107,13 @@ describe('TransactionThresholdButton', () => { metric: 'duration', }, }); - renderComponent(eventView, organization, onChangeThreshold); + render( + + ); const button = screen.getByRole('button'); await waitFor(() => expect(button).toBeEnabled()); @@ -116,7 +132,13 @@ describe('TransactionThresholdButton', () => { }, }); - renderComponent(eventView, organization, onChangeThreshold); + render( + + ); const button = screen.getByRole('button'); await waitFor(() => expect(button).toBeEnabled()); @@ -138,7 +160,13 @@ describe('TransactionThresholdButton', () => { // render before the store is populated. ProjectsStore.reset(); - renderComponent(eventView, organization, onChangeThreshold); + render( + + ); const button = screen.getByRole('button', {name: 'Settings'}); expect(button).toBeDisabled(); @@ -166,7 +194,13 @@ describe('TransactionThresholdButton', () => { body: {threshold: '200', metric: 'duration'}, }); - renderComponent(eventView, organization, onChangeThreshold); + render( + + ); renderGlobalModal(); const button = screen.getByRole('button', {name: 'Settings'}); diff --git a/static/app/views/preprod/install/installPage.spec.tsx b/static/app/views/preprod/install/installPage.spec.tsx index 70cc0987f5ee..af2aab24594a 100644 --- a/static/app/views/preprod/install/installPage.spec.tsx +++ b/static/app/views/preprod/install/installPage.spec.tsx @@ -42,20 +42,19 @@ describe('InstallPage', () => { }); }); - function renderInstallPage() { - return render( + function ExampleInstallPage() { + return ( {props =>
} - , - {organization, initialRouterConfig} + ); } it('renders the Releases breadcrumb linking to the mobile-builds distribution view', async () => { - renderInstallPage(); + render(, {organization, initialRouterConfig}); expect(await screen.findByText('Test App')).toBeInTheDocument(); @@ -69,7 +68,7 @@ describe('InstallPage', () => { }); it('renders the app info as the current crumb after Releases', async () => { - renderInstallPage(); + render(, {organization, initialRouterConfig}); expect(await screen.findByText('Test App')).toBeInTheDocument(); @@ -107,7 +106,7 @@ describe('InstallPage', () => { body: {platform: 'ios', install_url: 'https://example.com/install'}, }); - renderInstallPage(); + render(, {organization, initialRouterConfig}); expect(await screen.findByText('Install Groups')).toBeInTheDocument(); expect(screen.getByText('qa')).toBeInTheDocument(); @@ -122,7 +121,7 @@ describe('InstallPage', () => { body: {detail: 'Internal Error'}, }); - renderInstallPage(); + render(, {organization, initialRouterConfig}); expect(await screen.findByText('Install')).toBeInTheDocument(); diff --git a/static/app/views/preprod/snapshots/main/snapshotCards.spec.tsx b/static/app/views/preprod/snapshots/main/snapshotCards.spec.tsx index 727deb417590..ffff5e9147be 100644 --- a/static/app/views/preprod/snapshots/main/snapshotCards.spec.tsx +++ b/static/app/views/preprod/snapshots/main/snapshotCards.spec.tsx @@ -21,10 +21,13 @@ jest.mock('sentry/utils/useCopyToClipboard', () => ({ useCopyToClipboard: () => ({copy: jest.fn()}), })); -function renderImageCard( - canvasTheme: SnapshotImage['canvas_theme'], - onSelectSnapshot?: (key: string | null) => void -) { +function ExampleImageCard({ + canvasTheme, + onSelectSnapshot, +}: { + canvasTheme: SnapshotImage['canvas_theme']; + onSelectSnapshot?: (key: string | null) => void; +}) { const image: SnapshotImage = { display_name: 'Button', height: 180, @@ -34,7 +37,7 @@ function renderImageCard( width: 320, canvas_theme: canvasTheme, }; - render( + return ( describe('ImageCard canvas theme', () => { it('seeds the canvas from an explicit canvas_theme hint', () => { - renderImageCard('dark'); + render(); expectDarkCanvas(); }); it('toggles the canvas independently of the hint', async () => { - renderImageCard('dark'); + render(); expectDarkCanvas(); await userEvent.click(screen.getByRole('button', {name: 'Light preview'})); @@ -71,7 +74,7 @@ describe('ImageCard canvas theme', () => { describe('ImageCard zoom', () => { it('renders zoom controls wired to the image zoom', async () => { - renderImageCard(null); + render(); await userEvent.click(screen.getByRole('button', {name: 'Zoom in'})); await userEvent.click(screen.getByRole('button', {name: 'Zoom out'})); @@ -83,7 +86,7 @@ describe('ImageCard zoom', () => { }); it('hints at modifier scroll zoom on the zoom buttons', async () => { - renderImageCard(null); + render(); await userEvent.hover(screen.getByRole('button', {name: 'Zoom in'})); @@ -92,7 +95,7 @@ describe('ImageCard zoom', () => { it('does not toggle card selection when using zoom controls', async () => { const onSelectSnapshot = jest.fn(); - renderImageCard(null, onSelectSnapshot); + render(); await userEvent.click(screen.getByRole('button', {name: 'Zoom in'})); diff --git a/static/app/views/preprod/snapshots/main/snapshotListView.spec.tsx b/static/app/views/preprod/snapshots/main/snapshotListView.spec.tsx index 05af5af47162..9f6de503309e 100644 --- a/static/app/views/preprod/snapshots/main/snapshotListView.spec.tsx +++ b/static/app/views/preprod/snapshots/main/snapshotListView.spec.tsx @@ -50,8 +50,14 @@ const erroredPair: SnapshotDiffPair = { head_image: image(), }; -function renderListView(items: SidebarItem[], diffMode?: 'split' | 'wipe' | 'onion') { - return render( +function ExampleSnapshotListView({ + items, + diffMode, +}: { + items: SidebarItem[]; + diffMode?: 'split' | 'wipe' | 'onion'; +}) { + return ( { }); it('renders errored pairs as side-by-side cards with a failed badge', () => { - renderListView([erroredItem]); + render(); expect(screen.getByText('Failed to compare')).toBeInTheDocument(); }); it('renders errored pairs side-by-side even when the diff mode is onion', () => { - renderListView([erroredItem], 'onion'); + render(); expect(screen.getByText('Failed to compare')).toBeInTheDocument(); // Onion mode renders an opacity slider; side-by-side (split) does not. @@ -116,7 +122,7 @@ describe('SnapshotListView', () => { } it('renders every card in a large single group (per-card rows) plus one header', () => { - renderListView([changedGroup(6)]); + render(); expect(screen.getAllByRole('heading', {name: 'Screens'})).toHaveLength(1); expect(screen.getByText('Screen 0')).toBeInTheDocument(); @@ -124,7 +130,7 @@ describe('SnapshotListView', () => { }); it('frames the first row of a group as frame-top and the last card row as frame-bottom', () => { - renderListView([changedGroup(2)]); + render(); expect(document.querySelectorAll('[data-frame-top]')).toHaveLength(1); expect(document.querySelectorAll('[data-frame-bottom]')).toHaveLength(1); @@ -132,15 +138,19 @@ describe('SnapshotListView', () => { }); it('renders no group header for ungrouped items', () => { - renderListView([ - { - key: 'added:solo', - name: 'solo.png', - displayName: 'solo.png', - type: 'added', - images: [image({group: undefined, image_file_name: 'solo.png'})], - }, - ]); + render( + + ); expect(screen.queryByRole('heading', {name: 'solo.png'})).not.toBeInTheDocument(); }); diff --git a/static/app/views/preprod/snapshots/main/snapshotMainContent.spec.tsx b/static/app/views/preprod/snapshots/main/snapshotMainContent.spec.tsx index 97dcbe40e79f..0277a5da9a61 100644 --- a/static/app/views/preprod/snapshots/main/snapshotMainContent.spec.tsx +++ b/static/app/views/preprod/snapshots/main/snapshotMainContent.spec.tsx @@ -65,10 +65,10 @@ function buildProps( return {...defaultProps, ...props}; } -function renderSnapshotMainContent( - props: Partial> = {} +function ExampleSnapshotMainContent( + props: Partial> ) { - return render( + return ( @@ -151,7 +151,7 @@ describe('SnapshotMainContent', () => { it('keeps the diff/head toggle visible when viewing the head-only comparison', async () => { const onToggleSoloView = jest.fn(); - renderSnapshotMainContent({onToggleSoloView}); + render(); expect(screen.getByText('Diff')).toBeInTheDocument(); expect(screen.getByText('Head')).toBeInTheDocument(); @@ -165,31 +165,33 @@ describe('SnapshotMainContent', () => { it('renders focused changed snapshots with diff controls and navigation state', async () => { const onNavigateSingleView = jest.fn(); - renderSnapshotMainContent({ - canNavigateNext: true, - canNavigatePrev: false, - comparisonType: 'diff', - headBranch: 'feature/snapshot-updates', - isSoloView: false, - listItems: [ - { + render( + + ); expect(screen.getByText('Buttons')).toBeInTheDocument(); expect(screen.getByText('Button / light')).toBeInTheDocument(); @@ -220,16 +222,18 @@ describe('SnapshotMainContent', () => { type: 'changed' as const, }; - renderSnapshotMainContent({ - comparisonType: 'diff', - diffMode: 'split', - isSoloView: false, - listItems: [changedItem], - selectedItem: changedItem, - onOverlayOpacityChange, - overlayOpacity: 100, - viewMode: 'single', - }); + render( + + ); // Presets live inside the color picker popover, not the toolbar itself. expect( @@ -258,15 +262,17 @@ describe('SnapshotMainContent', () => { type: 'changed' as const, }; - renderSnapshotMainContent({ - comparisonType: 'diff', - diffMode: 'split', - isSoloView: false, - listItems: [changedItem], - selectedItem: changedItem, - overlayOpacity: 50, - viewMode: 'single', - }); + render( + + ); await userEvent.click(screen.getByRole('button', {name: 'Pick overlay color'})); @@ -301,16 +307,14 @@ describe('SnapshotMainContent', () => { viewMode: 'single' as const, }; - const {rerender} = renderSnapshotMainContent({...props, overlayOpacity: 100}); + const {rerender} = render( + + ); await userEvent.click(screen.getByRole('button', {name: 'Hide overlay'})); expect(onOverlayOpacityChange).toHaveBeenLastCalledWith(0); - rerender( - - - - ); + rerender(); await userEvent.click(screen.getByRole('button', {name: 'Show overlay'})); expect(onOverlayOpacityChange).toHaveBeenLastCalledWith(100); @@ -325,14 +329,16 @@ describe('SnapshotMainContent', () => { type: 'changed' as const, }; - renderSnapshotMainContent({ - comparisonType: 'diff', - diffMode: 'wipe', - isSoloView: false, - listItems: [changedItem], - selectedItem: changedItem, - viewMode: 'single', - }); + render( + + ); expect( screen.queryByRole('button', {name: 'Pick overlay color'}) @@ -341,18 +347,20 @@ describe('SnapshotMainContent', () => { }); it('renders focused errored snapshots side-by-side with a failed badge', () => { - renderSnapshotMainContent({ - comparisonType: 'diff', - isSoloView: false, - selectedItem: { - key: 'errored-screens', - name: 'Screens', - displayName: 'Screens', - pairs: [erroredPair], - type: 'errored', - }, - viewMode: 'single', - }); + render( + + ); expect(screen.getByText('Screens')).toBeInTheDocument(); expect(screen.getByText('Login screen')).toBeInTheDocument(); @@ -369,18 +377,20 @@ describe('SnapshotMainContent', () => { }); it('renders focused renamed snapshots as a single image with pair metadata', async () => { - renderSnapshotMainContent({ - comparisonType: 'diff', - isSoloView: false, - selectedItem: { - key: 'renamed-buttons', - name: 'Buttons', - displayName: 'Buttons', - pairs: [renamedPair], - type: 'renamed', - }, - viewMode: 'single', - }); + render( + + ); expect(screen.getByText('Buttons')).toBeInTheDocument(); expect(screen.getByText('Renamed')).toBeInTheDocument(); @@ -450,22 +460,20 @@ describe('SnapshotMainContent', () => { function renderSingleView(img: SnapshotImage) { const item = soloItem(img); - const view = renderSnapshotMainContent({ - listItems: [item], - selectedItem: item, - viewMode: 'single', - }); + const view = render( + + ); const renderItem = (nextItem: SidebarItem) => view.rerender( - - - + ); return { navigateTo: (nextImg: SnapshotImage) => renderItem(soloItem(nextImg)), diff --git a/static/app/views/preprod/snapshots/sidebar/snapshotSidebarContent.spec.tsx b/static/app/views/preprod/snapshots/sidebar/snapshotSidebarContent.spec.tsx index f330f930933d..dac7b8eb45f1 100644 --- a/static/app/views/preprod/snapshots/sidebar/snapshotSidebarContent.spec.tsx +++ b/static/app/views/preprod/snapshots/sidebar/snapshotSidebarContent.spec.tsx @@ -21,11 +21,14 @@ const statusCounts: Record = { [DiffStatus.SKIPPED]: 0, }; -function renderSidebar( - sections: SidebarSection[], - counts: Record = statusCounts -) { - return render( +function ExampleSnapshotSidebarContent({ + sections, + counts = statusCounts, +}: { + sections: SidebarSection[]; + counts?: Record; +}) { + return ( { it('renders displayName in the sidebar, not the key', async () => { - renderSidebar([ - { - type: DiffStatus.CHANGED, - groups: [ + render( + + ); expect(await screen.findByText('MyPreview')).toBeInTheDocument(); expect(screen.queryByText('com.example.MyClass.MyPreview')).not.toBeInTheDocument(); }); it('shows group name as displayName when group is set', async () => { - renderSidebar([ - { - type: DiffStatus.UNCHANGED, - groups: [ + render( + + ); expect(await screen.findByText('components')).toBeInTheDocument(); }); it('renders an errored pill when there are errored images', async () => { - renderSidebar( - [ - { - type: DiffStatus.ERRORED, - groups: [{key: 'errored:LoginScreen', displayName: 'LoginScreen', count: 2}], - }, - ], - { - [DiffStatus.CHANGED]: 0, - [DiffStatus.ADDED]: 0, - [DiffStatus.REMOVED]: 0, - [DiffStatus.RENAMED]: 0, - [DiffStatus.UNCHANGED]: 0, - [DiffStatus.ERRORED]: 2, - [DiffStatus.SKIPPED]: 0, - } + render( + ); expect(await screen.findByText('2 errored')).toBeInTheDocument(); diff --git a/static/gsApp/views/amCheckout/components/cartDiff.spec.tsx b/static/gsApp/views/amCheckout/components/cartDiff.spec.tsx index 2f42666cd584..f704ff478f03 100644 --- a/static/gsApp/views/amCheckout/components/cartDiff.spec.tsx +++ b/static/gsApp/views/amCheckout/components/cartDiff.spec.tsx @@ -33,7 +33,7 @@ describe('CartDiff', () => { }, }; - function renderCartDiff({ + function ExampleCartDiff({ activePlan = teamAnnualPlan, formData, subscription = sub, @@ -42,7 +42,7 @@ describe('CartDiff', () => { activePlan?: Plan; subscription?: Subscription; }) { - render( + return ( { }, }; - renderCartDiff({formData, activePlan: bizPlan}); + render(); expect(await screen.findByText('Changes')).toBeInTheDocument(); const planDiff = await screen.findByTestId('plan-diff'); @@ -95,7 +95,7 @@ describe('CartDiff', () => { }); it('does not render for returning customers with no changes', () => { - renderCartDiff({formData: defaultFormData}); + render(); expect(screen.queryByTestId('cart-diff')).not.toBeInTheDocument(); }); @@ -104,7 +104,7 @@ describe('CartDiff', () => { organization: org, plan: 'am3_f', }); - renderCartDiff({formData: defaultFormData, subscription: newSub}); + render(); expect(screen.queryByTestId('cart-diff')).not.toBeInTheDocument(); }); @@ -130,7 +130,7 @@ describe('CartDiff', () => { }, }; - renderCartDiff({formData, subscription: sharedOdSub}); + render(); expect(await screen.findByText('Changes')).toBeInTheDocument(); const paygDiff = await screen.findByTestId('shared-spend-limit-diff'); @@ -168,7 +168,7 @@ describe('CartDiff', () => { }, }; - renderCartDiff({formData, subscription: perCategorySub}); + render(); expect(await screen.findByText('Changes')).toBeInTheDocument(); const paygDiff = await screen.findByTestId('shared-spend-limit-diff'); expect(paygDiff).toHaveTextContent('PAYG spend limit'); @@ -191,7 +191,7 @@ describe('CartDiff', () => { }, }; - renderCartDiff({formData}); + render(); expect(screen.queryByTestId('cart-diff')).not.toBeInTheDocument(); }); @@ -204,7 +204,7 @@ describe('CartDiff', () => { }, }; - renderCartDiff({formData}); + render(); expect(await screen.findByText('Changes')).toBeInTheDocument(); const paygDiff = await screen.findByTestId('shared-spend-limit-diff'); expect(paygDiff).toHaveTextContent('PAYG spend limit'); @@ -224,7 +224,7 @@ describe('CartDiff', () => { }, }; - renderCartDiff({formData}); + render(); expect(await screen.findByText('Changes')).toBeInTheDocument(); const perCategoryDiff = await screen.findByTestId('per-category-spend-limit-diff'); expect(perCategoryDiff).toHaveTextContent('Per-product spend limits'); @@ -253,7 +253,7 @@ describe('CartDiff', () => { sharedMaxBudget: 0, }, }; - renderCartDiff({formData, subscription: subWithBudget}); + render(); expect(await screen.findByText('Changes')).toBeInTheDocument(); const paygDiff = await screen.findByTestId('shared-spend-limit-diff'); expect(paygDiff).toHaveTextContent('PAYG spend limit'); diff --git a/static/gsApp/views/amCheckout/steps/buildYourPlan.spec.tsx b/static/gsApp/views/amCheckout/steps/buildYourPlan.spec.tsx index cfb0527a4e93..8b14ff146750 100644 --- a/static/gsApp/views/amCheckout/steps/buildYourPlan.spec.tsx +++ b/static/gsApp/views/amCheckout/steps/buildYourPlan.spec.tsx @@ -1,3 +1,4 @@ +import type {ComponentProps} from 'react'; import {LocationFixture} from 'sentry-fixture/locationFixture'; import {OrganizationFixture} from 'sentry-fixture/organization'; import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture'; @@ -48,28 +49,20 @@ describe('BuildYourPlan', () => { }); }); - function renderCheckout(referrer?: string) { - let location = LocationFixture(); - if (referrer) { - location = LocationFixture({ - query: { - referrer, - }, - }); - } - render( - , - {organization} + const routeProps = RouteComponentPropsFixture(); + + function ExampleAMCheckout({ + location, + }: { + location: ComponentProps['location']; + }) { + return ( + ); } it('renders', async () => { - renderCheckout(); + render(, {organization}); expect(await screen.findByText('Select a plan')).toBeInTheDocument(); expect(screen.queryByTestId('body-choose-your-plan')).not.toBeInTheDocument(); @@ -83,7 +76,7 @@ describe('BuildYourPlan', () => { }); SubscriptionStore.set(bizOrg.slug, businessSubscription); - renderCheckout(); + render(, {organization}); const businessPlan = await screen.findByTestId('plan-option-am3_business'); expect(businessPlan).toBeInTheDocument(); @@ -93,7 +86,7 @@ describe('BuildYourPlan', () => { }); it('can select plan', async () => { - renderCheckout(); + render(, {organization}); const teamPlan = await screen.findByRole('radio', {name: 'Team'}); const businessPlan = screen.getByRole('radio', {name: 'Business'}); diff --git a/static/gsApp/views/amCheckout/steps/chooseYourBillingCycle.spec.tsx b/static/gsApp/views/amCheckout/steps/chooseYourBillingCycle.spec.tsx index ae4597105653..f21c05fa1a7b 100644 --- a/static/gsApp/views/amCheckout/steps/chooseYourBillingCycle.spec.tsx +++ b/static/gsApp/views/amCheckout/steps/chooseYourBillingCycle.spec.tsx @@ -1,3 +1,4 @@ +import type {ComponentProps} from 'react'; import {LocationFixture} from 'sentry-fixture/locationFixture'; import {OrganizationFixture} from 'sentry-fixture/organization'; import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture'; @@ -86,28 +87,20 @@ describe('ChooseYourBillingCycle', () => { ).toBeInTheDocument(); } - function renderCheckout(referrer?: string) { - let location = LocationFixture(); - if (referrer) { - location = LocationFixture({ - query: { - referrer, - }, - }); - } - render( - , - {organization} + const routeProps = RouteComponentPropsFixture(); + + function ExampleAMCheckout({ + location, + }: { + location: ComponentProps['location']; + }) { + return ( + ); } it('renders for upgrade from developer', async () => { - renderCheckout(); + render(, {organization}); await assertCycleText({ // org is on monthly cycle, but is on developer plan, so upgrade should apply immediately and create a new period monthlyInfo: /Billed on the 13th of each month/, @@ -122,7 +115,7 @@ describe('ChooseYourBillingCycle', () => { billingPeriodEnd: '2025-08-28', }); SubscriptionStore.set(organization.slug, monthlySub); - renderCheckout(); + render(, {organization}); await assertCycleText({ // org is on monthly cycle and is paid plan, so upgrade should apply immediately to the current period monthlyInfo: /Billed on the 29th of each month/, @@ -138,7 +131,7 @@ describe('ChooseYourBillingCycle', () => { organization, }); SubscriptionStore.set(organization.slug, annualSub); - renderCheckout(); + render(, {organization}); await assertCycleText({ monthlyInfo: /Billed on the 16th of each month/, yearlyInfo: /Billed annually/, @@ -162,7 +155,7 @@ describe('ChooseYourBillingCycle', () => { organization, }); SubscriptionStore.set(organization.slug, partnerSub); - renderCheckout(); + render(, {organization}); await assertCycleText({ monthlyInfo: /Billed monthly starting on your selected start date on submission/, yearlyInfo: /Billed annually from your selected start date on submission/, @@ -170,7 +163,7 @@ describe('ChooseYourBillingCycle', () => { }); it('can select billing cycle', async () => { - renderCheckout(); + render(, {organization}); const monthly = await screen.findByRole('radio', {name: 'Monthly billing cycle'}); const annual = screen.getByRole('radio', {name: 'Yearly billing cycle'});