modal.spec.tsx 3.5 KB

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