modal.spec.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import {EventEntryStacktrace} from 'sentry-fixture/eventEntryStacktrace';
  2. import {Members} from 'sentry-fixture/members';
  3. import {Organization} from 'sentry-fixture/organization';
  4. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  5. import ConfigStore from 'sentry/stores/configStore';
  6. import ProjectOwnershipModal from './modal';
  7. describe('Project Ownership', () => {
  8. const org = Organization();
  9. const project = TestStubs.Project();
  10. const issueId = '1234';
  11. const stacktrace = EventEntryStacktrace();
  12. const event = TestStubs.Event({
  13. entries: [stacktrace],
  14. });
  15. const user = TestStubs.User();
  16. beforeEach(() => {
  17. ConfigStore.set('user', user);
  18. MockApiClient.addMockResponse({
  19. url: `/issues/${issueId}/tags/url/`,
  20. body: {
  21. key: 'url',
  22. name: 'URL',
  23. uniqueValues: 1,
  24. totalValues: 1,
  25. topValues: [
  26. {
  27. key: 'url',
  28. name: 'https://example.com/path',
  29. value: 'https://example.com/path',
  30. count: 1,
  31. lastSeen: '2022-08-27T03:24:53Z',
  32. firstSeen: '2022-08-27T03:24:53Z',
  33. },
  34. ],
  35. },
  36. });
  37. MockApiClient.addMockResponse({
  38. url: `/projects/${org.slug}/${project.slug}/ownership/`,
  39. body: {
  40. fallthrough: false,
  41. autoAssignment: 'Auto Assign to Suspect Commits',
  42. codeownersAutoSync: false,
  43. raw: null,
  44. },
  45. });
  46. // Set one frame to in-app
  47. stacktrace.data.frames![0].inApp = true;
  48. MockApiClient.addMockResponse({
  49. url: `/organizations/${org.slug}/members/`,
  50. body: Members(),
  51. });
  52. });
  53. afterEach(() => {
  54. MockApiClient.clearMockResponses();
  55. });
  56. it('renders stacktrace suggestions', () => {
  57. render(
  58. <ProjectOwnershipModal
  59. issueId={issueId}
  60. organization={org}
  61. project={project}
  62. eventData={event}
  63. onCancel={() => {}}
  64. />
  65. );
  66. // Rule builder
  67. expect(screen.getByLabelText('Rule pattern')).toBeInTheDocument();
  68. expect(screen.getByText(/Match against Issue Data/)).toBeInTheDocument();
  69. // First in-app (default reverse order) frame is suggested
  70. expect(screen.getByText('raven/base.py')).toBeInTheDocument();
  71. expect(screen.getByText('https://example.com/path')).toBeInTheDocument();
  72. });
  73. it('renders streamline-targeting-context suggestions', () => {
  74. render(
  75. <ProjectOwnershipModal
  76. issueId={issueId}
  77. organization={{...org, features: ['streamline-targeting-context']}}
  78. project={project}
  79. eventData={event}
  80. onCancel={() => {}}
  81. />
  82. );
  83. // Description
  84. expect(screen.getByText(/Assign issues based on custom rules/)).toBeInTheDocument();
  85. // Suggestions
  86. expect(
  87. screen.getByText(/Here’s some suggestions based on this issue/)
  88. ).toBeInTheDocument();
  89. expect(
  90. screen.getByText(`path:raven/base.py ${user.email}`, {exact: false})
  91. ).toBeInTheDocument();
  92. expect(
  93. screen.getByText(`url:*/path ${user.email}`, {exact: false})
  94. ).toBeInTheDocument();
  95. // Rule builder hidden TODO: remove when streamline-targeting-context is GA
  96. expect(screen.queryByLabelText('Rule pattern')).not.toBeInTheDocument();
  97. });
  98. it('can cancel', async () => {
  99. const onCancel = jest.fn();
  100. render(
  101. <ProjectOwnershipModal
  102. issueId={issueId}
  103. organization={org}
  104. project={project}
  105. eventData={event}
  106. onCancel={onCancel}
  107. />
  108. );
  109. // Cancel
  110. await userEvent.click(screen.getByText('Cancel'));
  111. expect(onCancel).toHaveBeenCalled();
  112. });
  113. });