featureTourModal.spec.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import {Fragment} from 'react';
  2. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  3. import GlobalModal from 'sentry/components/globalModal';
  4. import FeatureTourModal from 'sentry/components/modals/featureTourModal';
  5. import ModalStore from 'sentry/stores/modalStore';
  6. const steps = [
  7. {
  8. title: 'First',
  9. body: 'First step',
  10. image: <em data-test-id="step-image">Image</em>,
  11. actions: (
  12. <a href="#" data-test-id="step-action">
  13. additional action
  14. </a>
  15. ),
  16. },
  17. {title: 'Second', body: 'Second step'},
  18. ];
  19. describe('FeatureTourModal', function () {
  20. let onAdvance, onCloseModal;
  21. const createWrapper = (props = {}) =>
  22. render(
  23. <Fragment>
  24. <GlobalModal />
  25. <FeatureTourModal
  26. steps={steps}
  27. onAdvance={onAdvance}
  28. onCloseModal={onCloseModal}
  29. {...props}
  30. >
  31. {({showModal}) => (
  32. <a href="#" onClick={showModal} data-test-id="reveal">
  33. Open
  34. </a>
  35. )}
  36. </FeatureTourModal>
  37. </Fragment>
  38. );
  39. async function clickModal() {
  40. await userEvent.click(screen.getByTestId('reveal'));
  41. }
  42. beforeEach(function () {
  43. ModalStore.reset();
  44. onAdvance = jest.fn();
  45. onCloseModal = jest.fn();
  46. });
  47. it('shows the modal on click', async function () {
  48. createWrapper();
  49. // No modal showing
  50. expect(screen.queryByTestId('feature-tour')).not.toBeInTheDocument();
  51. await clickModal();
  52. // Modal is now showing
  53. expect(screen.getByTestId('feature-tour')).toBeInTheDocument();
  54. });
  55. it('advances on click', async function () {
  56. createWrapper();
  57. await clickModal();
  58. // Should start on the first step.
  59. expect(screen.getByRole('heading')).toHaveTextContent(steps[0].title);
  60. // Advance to the next step.
  61. await userEvent.click(screen.getByRole('button', {name: 'Next'}));
  62. // Should move to next step.
  63. expect(screen.getByRole('heading')).toHaveTextContent(steps[1].title);
  64. expect(onAdvance).toHaveBeenCalled();
  65. });
  66. it('shows step content', async function () {
  67. createWrapper();
  68. await clickModal();
  69. // Should show title, image and actions
  70. expect(screen.getByRole('heading')).toHaveTextContent(steps[0].title);
  71. expect(screen.getByTestId('step-image')).toBeInTheDocument();
  72. expect(screen.getByTestId('step-action')).toBeInTheDocument();
  73. expect(screen.getByText('1 of 2')).toBeInTheDocument();
  74. });
  75. it('last step shows done', async function () {
  76. createWrapper();
  77. await clickModal();
  78. // Advance to the the last step.
  79. await userEvent.click(screen.getByRole('button', {name: 'Next'}));
  80. // Click the done
  81. await userEvent.click(screen.getByRole('button', {name: 'Complete tour'}));
  82. // Wait for the ModalStore action to propagate.
  83. expect(onAdvance).toHaveBeenCalledTimes(1);
  84. expect(onCloseModal).toHaveBeenCalledTimes(1);
  85. });
  86. it('last step shows doneText and uses doneUrl', async function () {
  87. const props = {doneText: 'Finished', doneUrl: 'http://example.org'};
  88. createWrapper(props);
  89. await clickModal();
  90. // Advance to the the last step.
  91. await userEvent.click(screen.getByRole('button', {name: 'Next'}));
  92. // Ensure button looks right
  93. const button = screen.getByRole('button', {name: 'Complete tour'});
  94. expect(button).toHaveTextContent(props.doneText);
  95. expect(button).toHaveAttribute('href', props.doneUrl);
  96. // Click the done
  97. await userEvent.click(button);
  98. // Wait for the ModalStore action to propagate.
  99. expect(onCloseModal).toHaveBeenCalledTimes(1);
  100. });
  101. it('close button dismisses modal', async function () {
  102. createWrapper();
  103. await clickModal();
  104. await userEvent.click(screen.getByRole('button', {name: 'Close tour'}));
  105. // Wait for the ModalStore action to propagate.
  106. expect(onCloseModal).toHaveBeenCalled();
  107. });
  108. });