@applicaster/zapp-react-native-bridge
Version:
Applicaster Zapp React Native modules
548 lines (427 loc) • 15.4 kB
text/typescript
import { sessionStorage as NativeSessionStorage } from "../__mocks__/ios";
import { DEFAULT_NAMESPACE } from "../__mocks__/storageMock";
import { NativeModules } from "react-native";
NativeModules.SessionStorage = NativeSessionStorage;
const { sessionStorage } = require("../SessionStorage");
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() {
NativeSessionStorage.setItem(test_key, test_value);
NativeSessionStorage.setItem(
namespaced_key,
namespaced_value,
test_namespace
);
NativeSessionStorage.setItem(obj_key, JSON.stringify(obj_value));
}
describe("sessionStorage", () => {
describe("setItem", () => {
beforeEach(async () => {
NativeSessionStorage.__clear();
});
it("sets an item in storage", async () => {
const key = "test_key";
const value = "test_value";
const result = await sessionStorage.setItem(key, value);
expect(result).toBe(true);
expect(
NativeSessionStorage.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 = sessionStorage.setItem;
const result = await setItem(key, value);
expect(result).toBe(true);
expect(
NativeSessionStorage.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 sessionStorage.setItem(key, value);
expect(result).toBe(true);
expect(
NativeSessionStorage.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 sessionStorage.setItem(key, value, namespace);
expect(result).toBe(true);
expect(NativeSessionStorage.items.get(namespace).get(key)).toEqual(value);
});
it("throws if key is null", async () => {
const value = "test_value";
expect(() =>
sessionStorage.setItem(null, value)
).rejects.toThrowErrorMatchingSnapshot();
});
it("throws if key is undefined", async () => {
const value = "test_value";
expect(() =>
sessionStorage.setItem(undefined, value)
).rejects.toThrowErrorMatchingSnapshot();
});
it("throws if value is null", async () => {
const key = "test_key";
expect(() =>
sessionStorage.setItem(key, null)
).rejects.toThrowErrorMatchingSnapshot();
});
it("throws if value is undefined", async () => {
const key = "test_key";
expect(() =>
sessionStorage.setItem(key, undefined)
).rejects.toThrowErrorMatchingSnapshot();
});
it("throws if there is an error in the native module", async () => {
const key = "fail";
const value = "value";
expect(() =>
sessionStorage.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 = sessionStorage.addListener(
{ key: namespaced_key, namespace: test_namespace },
listener
);
});
it("invokes the listener when this key is changed", async () => {
await sessionStorage.setItem(
namespaced_key,
new_value,
test_namespace
);
expect(listener).toHaveBeenCalledWith(
expect.objectContaining({
key: namespaced_key,
namespace: test_namespace,
value: new_value,
})
);
});
it("works as a bound method", async () => {
const setItem = sessionStorage.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 sessionStorage.setItem(test_key, new_value);
expect(listener).not.toHaveBeenCalled();
});
it("removes the listener when invoking the remove function", async () => {
removeListener();
await sessionStorage.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 = sessionStorage.addListener(
{ namespace: test_namespace },
listener
);
});
it("is invoked when a key in the namespace is changed", async () => {
await sessionStorage.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 sessionStorage.setItem(test_key, new_value, DEFAULT_NAMESPACE);
expect(listener).not.toHaveBeenCalled();
});
it("is not invoked after being removed", async () => {
removeListener();
await sessionStorage.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 = sessionStorage.addListener({}, listener);
});
it("is invoked when a key is changed in the default namespace", async () => {
await sessionStorage.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 sessionStorage.setItem(
namespaced_key,
new_value,
test_namespace
);
expect(listener).not.toHaveBeenCalled();
});
it("is not invoked after having been removed", async () => {
removeListener();
await sessionStorage.setItem(test_key, new_value);
expect(listener).not.toHaveBeenCalled();
});
});
});
});
describe("getItem", () => {
beforeAll(setUpStorage);
it("retrieves a value from storage", async () => {
const result = await sessionStorage.getItem(test_key);
expect(result).toBe(test_value);
});
it("works as a bound method", async () => {
const getItem = sessionStorage.getItem;
const result = await getItem(test_key);
expect(result).toBe(test_value);
});
it("retrieves a value in a namespace", async () => {
const result = await sessionStorage.getItem(
namespaced_key,
test_namespace
);
expect(result).toBe(namespaced_value);
});
it("retrieves non string values", async () => {
const result = await sessionStorage.getItem(obj_key);
expect(result).toEqual(obj_value);
});
it("throws if key is null", async () => {
expect(() =>
sessionStorage.getItem(null)
).rejects.toThrowErrorMatchingSnapshot();
});
it("throws if key is undefined", async () => {
expect(() =>
sessionStorage.getItem()
).rejects.toThrowErrorMatchingSnapshot();
});
it("throws if there is an error on the native side", async () => {
expect(() =>
sessionStorage.getItem("fail")
).rejects.toThrowErrorMatchingSnapshot();
});
});
describe("removeItem", () => {
beforeEach(setUpStorage);
it("removes a value from storage", async () => {
const result = await sessionStorage.removeItem(test_key);
expect(result).toBe(true);
expect(
NativeSessionStorage.items.get(DEFAULT_NAMESPACE).get(test_key)
).toBeUndefined();
});
it("works as a bound method", async () => {
const removeItem = sessionStorage.removeItem;
const result = await removeItem(test_key);
expect(result).toBe(true);
expect(
NativeSessionStorage.items.get(DEFAULT_NAMESPACE).get(test_key)
).toBeUndefined();
});
it("removes a value in a namespace", async () => {
const result = await sessionStorage.removeItem(
namespaced_key,
test_namespace
);
expect(result).toBe(true);
expect(
NativeSessionStorage.items.get(test_namespace).get(namespaced_key)
).toBeUndefined();
});
it("throws if key is null", async () => {
expect(() =>
sessionStorage.removeItem(null)
).rejects.toThrowErrorMatchingSnapshot();
});
it("throws if key is undefined", async () => {
expect(() =>
sessionStorage.removeItem()
).rejects.toThrowErrorMatchingSnapshot();
});
it("throws if a native error is thrown", async () => {
expect(() =>
sessionStorage.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 = sessionStorage.addListener(
{ key: namespaced_key, namespace: test_namespace },
listener
);
});
it("invokes the listener when this key is changed", async () => {
await sessionStorage.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 sessionStorage.removeItem(test_key);
expect(listener).not.toHaveBeenCalled();
});
it("removes the listener when invoking the remove function", async () => {
removeListener();
await sessionStorage.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 = sessionStorage.addListener(
{ namespace: test_namespace },
listener
);
});
it("is invoked when a key in the namespace is changed", async () => {
await sessionStorage.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 sessionStorage.removeItem(test_key, DEFAULT_NAMESPACE);
expect(listener).not.toHaveBeenCalled();
});
it("is not invoked after being removed", async () => {
removeListener();
await sessionStorage.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 = sessionStorage.addListener({}, listener);
});
it("is invoked when a key is changed in the default namespace", async () => {
await sessionStorage.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 sessionStorage.removeItem(namespaced_key, test_namespace);
expect(listener).not.toHaveBeenCalled();
});
it("is not invoked after having been removed", async () => {
removeListener();
await sessionStorage.removeItem(test_key);
expect(listener).not.toHaveBeenCalled();
});
});
});
});
describe("getAllItems", () => {
beforeAll(setUpStorage);
it("retrieves all values", async () => {
const result = await sessionStorage.getAllItems();
expect(result).toEqual(
expect.objectContaining({
[test_key]: test_value,
[obj_key]: obj_value,
})
);
});
it("works as a bound method", async () => {
const getAllItems = sessionStorage.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 sessionStorage.getAllItems(test_namespace);
expect(result).toEqual(
expect.objectContaining({ [namespaced_key]: namespaced_value })
);
});
it("throws if an error happen on native side", async () => {
expect(() =>
sessionStorage.getAllItems("undefined_namespace")
).rejects.toThrowErrorMatchingSnapshot();
});
});
});