import { ContextKeysManager } from "../../";

describe("Context Keys Manager - removeKey", () => {
  it("returns false when key is invalid", async () => {
    // setup
    const key = null;

    const mockedLogger = {
      warn: jest.fn(),
    };

    const mockedSessionStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedLocalStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedSecureStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const contextManager = new ContextKeysManager({
      logger: mockedLogger,
      sessionStorage: mockedSessionStorage,
      localStorage: mockedLocalStorage,
      secureStorage: mockedSecureStorage,
    });

    const removeReferenceForKey = jest.spyOn(
      contextManager,
      "removeReferenceForKey"
    );

    // run
    const result = await contextManager.removeKey(key);

    // verify
    expect(result).toEqual(false);

    expect(mockedLogger.warn).toHaveBeenCalledWith({
      message:
        "Provided key is not valid - expecing an object with namespace and key properties",
      data: { key },
    });

    expect(removeReferenceForKey).not.toHaveBeenCalled();

    expect(mockedSessionStorage.removeItem).not.toHaveBeenCalled();
    expect(mockedLocalStorage.removeItem).not.toHaveBeenCalled();
    expect(mockedSecureStorage.removeItem).not.toHaveBeenCalled();
  });

  it("returns false while removing session-storage throw error", async () => {
    // setup
    const key = "namespace.key";
    const error = Error("oops");

    const mockedLogger = {
      warn: jest.fn(),
    };

    const mockedSessionStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockRejectedValueOnce(error),
    };

    const mockedLocalStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockResolvedValueOnce(true),
    };

    const mockedSecureStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockResolvedValueOnce(true),
    };

    const contextManager = new ContextKeysManager({
      logger: mockedLogger,
      sessionStorage: mockedSessionStorage,
      localStorage: mockedLocalStorage,
      secureStorage: mockedSecureStorage,
    });

    const removeReferenceForKey = jest
      .spyOn(contextManager, "removeReferenceForKey")
      .mockResolvedValueOnce(true);

    // run
    const result = await contextManager.removeKey(key);

    // verify
    expect(result).toEqual(false);

    expect(mockedLogger.warn).toHaveBeenCalledWith({
      message: error.message,
      data: { key },
    });

    expect(removeReferenceForKey).toHaveBeenCalledWith("key", "namespace");

    expect(mockedSessionStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );

    expect(mockedLocalStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );

    expect(mockedSecureStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );
  });

  it("returns false while removing local-storage throw error", async () => {
    // setup
    const key = "namespace.key";
    const error = Error("oops");

    const mockedLogger = {
      warn: jest.fn(),
    };

    const mockedSessionStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockResolvedValueOnce(true),
    };

    const mockedLocalStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockRejectedValueOnce(error),
    };

    const mockedSecureStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockResolvedValueOnce(true),
    };

    const contextManager = new ContextKeysManager({
      logger: mockedLogger,
      sessionStorage: mockedSessionStorage,
      localStorage: mockedLocalStorage,
      secureStorage: mockedSecureStorage,
    });

    const removeReferenceForKey = jest
      .spyOn(contextManager, "removeReferenceForKey")
      .mockResolvedValueOnce(true);

    // run
    const result = await contextManager.removeKey(key);

    // verify
    expect(result).toEqual(false);

    expect(mockedLogger.warn).toHaveBeenCalledWith({
      message: error.message,
      data: { key },
    });

    expect(removeReferenceForKey).toHaveBeenCalledWith("key", "namespace");

    expect(mockedSessionStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );

    expect(mockedLocalStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );

    expect(mockedSecureStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );
  });

  it("returns false while removing secure-storage throw error", async () => {
    // setup
    const key = "namespace.key";
    const error = Error("oops");

    const mockedLogger = {
      warn: jest.fn(),
    };

    const mockedSessionStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockResolvedValueOnce(true),
    };

    const mockedLocalStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockResolvedValueOnce(true),
    };

    const mockedSecureStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn().mockRejectedValueOnce(error),
    };

    const contextManager = new ContextKeysManager({
      logger: mockedLogger,
      sessionStorage: mockedSessionStorage,
      localStorage: mockedLocalStorage,
      secureStorage: mockedSecureStorage,
    });

    const removeReferenceForKey = jest
      .spyOn(contextManager, "removeReferenceForKey")
      .mockResolvedValueOnce(true);

    // run
    const result = await contextManager.removeKey(key);

    // verify
    expect(result).toEqual(false);

    expect(mockedLogger.warn).toHaveBeenCalledWith({
      message: error.message,
      data: { key },
    });

    expect(removeReferenceForKey).toHaveBeenCalledWith("key", "namespace");

    expect(mockedSessionStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );

    expect(mockedLocalStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );

    expect(mockedSecureStorage.removeItem).toHaveBeenCalledWith(
      "key",
      "namespace"
    );
  });
});
