-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reader Recent Feed: Refetch subscriptions from empty state (#97030)
* Extract subscription logic and refresh subscriptions when the count changes. * Clean up hook for readability. * Rename hook, simplify return, and add JSDoc comment. * Rename file and add tests.
- Loading branch information
1 parent
2285468
commit 0fce49b
Showing
3 changed files
with
172 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
client/reader/following/test/use-site-subscriptions.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/** | ||
* @jest-environment jsdom | ||
*/ | ||
import { SubscriptionManager } from '@automattic/data-stores'; | ||
import { renderHook } from '@testing-library/react'; | ||
import { useSiteSubscriptions } from '../use-site-subscriptions'; | ||
|
||
jest.mock( '@automattic/data-stores', () => ( { | ||
SubscriptionManager: { | ||
useSubscriptionsCountQuery: jest.fn(), | ||
useSiteSubscriptionsQuery: jest.fn(), | ||
}, | ||
} ) ); | ||
|
||
describe( 'useSiteSubscriptions', () => { | ||
beforeEach( () => { | ||
jest.clearAllMocks(); | ||
} ); | ||
|
||
it( 'should return loading state when either query is loading', () => { | ||
( SubscriptionManager.useSubscriptionsCountQuery as jest.Mock ).mockReturnValue( { | ||
data: null, | ||
isLoading: true, | ||
} ); | ||
( SubscriptionManager.useSiteSubscriptionsQuery as jest.Mock ).mockReturnValue( { | ||
data: null, | ||
isLoading: false, | ||
refetch: jest.fn(), | ||
} ); | ||
|
||
const { result } = renderHook( () => useSiteSubscriptions() ); | ||
|
||
expect( result.current.isLoading ).toBe( true ); | ||
} ); | ||
|
||
it( 'should return false for hasNonSelfSubscriptions when blog count is 0', () => { | ||
( SubscriptionManager.useSubscriptionsCountQuery as jest.Mock ).mockReturnValue( { | ||
data: { blogs: 0 }, | ||
isLoading: false, | ||
} ); | ||
( SubscriptionManager.useSiteSubscriptionsQuery as jest.Mock ).mockReturnValue( { | ||
data: null, | ||
isLoading: false, | ||
refetch: jest.fn(), | ||
} ); | ||
|
||
const { result } = renderHook( () => useSiteSubscriptions() ); | ||
|
||
expect( result.current.hasNonSelfSubscriptions ).toBe( false ); | ||
} ); | ||
|
||
it( 'should filter out self-owned blogs when calculating hasNonSelfSubscriptions', () => { | ||
( SubscriptionManager.useSubscriptionsCountQuery as jest.Mock ).mockReturnValue( { | ||
data: { blogs: 2 }, | ||
isLoading: false, | ||
} ); | ||
( SubscriptionManager.useSiteSubscriptionsQuery as jest.Mock ).mockReturnValue( { | ||
data: { | ||
subscriptions: [ { is_owner: true }, { is_owner: false } ], | ||
}, | ||
isLoading: false, | ||
refetch: jest.fn(), | ||
} ); | ||
|
||
const { result } = renderHook( () => useSiteSubscriptions() ); | ||
|
||
expect( result.current.hasNonSelfSubscriptions ).toBe( true ); | ||
} ); | ||
|
||
it( 'should return false for hasNonSelfSubscriptions when all subscriptions are self-owned', () => { | ||
( SubscriptionManager.useSubscriptionsCountQuery as jest.Mock ).mockReturnValue( { | ||
data: { blogs: 2 }, | ||
isLoading: false, | ||
} ); | ||
( SubscriptionManager.useSiteSubscriptionsQuery as jest.Mock ).mockReturnValue( { | ||
data: { | ||
subscriptions: [ { is_owner: true }, { is_owner: true } ], | ||
}, | ||
isLoading: false, | ||
refetch: jest.fn(), | ||
} ); | ||
|
||
const { result } = renderHook( () => useSiteSubscriptions() ); | ||
|
||
expect( result.current.hasNonSelfSubscriptions ).toBe( false ); | ||
} ); | ||
|
||
it( 'should return true for hasNonSelfSubscriptions when blog count > 0 but no subscription data yet', () => { | ||
( SubscriptionManager.useSubscriptionsCountQuery as jest.Mock ).mockReturnValue( { | ||
data: { blogs: 1 }, | ||
isLoading: false, | ||
} ); | ||
( SubscriptionManager.useSiteSubscriptionsQuery as jest.Mock ).mockReturnValue( { | ||
data: null, | ||
isLoading: false, | ||
refetch: jest.fn(), | ||
} ); | ||
|
||
const { result } = renderHook( () => useSiteSubscriptions() ); | ||
|
||
expect( result.current.hasNonSelfSubscriptions ).toBe( true ); | ||
} ); | ||
|
||
it( 'should call refetch when blog count changes from 0 to positive', () => { | ||
const refetchMock = jest.fn(); | ||
( SubscriptionManager.useSubscriptionsCountQuery as jest.Mock ).mockReturnValue( { | ||
data: { blogs: 1 }, | ||
isLoading: false, | ||
} ); | ||
( SubscriptionManager.useSiteSubscriptionsQuery as jest.Mock ).mockReturnValue( { | ||
data: null, | ||
isLoading: false, | ||
refetch: refetchMock, | ||
} ); | ||
|
||
renderHook( () => useSiteSubscriptions() ); | ||
|
||
expect( refetchMock ).toHaveBeenCalled(); | ||
} ); | ||
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { SubscriptionManager } from '@automattic/data-stores'; | ||
import { useMemo, useEffect } from 'react'; | ||
|
||
/** | ||
* Custom hook to manage site subscriptions data. | ||
* Fetches and tracks subscription counts and site subscription details, | ||
* filtering out self-owned blogs to determine if the user has any external subscriptions. | ||
* @returns {Object} An object containing: | ||
* - isLoading: boolean indicating if subscription data is being loaded | ||
* - hasNonSelfSubscriptions: boolean indicating if user has any subscriptions to non-self-owned blogs | ||
*/ | ||
export function useSiteSubscriptions() { | ||
const { data: subscriptionsCount, isLoading: isLoadingCount } = | ||
SubscriptionManager.useSubscriptionsCountQuery(); | ||
const { | ||
data: siteSubscriptions, | ||
isLoading: isLoadingSiteSubscriptions, | ||
refetch: refetchSiteSubscriptions, | ||
} = SubscriptionManager.useSiteSubscriptionsQuery(); | ||
|
||
const isLoading = isLoadingCount || isLoadingSiteSubscriptions; | ||
const blogCount = subscriptionsCount?.blogs ?? 0; | ||
|
||
const hasNonSelfSubscriptions = useMemo( () => { | ||
if ( blogCount === 0 ) { | ||
return false; | ||
} | ||
|
||
// If we have site subscriptions data, filter out self-owned blogs. | ||
if ( siteSubscriptions?.subscriptions ) { | ||
const nonSelfSubscriptions = siteSubscriptions.subscriptions.filter( | ||
( sub ) => ! sub.is_owner | ||
); | ||
return nonSelfSubscriptions.length > 0; | ||
} | ||
|
||
return true; | ||
}, [ blogCount, siteSubscriptions ] ); | ||
|
||
useEffect( () => { | ||
if ( blogCount > 0 ) { | ||
refetchSiteSubscriptions(); | ||
} | ||
}, [ refetchSiteSubscriptions, blogCount ] ); | ||
|
||
return { | ||
isLoading, | ||
hasNonSelfSubscriptions, | ||
}; | ||
} |