react-use/tests/useLocalStorage.test.ts
2019-11-19 22:24:59 -08:00

156 lines
5.6 KiB
TypeScript

import useLocalStorage from "../src/useLocalStorage";
import "jest-localstorage-mock";
import { renderHook, act } from "@testing-library/react-hooks";
describe(useLocalStorage, () => {
afterEach(() => localStorage.clear());
it("retrieves an existing value from localStorage", () => {
localStorage.setItem("foo", "bar");
const { result } = renderHook(() => useLocalStorage("foo"));
const [state] = result.current;
expect(state).toEqual("bar");
});
it("sets initial state", () => {
const { result } = renderHook(() => useLocalStorage("foo", "bar"));
const [state] = result.current;
expect(state).toEqual("bar");
expect(localStorage.__STORE__["foo"]).toEqual("bar");
});
it("prefers existing value over initial state", () => {
localStorage.setItem("foo", "bar");
const { result } = renderHook(() => useLocalStorage("foo", "baz"));
const [state] = result.current;
expect(state).toEqual("bar");
});
it("does not clobber existing localStorage with initialState", () => {
localStorage.setItem('foo', 'bar')
const { result } = renderHook(() => useLocalStorage('foo', 'buzz'));
result.current; // invoke current to make sure things are set
expect(localStorage.__STORE__['foo']).toEqual('bar');
})
it("correctly updates localStorage", () => {
const { result, rerender } = renderHook(() => useLocalStorage("foo", "bar"));
const [, setFoo] = result.current;
act(() => setFoo("baz"));
rerender();
expect(localStorage.__STORE__["foo"]).toEqual("baz");
});
it("correctly and promptly returns a new value", () => {
const { result, rerender } = renderHook(() => useLocalStorage("foo", "bar"));
const [, setFoo] = result.current;
act(() => setFoo("baz"));
rerender();
const [foo] = result.current;
expect(foo).toEqual("baz");
});
it("should not double-JSON-stringify stringy values", () => {
const { result, rerender } = renderHook(() => useLocalStorage("foo", "bar"));
const [, setFoo] = result.current;
act(() => setFoo(JSON.stringify("baz")));
rerender();
const [foo] = result.current;
expect(foo).not.toMatch(/\\/i); // should not contain extra escapes
expect(foo).toBe('baz');
});
it("keeps multiple hooks accessing the same key in sync", () => {
localStorage.setItem("foo", "bar");
const { result: r1, rerender: rerender1 } = renderHook(() => useLocalStorage("foo"));
const { result: r2, rerender: rerender2 } = renderHook(() => useLocalStorage("foo"));
const [, setFoo] = r1.current;
act(() => setFoo("potato"));
rerender1();
rerender2();
const [val1] = r1.current;
const [val2] = r2.current;
expect(val1).toEqual(val2);
expect(val1).toEqual("potato");
expect(val2).toEqual("potato");
});
it("parses out objects from localStorage", () => {
localStorage.setItem("foo", JSON.stringify({ ok: true }));
const { result } = renderHook(() => useLocalStorage<{ ok: boolean }>("foo"));
const [foo] = result.current;
expect(foo.ok).toEqual(true);
});
it("safely initializes objects to localStorage", () => {
const { result } = renderHook(() => useLocalStorage<{ ok: boolean }>("foo", { ok: true }));
const [foo] = result.current;
expect(foo.ok).toEqual(true);
});
it("safely sets objects to localStorage", () => {
const { result, rerender } = renderHook(() => useLocalStorage<{ ok: any }>("foo", { ok: true }));
const [, setFoo] = result.current;
act(() => setFoo({ ok: "bar" }));
rerender();
const [foo] = result.current;
expect(foo.ok).toEqual("bar");
});
it("safely returns objects from updates", () => {
const { result, rerender } = renderHook(() => useLocalStorage<{ ok: any }>("foo", { ok: true }));
const [, setFoo] = result.current;
act(() => setFoo({ ok: "bar" }));
rerender();
const [foo] = result.current;
expect(foo).toBeInstanceOf(Object);
expect(foo.ok).toEqual("bar");
});
it("sets localStorage from the function updater", () => {
const { result, rerender } = renderHook(() =>
useLocalStorage<{ foo: string; fizz?: string }>("foo", { foo: "bar" })
);
const [, setFoo] = result.current;
act(() => setFoo(state => ({ ...state, fizz: "buzz" })));
rerender();
const [value] = result.current;
expect(value.foo).toEqual("bar");
expect(value.fizz).toEqual("buzz");
});
describe("raw setting", () => {
it('returns a string when localStorage is a stringified object', () => {
localStorage.setItem('foo', JSON.stringify({ fizz: 'buzz' }));
const { result } = renderHook(() => useLocalStorage('foo', null, true));
const [foo] = result.current;
expect(typeof foo).toBe('string');
});
it('returns a string after an update', () => {
localStorage.setItem('foo', JSON.stringify({ fizz: 'buzz' }));
const { result, rerender } = renderHook(() => useLocalStorage('foo', null, true));
const [,setFoo] = result.current;
act(() => setFoo({ fizz: 'bang' }))
rerender();
const [foo] = result.current;
expect(typeof foo).toBe('string');
expect(JSON.parse(foo)).toBeInstanceOf(Object);
expect(JSON.parse(foo).fizz).toEqual('bang');
});
it('still forces setState to a string', () => {
localStorage.setItem('foo', JSON.stringify({ fizz: 'buzz' }));
const { result, rerender } = renderHook(() => useLocalStorage('foo', null, true));
const [,setFoo] = result.current;
act(() => setFoo({ fizz: 'bang' }))
rerender();
const [value] = result.current;
expect(JSON.parse(value).fizz).toEqual('bang');
});
});
});