Skip to content

Commit

Permalink
ref(onboarding): Reactivate project deletion in the the onboarding of…
Browse files Browse the repository at this point in the history
… new organizations (#48318)
  • Loading branch information
priscilawebdev authored May 3, 2023
1 parent 5ba334b commit d8ac56e
Show file tree
Hide file tree
Showing 4 changed files with 346 additions and 77 deletions.
3 changes: 3 additions & 0 deletions static/app/utils/eventWaiter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {Component} from 'react';
import * as Sentry from '@sentry/react';

import {Client} from 'sentry/api';
import ProjectsStore from 'sentry/stores/projectsStore';
import {Group, Organization, Project} from 'sentry/types';
import withApi from 'sentry/utils/withApi';

Expand Down Expand Up @@ -80,6 +81,8 @@ class EventWaiter extends Component<EventWaiterProps, EventWaiterState> {
const resp = await api.requestPromise(
`/projects/${organization.slug}/${project.slug}/`
);
// update the project independently of an event of the defined type was received
ProjectsStore.onUpdateSuccess(resp);
firstEvent = getFirstEvent(eventType, resp);
} catch (resp) {
if (!resp) {
Expand Down
22 changes: 17 additions & 5 deletions static/app/views/onboarding/components/createProjectsFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export function CreateProjectsFooter({
}

try {
addLoadingMessage(t('Creating project'));
addLoadingMessage(t('Loading SDK configuration\u2026'));

const response = (await createProject({
api,
Expand All @@ -105,11 +105,23 @@ export function CreateProjectsFooter({

ProjectsStore.onCreateSuccess(response, organization.slug);

// Measure to filter out projects that might have been created during the onboarding and not deleted from the session due to an error
// Note: in the onboarding flow the projects are created based on the platform slug
const newProjects = Object.keys(onboardingContext.data.projects).reduce(
(acc, key) => {
if (onboardingContext.data.projects[key].slug !== response.slug) {
acc[key] = onboardingContext.data.projects[key];
}
return acc;
},
{}
);

onboardingContext.setData({
selectedSDK: createProjectForPlatform,
projects: {
...onboardingContext.data.projects,
[response.slug]: {
...newProjects,
[response.id]: {
slug: response.slug,
status: OnboardingProjectStatus.WAITING,
},
Expand All @@ -124,7 +136,7 @@ export function CreateProjectsFooter({
clearIndicators();
setTimeout(() => onComplete(createProjectForPlatform!));
} catch (err) {
addErrorMessage(t('Failed to create project'));
addErrorMessage(t('Failed to load SDK configuration'));
Sentry.captureException(err);
}
},
Expand Down Expand Up @@ -204,7 +216,7 @@ export function CreateProjectsFooter({
disabled={!selectedPlatform}
data-test-id="platform-select-next"
>
{t('Create Project')}
{t('Configure SDK')}
</Button>
</ButtonWrapper>
</GenericFooter>
Expand Down
201 changes: 191 additions & 10 deletions static/app/views/onboarding/onboarding.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {

import {OnboardingContextProvider} from 'sentry/components/onboarding/onboardingContext';
import {PlatformKey} from 'sentry/data/platformCategories';
import OrganizationStore from 'sentry/stores/organizationStore';
import ProjectsStore from 'sentry/stores/projectsStore';
import {OnboardingProjectStatus, Project} from 'sentry/types';
import Onboarding from 'sentry/views/onboarding/onboarding';
Expand All @@ -23,7 +22,7 @@ describe('Onboarding', function () {
step: 'welcome',
};

const {router, route, routerContext} = initializeOrg({
const {router, route, routerContext, organization} = initializeOrg({
...initializeOrg(),
router: {
params: routeParams,
Expand All @@ -43,6 +42,7 @@ describe('Onboarding', function () {
</OnboardingContextProvider>,
{
context: routerContext,
organization,
}
);

Expand All @@ -62,8 +62,6 @@ describe('Onboarding', function () {
},
});

OrganizationStore.onUpdate(organization);

render(
<OnboardingContextProvider>
<Onboarding
Expand All @@ -77,6 +75,7 @@ describe('Onboarding', function () {
</OnboardingContextProvider>,
{
context: routerContext,
organization,
}
);

Expand Down Expand Up @@ -120,8 +119,6 @@ describe('Onboarding', function () {

ProjectsStore.loadInitialData([nextJsProject]);

OrganizationStore.onUpdate(organization);

render(
<OnboardingContextProvider
value={{
Expand Down Expand Up @@ -151,12 +148,196 @@ describe('Onboarding', function () {
</OnboardingContextProvider>,
{
context: routerContext,
organization,
}
);

expect(await screen.findByText('Configure Next.js SDK')).toBeInTheDocument();
});

it('renders SDK data removal modal when going back', async function () {
const reactProject: Project = TestStubs.Project({
platform: 'javascript-react',
id: '2',
slug: 'javascript-react-slug',
firstTransactionEvent: false,
firstEvent: false,
hasReplays: false,
hasSessions: false,
});

const routeParams = {
step: 'setup-docs',
};

const {router, route, routerContext, organization} = initializeOrg({
...initializeOrg(),
organization: {
...initializeOrg().organization,
features: ['onboarding-project-deletion-on-back-click'],
},
router: {
params: routeParams,
},
});

MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${reactProject.slug}/docs/javascript-react-with-error-monitoring/`,
body: null,
});

MockApiClient.addMockResponse({
url: `/projects/org-slug/${reactProject.slug}/`,
body: [reactProject],
});

MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${reactProject.slug}/issues/`,
body: [],
});

ProjectsStore.loadInitialData([reactProject]);

render(
<OnboardingContextProvider
value={{
selectedSDK: {
key: reactProject.slug as PlatformKey,
type: 'framework',
language: 'javascript',
category: 'browser',
},
projects: {
[reactProject.id]: {
slug: reactProject.slug,
status: OnboardingProjectStatus.WAITING,
firstIssueId: undefined,
},
},
}}
>
<Onboarding
router={router}
location={router.location}
params={routeParams}
routes={router.routes}
routeParams={router.params}
route={route}
/>
</OnboardingContextProvider>,
{
context: routerContext,
organization,
}
);

// Await for the docs to be loaded
await screen.findByText('Configure React SDK');

renderGlobalModal();

// Click on back button
await userEvent.click(screen.getByRole('button', {name: 'Back'}));

// Await for the modal to be open
expect(
await screen.findByText(/Are you sure you want to head back?/)
).toBeInTheDocument();

// Close modal
await userEvent.click(screen.getByRole('button', {name: 'Cancel'}));
});

it('does not render SDK data removal modal when going back', async function () {
const reactProject: Project = TestStubs.Project({
platform: 'javascript-react',
id: '2',
slug: 'javascript-react-slug',
firstTransactionEvent: false,
firstEvent: false,
hasReplays: false,
hasSessions: true,
});

const routeParams = {
step: 'setup-docs',
};

const {router, route, routerContext, organization} = initializeOrg({
...initializeOrg(),
organization: {
...initializeOrg().organization,
features: ['onboarding-project-deletion-on-back-click'],
},
router: {
params: routeParams,
},
});

MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${reactProject.slug}/docs/javascript-react-with-error-monitoring/`,
body: null,
});

MockApiClient.addMockResponse({
url: `/projects/org-slug/${reactProject.slug}/`,
body: [reactProject],
});

MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${reactProject.slug}/issues/`,
body: [],
});

ProjectsStore.loadInitialData([reactProject]);

render(
<OnboardingContextProvider
value={{
selectedSDK: {
key: reactProject.slug as PlatformKey,
type: 'framework',
language: 'javascript',
category: 'browser',
},
projects: {
[reactProject.id]: {
slug: reactProject.slug,
status: OnboardingProjectStatus.WAITING,
firstIssueId: undefined,
},
},
}}
>
<Onboarding
router={router}
location={router.location}
params={routeParams}
routes={router.routes}
routeParams={router.params}
route={route}
/>
</OnboardingContextProvider>,
{
context: routerContext,
organization,
}
);

// Await for the docs to be loaded
await screen.findByText('Configure React SDK');

renderGlobalModal();

// Click on back button
await userEvent.click(screen.getByRole('button', {name: 'Back'}));

// Await for the modal to be open
expect(
screen.queryByText(/Are you sure you want to head back?/)
).not.toBeInTheDocument();
});

it('renders framework selection modal if vanilla js is selected', async function () {
const routeParams = {
step: 'select-platform',
Expand Down Expand Up @@ -195,8 +376,8 @@ describe('Onboarding', function () {
// Select the JavaScript platform
await userEvent.click(screen.getByTestId('platform-javascript'));

// Click on create project button
await userEvent.click(screen.getByRole('button', {name: 'Create Project'}));
// Click on 'configure SDK' button
await userEvent.click(screen.getByRole('button', {name: 'Configure SDK'}));

// Modal is open
await screen.findByText('Do you use a framework?');
Expand Down Expand Up @@ -241,8 +422,8 @@ describe('Onboarding', function () {
// Select the React platform
await userEvent.click(screen.getByTestId('platform-javascript-react'));

// Click on create project button
await userEvent.click(screen.getByRole('button', {name: 'Create Project'}));
// Click on 'configure SDK' button
await userEvent.click(screen.getByRole('button', {name: 'Configure SDK'}));

// Modal shall not be open
expect(screen.queryByText('Do you use a framework?')).not.toBeInTheDocument();
Expand Down
Loading

0 comments on commit d8ac56e

Please sign in to comment.