Skip to content

Commit

Permalink
test: complete tests for useStorageValue
Browse files Browse the repository at this point in the history
  • Loading branch information
xobotyi committed May 8, 2021
1 parent ed80fc2 commit 2909e46
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/useStorageValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useMountEffect } from './useMountEffect';
import { useSyncedRef } from './useSyncedRef';
import { isBrowser } from './util/const';
import { useFirstMountState } from './useFirstMountState';
import { usePrevious } from './usePrevious';

export type IUseStorageValueAdapter = {
getItem(key: string): string | null;
Expand Down Expand Up @@ -238,6 +239,7 @@ export function useStorageValue<T>(
const [state, setState] = useSafeState<T | null | string | undefined>(
initializeWithStorageValue && isBrowser && isFirstMount ? methods.current.getVal() : undefined
);
const prevState = usePrevious(state);
const stateRef = useSyncedRef(state);

// fetch value on mount for the case `initializeWithStorageValue` is false
Expand All @@ -250,7 +252,7 @@ export function useStorageValue<T>(
// store default value if it is not null and options configured to store default value
useConditionalEffect(() => {
methods.current.setVal(defaultValue as T);
}, [state === null && defaultValue !== null && storeDefaultValue]);
}, [prevState !== state, state === defaultValue && defaultValue !== null && storeDefaultValue]);

// refetch value when key changed
useUpdateEffect(() => {
Expand Down
63 changes: 63 additions & 0 deletions tests/dom/useStorageValue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,67 @@ describe('useStorageValue', () => {
rerender({ key: 'bar' });
expect(result.current[0]).toBe('bar');
});

it('should store initially default value to storage if configured', () => {
adapter.getItem.mockImplementationOnce(() => null);
const { result } = renderHook(() =>
useStorageValue<string>(adapter, 'foo', 'default value', {
raw: true,
storeDefaultValue: true,
})
);

expect(result.current[0]).toBe('default value');
expect(adapter.setItem).toHaveBeenCalledWith('foo', 'default value');
});

it('should store default value if it became default after initial render', () => {
adapter.getItem.mockImplementationOnce(() => 'bar');
const { result } = renderHook(() =>
useStorageValue<string>(adapter, 'foo', 'default value', {
raw: true,
storeDefaultValue: true,
})
);
adapter.getItem.mockImplementationOnce(() => null);

expect(result.current[0]).toBe('bar');
expect(adapter.setItem).not.toHaveBeenCalled();

act(() => {
result.current[2]();
});

expect(result.current[0]).toBe('default value');
expect(adapter.setItem).toHaveBeenCalledWith('foo', 'default value');
});

it('should not store default value on rerenders with persisted state', () => {
adapter.getItem.mockImplementationOnce(() => null);
const { result, rerender } = renderHook(() =>
useStorageValue<string>(adapter, 'foo', 'default value', {
raw: true,
storeDefaultValue: true,
})
);

expect(result.current[0]).toBe('default value');
expect(adapter.setItem).toHaveBeenCalledWith('foo', 'default value');
rerender();
rerender();
rerender();
expect(adapter.setItem).toHaveBeenCalledTimes(1);
});

it('should not store null default value to store', () => {
adapter.getItem.mockImplementationOnce(() => null);
renderHook(() =>
useStorageValue<string>(adapter, 'foo', null, {
raw: true,
storeDefaultValue: true,
})
);

expect(adapter.setItem).not.toHaveBeenCalled();
});
});

0 comments on commit 2909e46

Please sign in to comment.