Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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