Skip to content

Commit

Permalink
Tests for local storage hook
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswilty committed Feb 29, 2024
1 parent 179ae90 commit 594b2ea
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 6 deletions.
116 changes: 116 additions & 0 deletions frontend/src/hooks/useLocalStorage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { act, renderHook } from '@testing-library/react';
import { afterEach, describe, expect, test } from 'vitest';

import { LEVEL_NAMES } from '@src/models/level';

import useLocalStorage from './useLocalStorage';

const newUserKey = 'isNewUser';
const currentLevelKey = 'currentLevel';
const completedLevelsKey = 'numCompletedLevels';

describe('useLocalStorage hook', () => {
afterEach(() => {
localStorage.clear();
});

test.each([true, false])(
`Reads ${newUserKey} from localStorage on init`,
(isNewUser) => {
localStorage.setItem(newUserKey, `${isNewUser}`);

const { result } = renderHook(useLocalStorage);
expect(result.current.isNewUser).toBe(isNewUser);
}
);

test(`Default to ${newUserKey}=true when unset`, () => {
const { result } = renderHook(useLocalStorage);
expect(result.current.isNewUser).toBe(true);
});

test(`Reads ${currentLevelKey} from localStorage on init, if not new user`, () => {
localStorage.setItem(newUserKey, 'false');
localStorage.setItem(currentLevelKey, LEVEL_NAMES.LEVEL_3.toString());

const { result } = renderHook(useLocalStorage);
expect(result.current.currentLevel).toBe(LEVEL_NAMES.LEVEL_3);
});

test(`Ignores ${currentLevelKey} in localStorage on init, if new user`, () => {
localStorage.setItem(newUserKey, 'true');
localStorage.setItem(currentLevelKey, LEVEL_NAMES.LEVEL_3.toString());

const { result } = renderHook(useLocalStorage);
expect(result.current.currentLevel).toBe(LEVEL_NAMES.LEVEL_1);
});

test(`Reads ${completedLevelsKey} from localStorage on init, if not new user`, () => {
localStorage.setItem(newUserKey, 'false');
localStorage.setItem(completedLevelsKey, '2');

const { result } = renderHook(useLocalStorage);
expect(result.current.numCompletedLevels).toBe(2);
});

test(`Ignores ${completedLevelsKey} in localStorage on init, if new user`, () => {
localStorage.setItem(newUserKey, 'true');
localStorage.setItem(completedLevelsKey, '2');

const { result } = renderHook(useLocalStorage);
expect(result.current.currentLevel).toBe(0);
});

test(`Persists ${newUserKey} in storage when set`, () => {
const { result } = renderHook(useLocalStorage);
expect(result.current.isNewUser).toBe(true);

act(() => {
result.current.setIsNewUser(false);
});

expect(result.current.isNewUser).toBe(false);
expect(localStorage.getItem(newUserKey)).toEqual('false');
});

test(`Persists ${currentLevelKey} in storage when set`, () => {
const { result } = renderHook(useLocalStorage);
expect(result.current.currentLevel).toBe(LEVEL_NAMES.LEVEL_1);

act(() => {
result.current.setCurrentLevel(LEVEL_NAMES.LEVEL_3);
});

expect(result.current.currentLevel).toBe(LEVEL_NAMES.LEVEL_3);
expect(localStorage.getItem(currentLevelKey)).toEqual(
`${LEVEL_NAMES.LEVEL_3}`
);
});

test(`Persists ${completedLevelsKey} in storage when set`, () => {
const { result } = renderHook(useLocalStorage);
expect(result.current.numCompletedLevels).toBe(0);

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

expect(result.current.numCompletedLevels).toBe(2);
expect(localStorage.getItem(completedLevelsKey)).toEqual('2');
});

test(`${completedLevelsKey} is unchanged when setting it lower than current`, () => {
localStorage.setItem(newUserKey, 'false');
localStorage.setItem(completedLevelsKey, '3');

const { result } = renderHook(useLocalStorage);
expect(result.current.numCompletedLevels).toBe(3);

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

expect(result.current.numCompletedLevels).toBe(3);
expect(localStorage.getItem(completedLevelsKey)).toEqual('3');
});
});
24 changes: 18 additions & 6 deletions frontend/src/hooks/useLocalStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { LEVEL_NAMES } from '@src/models/level';

export default function useLocalStorage() {
const [isNewUser, setNewUser] = useState(loadIsNewUser);

const setIsNewUser = useCallback((isNew: boolean) => {
setNewUser(isNew);
localStorage.setItem('isNewUser', isNew.toString());
Expand All @@ -12,6 +13,7 @@ export default function useLocalStorage() {
const [currentLevel, setLevel] = useState<LEVEL_NAMES>(
loadCurrentLevel(isNewUser)
);

const setCurrentLevel = useCallback((level: LEVEL_NAMES) => {
setLevel(level);
localStorage.setItem('currentLevel', level.toString());
Expand All @@ -20,10 +22,15 @@ export default function useLocalStorage() {
const [numCompletedLevels, setNumCompletedLevels] = useState(
loadNumCompletedLevels(isNewUser)
);

const setCompletedLevels = useCallback((levels: number) => {
setNumCompletedLevels((prev) => Math.max(prev, levels));
localStorage.setItem('numCompletedLevels', levels.toString());
setNumCompletedLevels((prev) => {
const completed = Math.max(prev, levels);
localStorage.setItem('numCompletedLevels', `${completed}`);
return completed;
});
}, []);

const resetCompletedLevels = useCallback(() => {
setNumCompletedLevels(0);
localStorage.setItem('numCompletedLevels', '0');
Expand All @@ -47,11 +54,16 @@ function loadIsNewUser() {

function loadCurrentLevel(isNewUser: boolean) {
const levelInStorage = localStorage.getItem('currentLevel');
const level = (levelInStorage && !isNewUser)
? parseInt(levelInStorage)
: LEVEL_NAMES.LEVEL_1
const level =
levelInStorage && !isNewUser
? parseInt(levelInStorage)
: LEVEL_NAMES.LEVEL_1;

if (Number.isNaN(level) || level < LEVEL_NAMES.LEVEL_1 || level > LEVEL_NAMES.SANDBOX) {
if (
Number.isNaN(level) ||
level < LEVEL_NAMES.LEVEL_1 ||
level > LEVEL_NAMES.SANDBOX
) {
console.error(
`Invalid level ${level} in local storage, defaulting to level 1`
);
Expand Down

0 comments on commit 594b2ea

Please sign in to comment.