ruleBuilder.spec.jsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import React from 'react';
  2. import {mountWithTheme} from 'sentry-test/enzyme';
  3. import MemberListStore from 'app/stores/memberListStore';
  4. import TeamStore from 'app/stores/teamStore';
  5. import ProjectsStore from 'app/stores/projectsStore';
  6. import RuleBuilder from 'app/views/settings/project/projectOwnership/ruleBuilder';
  7. jest.mock('jquery');
  8. describe('RuleBuilder', function() {
  9. const organization = TestStubs.Organization();
  10. let project;
  11. let handleAdd;
  12. const USER_1 = TestStubs.User({
  13. id: '1',
  14. name: 'Jane Doe',
  15. email: 'janedoe@example.com',
  16. user: {
  17. id: '1',
  18. name: 'Jane Doe',
  19. email: 'janedoe@example.com',
  20. },
  21. });
  22. const USER_2 = TestStubs.User({
  23. id: '2',
  24. name: 'John Smith',
  25. email: 'johnsmith@example.com',
  26. user: {
  27. id: '2',
  28. name: 'John Smith',
  29. email: 'johnsmith@example.com',
  30. },
  31. });
  32. const TEAM_1 = TestStubs.Team({
  33. id: '3',
  34. name: 'COOL TEAM',
  35. slug: 'cool-team',
  36. });
  37. // This team is in project
  38. const TEAM_2 = TestStubs.Team({
  39. id: '4',
  40. name: 'TEAM NOT IN PROJECT',
  41. slug: 'team-not-in-project',
  42. });
  43. beforeEach(function() {
  44. // User in project
  45. MemberListStore.loadInitialData([USER_1]);
  46. // All teams
  47. jest.spyOn(TeamStore, 'getAll').mockImplementation(() => [TEAM_1, TEAM_2]);
  48. handleAdd = jest.fn();
  49. project = TestStubs.Project({
  50. // Teams in project
  51. teams: [TEAM_1],
  52. });
  53. ProjectsStore.loadInitialData([project]);
  54. jest.spyOn(ProjectsStore, 'getBySlug').mockImplementation(() => project);
  55. MockApiClient.clearMockResponses();
  56. MockApiClient.addMockResponse({
  57. url: '/organizations/org-slug/members/',
  58. body: [USER_1, USER_2],
  59. });
  60. });
  61. afterEach(function() {});
  62. it('renders', async function() {
  63. const wrapper = mountWithTheme(
  64. <RuleBuilder project={project} organization={organization} onAddRule={handleAdd} />,
  65. TestStubs.routerContext()
  66. );
  67. await tick();
  68. wrapper.update();
  69. const add = wrapper.find('Button');
  70. add.simulate('click');
  71. expect(handleAdd).not.toHaveBeenCalled();
  72. const text = wrapper.find('BuilderInput');
  73. text.simulate('change', {target: {value: 'some/path/*'}});
  74. expect(wrapper.find('Button').prop('disabled')).toBe(true);
  75. add.simulate('click');
  76. expect(handleAdd).not.toHaveBeenCalled();
  77. // Simulate select first element via down arrow / enter
  78. wrapper.find('SelectOwners .Select-control').simulate('keyDown', {keyCode: 40});
  79. wrapper.find('SelectOwners .Select-control').simulate('keyDown', {keyCode: 13});
  80. expect(wrapper.find('Button').prop('disabled')).toBe(false);
  81. add.simulate('click');
  82. expect(handleAdd).toHaveBeenCalled();
  83. // This is because after selecting, react-select (async) reloads
  84. await tick();
  85. wrapper.update();
  86. expect(wrapper.find(RuleBuilder)).toMatchSnapshot();
  87. });
  88. it('renders with suggestions', async function() {
  89. const wrapper = mountWithTheme(
  90. <RuleBuilder
  91. project={project}
  92. organization={organization}
  93. onAddRule={handleAdd}
  94. urls={['example.com/a', 'example.com/a/foo']}
  95. paths={['a/bar', 'a/foo']}
  96. />,
  97. TestStubs.routerContext()
  98. );
  99. wrapper.find('SelectOwners .Select-input input').simulate('focus');
  100. await tick();
  101. wrapper.update();
  102. // Simulate select first element via down arrow / enter
  103. wrapper.find('SelectOwners .Select-control').simulate('keyDown', {keyCode: 40});
  104. // Should have all 4 users/teams listed
  105. expect(wrapper.find('IdBadge')).toHaveLength(4);
  106. // Should have 1 user not in project and 1 team not in project
  107. expect(wrapper.find('DisabledLabel IdBadge')).toHaveLength(2);
  108. // Team not in project should not be selectable
  109. expect(
  110. wrapper
  111. .find('DisabledLabel IdBadge')
  112. .at(0)
  113. .prop('team').id
  114. ).toBe('4');
  115. // John Smith should not be selectable
  116. expect(
  117. wrapper
  118. .find('DisabledLabel IdBadge')
  119. .at(1)
  120. .prop('user').id
  121. ).toBe('2');
  122. // Enter to select Jane Doe
  123. wrapper.find('SelectOwners .Select-control').simulate('keyDown', {keyCode: 13});
  124. const ruleCandidate = wrapper.find('RuleCandidate').first();
  125. ruleCandidate.simulate('click');
  126. // This is because after selecting, react-select (async) reloads
  127. await tick();
  128. wrapper.update();
  129. expect(wrapper.find(RuleBuilder)).toMatchSnapshot();
  130. wrapper.find('Button').simulate('click');
  131. expect(handleAdd).toHaveBeenCalled();
  132. });
  133. });