Skip to content

Commit

Permalink
Merge pull request #564 from fabioh8010/bugfix/use-onyx-selector-retu…
Browse files Browse the repository at this point in the history
…rn-type

[No QA] Fix useOnyx selector return type
  • Loading branch information
iwiznia authored Jun 24, 2024
2 parents e922e81 + 933a5d1 commit e6ee4bb
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 5 deletions.
6 changes: 4 additions & 2 deletions lib/useOnyx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {IsEqual} from 'type-fest';
import Onyx from './Onyx';
import OnyxCache from './OnyxCache';
import OnyxUtils from './OnyxUtils';
import type {CollectionKeyBase, OnyxCollection, OnyxKey, OnyxValue, Selector} from './types';
import type {CollectionKeyBase, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, Selector} from './types';
import useLiveRef from './useLiveRef';
import usePrevious from './usePrevious';

Expand Down Expand Up @@ -46,7 +46,9 @@ type UseOnyxOptions<TKey extends OnyxKey, TReturnValue> = BaseUseOnyxOptions & U

type FetchStatus = 'loading' | 'loaded';

type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue, OnyxValue<TKey>> extends true ? TValue : TKey extends CollectionKeyBase ? NonNullable<OnyxCollection<TValue>> : TValue;
type SelectedValue<TKey, TValue> = TKey extends CollectionKeyBase ? OnyxCollection<TValue> : OnyxEntry<TValue>;

type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue, OnyxValue<TKey>> extends true ? TValue : SelectedValue<TKey, TValue>;

type ResultMetadata = {
status: FetchStatus;
Expand Down
49 changes: 46 additions & 3 deletions tests/unit/useOnyxTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ describe('useOnyx', () => {
expect(result.current[1].status).toEqual('loaded');
});

it('should initially return null and then return cached value after multiple merge operations', async () => {
it('should initially return undefined and then return cached value after multiple merge operations', async () => {
Onyx.merge(ONYXKEYS.TEST_KEY, 'test1');
Onyx.merge(ONYXKEYS.TEST_KEY, 'test2');
Onyx.merge(ONYXKEYS.TEST_KEY, 'test3');
Expand Down Expand Up @@ -285,7 +285,7 @@ describe('useOnyx', () => {
});

describe('initialValue', () => {
it('should return initial value from non-cached key and then return null', async () => {
it('should return initial value from non-cached key and then return undefined', async () => {
const {result} = renderHook(() =>
useOnyx(ONYXKEYS.TEST_KEY, {
initialValue: 'initial value',
Expand Down Expand Up @@ -318,10 +318,30 @@ describe('useOnyx', () => {
expect(result.current[0]).toEqual('test');
expect(result.current[1].status).toEqual('loaded');
});

it('should return initial value from cached key and then return selected data', async () => {
await StorageMock.setItem(ONYXKEYS.TEST_KEY, 'test');

const {result} = renderHook(() =>
useOnyx(ONYXKEYS.TEST_KEY, {
initialValue: 'initial value',
// @ts-expect-error bypass
selector: (entry: OnyxEntry<string>) => `${entry}_changed`,
}),
);

expect(result.current[0]).toEqual('initial value');
expect(result.current[1].status).toEqual('loaded');

await act(async () => waitForPromisesToResolve());

expect(result.current[0]).toEqual('test_changed');
expect(result.current[1].status).toEqual('loaded');
});
});

describe('allowStaleData', () => {
it('should return null and loading state while we have pending merges for the key, and then return updated value and loaded state', async () => {
it('should return undefined and loading state while we have pending merges for the key, and then return updated value and loaded state', async () => {
Onyx.set(ONYXKEYS.TEST_KEY, 'test1');

Onyx.merge(ONYXKEYS.TEST_KEY, 'test2');
Expand All @@ -339,6 +359,29 @@ describe('useOnyx', () => {
expect(result.current[1].status).toEqual('loaded');
});

it('should return undefined and loading state while we have pending merges for the key, and then return selected data and loaded state', async () => {
Onyx.set(ONYXKEYS.TEST_KEY, 'test1');

Onyx.merge(ONYXKEYS.TEST_KEY, 'test2');
Onyx.merge(ONYXKEYS.TEST_KEY, 'test3');
Onyx.merge(ONYXKEYS.TEST_KEY, 'test4');

const {result} = renderHook(() =>
useOnyx(ONYXKEYS.TEST_KEY, {
// @ts-expect-error bypass
selector: (entry: OnyxEntry<string>) => `${entry}_changed`,
}),
);

expect(result.current[0]).toBeUndefined();
expect(result.current[1].status).toEqual('loading');

await act(async () => waitForPromisesToResolve());

expect(result.current[0]).toEqual('test4_changed');
expect(result.current[1].status).toEqual('loaded');
});

it('should return initial value and loaded state while we have pending merges for the key, and then return updated value and loaded state', async () => {
const {result} = renderHook(() =>
useOnyx(ONYXKEYS.TEST_KEY, {
Expand Down

0 comments on commit e6ee4bb

Please sign in to comment.