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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion static/app/components/waitingForEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {t} from 'sentry/locale';
import type {Organization} from 'sentry/types/organization';
import type {Project} from 'sentry/types/project';
import {apiOptions} from 'sentry/utils/api/apiOptions';
import CreateSampleEventButton from 'sentry/views/onboarding/createSampleEventButton';
import {CreateSampleEventButton} from 'sentry/views/onboarding/createSampleEventButton';
import {makeProjectsPathname} from 'sentry/views/projects/pathname';

type Props = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {trackAnalytics} from 'sentry/utils/analytics';
import {getApiUrl} from 'sentry/utils/api/getApiUrl';
import {useApiQuery} from 'sentry/utils/queryClient';
import {useExperiment} from 'sentry/utils/useExperiment';
import CreateSampleEventButton from 'sentry/views/onboarding/createSampleEventButton';
import {CreateSampleEventButton} from 'sentry/views/onboarding/createSampleEventButton';
import {useOnboardingSidebar} from 'sentry/views/onboarding/useOnboardingSidebar';

import {GridFooter} from './genericFooter';
Expand Down
118 changes: 61 additions & 57 deletions static/app/views/onboarding/createSampleEventButton.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import * as Sentry from '@sentry/react';
import {OrganizationFixture} from 'sentry-fixture/organization';
import {ProjectFixture} from 'sentry-fixture/project';

import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
import {act, render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';

import {trackAnalytics} from 'sentry/utils/analytics';
import CreateSampleEventButton from 'sentry/views/onboarding/createSampleEventButton';
import {CreateSampleEventButton} from 'sentry/views/onboarding/createSampleEventButton';

jest.useFakeTimers();
jest.mock('sentry/utils/analytics');

describe('CreateSampleEventButton', () => {
Expand Down Expand Up @@ -36,45 +35,30 @@ describe('CreateSampleEventButton', () => {

it('creates a sample event', async () => {
const {router} = renderComponent();
const createRequest = MockApiClient.addMockResponse({
MockApiClient.addMockResponse({
url: `/projects/${org.slug}/${project.slug}/create-sample/`,
method: 'POST',
body: {groupID},
});

const sampleButton = await screen.findByRole('button', {name: createSampleText});
await userEvent.click(sampleButton, {delay: null});

// The button should be disabled while creating the event
expect(sampleButton).toBeDisabled();

// We have to await the API calls. We could normally do this using tick(),
// however since we have enabled fake timers to handle the spin-wait on the
// event creation, we cannot use tick.
await Promise.resolve();
expect(createRequest).toHaveBeenCalled();

const latestIssueRequest = MockApiClient.addMockResponse({
MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/issues/${groupID}/events/latest/`,
body: {},
});

// There is a timeout before we check for the existence of the latest
// event. Wait for it then wait for the request to complete
jest.runAllTimers();
await waitFor(() => expect(latestIssueRequest).toHaveBeenCalled());

// Wait for the api request and latestEventAvailable to resolve
expect(sampleButton).toBeEnabled();
const sampleButton = await screen.findByRole('button', {name: createSampleText});
await userEvent.click(sampleButton, {delay: null});

expect(router.location).toEqual(
expect.objectContaining({
pathname: `/organizations/${org.slug}/issues/${groupID}/`,
query: expect.objectContaining({
project: project.id,
referrer: 'sample-error',
}),
})
await waitFor(() =>
expect(router.location).toEqual(
expect.objectContaining({
pathname: `/organizations/${org.slug}/issues/${groupID}/`,
query: expect.objectContaining({
project: project.id,
referrer: 'sample-error',
}),
})
)
);
});

Expand All @@ -85,14 +69,20 @@ describe('CreateSampleEventButton', () => {
method: 'POST',
body: {groupID},
});
MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/issues/${groupID}/events/latest/`,
body: {},
});

await userEvent.click(await screen.findByRole('button', {name: createSampleText}), {
delay: null,
});

expect(trackAnalytics).toHaveBeenCalledWith(
'growth.onboarding_view_sample_event',
expect.objectContaining({platform: 'javascript'})
await waitFor(() =>
expect(trackAnalytics).toHaveBeenCalledWith(
'growth.onboarding_view_sample_event',
expect.objectContaining({platform: 'javascript'})
)
);
expect(trackAnalytics).not.toHaveBeenCalledWith(
'onboarding.scm_view_sample_event_clicked',
Expand All @@ -116,14 +106,20 @@ describe('CreateSampleEventButton', () => {
method: 'POST',
body: {groupID},
});
MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/issues/${groupID}/events/latest/`,
body: {},
});

await userEvent.click(await screen.findByRole('button', {name: createSampleText}), {
delay: null,
});

expect(trackAnalytics).toHaveBeenCalledWith(
'onboarding.scm_view_sample_event_clicked',
expect.objectContaining({platform: 'javascript'})
await waitFor(() =>
expect(trackAnalytics).toHaveBeenCalledWith(
'onboarding.scm_view_sample_event_clicked',
expect.objectContaining({platform: 'javascript'})
)
);
expect(trackAnalytics).not.toHaveBeenCalledWith(
'growth.onboarding_view_sample_event',
Expand All @@ -132,49 +128,53 @@ describe('CreateSampleEventButton', () => {
});

it('waits for the latest event to be processed', async () => {
jest.useFakeTimers();
const {router} = renderComponent();
const createRequest = MockApiClient.addMockResponse({
url: `/projects/${org.slug}/${project.slug}/create-sample/`,
method: 'POST',
body: {groupID},
});

await userEvent.click(await screen.findByRole('button', {name: createSampleText}), {
delay: null,
});

await waitFor(() => expect(createRequest).toHaveBeenCalled());

// Start with no latest event
// Start with 404 — fetchQuery will retry after retryDelay
let latestIssueRequest = MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/issues/${groupID}/events/latest/`,
statusCode: 404,
body: {},
});

// Wait for the timeout once, the first request will 404
jest.runAllTimers();
await userEvent.click(await screen.findByRole('button', {name: createSampleText}), {
delay: null,
});

await waitFor(() => expect(createRequest).toHaveBeenCalled());

// fetchQuery fires immediately — wait for the first (404) attempt
await waitFor(() => expect(latestIssueRequest).toHaveBeenCalled());

// Second request will be successful
// Set up 200 for the retry
MockApiClient.clearMockResponses();
latestIssueRequest = MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/issues/${groupID}/events/latest/`,
statusCode: 200,
body: {},
});

jest.runAllTimers();
// Advance past the retry delay so fetchQuery retries, wrapped in act
// to capture the navigate state update from onSuccess
await act(() => jest.advanceTimersByTimeAsync(EVENT_POLL_INTERVAL));
await waitFor(() => expect(latestIssueRequest).toHaveBeenCalled());

expect(router.location).toEqual(
expect.objectContaining({
pathname: `/organizations/${org.slug}/issues/${groupID}/`,
query: expect.objectContaining({
project: project.id,
referrer: 'sample-error',
}),
})
await waitFor(() =>
expect(router.location).toEqual(
expect.objectContaining({
pathname: `/organizations/${org.slug}/issues/${groupID}/`,
query: expect.objectContaining({
project: project.id,
referrer: 'sample-error',
}),
})
)
);

expect(trackAnalytics).toHaveBeenCalledWith(
Expand All @@ -190,5 +190,9 @@ describe('CreateSampleEventButton', () => {
);

expect(Sentry.captureMessage).not.toHaveBeenCalled();

jest.useRealTimers();
});
});

const EVENT_POLL_INTERVAL = 1000;
Loading
Loading