reactTestingLibrary.spec.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import {useRef} from 'react';
  2. import {useSearchParams} from 'react-router-dom';
  3. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  4. import Link from 'sentry/components/links/link';
  5. import {useLocation} from 'sentry/utils/useLocation';
  6. import {useNavigate} from 'sentry/utils/useNavigate';
  7. import {useParams} from 'sentry/utils/useParams';
  8. describe('rerender', () => {
  9. // Taken from https://testing-library.com/docs/example-update-props/
  10. let idCounter = 1;
  11. function NumberDisplay({number}: {number: number}) {
  12. const id = useRef(idCounter++); // to ensure we don't remount a different instance
  13. return (
  14. <div>
  15. <span data-test-id="number-display">{number}</span>
  16. <span data-test-id="instance-id">{id.current}</span>
  17. </div>
  18. );
  19. }
  20. test('calling render with the same component on the same container does not remount', () => {
  21. const {rerender} = render(<NumberDisplay number={1} />);
  22. expect(screen.getByTestId('number-display')).toHaveTextContent('1');
  23. // re-render the same component with different props
  24. rerender(<NumberDisplay number={2} />);
  25. expect(screen.getByTestId('number-display')).toHaveTextContent('2');
  26. expect(screen.getByTestId('instance-id')).toHaveTextContent('1');
  27. });
  28. });
  29. describe('disableRouterMocks', () => {
  30. it('starts with the correct initial location', () => {
  31. const {router} = render(<div />, {
  32. disableRouterMocks: true,
  33. initialRouterConfig: {location: '/foo/'},
  34. });
  35. expect(router.location.pathname).toBe('/foo/');
  36. });
  37. it('should react to clicking a Link', async () => {
  38. function TestComp() {
  39. const location = useLocation();
  40. return (
  41. <div>
  42. <Link to="/foo/bar/">Click me</Link>
  43. <div>You are at: {location.pathname}</div>
  44. </div>
  45. );
  46. }
  47. const {router} = render(<TestComp />, {
  48. disableRouterMocks: true,
  49. });
  50. const link = screen.getByText('Click me');
  51. await userEvent.click(link);
  52. expect(await screen.findByText('You are at: /foo/bar/')).toBeInTheDocument();
  53. expect(router.location.pathname).toBe('/foo/bar/');
  54. });
  55. it('should react to useNavigate()', async () => {
  56. function TestComp() {
  57. const location = useLocation();
  58. const navigate = useNavigate();
  59. return (
  60. <div>
  61. <button onClick={() => navigate('/foo/bar/')}>Click me</button>
  62. <div>You are at: {location.pathname}</div>
  63. </div>
  64. );
  65. }
  66. const {router} = render(<TestComp />, {
  67. disableRouterMocks: true,
  68. });
  69. const button = screen.getByText('Click me');
  70. await userEvent.click(button);
  71. expect(await screen.findByText('You are at: /foo/bar/')).toBeInTheDocument();
  72. expect(router.location.pathname).toBe('/foo/bar/');
  73. });
  74. it('can navigate in the test', async () => {
  75. function TestComp() {
  76. const location = useLocation();
  77. return <div>{location.pathname}</div>;
  78. }
  79. const {router} = render(<TestComp />, {disableRouterMocks: true});
  80. expect(screen.getByText('/mock-pathname/')).toBeInTheDocument();
  81. // Navigate to a new path
  82. router.navigate('/foo/bar/');
  83. await waitFor(() => {
  84. expect(router.location.pathname).toBe('/foo/bar/');
  85. });
  86. expect(screen.getByText('/foo/bar/')).toBeInTheDocument();
  87. // Navigate back to the previous path
  88. router.navigate(-1);
  89. await waitFor(() => {
  90. expect(router.location.pathname).toBe('/mock-pathname/');
  91. });
  92. expect(screen.getByText('/mock-pathname/')).toBeInTheDocument();
  93. });
  94. it('works with useParams()', async () => {
  95. function TestComp() {
  96. const params = useParams<{projectId: string}>();
  97. return <div>{params.projectId}</div>;
  98. }
  99. render(<TestComp />, {
  100. disableRouterMocks: true,
  101. initialRouterConfig: {
  102. route: '/projects/:projectId/',
  103. location: '/projects/123/',
  104. },
  105. });
  106. expect(await screen.findByText('123')).toBeInTheDocument();
  107. });
  108. it('works with useSearchParams()', async () => {
  109. function TestComp() {
  110. const [searchParams, setSearchParams] = useSearchParams();
  111. return (
  112. <div>
  113. <button onClick={() => setSearchParams({id: '200', name: 'Jane Doe'})}>
  114. Click me
  115. </button>
  116. <div>ID: {searchParams.get('id') ?? 'None'}</div>
  117. <div>Name: {searchParams.get('name') ?? 'None'}</div>
  118. </div>
  119. );
  120. }
  121. const {router} = render(<TestComp />, {
  122. disableRouterMocks: true,
  123. initialRouterConfig: {
  124. location: {
  125. pathname: '/organizations/org-slug/issues/',
  126. query: {
  127. id: '100',
  128. name: 'John Doe',
  129. },
  130. },
  131. },
  132. });
  133. expect(await screen.findByText('ID: 100')).toBeInTheDocument();
  134. expect(screen.getByText('Name: John Doe')).toBeInTheDocument();
  135. await userEvent.click(screen.getByText('Click me'));
  136. expect(await screen.findByText('ID: 200')).toBeInTheDocument();
  137. expect(screen.getByText('Name: Jane Doe')).toBeInTheDocument();
  138. expect(router.location.query).toEqual({id: '200', name: 'Jane Doe'});
  139. });
  140. });