guideStore.spec.jsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import {logExperiment, trackAnalyticsEvent} from 'app/utils/analytics';
  2. import ConfigStore from 'app/stores/configStore';
  3. import GuideStore from 'app/stores/guideStore';
  4. jest.mock('app/utils/analytics');
  5. describe('GuideStore', function() {
  6. let data;
  7. const user = {
  8. id: '5',
  9. isSuperuser: false,
  10. dateJoined: new Date(2020, 0, 1),
  11. };
  12. beforeEach(function() {
  13. trackAnalyticsEvent.mockClear();
  14. logExperiment.mockClear();
  15. ConfigStore.config = {
  16. user,
  17. };
  18. GuideStore.init();
  19. data = [
  20. {
  21. guide: 'issue',
  22. seen: false,
  23. },
  24. {guide: 'issue_stream', seen: true},
  25. ];
  26. GuideStore.onRegisterAnchor('issue_title');
  27. GuideStore.onRegisterAnchor('exception');
  28. GuideStore.onRegisterAnchor('breadcrumbs');
  29. GuideStore.onRegisterAnchor('issue_stream');
  30. });
  31. it('should move through the steps in the guide', function() {
  32. GuideStore.onFetchSucceeded(data);
  33. // Should pick the first non-seen guide in alphabetic order.
  34. expect(GuideStore.state.currentStep).toEqual(0);
  35. expect(GuideStore.state.currentGuide.guide).toEqual('issue');
  36. // Should prune steps that don't have anchors.
  37. expect(GuideStore.state.currentGuide.steps).toHaveLength(3);
  38. GuideStore.onNextStep();
  39. expect(GuideStore.state.currentStep).toEqual(1);
  40. GuideStore.onNextStep();
  41. expect(GuideStore.state.currentStep).toEqual(2);
  42. GuideStore.onCloseGuide();
  43. expect(GuideStore.state.currentGuide).toEqual(null);
  44. });
  45. it('should force show a guide with #assistant', function() {
  46. data = [
  47. {
  48. guide: 'issue',
  49. seen: true,
  50. },
  51. {guide: 'issue_stream', seen: false},
  52. ];
  53. GuideStore.onFetchSucceeded(data);
  54. window.location.hash = '#assistant';
  55. GuideStore.onURLChange();
  56. expect(GuideStore.state.currentGuide.guide).toEqual('issue');
  57. GuideStore.onCloseGuide();
  58. expect(GuideStore.state.currentGuide.guide).toEqual('issue_stream');
  59. window.location.hash = '';
  60. });
  61. it('should record analytics events when guide is cued', function() {
  62. const spy = jest.spyOn(GuideStore, 'recordCue');
  63. GuideStore.onFetchSucceeded(data);
  64. expect(spy).toHaveBeenCalledWith('issue');
  65. expect(trackAnalyticsEvent).toHaveBeenCalledWith({
  66. guide: 'issue',
  67. eventKey: 'assistant.guide_cued',
  68. eventName: 'Assistant Guide Cued',
  69. organization_id: null,
  70. user_id: parseInt(user.id, 10),
  71. });
  72. expect(spy).toHaveBeenCalledTimes(1);
  73. GuideStore.updateCurrentGuide();
  74. expect(spy).toHaveBeenCalledTimes(1);
  75. GuideStore.onNextStep();
  76. expect(spy).toHaveBeenCalledTimes(1);
  77. spy.mockRestore();
  78. expect(logExperiment).toHaveBeenCalledWith({
  79. key: 'AssistantGuideExperiment',
  80. unitName: 'user_id',
  81. unitId: parseInt(user.id, 10),
  82. param: 'variant',
  83. });
  84. });
  85. it('only shows guides with server data and content', function() {
  86. data = [
  87. {
  88. guide: 'issue',
  89. seen: true,
  90. },
  91. {
  92. guide: 'has_no_content',
  93. seen: false,
  94. },
  95. ];
  96. GuideStore.onFetchSucceeded(data);
  97. expect(GuideStore.state.guides.length).toBe(1);
  98. expect(GuideStore.state.guides[0].guide).toBe(data[0].guide);
  99. });
  100. describe('discover sidebar guide', function() {
  101. beforeEach(function() {
  102. data = [
  103. {
  104. guide: 'discover_sidebar',
  105. seen: false,
  106. },
  107. ];
  108. GuideStore.onRegisterAnchor('discover_sidebar');
  109. });
  110. it('does not render without user', function() {
  111. ConfigStore.config = {};
  112. GuideStore.onFetchSucceeded(data);
  113. expect(GuideStore.state.currentGuide).toBe(null);
  114. });
  115. it('shows discover sidebar guide to superusers', function() {
  116. ConfigStore.config = {
  117. user: {
  118. isSuperuser: true,
  119. },
  120. };
  121. GuideStore.onFetchSucceeded(data);
  122. expect(GuideStore.state.currentGuide.guide).toBe('discover_sidebar');
  123. });
  124. it('shows discover sidebar guide to previously existing users', function() {
  125. ConfigStore.config = {
  126. user: {
  127. isSuperuser: false,
  128. dateJoined: new Date(2020, 0, 1),
  129. },
  130. };
  131. GuideStore.onFetchSucceeded(data);
  132. expect(GuideStore.state.currentGuide.guide).toBe('discover_sidebar');
  133. });
  134. it('does not show discover sidebar guide to new users', function() {
  135. ConfigStore.config = {
  136. user: {
  137. isSuperuser: false,
  138. dateJoined: new Date(2020, 1, 22),
  139. },
  140. };
  141. GuideStore.onFetchSucceeded(data);
  142. expect(GuideStore.state.currentGuide).toBe(null);
  143. });
  144. it('hides discover sidebar guide once seen', function() {
  145. data[0].seen = true;
  146. // previous user
  147. ConfigStore.config = {
  148. user: {
  149. isSuperuser: false,
  150. dateJoined: new Date(2020, 0, 1),
  151. },
  152. };
  153. GuideStore.onFetchSucceeded(data);
  154. expect(GuideStore.state.currentGuide).toBe(null);
  155. });
  156. it('does not force show the discover sidebar guide once seen', function() {
  157. data[0].seen = true;
  158. // previous user
  159. ConfigStore.config = {
  160. user: {
  161. isSuperuser: false,
  162. dateJoined: new Date(2020, 0, 1),
  163. },
  164. };
  165. GuideStore.onFetchSucceeded(data);
  166. window.location.hash = '#assistant';
  167. GuideStore.onURLChange();
  168. expect(GuideStore.state.currentGuide).toBe(null);
  169. });
  170. });
  171. });