useProjects.spec.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import type {ReactNode} from 'react';
  2. import {OrganizationFixture} from 'sentry-fixture/organization';
  3. import {ProjectFixture} from 'sentry-fixture/project';
  4. import {act, renderHook, waitFor} from 'sentry-test/reactTestingLibrary';
  5. import ProjectsStore from 'sentry/stores/projectsStore';
  6. import useProjects from 'sentry/utils/useProjects';
  7. import {OrganizationContext} from 'sentry/views/organizationContext';
  8. const org = OrganizationFixture();
  9. function TestContext({children}: {children?: ReactNode}) {
  10. return (
  11. <OrganizationContext.Provider value={org}>{children}</OrganizationContext.Provider>
  12. );
  13. }
  14. describe('useProjects', function () {
  15. const mockProjects = [ProjectFixture()];
  16. it('provides projects from the team store', function () {
  17. act(() => void ProjectsStore.loadInitialData(mockProjects));
  18. const {result} = renderHook(useProjects, {wrapper: TestContext});
  19. const {projects} = result.current;
  20. expect(projects).toEqual(mockProjects);
  21. });
  22. it('loads more projects when using onSearch', async function () {
  23. act(() => void ProjectsStore.loadInitialData(mockProjects));
  24. const newProject3 = ProjectFixture({id: '3', slug: 'test-project3'});
  25. const newProject4 = ProjectFixture({id: '4', slug: 'test-project4'});
  26. const mockRequest = MockApiClient.addMockResponse({
  27. url: `/organizations/${org.slug}/projects/`,
  28. method: 'GET',
  29. body: [newProject3, newProject4],
  30. });
  31. const {result} = renderHook(useProjects, {
  32. wrapper: TestContext,
  33. });
  34. const {onSearch} = result.current;
  35. // Works with append
  36. await act(() => onSearch('test'));
  37. expect(result.current.fetching).toBe(false);
  38. // Wait for state to be reflected from the store
  39. await waitFor(() => result.current.projects.length === 3);
  40. expect(mockRequest).toHaveBeenCalled();
  41. expect(result.current.projects).toEqual([...mockProjects, newProject3, newProject4]);
  42. // de-duplicates items in the query results
  43. mockRequest.mockClear();
  44. await act(() => onSearch('test'));
  45. // No new items have been added
  46. expect(mockRequest).toHaveBeenCalled();
  47. expect(result.current.projects).toEqual([...mockProjects, newProject3, newProject4]);
  48. });
  49. it('provides only the specified slugs', async function () {
  50. act(() => void ProjectsStore.loadInitialData(mockProjects));
  51. const projectFoo = ProjectFixture({id: '3', slug: 'foo'});
  52. const mockRequest = MockApiClient.addMockResponse({
  53. url: `/organizations/${org.slug}/projects/`,
  54. method: 'GET',
  55. body: [projectFoo],
  56. });
  57. const {result} = renderHook(useProjects, {
  58. initialProps: {slugs: ['foo']},
  59. wrapper: TestContext,
  60. });
  61. expect(result.current.initiallyLoaded).toBe(false);
  62. expect(mockRequest).toHaveBeenCalled();
  63. await waitFor(() => expect(result.current.projects.length).toBe(1));
  64. const {projects} = result.current;
  65. expect(projects).toEqual(expect.arrayContaining([projectFoo]));
  66. });
  67. it('only loads slugs when needed', function () {
  68. act(() => void ProjectsStore.loadInitialData(mockProjects));
  69. const {result} = renderHook(useProjects, {
  70. initialProps: {slugs: [mockProjects[0].slug]},
  71. wrapper: TestContext,
  72. });
  73. const {projects, initiallyLoaded} = result.current;
  74. expect(initiallyLoaded).toBe(true);
  75. expect(projects).toEqual(expect.arrayContaining(mockProjects));
  76. });
  77. });