123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- import {OrganizationFixture} from 'sentry-fixture/organization';
- import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture';
- import {initializeOrg} from 'sentry-test/initializeOrg';
- import {
- render,
- renderGlobalModal,
- screen,
- userEvent,
- waitFor,
- } from 'sentry-test/reactTestingLibrary';
- import SentryAppDetailedView from 'sentry/views/settings/organizationIntegrations/sentryAppDetailedView';
- describe('SentryAppDetailedView', function () {
- const org = OrganizationFixture();
- const {router} = initializeOrg({
- projects: [
- {isMember: true, isBookmarked: true},
- {isMember: true, slug: 'new-project', id: '3'},
- ],
- organization: {
- features: ['events'],
- },
- router: {
- location: {
- pathname: '/organizations/org-slug/events/',
- query: {},
- },
- },
- });
- afterEach(() => {
- MockApiClient.clearMockResponses();
- jest.clearAllMocks();
- });
- describe('Published Sentry App', function () {
- let createRequest;
- let deleteRequest;
- let sentryAppInteractionRequest;
- beforeEach(() => {
- sentryAppInteractionRequest = MockApiClient.addMockResponse({
- url: `/sentry-apps/clickup/interaction/`,
- method: 'POST',
- statusCode: 200,
- body: {},
- });
- MockApiClient.addMockResponse({
- url: '/sentry-apps/clickup/',
- body: {
- status: 'published',
- scopes: [],
- isAlertable: false,
- clientSecret:
- '193583e573d14d61832de96a9efc32ceb64e59a494284f58b50328a656420a55',
- overview: null,
- verifyInstall: false,
- owner: {id: 1, slug: 'sentry'},
- slug: 'clickup',
- name: 'ClickUp',
- uuid: '5d547ecb-7eb8-4ed2-853b-40256177d526',
- author: 'Nisanthan',
- webhookUrl: 'http://localhost:7000',
- clientId: 'c215db1accc040919e0b0dce058e0ecf4ea062bb82174d70aee8eba62351be24',
- redirectUrl: null,
- allowedOrigins: [],
- events: [],
- schema: {},
- },
- });
- MockApiClient.addMockResponse({
- url: '/sentry-apps/clickup/features/',
- body: [
- {
- featureGate: 'integrations-api',
- description:
- 'ClickUp can **utilize the Sentry API** to pull data or update resources in Sentry (with permissions granted, of course).',
- },
- ],
- });
- MockApiClient.addMockResponse({
- url: `/organizations/${org.slug}/sentry-app-installations/`,
- body: [],
- });
- createRequest = MockApiClient.addMockResponse({
- url: `/organizations/${org.slug}/sentry-app-installations/`,
- body: {
- status: 'installed',
- organization: {slug: `${org.slug}`},
- app: {uuid: '5d547ecb-7eb8-4ed2-853b-40256177d526', slug: 'clickup'},
- code: '1dc8b0a28b7f45959d01bbc99d9bd568',
- uuid: '687323fd-9fa4-4f8f-9bee-ca0089224b3e',
- },
- method: 'POST',
- });
- deleteRequest = MockApiClient.addMockResponse({
- url: '/sentry-app-installations/687323fd-9fa4-4f8f-9bee-ca0089224b3e/',
- body: {},
- method: 'DELETE',
- });
- });
- it('renders a published sentry app', () => {
- render(
- <SentryAppDetailedView
- {...RouteComponentPropsFixture()}
- params={{integrationSlug: 'clickup'}}
- />
- );
- expect(sentryAppInteractionRequest).toHaveBeenCalledWith(
- `/sentry-apps/clickup/interaction/`,
- expect.objectContaining({
- method: 'POST',
- data: {
- tsdbField: 'sentry_app_viewed',
- },
- })
- );
- // Shows the Integration name and install status
- expect(screen.getByText('ClickUp')).toBeInTheDocument();
- expect(screen.getByText('Not Installed')).toBeInTheDocument();
- // Shows the Accept & Install button
- expect(screen.getByRole('button', {name: 'Accept & Install'})).toBeEnabled();
- });
- it('installs and uninstalls', async function () {
- render(
- <SentryAppDetailedView
- {...RouteComponentPropsFixture()}
- params={{integrationSlug: 'clickup'}}
- />
- );
- renderGlobalModal();
- await userEvent.click(screen.getByRole('button', {name: 'Accept & Install'}));
- expect(createRequest).toHaveBeenCalledTimes(1);
- expect(await screen.findByRole('button', {name: 'Uninstall'})).toBeInTheDocument();
- await userEvent.click(screen.getByRole('button', {name: 'Uninstall'}));
- await userEvent.click(screen.getByRole('button', {name: 'Confirm'}));
- expect(deleteRequest).toHaveBeenCalledTimes(1);
- });
- });
- describe('Internal Sentry App', function () {
- beforeEach(() => {
- MockApiClient.addMockResponse({
- url: `/sentry-apps/my-headband-washer-289499/interaction/`,
- method: 'POST',
- statusCode: 200,
- body: {},
- });
- MockApiClient.addMockResponse({
- url: '/sentry-apps/my-headband-washer-289499/',
- body: {
- status: 'internal',
- scopes: [
- 'project:read',
- 'team:read',
- 'team:write',
- 'project:releases',
- 'event:read',
- 'org:read',
- 'member:read',
- 'member:write',
- ],
- isAlertable: false,
- clientSecret:
- '8f47dcef40f7486f9bacfeca257022e092a483add7cf4d619993b9ace9775a79',
- overview: null,
- verifyInstall: false,
- owner: {id: 1, slug: 'sentry'},
- slug: 'my-headband-washer-289499',
- name: 'My Headband Washer',
- uuid: 'a806ab10-9608-4a4f-8dd9-ca6d6c09f9f5',
- author: 'Sentry',
- webhookUrl: 'https://myheadbandwasher.com',
- clientId: 'a6d35972d4164ef18845b1e2ca954fe70ac196e0b20d4d1e8760a38772cf6f1c',
- redirectUrl: null,
- allowedOrigins: [],
- events: [],
- schema: {},
- },
- });
- MockApiClient.addMockResponse({
- url: '/sentry-apps/my-headband-washer-289499/features/',
- body: [
- {
- featureGate: 'integrations-api',
- description:
- 'My Headband Washer can **utilize the Sentry API** to pull data or update resources in Sentry (with permissions granted, of course).',
- },
- ],
- });
- MockApiClient.addMockResponse({
- url: `/organizations/${org.slug}/sentry-app-installations/`,
- body: [],
- });
- });
- it('should get redirected to Developer Settings', () => {
- render(
- <SentryAppDetailedView
- {...RouteComponentPropsFixture()}
- params={{integrationSlug: 'my-headband-washer-289499'}}
- router={router}
- />
- );
- expect(router.push).toHaveBeenLastCalledWith(
- `/settings/${org.slug}/developer-settings/my-headband-washer-289499/`
- );
- });
- });
- describe('Unpublished Sentry App without Redirect Url', function () {
- let createRequest;
- beforeEach(() => {
- MockApiClient.addMockResponse({
- url: `/sentry-apps/la-croix-monitor/interaction/`,
- method: 'POST',
- statusCode: 200,
- body: {},
- });
- MockApiClient.addMockResponse({
- url: '/sentry-apps/la-croix-monitor/',
- body: {
- status: 'unpublished',
- scopes: [
- 'project:read',
- 'project:write',
- 'team:read',
- 'project:releases',
- 'event:read',
- 'org:read',
- ],
- isAlertable: false,
- clientSecret:
- '2b2aeb743c3745ab832e03bf02a7d91851908d379646499f900cd115780e8b2b',
- overview: null,
- verifyInstall: false,
- owner: {id: 1, slug: 'sentry'},
- slug: 'la-croix-monitor',
- name: 'La Croix Monitor',
- uuid: 'a59c8fcc-2f27-49f8-af9e-02661fc3e8d7',
- author: 'La Croix',
- webhookUrl: 'https://lacroix.com',
- clientId: '8cc36458a0f94c93816e06dce7d808f882cbef59af6040d2b9ec4d67092c80f1',
- redirectUrl: null,
- allowedOrigins: [],
- events: [],
- schema: {},
- },
- });
- MockApiClient.addMockResponse({
- url: '/sentry-apps/la-croix-monitor/features/',
- body: [
- {
- featureGate: 'integrations-api',
- description:
- 'La Croix Monitor can **utilize the Sentry API** to pull data or update resources in Sentry (with permissions granted, of course).',
- },
- ],
- });
- MockApiClient.addMockResponse({
- url: `/organizations/${org.slug}/sentry-app-installations/`,
- body: [],
- });
- createRequest = MockApiClient.addMockResponse({
- url: `/organizations/${org.slug}/sentry-app-installations/`,
- method: 'POST',
- body: {
- status: 'installed',
- organization: {slug: 'sentry'},
- app: {uuid: 'a59c8fcc-2f27-49f8-af9e-02661fc3e8d7', slug: 'la-croix-monitor'},
- code: '21c87231918a4e5c85d9b9e799c07382',
- uuid: '258ad77c-7e6c-4cfe-8a40-6171cff30d61',
- },
- });
- });
- it('shows the Integration name and install status', function () {
- render(
- <SentryAppDetailedView
- {...RouteComponentPropsFixture()}
- params={{integrationSlug: 'la-croix-monitor'}}
- />
- );
- expect(screen.getByText('La Croix Monitor')).toBeInTheDocument();
- expect(screen.getByText('Not Installed')).toBeInTheDocument();
- });
- it('installs and uninstalls', async function () {
- render(
- <SentryAppDetailedView
- {...RouteComponentPropsFixture()}
- params={{integrationSlug: 'la-croix-monitor'}}
- />
- );
- renderGlobalModal();
- await userEvent.click(screen.getByRole('button', {name: 'Accept & Install'}));
- expect(createRequest).toHaveBeenCalledTimes(1);
- });
- });
- describe('Unpublished Sentry App with Redirect Url', function () {
- let createRequest;
- beforeEach(() => {
- MockApiClient.addMockResponse({
- url: `/sentry-apps/go-to-google/interaction/`,
- method: 'POST',
- statusCode: 200,
- body: {},
- });
- MockApiClient.addMockResponse({
- url: '/sentry-apps/go-to-google/',
- body: {
- status: 'unpublished',
- scopes: ['project:read', 'team:read'],
- isAlertable: false,
- clientSecret:
- '6405a4a7b8084cdf8dbea53b53e2163983deb428b78e4c6997bc408d44d93878',
- overview: null,
- verifyInstall: false,
- owner: {id: 1, slug: 'sentry'},
- slug: 'go-to-google',
- name: 'Go to Google',
- uuid: 'a4b8f364-4300-41ac-b8af-d8791ad50e77',
- author: 'Nisanthan Nanthakumar',
- webhookUrl: 'https://www.google.com',
- clientId: '0974b5df6b57480b99c2e1f238eef769ef2c27ec156d4791a26903a896d5807e',
- redirectUrl: 'https://www.google.com',
- allowedOrigins: [],
- events: [],
- schema: {},
- },
- });
- MockApiClient.addMockResponse({
- url: '/sentry-apps/go-to-google/features/',
- body: [
- {
- featureGate: 'integrations-api',
- description:
- 'Go to Google can **utilize the Sentry API** to pull data or update resources in Sentry (with permissions granted, of course).',
- },
- ],
- });
- MockApiClient.addMockResponse({
- url: `/organizations/${org.slug}/sentry-app-installations/`,
- body: [],
- });
- createRequest = MockApiClient.addMockResponse({
- url: `/organizations/${org.slug}/sentry-app-installations/`,
- body: {
- status: 'installed',
- organization: {slug: 'sentry'},
- app: {uuid: 'a4b8f364-4300-41ac-b8af-d8791ad50e77', slug: 'go-to-google'},
- code: '1f0e7c1b99b940abac7a19b86e69bbe1',
- uuid: '4d803538-fd42-4278-b410-492f5ab677b5',
- },
- method: 'POST',
- });
- });
- it('shows the Integration name and install status', function () {
- render(
- <SentryAppDetailedView
- {...RouteComponentPropsFixture()}
- params={{integrationSlug: 'go-to-google'}}
- />
- );
- expect(screen.getByText('Go to Google')).toBeInTheDocument();
- expect(screen.getByText('Not Installed')).toBeInTheDocument();
- // Shows the Accept & Install button
- expect(screen.getByRole('button', {name: 'Accept & Install'})).toBeEnabled();
- });
- it('onClick: redirects url', async function () {
- render(
- <SentryAppDetailedView
- {...RouteComponentPropsFixture()}
- params={{integrationSlug: 'go-to-google'}}
- />
- );
- const locationAssignSpy = jest.spyOn(window.location, 'assign');
- await userEvent.click(screen.getByRole('button', {name: 'Accept & Install'}));
- expect(createRequest).toHaveBeenCalled();
- await waitFor(() => {
- expect(locationAssignSpy).toHaveBeenLastCalledWith(
- 'https://www.google.com/?code=1f0e7c1b99b940abac7a19b86e69bbe1&installationId=4d803538-fd42-4278-b410-492f5ab677b5&orgSlug=org-slug'
- );
- });
- });
- });
- });
|