ruleBuilder.spec.jsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import selectEvent from 'react-select-event';
  2. import {
  3. render,
  4. screen,
  5. userEvent,
  6. waitFor,
  7. waitForElementToBeRemoved,
  8. } from 'sentry-test/reactTestingLibrary';
  9. import MemberListStore from 'sentry/stores/memberListStore';
  10. import ProjectsStore from 'sentry/stores/projectsStore';
  11. import TeamStore from 'sentry/stores/teamStore';
  12. import RuleBuilder from 'sentry/views/settings/project/projectOwnership/ruleBuilder';
  13. describe('RuleBuilder', function () {
  14. const organization = TestStubs.Organization();
  15. let project;
  16. let handleAdd;
  17. const USER_1 = TestStubs.User({
  18. id: '1',
  19. name: 'Jane Bloggs',
  20. email: 'janebloggs@example.com',
  21. user: {
  22. id: '1',
  23. name: 'Jane Bloggs',
  24. email: 'janebloggs@example.com',
  25. },
  26. });
  27. const USER_2 = TestStubs.User({
  28. id: '2',
  29. name: 'John Smith',
  30. email: 'johnsmith@example.com',
  31. user: {
  32. id: '2',
  33. name: 'John Smith',
  34. email: 'johnsmith@example.com',
  35. },
  36. });
  37. const TEAM_1 = TestStubs.Team({
  38. id: '3',
  39. slug: 'cool-team',
  40. });
  41. // This team is in project
  42. const TEAM_2 = TestStubs.Team({
  43. id: '4',
  44. slug: 'team-not-in-project',
  45. });
  46. beforeEach(function () {
  47. // User in project
  48. MemberListStore.loadInitialData([USER_1]);
  49. // All teams
  50. jest.spyOn(TeamStore, 'getAll').mockImplementation(() => [TEAM_1, TEAM_2]);
  51. handleAdd = jest.fn();
  52. project = TestStubs.Project({
  53. // Teams in project
  54. teams: [TEAM_1],
  55. });
  56. ProjectsStore.loadInitialData([project]);
  57. jest.spyOn(ProjectsStore, 'getBySlug').mockImplementation(() => project);
  58. MockApiClient.clearMockResponses();
  59. MockApiClient.addMockResponse({
  60. url: '/organizations/org-slug/members/',
  61. body: [USER_1, USER_2],
  62. });
  63. });
  64. it('renders', async function () {
  65. const {container} = render(
  66. <RuleBuilder project={project} organization={organization} onAddRule={handleAdd} />
  67. );
  68. const addButton = screen.getByRole('button', {name: 'Add rule'});
  69. await userEvent.click(addButton);
  70. expect(handleAdd).not.toHaveBeenCalled();
  71. await userEvent.type(
  72. screen.getByRole('textbox', {name: 'Rule pattern'}),
  73. 'some/path/*'
  74. );
  75. expect(addButton).toBeDisabled();
  76. await selectEvent.select(
  77. screen.getByRole('textbox', {name: 'Rule owner'}),
  78. 'Jane Bloggs'
  79. );
  80. expect(addButton).toBeEnabled();
  81. await userEvent.click(addButton);
  82. expect(handleAdd).toHaveBeenCalled();
  83. expect(container).toSnapshot();
  84. });
  85. it('renders with suggestions', async function () {
  86. const {container} = render(
  87. <RuleBuilder
  88. project={project}
  89. organization={organization}
  90. onAddRule={handleAdd}
  91. urls={['example.com/a', 'example.com/a/foo']}
  92. paths={['a/bar', 'a/foo']}
  93. />
  94. );
  95. // Open the menu so we can do some assertions.
  96. const ownerInput = screen.getByRole('textbox', {name: 'Rule owner'});
  97. selectEvent.openMenu(ownerInput);
  98. await waitForElementToBeRemoved(() => screen.queryByText('Loading...'));
  99. expect(screen.getByText('Jane Bloggs')).toBeInTheDocument();
  100. expect(screen.getByText('John Smith')).toBeInTheDocument();
  101. expect(screen.getByText('#cool-team')).toBeInTheDocument();
  102. expect(screen.getByText('#team-not-in-project')).toBeInTheDocument();
  103. // TODO Check that the last two are disabled
  104. // Enter to select Jane Bloggs
  105. await selectEvent.select(ownerInput, 'Jane Bloggs');
  106. const candidates = screen.getAllByRole('button', {name: 'Path rule candidate'});
  107. await userEvent.click(candidates[0]);
  108. expect(screen.getByRole('textbox', {name: 'Rule pattern'})).toHaveValue('a/bar');
  109. const addButton = screen.getByRole('button', {name: 'Add rule'});
  110. await waitFor(() => expect(addButton).toBeEnabled());
  111. expect(container).toSnapshot();
  112. await userEvent.click(addButton);
  113. expect(handleAdd).toHaveBeenCalled();
  114. });
  115. it('builds a tag rule', async function () {
  116. render(
  117. <RuleBuilder project={project} organization={organization} onAddRule={handleAdd} />
  118. );
  119. await selectEvent.select(screen.getByText('Path'), 'Tag');
  120. await userEvent.type(screen.getByPlaceholderText('tag-name'), 'mytag');
  121. await userEvent.type(screen.getByPlaceholderText('tag-value'), 'value');
  122. await selectEvent.select(
  123. screen.getByRole('textbox', {name: 'Rule owner'}),
  124. 'Jane Bloggs'
  125. );
  126. await userEvent.click(screen.getByRole('button', {name: 'Add rule'}));
  127. expect(handleAdd).toHaveBeenCalledWith('tags.mytag:value janebloggs@example.com');
  128. });
  129. });