From 65332d7440419e275e76ffde104b7d0fe98ceeda Mon Sep 17 00:00:00 2001 From: Clerk Cookie <136073014+clerk-cookie@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:50:27 -0300 Subject: [PATCH] fix(shared): Invitations depends on wrong options (useOrganization) (#2472) (#2481) * fix(shared): Invitations depends on wrong options (useOrganization) (#2472) * fix(shared): Invitations depends on wrong options (useOrganization) * fix(shared): Invitations is depending on wrong options * test(clerk-js): Add unit test * chore(clerk-js): Update changeset (cherry picked from commit 38d8b3e8a0387bcf0b9c8d16e3bbfcfe9b643ca2) * fix(clerk-js): Use useCoreOrganization --------- Co-authored-by: panteliselef --- .changeset/thirty-cooks-cheer.md | 5 + .../__tests__/useCoreOrganization.test.tsx | 204 ++++++++++++++++++ .../src/react/hooks/useOrganization.tsx | 4 +- 3 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 .changeset/thirty-cooks-cheer.md diff --git a/.changeset/thirty-cooks-cheer.md b/.changeset/thirty-cooks-cheer.md new file mode 100644 index 0000000000..9537a0a571 --- /dev/null +++ b/.changeset/thirty-cooks-cheer.md @@ -0,0 +1,5 @@ +--- +'@clerk/shared': patch +--- + +Fixes a bug where Invitations from `useOrganization` incorrectly depended on options for memberships. diff --git a/packages/clerk-js/src/ui/hooks/__tests__/useCoreOrganization.test.tsx b/packages/clerk-js/src/ui/hooks/__tests__/useCoreOrganization.test.tsx index ea43759989..6f41f4910c 100644 --- a/packages/clerk-js/src/ui/hooks/__tests__/useCoreOrganization.test.tsx +++ b/packages/clerk-js/src/ui/hooks/__tests__/useCoreOrganization.test.tsx @@ -3,6 +3,7 @@ import { describe } from '@jest/globals'; import { act, bindCreateFixtures, renderHook, waitFor } from '../../../testUtils'; import { createFakeDomain, + createFakeOrganizationInvitation, createFakeOrganizationMembershipRequest, } from '../../components/OrganizationProfile/__tests__/utils'; import { createFakeUserOrganizationMembership } from '../../components/OrganizationSwitcher/__tests__/utlis'; @@ -15,6 +16,9 @@ const defaultRenderer = () => domains: { pageSize: 2, }, + invitations: { + pageSize: 2, + }, membershipRequests: { pageSize: 2, }, @@ -427,4 +431,204 @@ describe('useOrganization', () => { }); }); }); + + describe('invitations', () => { + it('fetch with pages', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withOrganizations(); + f.withUser({ + email_addresses: ['test@clerk.com'], + organization_memberships: [{ name: 'Org1', role: 'basic_member' }], + }); + }); + + fixtures.clerk.organization?.getInvitations.mockReturnValue( + Promise.resolve({ + data: [ + createFakeOrganizationInvitation({ + id: '1', + emailAddress: 'admin1@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + createFakeOrganizationInvitation({ + id: '2', + emailAddress: 'member2@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + ], + total_count: 4, + }), + ); + const { result } = renderHook(defaultRenderer, { wrapper }); + expect(result.current.invitations?.isLoading).toBe(true); + expect(result.current.invitations?.isFetching).toBe(true); + expect(result.current.invitations?.count).toBe(0); + + await waitFor(() => expect(result.current.invitations?.isLoading).toBe(false)); + + expect(result.current.invitations?.isFetching).toBe(false); + expect(result.current.invitations?.count).toBe(4); + expect(result.current.invitations?.page).toBe(1); + expect(result.current.invitations?.pageCount).toBe(2); + expect(result.current.invitations?.hasNextPage).toBe(true); + + fixtures.clerk.organization?.getInvitations.mockReturnValue( + Promise.resolve({ + data: [ + createFakeOrganizationInvitation({ + id: '3', + emailAddress: 'admin3@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + createFakeOrganizationInvitation({ + id: '4', + emailAddress: 'member4@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + ], + total_count: 4, + }), + ); + + act(() => result.current.invitations?.fetchNext?.()); + + await waitFor(() => expect(result.current.invitations?.isLoading).toBe(true)); + await waitFor(() => expect(result.current.invitations?.isLoading).toBe(false)); + + expect(result.current.invitations?.page).toBe(2); + expect(result.current.invitations?.hasNextPage).toBe(false); + expect(result.current.invitations?.data).toEqual( + expect.arrayContaining([ + expect.not.objectContaining({ + id: '1', + }), + expect.not.objectContaining({ + id: '2', + }), + expect.objectContaining({ + organizationId: '1', + id: '3', + emailAddress: 'admin3@clerk.com', + }), + expect.objectContaining({ + organizationId: '1', + id: '4', + emailAddress: 'member4@clerk.com', + }), + ]), + ); + }); + + it('infinite fetch', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withOrganizations(); + f.withUser({ + email_addresses: ['test@clerk.com'], + organization_memberships: [{ name: 'Org1', role: 'basic_member' }], + }); + }); + + fixtures.clerk.organization?.getInvitations.mockReturnValueOnce( + Promise.resolve({ + data: [ + createFakeOrganizationInvitation({ + id: '1', + emailAddress: 'admin1@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + createFakeOrganizationInvitation({ + id: '2', + emailAddress: 'member2@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + ], + total_count: 4, + }), + ); + const { result } = renderHook( + () => + useCoreOrganization({ + invitations: { + pageSize: 2, + infinite: true, + }, + }), + { wrapper }, + ); + expect(result.current.invitations?.isLoading).toBe(true); + expect(result.current.invitations?.isFetching).toBe(true); + + await waitFor(() => expect(result.current.invitations?.isLoading).toBe(false)); + expect(result.current.invitations?.isFetching).toBe(false); + + fixtures.clerk.organization?.getInvitations.mockReturnValueOnce( + Promise.resolve({ + data: [ + createFakeOrganizationInvitation({ + id: '1', + emailAddress: 'admin1@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + createFakeOrganizationInvitation({ + id: '2', + emailAddress: 'member2@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + ], + total_count: 4, + }), + ); + + fixtures.clerk.organization?.getInvitations.mockReturnValueOnce( + Promise.resolve({ + data: [ + createFakeOrganizationInvitation({ + id: '3', + emailAddress: 'admin3@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + createFakeOrganizationInvitation({ + id: '4', + emailAddress: 'member4@clerk.com', + organizationId: '1', + createdAt: new Date('2022-01-01'), + }), + ], + total_count: 4, + }), + ); + + act(() => result.current.invitations?.fetchNext?.()); + + await waitFor(() => expect(result.current.invitations?.isFetching).toBe(true)); + expect(result.current.invitations?.isLoading).toBe(false); + + await waitFor(() => expect(result.current.invitations?.isFetching).toBe(false)); + expect(result.current.invitations?.data).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: '1', + }), + expect.objectContaining({ + id: '2', + }), + expect.objectContaining({ + id: '3', + }), + expect.objectContaining({ + id: '4', + }), + ]), + ); + }); + }); }); diff --git a/packages/shared/src/react/hooks/useOrganization.tsx b/packages/shared/src/react/hooks/useOrganization.tsx index 15a6f776bd..181297d55d 100644 --- a/packages/shared/src/react/hooks/useOrganization.tsx +++ b/packages/shared/src/react/hooks/useOrganization.tsx @@ -282,8 +282,8 @@ export const useOrganization: UseOrganization = params => { }, organization?.getInvitations, { - keepPreviousData: membersSafeValues.keepPreviousData, - infinite: membersSafeValues.infinite, + keepPreviousData: invitationsSafeValues.keepPreviousData, + infinite: invitationsSafeValues.infinite, enabled: !!invitationsParams, }, {