UNPKG

@applicaster/zapp-react-native-bridge

Version:

Applicaster Zapp React Native modules

521 lines (400 loc) • 15 kB
import { localStorage as NativeLocalStorage } from "../__mocks__/ios"; import { DEFAULT_NAMESPACE } from "../__mocks__/storageMock"; const { localStorage } = require("../LocalStorage"); const RN = require("react-native"); RN.NativeModules.LocalStorage = NativeLocalStorage; const test_key = "test_key"; const test_value = "test_value"; const namespaced_key = "namespaced_key"; const namespaced_value = "namespaced_value"; const test_namespace = "test_namespace"; const obj_key = "obj_key"; const obj_value = { prop: "value" }; function setUpStorage() { NativeLocalStorage.setItem(test_key, test_value); NativeLocalStorage.setItem(namespaced_key, namespaced_value, test_namespace); NativeLocalStorage.setItem(obj_key, JSON.stringify(obj_value)); } describe("localStorage", () => { describe("setItem", () => { beforeEach(async () => { NativeLocalStorage.__clear(); }); it("sets an item in storage", async () => { const key = "test_key"; const value = "test_value"; const result = await localStorage.setItem(key, value); expect(result).toBe(true); expect(NativeLocalStorage.items.get(DEFAULT_NAMESPACE).get(key)).toEqual( value ); }); it("works as a bound method", async () => { const key = "test_key"; const value = "test_value"; const setItem = localStorage.setItem; const result = await setItem(key, value); expect(result).toBe(true); expect(NativeLocalStorage.items.get(DEFAULT_NAMESPACE).get(key)).toEqual( value ); }); it("stringifies the value if its not a string", async () => { const key = "test_key"; const value = { objVal: "test_value" }; const result = await localStorage.setItem(key, value); expect(result).toBe(true); expect(NativeLocalStorage.items.get(DEFAULT_NAMESPACE).get(key)).toEqual( JSON.stringify(value) ); }); it("sets a value in a specific namespace", async () => { const key = "test_key"; const value = "test_value"; const namespace = "test_namespace"; const result = await localStorage.setItem(key, value, namespace); expect(result).toBe(true); expect(NativeLocalStorage.items.get(namespace).get(key)).toEqual(value); }); it("throws if key is null", async () => { const value = "test_value"; expect(() => localStorage.setItem(null, value) ).rejects.toThrowErrorMatchingSnapshot(); }); it("throws if key is undefined", async () => { const value = "test_value"; expect(() => localStorage.setItem(undefined, value) ).rejects.toThrowErrorMatchingSnapshot(); }); it("throws if value is null", async () => { const key = "test_key"; expect(() => localStorage.setItem(key, null) ).rejects.toThrowErrorMatchingSnapshot(); }); it("throws if value is undefined", async () => { const key = "test_key"; expect(() => localStorage.setItem(key, undefined) ).rejects.toThrowErrorMatchingSnapshot(); }); it("throws if there is an error in the native module", async () => { const key = "fail"; const value = "value"; expect(() => localStorage.setItem(key, value) ).rejects.toThrowErrorMatchingSnapshot(); }); describe("listeners", () => { describe("listening for a specific key and namespace change", () => { const listener = jest.fn(); const new_value = "new_value"; let removeListener; beforeEach(() => { setUpStorage(); listener.mockClear(); removeListener = localStorage.addListener( { key: namespaced_key, namespace: test_namespace }, listener ); }); it("invokes the listener when this key is changed", async () => { await localStorage.setItem(namespaced_key, new_value, test_namespace); expect(listener).toHaveBeenCalledWith( expect.objectContaining({ key: namespaced_key, namespace: test_namespace, value: new_value, }) ); }); it("invokes the listener when the key is changed and is invoked as a bound method", async () => { const setItem = localStorage.setItem; await setItem(namespaced_key, new_value, test_namespace); expect(listener).toHaveBeenCalledWith( expect.objectContaining({ key: namespaced_key, namespace: test_namespace, value: new_value, }) ); }); it("is not invoked when another key is changed", async () => { await localStorage.setItem(test_key, new_value); expect(listener).not.toHaveBeenCalled(); }); it("removes the listener when invoking the remove function", async () => { removeListener(); await localStorage.setItem(namespaced_key, new_value, test_namespace); expect(listener).not.toHaveBeenCalled(); }); }); describe("listening for any key change in a namespace", () => { const listener = jest.fn(); const new_value = "new_value"; let removeListener; beforeEach(() => { setUpStorage(); listener.mockClear(); removeListener = localStorage.addListener( { namespace: test_namespace }, listener ); }); it("is invoked when a key in the namespace is changed", async () => { await localStorage.setItem(namespaced_key, new_value, test_namespace); expect(listener).toHaveBeenCalledWith( expect.objectContaining({ key: namespaced_key, value: new_value, namespace: test_namespace, }) ); }); it("is not invoked when a key in a different namespace is changed", async () => { await localStorage.setItem(test_key, new_value, DEFAULT_NAMESPACE); expect(listener).not.toHaveBeenCalled(); }); it("is not invoked after being removed", async () => { removeListener(); await localStorage.setItem(namespaced_key, new_value, test_namespace); expect(listener).not.toHaveBeenCalled(); }); }); describe("listening for key changes in the default namespace", () => { const listener = jest.fn(); const new_value = "new_value"; let removeListener; beforeEach(() => { setUpStorage(); listener.mockClear(); removeListener = localStorage.addListener({}, listener); }); it("is invoked when a key is changed in the default namespace", async () => { await localStorage.setItem(test_key, new_value); expect(listener).toHaveBeenCalledWith( expect.objectContaining({ key: test_key, value: new_value, namespace: DEFAULT_NAMESPACE, }) ); }); it("is not invoked when a key in a nother namespace is changed", async () => { await localStorage.setItem(namespaced_key, new_value, test_namespace); expect(listener).not.toHaveBeenCalled(); }); it("is not invoked after having been removed", async () => { removeListener(); await localStorage.setItem(test_key, new_value); expect(listener).not.toHaveBeenCalled(); }); }); }); }); describe("getItem", () => { beforeAll(setUpStorage); it("retrieves a value from storage", async () => { const result = await localStorage.getItem(test_key); expect(result).toBe(test_value); }); it("retrieves a value in a namespace", async () => { const result = await localStorage.getItem(namespaced_key, test_namespace); expect(result).toBe(namespaced_value); }); it("retrieves non string values", async () => { const result = await localStorage.getItem(obj_key); expect(result).toEqual(obj_value); }); it("works as a bound method", async () => { const getItem = localStorage.getItem; const result = await getItem(test_key); expect(result).toBe(test_value); }); it("throws if key is null", async () => { expect(() => localStorage.getItem(null) ).rejects.toThrowErrorMatchingSnapshot(); }); it("throws if key is undefined", async () => { expect(() => localStorage.getItem() ).rejects.toThrowErrorMatchingSnapshot(); }); it("throws if there is an error on the native side", async () => { expect(() => localStorage.getItem("fail") ).rejects.toThrowErrorMatchingSnapshot(); }); }); describe("removeItem", () => { beforeEach(setUpStorage); it("removes a value from storage", async () => { const result = await localStorage.removeItem(test_key); expect(result).toBe(true); expect( NativeLocalStorage.items.get(DEFAULT_NAMESPACE).get(test_key) ).toBeUndefined(); }); it("works as a bound method", async () => { const removeItem = localStorage.removeItem; const result = await removeItem(test_key); expect(result).toBe(true); expect( NativeLocalStorage.items.get(DEFAULT_NAMESPACE).get(test_key) ).toBeUndefined(); }); it("removes a value in a namespace", async () => { const result = await localStorage.removeItem( namespaced_key, test_namespace ); expect(result).toBe(true); expect( NativeLocalStorage.items.get(test_namespace).get(namespaced_key) ).toBeUndefined(); }); it("throws if key is null", async () => { expect(() => localStorage.removeItem(null) ).rejects.toThrowErrorMatchingSnapshot(); }); it("throws if key is undefined", async () => { expect(() => localStorage.removeItem() ).rejects.toThrowErrorMatchingSnapshot(); }); it("throws if a native error is thrown", async () => { expect(() => localStorage.removeItem("fail") ).rejects.toThrowErrorMatchingSnapshot(); }); describe("listeners", () => { describe("listening for a specific key and namespace change", () => { const listener = jest.fn(); let removeListener; beforeEach(() => { setUpStorage(); listener.mockClear(); removeListener = localStorage.addListener( { key: namespaced_key, namespace: test_namespace }, listener ); }); it("invokes the listener when this key is changed", async () => { await localStorage.removeItem(namespaced_key, test_namespace); expect(listener).toHaveBeenCalledWith( expect.objectContaining({ key: namespaced_key, namespace: test_namespace, value: null, }) ); }); it("is not invoked when another key is changed", async () => { await localStorage.removeItem(test_key); expect(listener).not.toHaveBeenCalled(); }); it("removes the listener when invoking the remove function", async () => { removeListener(); await localStorage.removeItem(namespaced_key, test_namespace); expect(listener).not.toHaveBeenCalled(); }); }); describe("listening for any key change in a namespace", () => { const listener = jest.fn(); let removeListener; beforeEach(() => { setUpStorage(); listener.mockClear(); removeListener = localStorage.addListener( { namespace: test_namespace }, listener ); }); it("is invoked when a key in the namespace is changed", async () => { await localStorage.removeItem(namespaced_key, test_namespace); expect(listener).toHaveBeenCalledWith( expect.objectContaining({ key: namespaced_key, value: null, namespace: test_namespace, }) ); }); it("is not invoked when a key in a different namespace is changed", async () => { await localStorage.removeItem(test_key, DEFAULT_NAMESPACE); expect(listener).not.toHaveBeenCalled(); }); it("is not invoked after being removed", async () => { removeListener(); await localStorage.removeItem(namespaced_key, test_namespace); expect(listener).not.toHaveBeenCalled(); }); }); describe("listening for key changes in the default namespace", () => { const listener = jest.fn(); let removeListener; beforeEach(() => { setUpStorage(); listener.mockClear(); removeListener = localStorage.addListener({}, listener); }); it("is invoked when a key is changed in the default namespace", async () => { await localStorage.removeItem(test_key); expect(listener).toHaveBeenCalledWith( expect.objectContaining({ key: test_key, value: null, namespace: DEFAULT_NAMESPACE, }) ); }); it("is not invoked when a key in a nother namespace is changed", async () => { await localStorage.removeItem(namespaced_key, test_namespace); expect(listener).not.toHaveBeenCalled(); }); it("is not invoked after having been removed", async () => { removeListener(); await localStorage.removeItem(test_key); expect(listener).not.toHaveBeenCalled(); }); }); }); }); describe("getAllItems", () => { beforeAll(setUpStorage); it("retrieves all values", async () => { const result = await localStorage.getAllItems(); expect(result).toEqual( expect.objectContaining({ [test_key]: test_value, [obj_key]: obj_value, }) ); }); it("works as a bound method", async () => { const getAllItems = localStorage.getAllItems; const result = await getAllItems(); expect(result).toEqual( expect.objectContaining({ [test_key]: test_value, [obj_key]: obj_value, }) ); }); it("retrieves all values in a namespace", async () => { const result = await localStorage.getAllItems(test_namespace); expect(result).toEqual( expect.objectContaining({ [namespaced_key]: namespaced_value }) ); }); it("throws if an error happen on native side", async () => { expect(() => localStorage.getAllItems("undefined_namespace") ).rejects.toThrowErrorMatchingSnapshot(); }); }); });