indicators.spec.jsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import React from 'react';
  2. import {mount} from 'sentry-test/enzyme';
  3. import Indicators from 'app/components/indicators';
  4. import IndicatorStore from 'app/stores/indicatorStore';
  5. import {
  6. clearIndicators,
  7. addSuccessMessage,
  8. addErrorMessage,
  9. addMessage,
  10. } from 'app/actionCreators/indicator';
  11. // Make sure we use `duration: null` to test add/remove
  12. jest.useFakeTimers();
  13. describe('Indicators', function() {
  14. let wrapper;
  15. beforeEach(function() {
  16. wrapper = mount(<Indicators />, TestStubs.routerContext());
  17. clearIndicators();
  18. jest.runAllTimers();
  19. });
  20. it('renders nothing by default', function() {
  21. expect(wrapper.find('ToastIndicator')).toHaveLength(0);
  22. });
  23. it('has a loading indicator by default', function() {
  24. // when "type" is empty, we should treat it as loading state
  25. IndicatorStore.add('Loading');
  26. wrapper.update();
  27. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  28. });
  29. it('adds and removes a toast by calling IndicatorStore directly', function() {
  30. // when "type" is empty, we should treat it as loading state
  31. const indicator = IndicatorStore.add('Loading');
  32. wrapper.update();
  33. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  34. expect(wrapper.find('Message').text()).toBe('Loading');
  35. jest.runAllTimers();
  36. wrapper.update();
  37. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  38. // Old indicator gets replaced when a new one is added
  39. IndicatorStore.remove(indicator);
  40. jest.runAllTimers();
  41. wrapper.update();
  42. expect(wrapper.find('ToastIndicator').prop('_pose')).toBe('exit');
  43. });
  44. // This is a common pattern used throughout the code for API calls
  45. it('adds and replaces toast by calling IndicatorStore directly', function() {
  46. IndicatorStore.add('Loading');
  47. wrapper.update();
  48. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  49. expect(wrapper.find('Message').text()).toBe('Loading');
  50. // Old indicator gets replaced when a new one is added
  51. IndicatorStore.add('success', 'success');
  52. jest.runAllTimers();
  53. wrapper.update();
  54. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  55. expect(wrapper.find('Message').text()).toBe('success');
  56. });
  57. it('does not have loading indicator when "type" is empty (default)', function() {
  58. addMessage('Loading', '', {duration: null});
  59. jest.runAllTimers();
  60. wrapper.update();
  61. expect(wrapper.find('LoadingIndicator')).toHaveLength(0);
  62. });
  63. it('has a loading indicator when type is "loading"', function() {
  64. addMessage('Loading', 'loading', {duration: null});
  65. jest.runAllTimers();
  66. wrapper.update();
  67. expect(wrapper.find('LoadingIndicator')).toHaveLength(1);
  68. });
  69. it('adds and removes toast by calling action creators', function() {
  70. // action creators don't return anything
  71. addMessage('Loading', '', {duration: null});
  72. jest.runAllTimers();
  73. wrapper.update();
  74. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  75. expect(wrapper.find('Message').text()).toBe('Loading');
  76. // If no indicator is specified, will remove all indicators
  77. clearIndicators();
  78. jest.runAllTimers();
  79. wrapper.update();
  80. expect(wrapper.find('ToastIndicator').prop('_pose')).toBe('exit');
  81. });
  82. it('adds and replaces toast by calling action creators', function() {
  83. addMessage('Loading', '', {duration: null});
  84. jest.runAllTimers();
  85. wrapper.update();
  86. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  87. expect(wrapper.find('Message').text()).toBe('Loading');
  88. // Old indicator gets replaced when a new one is added
  89. addMessage('success', 'success', {duration: null});
  90. jest.runAllTimers();
  91. wrapper.update();
  92. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  93. expect(wrapper.find('Message').text()).toBe('success');
  94. });
  95. it('adds and replaces toasts by calling action creators helpers', function() {
  96. // Old indicator gets replaced when a new one is added
  97. addSuccessMessage('success', null);
  98. jest.runAllTimers();
  99. wrapper.update();
  100. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  101. expect(wrapper.find('Message').text()).toBe('success');
  102. clearIndicators();
  103. addErrorMessage('error', null);
  104. jest.runAllTimers();
  105. wrapper.update();
  106. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  107. expect(wrapper.find('Message').text()).toBe('error');
  108. });
  109. it('appends toasts', function() {
  110. addMessage('Loading', '', {append: true, duration: null});
  111. jest.runAllTimers();
  112. wrapper.update();
  113. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  114. expect(wrapper.find('Message').text()).toBe('Loading');
  115. addMessage('Success', 'success', {append: true, duration: null});
  116. jest.runAllTimers();
  117. wrapper.update();
  118. expect(wrapper.find('ToastIndicator')).toHaveLength(2);
  119. // Toasts get appended to the end
  120. expect(
  121. wrapper
  122. .find('Message')
  123. .at(1)
  124. .text()
  125. ).toBe('Success');
  126. addMessage('Error', 'error', {append: true, duration: null});
  127. jest.runAllTimers();
  128. wrapper.update();
  129. expect(wrapper.find('ToastIndicator')).toHaveLength(3);
  130. // Toasts get appended to the end
  131. expect(
  132. wrapper
  133. .find('Message')
  134. .at(2)
  135. .text()
  136. ).toBe('Error');
  137. // clears all toasts
  138. clearIndicators();
  139. jest.runAllTimers();
  140. wrapper.update();
  141. expect(wrapper.find('ToastIndicator[_pose="exit"]')).toHaveLength(3);
  142. });
  143. it('dismisses on click', function() {
  144. addMessage('Loading', '', {append: true, duration: null});
  145. jest.runAllTimers();
  146. wrapper.update();
  147. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  148. expect(wrapper.find('Message').text()).toBe('Loading');
  149. wrapper.find('ToastIndicator').simulate('click');
  150. jest.runAllTimers();
  151. wrapper.update();
  152. expect(wrapper.find('ToastIndicator').prop('_pose')).toBe('exit');
  153. });
  154. it('hides after 10s', function() {
  155. addMessage('Duration', '', {append: true, duration: 10000});
  156. jest.advanceTimersByTime(9000);
  157. wrapper.update();
  158. expect(wrapper.find('Indicators')).toHaveLength(1);
  159. expect(wrapper.find('Indicators').prop('items')).toHaveLength(1);
  160. expect(wrapper.find('Message').text()).toBe('Duration');
  161. // Still visible
  162. jest.advanceTimersByTime(999);
  163. wrapper.update();
  164. expect(wrapper.find('Indicators').prop('items')).toHaveLength(1);
  165. // ToastIndicator still exist because of animations
  166. // but `items` prop should be empty
  167. jest.advanceTimersByTime(2);
  168. wrapper.update();
  169. expect(wrapper.find('Indicators').prop('items')).toHaveLength(0);
  170. // Animation is exiting
  171. expect(wrapper.find('ToastIndicator').prop('_pose')).toBe('exit');
  172. });
  173. });