guideStore.spec.jsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import React from 'react';
  2. import GuideStore from 'app/stores/guideStore';
  3. import GuideAnchor from 'app/components/assistant/guideAnchor';
  4. import ConfigStore from 'app/stores/configStore';
  5. describe('GuideStore', function() {
  6. let sandbox;
  7. let anchor1 = <GuideAnchor target="target 1" type="text" />;
  8. let anchor2 = <GuideAnchor target="target 2" type="text" />;
  9. let data;
  10. beforeEach(function() {
  11. ConfigStore.config = {
  12. user: {
  13. isSuperuser: true,
  14. },
  15. };
  16. GuideStore.init();
  17. sandbox = sinon.sandbox.create();
  18. data = {
  19. Guide1: {
  20. cue: 'Click here for a tour of the issue page',
  21. id: 1,
  22. required_targets: ['target 1'],
  23. steps: [
  24. {message: 'Message 1', target: 'target 1', title: '1. Title 1'},
  25. {message: 'Message 2', target: 'target 2', title: '2. Title 2'},
  26. {message: 'Message 3', target: 'target 3', title: '3. Title 3'},
  27. ],
  28. seen: true,
  29. },
  30. Guide2: {
  31. cue: 'Some other guide here',
  32. id: 2,
  33. required_targets: ['target 1'],
  34. steps: [
  35. {message: 'Message 1', target: 'target 1', title: '1. Title 1'},
  36. {message: 'Message 2', target: 'target 2', title: '2. Title 2'},
  37. ],
  38. seen: false,
  39. },
  40. alert_reminder_1: {
  41. id: 3,
  42. guide_type: 'tip',
  43. required_targets: ['target 1'],
  44. steps: [{message: 'Message 1', target: 'target 1', title: '1. Title 1'}],
  45. seen: false,
  46. },
  47. };
  48. GuideStore.onRegisterAnchor(anchor1);
  49. GuideStore.onRegisterAnchor(anchor2);
  50. MockApiClient.addMockResponse({
  51. url: '/projects/org/proj/stats/',
  52. body: [[1, 500], [2, 300], [3, 500]],
  53. });
  54. MockApiClient.addMockResponse({
  55. url: '/projects/org/proj/rules/',
  56. body: [],
  57. });
  58. });
  59. afterEach(function() {
  60. sandbox.restore();
  61. });
  62. it('should move through the steps in the guide', async function() {
  63. GuideStore.onFetchSucceeded(data);
  64. await tick();
  65. let guide = GuideStore.state.currentGuide;
  66. // Should pick the first non-seen guide in alphabetic order.
  67. expect(guide.id).toEqual(2);
  68. expect(guide.steps).toHaveLength(2);
  69. GuideStore.onNextStep();
  70. expect(GuideStore.state.currentStep).toEqual(1);
  71. GuideStore.onCloseGuide();
  72. await tick();
  73. guide = GuideStore.state.currentGuide;
  74. // We don't have the alert reminder guide's data yet, so we can't show it.
  75. expect(guide).toEqual(null);
  76. });
  77. it('should force show a guide', async function() {
  78. GuideStore.onFetchSucceeded(data);
  79. await tick();
  80. window.location.hash = '#assistant';
  81. GuideStore.onURLChange();
  82. await tick();
  83. expect(GuideStore.state.currentGuide.id).toEqual(1);
  84. // Should prune steps that don't have anchors.
  85. expect(GuideStore.state.currentGuide.steps).toHaveLength(2);
  86. GuideStore.onCloseGuide();
  87. await tick();
  88. expect(GuideStore.state.currentGuide.id).toEqual(2);
  89. window.location.hash = '';
  90. });
  91. it('should render tip', async function() {
  92. GuideStore.onFetchSucceeded({
  93. ...data,
  94. Guide2: {
  95. ...data.Guide2,
  96. seen: true,
  97. },
  98. });
  99. expect(GuideStore.state.currentGuide).toEqual(null);
  100. let spy = jest.spyOn(GuideStore, 'isDefaultAlert').mockImplementation(() => true);
  101. GuideStore.onSetActiveOrganization({id: 1, slug: 'org'});
  102. GuideStore.onSetActiveProject({id: 1, slug: 'proj'});
  103. await tick();
  104. expect(GuideStore.state.currentGuide.id).toEqual(3);
  105. spy.mockRestore();
  106. });
  107. it('should record analytics events when guide is cued', async function() {
  108. let spy = jest.spyOn(GuideStore, 'recordCue');
  109. GuideStore.onFetchSucceeded(data);
  110. await tick();
  111. expect(spy).toHaveBeenCalledWith(data.Guide2.id, data.Guide2.cue);
  112. expect(spy).toHaveBeenCalledTimes(1);
  113. spy.mockRestore();
  114. });
  115. it('should not send multiple cue analytics events for same guide', async function() {
  116. let spy = jest.spyOn(GuideStore, 'recordCue');
  117. GuideStore.onFetchSucceeded(data);
  118. await tick();
  119. expect(spy).toHaveBeenCalledWith(data.Guide2.id, data.Guide2.cue);
  120. expect(spy).toHaveBeenCalledTimes(1);
  121. GuideStore.updateCurrentGuide();
  122. await tick();
  123. expect(spy).toHaveBeenCalledTimes(1);
  124. spy.mockRestore();
  125. });
  126. });