indicators.spec.jsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 div').first().prop('style').opacity).toBe(0);
  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 div').first().prop('style').opacity).toBe(0);
  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');
  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');
  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(wrapper.find('Message').at(1).text()).toBe('Success');
  121. addMessage('Error', 'error', {append: true, duration: null});
  122. jest.runAllTimers();
  123. wrapper.update();
  124. expect(wrapper.find('ToastIndicator')).toHaveLength(3);
  125. // Toasts get appended to the end
  126. expect(wrapper.find('Message').at(2).text()).toBe('Error');
  127. // clears all toasts
  128. clearIndicators();
  129. jest.runAllTimers();
  130. wrapper.update();
  131. expect(
  132. wrapper
  133. .find('ToastIndicator div[style]')
  134. .everyWhere(div => div.prop('style').opacity === 0)
  135. ).toBe(true);
  136. });
  137. it('dismisses on click', function () {
  138. addMessage('Loading', '', {append: true, duration: null});
  139. jest.runAllTimers();
  140. wrapper.update();
  141. expect(wrapper.find('ToastIndicator')).toHaveLength(1);
  142. expect(wrapper.find('Message').text()).toBe('Loading');
  143. wrapper.find('ToastIndicator').simulate('click');
  144. jest.runAllTimers();
  145. wrapper.update();
  146. expect(wrapper.find('ToastIndicator div').first().prop('style').opacity).toBe(0);
  147. });
  148. it('hides after 10s', function () {
  149. addMessage('Duration', '', {append: true, duration: 10000});
  150. jest.advanceTimersByTime(9000);
  151. wrapper.update();
  152. expect(wrapper.find('Indicators')).toHaveLength(1);
  153. expect(wrapper.find('Indicators').prop('items')).toHaveLength(1);
  154. expect(wrapper.find('Message').text()).toBe('Duration');
  155. // Still visible
  156. jest.advanceTimersByTime(999);
  157. wrapper.update();
  158. expect(wrapper.find('Indicators').prop('items')).toHaveLength(1);
  159. // ToastIndicator still exist because of animations
  160. // but `items` prop should be empty
  161. jest.advanceTimersByTime(2);
  162. wrapper.update();
  163. expect(wrapper.find('Indicators').prop('items')).toHaveLength(0);
  164. // Animation is exiting
  165. expect(wrapper.find('ToastIndicator div').first().prop('style').opacity).toBe(0);
  166. });
  167. });