modal.spec.tsx 3.4 KB

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