/* eslint-disable no-restricted-globals, no-restricted-syntax */

import {
  translateToNewGQLCollection,
  translateToNewRESTCollection,
} from "@hoppscotch/data"
import { watchDebounced } from "@vueuse/core"
import { TestContainer } from "dioc/testing"
import { cloneDeep } from "lodash-es"
import superjson from "superjson"
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"

import { MQTTRequest$, setMQTTRequest } from "~/newstore/MQTTSession"
import { SSERequest$, setSSERequest } from "~/newstore/SSESession"
import { SIORequest$, setSIORequest } from "~/newstore/SocketIOSession"
import { WSRequest$, setWSRequest } from "~/newstore/WebSocketSession"
import {
  graphqlCollectionStore,
  restCollectionStore,
  setGraphqlCollections,
  setRESTCollections,
} from "~/newstore/collections"
import {
  addGlobalEnvVariable,
  environments$,
  globalEnv$,
  replaceEnvironments,
  selectedEnvironmentIndex$,
  setGlobalEnvVariables,
  setSelectedEnvironmentIndex,
} from "~/newstore/environments"
import {
  graphqlHistoryStore,
  restHistoryStore,
  setGraphqlHistoryEntries,
  setRESTHistoryEntries,
  translateToNewGQLHistory,
  translateToNewRESTHistory,
} from "~/newstore/history"
import { bulkApplyLocalState, localStateStore } from "~/newstore/localstate"
import {
  applySetting,
  bulkApplySettings,
  performSettingsDataMigrations,
  settingsStore,
} from "~/newstore/settings"
import { GQLTabService } from "~/services/tab/graphql"
import { RESTTabService } from "~/services/tab/rest"
import {
  PersistenceService,
  STORE_KEYS,
  STORE_NAMESPACE,
} from "../../persistence"
import {
  ENVIRONMENTS_MOCK,
  GLOBAL_ENV_MOCK,
  GQL_COLLECTIONS_MOCK,
  GQL_HISTORY_MOCK,
  GQL_TAB_STATE_MOCK,
  MQTT_REQUEST_MOCK,
  REST_COLLECTIONS_MOCK,
  REST_HISTORY_MOCK,
  REST_TAB_STATE_MOCK,
  SECRET_ENVIRONMENTS_MOCK,
  SELECTED_ENV_INDEX_MOCK,
  SOCKET_IO_REQUEST_MOCK,
  SSE_REQUEST_MOCK,
  VUEX_DATA_MOCK,
  WEBSOCKET_REQUEST_MOCK,
} from "./__mocks__"
import { SecretEnvironmentService } from "~/services/secret-environment.service"
import { getKernelMode, initKernel } from "@hoppscotch/kernel"
import { Store } from "~/kernel"

initKernel(getKernelMode())

vi.mock("~/modules/i18n", () => {
  return {
    __esModule: true,
    getI18n: vi.fn().mockImplementation(() => () => "test"),
  }
})

// Define modules that are shared across methods here
vi.mock("@vueuse/core", async (importOriginal) => {
  const actualModule: Record<string, unknown> = await importOriginal()

  return {
    ...actualModule,
    watchDebounced: vi.fn(),
  }
})

vi.mock("~/newstore/environments", () => {
  return {
    addGlobalEnvVariable: vi.fn(),
    setGlobalEnvVariables: vi.fn(),
    replaceEnvironments: vi.fn(),
    setSelectedEnvironmentIndex: vi.fn(),
    environments$: {
      subscribe: vi.fn(),
    },
    globalEnv$: {
      subscribe: vi.fn(),
    },
    selectedEnvironmentIndex$: {
      subscribe: vi.fn(),
    },
  }
})

vi.mock("~/newstore/settings", () => {
  return {
    applySetting: vi.fn(),
  }
})

const toastErrorFn = vi.fn()

vi.mock("~/composables/toast", () => {
  return {
    useToast: () => ({ error: toastErrorFn }),
  }
})

/**
 * Helper functions
 */
const spyOnGetItem = () => vi.spyOn(Storage.prototype, "getItem")
const spyOnRemoveItem = () => vi.spyOn(Storage.prototype, "removeItem")
const spyOnSetItem = () => vi.spyOn(Storage.prototype, "setItem")

const schemaVersionKey = `${STORE_NAMESPACE}:${STORE_KEYS.SCHEMA_VERSION}`

const getStoreItem = async (key: string) => {
  const storedData = window.localStorage.getItem(key)

  if (!storedData) return

  const parsedData = superjson.parse<{ data: string }>(storedData)

  return JSON.stringify(parsedData.data)
}

const setStoreItem = async <T>(key: string, value: T) => {
  const storedData = {
    schemaVersion: 1,
    metadata: {
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
      namespace: STORE_NAMESPACE,
      encrypted: false,
      compressed: false,
    },
    data: value,
  }

  window.localStorage.setItem(key, superjson.stringify(storedData))
}

const bindPersistenceService = ({
  mockGQLTabService = false,
  mockRESTTabService = false,
  mockSecretEnvironmentsService = false,
  mock = {},
}: {
  mockGQLTabService?: boolean
  mockRESTTabService?: boolean
  mockSecretEnvironmentsService?: boolean
  mock?: Record<string, unknown>
} = {}) => {
  const container = new TestContainer()

  if (mockGQLTabService) {
    container.bindMock(GQLTabService, mock)
  }

  if (mockRESTTabService) {
    container.bindMock(RESTTabService, mock)
  }

  if (mockSecretEnvironmentsService) {
    container.bindMock(SecretEnvironmentService, mock)
  }

  container.bind(PersistenceService)

  const service = container.bind(PersistenceService)
  return service
}

const invokeSetupLocalPersistence = async (
  serviceBindMock?: Record<string, unknown>
) => {
  const service = bindPersistenceService(serviceBindMock)
  await service.setupFirst()
  await service.setupLater()
}

describe("PersistenceService", () => {
  beforeEach(() => {
    window.localStorage.clear()
  })

  beforeEach(async () => {
    await Store.remove(STORE_NAMESPACE, STORE_KEYS.SCHEMA_VERSION)
  })

  afterAll(() => {
    // Clear all mocks
    vi.clearAllMocks()

    // Restore the original implementation for any spied functions
    vi.restoreAllMocks()
  })

  describe("setup", () => {
    describe("Check and migrate old settings", () => {
      // Set of keys read from localStorage across test cases
      const bgColorKey = "BG_COLOR"
      const nuxtColorModeKey = "nuxt-color-mode"
      const selectedEnvIndexKey = "selectedEnvIndex"
      const themeColorKey = "THEME_COLOR"
      const vuexKey = "vuex"
      const storagePrefix = "persistence.v1:"

      beforeEach(() => {
        window.localStorage.clear()
      })

      beforeEach(async () => {
        await Store.remove(STORE_NAMESPACE, STORE_KEYS.SCHEMA_VERSION)
      })

      it(`sets the selected environment index type as "NO_ENV" in localStorage if the value retrieved for ${selectedEnvIndexKey} is "-1"`, async () => {
        window.localStorage.setItem(selectedEnvIndexKey, "-1")

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(selectedEnvIndexKey)
        expect(setItemSpy).toHaveBeenCalledWith(
          `${storagePrefix}selectedEnv`,
          expect.stringContaining(
            JSON.stringify({
              type: "NO_ENV_SELECTED",
            })
          )
        )
      })

      it(`sets the selected environment index type as "MY_ENV" in localStorage if the value retrieved for "${selectedEnvIndexKey}" is greater than "0"`, async () => {
        window.localStorage.setItem(selectedEnvIndexKey, "1")

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(selectedEnvIndexKey)
        expect(setItemSpy).toHaveBeenCalledWith(
          `${storagePrefix}selectedEnv`,
          expect.stringContaining(
            JSON.stringify({
              type: "MY_ENV",
              index: 1,
            })
          )
        )
      })

      it(`skips schema parsing and setting other properties if ${vuexKey} read from localStorage is an empty entity`, async () => {
        window.localStorage.setItem(vuexKey, JSON.stringify({}))

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(vuexKey)
        expect(toastErrorFn).not.toHaveBeenCalled()
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          `${storagePrefix}schema_version`,
          expect.stringMatching(/"schemaVersion":1/)
        )
      })

      it(`shows an error and sets the entry as a backup in localStorage if "${vuexKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `vuex`
        // `postwoman.settings.CURRENT_INTERCEPTOR_ID` -> `string`
        const vuexData = {
          ...VUEX_DATA_MOCK,
          postwoman: {
            ...VUEX_DATA_MOCK.postwoman,
            settings: {
              ...VUEX_DATA_MOCK.postwoman.settings,
              CURRENT_INTERCEPTOR_ID: 1234,
            },
          },
        }

        window.localStorage.setItem(vuexKey, JSON.stringify(vuexData))

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(vuexKey)
        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(vuexKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${vuexKey}-backup`,
          expect.stringContaining(JSON.stringify(vuexData))
        )
      })

      it(`shows an error and sets the entry as a backup in localStorage if "${themeColorKey}" read from localStorage doesn't match the schema`, async () => {
        const vuexData = cloneDeep(VUEX_DATA_MOCK)
        window.localStorage.setItem(vuexKey, JSON.stringify(vuexData))

        const themeColorValue = "invalid-color"
        window.localStorage.setItem(themeColorKey, themeColorValue)

        const getItemSpy = spyOnGetItem()
        const removeItemSpy = spyOnRemoveItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(vuexKey)
        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(themeColorKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${themeColorKey}-backup`,
          themeColorValue
        )
        expect(applySetting).not.toHaveBeenCalledWith(
          themeColorKey,
          themeColorValue
        )
        expect(removeItemSpy).toHaveBeenCalledWith(themeColorKey)
      })

      it(`shows an error and sets the entry as a backup in localStorage if "${nuxtColorModeKey}" read from localStorage doesn't match the schema`, async () => {
        const vuexData = cloneDeep(VUEX_DATA_MOCK)
        window.localStorage.setItem(vuexKey, JSON.stringify(vuexData))

        const nuxtColorModeValue = "invalid-color"
        window.localStorage.setItem(nuxtColorModeKey, nuxtColorModeValue)

        const getItemSpy = spyOnGetItem()
        const removeItemSpy = spyOnRemoveItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(vuexKey)
        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(nuxtColorModeKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${nuxtColorModeKey}-backup`,
          nuxtColorModeValue
        )
        expect(applySetting).not.toHaveBeenCalledWith(
          bgColorKey,
          nuxtColorModeValue
        )
        expect(removeItemSpy).toHaveBeenCalledWith(nuxtColorModeKey)
      })

      it(`extracts individual properties from the key "${vuexKey}" and sets them in localStorage`, async () => {
        const vuexData = cloneDeep(VUEX_DATA_MOCK)
        window.localStorage.setItem(vuexKey, JSON.stringify(vuexData))

        const themeColor = "red"
        const nuxtColorMode = "dark"

        window.localStorage.setItem(themeColorKey, themeColor)
        window.localStorage.setItem(nuxtColorModeKey, nuxtColorMode)

        const getItemSpy = spyOnGetItem()
        const removeItemSpy = spyOnRemoveItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(vuexKey)
        expect(toastErrorFn).not.toHaveBeenCalledWith(nuxtColorModeKey)
        expect(setItemSpy).not.toHaveBeenCalledWith(
          `${nuxtColorModeKey}-backup`
        )

        // Check settings is saved with new format
        expect(setItemSpy).toHaveBeenCalledWith(
          `${storagePrefix}settings`,
          expect.stringContaining(JSON.stringify(vuexData.postwoman.settings))
        )

        const { postwoman } = vuexData
        delete postwoman.settings

        // Check collections is saved with new format
        expect(setItemSpy).toHaveBeenCalledWith(
          `${storagePrefix}restCollections`,
          expect.stringContaining(JSON.stringify(postwoman.collections))
        )

        delete postwoman.collections

        // Check graphql collections is saved with new format
        expect(setItemSpy).toHaveBeenCalledWith(
          `${storagePrefix}gqlCollections`,
          expect.stringContaining(JSON.stringify(postwoman.collectionsGraphql))
        )

        delete postwoman.collectionsGraphql

        // Check environments is saved with new format
        expect(setItemSpy).toHaveBeenCalledWith(
          `${storagePrefix}environments`,
          expect.stringContaining(JSON.stringify(postwoman.environments))
        )

        delete postwoman.environments

        // Check theme color handling
        expect(getItemSpy).toHaveBeenCalledWith(themeColorKey)
        expect(applySetting).toHaveBeenCalledWith(themeColorKey, themeColor)
        expect(removeItemSpy).toHaveBeenCalledWith(themeColorKey)
        expect(window.localStorage.getItem(themeColorKey)).toBe(null)

        // Check color mode handling
        expect(getItemSpy).toHaveBeenCalledWith(nuxtColorModeKey)
        expect(applySetting).toHaveBeenCalledWith(bgColorKey, nuxtColorMode)
        expect(removeItemSpy).toHaveBeenCalledWith(nuxtColorModeKey)
        expect(window.localStorage.getItem(nuxtColorModeKey)).toBe(null)
      })
    })

    describe("Setup local state persistence", () => {
      // Key read from localStorage across test cases
      const localStateKey = `${STORE_NAMESPACE}:${STORE_KEYS.LOCAL_STATE}`

      it(`shows an error and sets the entry as a backup in localStorage if "${localStateKey}" read from localStorage has a value which is not a "string" or "undefined"`, async () => {
        const localStateData = {
          REMEMBERED_TEAM_ID: null,
        }
        await setStoreItem(localStateKey, localStateData)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(localStateKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(localStateKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${localStateKey}-backup`,
          expect.stringContaining(JSON.stringify(localStateData))
        )
      })

      it(`shows an error and sets the entry as a backup in localStorage if "${localStateKey}" read from localStorage has an invalid key`, async () => {
        const localStateData = {
          INVALID_KEY: null,
        }
        await setStoreItem(localStateKey, localStateData)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(localStateKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(localStateKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${localStateKey}-backup`,
          expect.stringContaining(JSON.stringify(localStateData))
        )
      })

      it(`schema parsing succeeds if there is no "${localStateKey}" key present in localStorage where the fallback of "{}" is chosen`, async () => {
        window.localStorage.removeItem(localStateKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(localStateKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(localStateKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )
      })

      it(`reads the value for "${localStateKey}" key from localStorage, invokes "bulkApplyLocalState" function if a value is yielded and subscribes to "localStateStore" updates`, async () => {
        vi.mock("~/newstore/localstate", () => {
          return {
            bulkApplyLocalState: vi.fn(),
            localStateStore: {
              subject$: {
                subscribe: vi.fn(),
              },
            },
          }
        })

        const localStateData = {
          REMEMBERED_TEAM_ID: "test-id",
        }
        await setStoreItem(localStateKey, localStateData)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(localStateKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(localStateKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )

        expect(bulkApplyLocalState).toHaveBeenCalledWith(localStateData)
        expect(localStateStore.subject$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })
    })

    describe("setup settings persistence", () => {
      // Key read from localStorage across test cases
      const settingsKey = `${STORE_NAMESPACE}:${STORE_KEYS.SETTINGS}`

      it(`shows an error and sets the entry as a backup in localStorage if "${settingsKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `settings`
        // Expected values are booleans
        const settings = {
          EXTENSIONS_ENABLED: "true",
          PROXY_ENABLED: "true",
        }
        await setStoreItem(settingsKey, settings)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(settingsKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(settingsKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${settingsKey}-backup`,
          expect.stringContaining(JSON.stringify(settings))
        )
      })

      it(`schema parsing succeeds if there is no "${settingsKey}" key present in localStorage where the fallback of "{}" is chosen`, async () => {
        window.localStorage.removeItem(settingsKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(settingsKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(settingsKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )
      })

      it(`reads the value for "${settingsKey}" from localStorage, invokes "performSettingsDataMigrations" and "bulkApplySettings" functions as required and subscribes to "settingsStore" updates`, async () => {
        vi.mock("~/newstore/settings", async (importOriginal) => {
          const actualModule: Record<string, unknown> = await importOriginal()

          return {
            ...actualModule,
            applySetting: vi.fn(),
            bulkApplySettings: vi.fn(),
            performSettingsDataMigrations: vi
              .fn()
              .mockImplementation((data: any) => data),
            settingsStore: {
              subject$: {
                subscribe: vi.fn(),
              },
            },
          }
        })

        const { settings } = VUEX_DATA_MOCK.postwoman
        await setStoreItem(settingsKey, settings)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(settingsKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(settingsKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )

        expect(performSettingsDataMigrations).toHaveBeenCalledWith(settings)
        expect(bulkApplySettings).toHaveBeenCalledWith(settings)

        expect(settingsStore.subject$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })
    })

    describe("setup history persistence", () => {
      // Keys read from localStorage across test cases
      const historyKey = `${STORE_NAMESPACE}:${STORE_KEYS.REST_HISTORY}`
      const graphqlHistoryKey = `${STORE_NAMESPACE}:${STORE_KEYS.GQL_HISTORY}`

      it(`shows an error and sets the entry as a backup in localStorage if "${historyKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `history`
        // `v` -> `number`
        const restHistoryData = [{ ...REST_HISTORY_MOCK, v: "1" }]
        await setStoreItem(historyKey, restHistoryData)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(historyKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(historyKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${historyKey}-backup`,
          expect.stringContaining(JSON.stringify(restHistoryData))
        )
      })

      it(`REST history schema parsing succeeds if there is no "${historyKey}" key present in localStorage where the fallback of "[]" is chosen`, async () => {
        window.localStorage.removeItem(historyKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(historyKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(historyKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )
      })

      it(`shows an error and sets the entry as a backup in localStorage if "${graphqlHistoryKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `graphqlHistory`
        // `v` -> `number`
        const graphqlHistoryData = [{ ...GQL_HISTORY_MOCK, v: "1" }]
        await setStoreItem(graphqlHistoryKey, graphqlHistoryData)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(graphqlHistoryKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(graphqlHistoryKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${graphqlHistoryKey}-backup`,
          expect.stringContaining(JSON.stringify(graphqlHistoryData))
        )
      })

      it(`GQL history schema parsing succeeds if there is no "${graphqlHistoryKey}" key present in localStorage where the fallback of "[]" is chosen`, async () => {
        window.localStorage.removeItem(graphqlHistoryKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(graphqlHistoryKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(graphqlHistoryKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )
      })

      it("reads REST and GQL history entries from localStorage, translates them to the new format, writes back the updates and subscribes to the respective store for updates", async () => {
        vi.mock("~/newstore/history", () => {
          return {
            setGraphqlHistoryEntries: vi.fn(),
            setRESTHistoryEntries: vi.fn(),
            translateToNewGQLHistory: vi
              .fn()
              .mockImplementation((data: any) => data),
            translateToNewRESTHistory: vi
              .fn()
              .mockImplementation((data: any) => data),
            graphqlHistoryStore: {
              subject$: {
                subscribe: vi.fn(),
              },
            },
            restHistoryStore: {
              subject$: {
                subscribe: vi.fn(),
              },
            },
          }
        })

        const restHistory = REST_HISTORY_MOCK
        const gqlHistory = GQL_HISTORY_MOCK

        await setStoreItem(historyKey, restHistory)
        await setStoreItem(graphqlHistoryKey, gqlHistory)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(historyKey)
        expect(getItemSpy).toHaveBeenCalledWith(graphqlHistoryKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(
          historyKey,
          graphqlHistoryKey
        )
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )

        expect(translateToNewRESTHistory).toHaveBeenCalled()
        expect(translateToNewGQLHistory).toHaveBeenCalled()

        expect(setRESTHistoryEntries).toHaveBeenCalledWith(restHistory)
        expect(setGraphqlHistoryEntries).toHaveBeenCalledWith(gqlHistory)

        expect(restHistoryStore.subject$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
        expect(graphqlHistoryStore.subject$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })
    })

    describe("setup collections persistence", () => {
      // Keys read from localStorage across test cases
      const collectionsRESTKey = `${STORE_NAMESPACE}:${STORE_KEYS.REST_COLLECTIONS}`
      const collectionsGraphqlKey = `${STORE_NAMESPACE}:${STORE_KEYS.GQL_COLLECTIONS}`

      it(`shows an error and sets the entry as a backup in localStorage if "${collectionsRESTKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `collections`
        // `v` -> `number`
        const restCollectionsData = [{ ...REST_COLLECTIONS_MOCK, v: "1" }]
        await setStoreItem(collectionsRESTKey, restCollectionsData)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(collectionsRESTKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(collectionsRESTKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${collectionsRESTKey}-backup`,
          expect.stringContaining(JSON.stringify(restCollectionsData))
        )
      })

      it(`REST collections schema parsing succeeds if there is no "${collectionsRESTKey}" key present in localStorage where the fallback of "[]" is chosen`, async () => {
        window.localStorage.removeItem(collectionsRESTKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(collectionsRESTKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(collectionsRESTKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )
      })

      it(`shows an error and sets the entry as a backup in localStorage if "${collectionsGraphqlKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `collectionsGraphql`
        // `v` -> `number`
        const graphqlCollectionsData = [{ ...GQL_COLLECTIONS_MOCK, v: "1" }]
        await setStoreItem(collectionsGraphqlKey, graphqlCollectionsData)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(collectionsGraphqlKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(collectionsGraphqlKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${collectionsGraphqlKey}-backup`,
          expect.stringContaining(JSON.stringify(graphqlCollectionsData))
        )
      })

      it(`GQL collections schema parsing succeeds if there is no "${collectionsGraphqlKey}" key present in localStorage where the fallback of "[]" is chosen`, async () => {
        window.localStorage.removeItem(collectionsGraphqlKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(collectionsGraphqlKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(collectionsGraphqlKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )
      })

      it("reads REST and GQL collection entries from localStorage, translates them to the new format, writes back the updates and subscribes to the respective store for updates", async () => {
        vi.mock("@hoppscotch/data", async (importOriginal) => {
          const actualModule: Record<string, unknown> = await importOriginal()

          return {
            ...actualModule,
            translateToNewGQLCollection: vi
              .fn()
              .mockImplementation((data: any) => data),
            translateToNewRESTCollection: vi
              .fn()
              .mockImplementation((data: any) => data),
          }
        })

        vi.mock("~/newstore/collections", () => {
          return {
            setGraphqlCollections: vi.fn(),
            setRESTCollections: vi.fn(),
            graphqlCollectionStore: {
              subject$: {
                subscribe: vi.fn(),
              },
            },
            restCollectionStore: {
              subject$: {
                subscribe: vi.fn(),
              },
            },
          }
        })

        const restCollections = REST_COLLECTIONS_MOCK
        const gqlCollections = GQL_COLLECTIONS_MOCK

        await setStoreItem(collectionsRESTKey, restCollections)
        await setStoreItem(collectionsGraphqlKey, gqlCollections)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(collectionsRESTKey)
        expect(getItemSpy).toHaveBeenCalledWith(collectionsGraphqlKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(
          collectionsRESTKey,
          collectionsGraphqlKey
        )
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(translateToNewGQLCollection).toHaveBeenCalled()
        expect(translateToNewRESTCollection).toHaveBeenCalled()

        expect(setRESTCollections).toHaveBeenCalledWith(restCollections)
        expect(setGraphqlCollections).toHaveBeenCalledWith(gqlCollections)

        expect(graphqlCollectionStore.subject$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
        expect(restCollectionStore.subject$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })
    })

    describe("setup environments persistence", () => {
      // Key read from localStorage across test cases
      const environmentsKey = `${STORE_NAMESPACE}:${STORE_KEYS.ENVIRONMENTS}`

      it(`shows an error and sets the entry as a backup in localStorage if "${environmentsKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `environments`
        const environments = [
          // `entries` -> `variables`
          {
            v: 1,
            id: "ENV_1",
            name: "Test",
            entries: [{ key: "test-key", value: "test-value", secret: false }],
          },
        ]

        await setStoreItem(environmentsKey, environments)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(environmentsKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(environmentsKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${environmentsKey}-backup`,
          expect.stringContaining(JSON.stringify(environments))
        )
      })

      it(`separates "globals" entries from "${environmentsKey}", subscribes to the "environmentStore" and updates localStorage entries`, async () => {
        const environments = cloneDeep(ENVIRONMENTS_MOCK)
        await setStoreItem(environmentsKey, environments)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(environmentsKey)
        expect(toastErrorFn).not.toHaveBeenCalledWith(environmentsKey)
        expect(setItemSpy).not.toHaveBeenCalledWith(`${environmentsKey}-backup`)

        expect(addGlobalEnvVariable).toHaveBeenCalledWith(
          environments[0].variables[0]
        )

        // Removes `globals` from environments
        environments.splice(0, 1)

        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )
        expect(replaceEnvironments).toBeCalledWith(environments)
        expect(environments$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })
    })

    describe("setup selected environment persistence", () => {
      // Key read from localStorage across test cases
      const selectedEnvIndexKey = `${STORE_NAMESPACE}:${STORE_KEYS.SELECTED_ENV}`

      it(`shows an error and sets the entry as a backup in localStorage if "${selectedEnvIndexKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `selectedEnvIndex`
        // `index` -> `number`
        const selectedEnvIndex = { ...SELECTED_ENV_INDEX_MOCK, index: "1" }

        await setStoreItem(selectedEnvIndexKey, selectedEnvIndex)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(selectedEnvIndexKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(selectedEnvIndexKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${selectedEnvIndexKey}-backup`,
          expect.stringContaining(JSON.stringify(selectedEnvIndex))
        )
      })

      it(`schema parsing succeeds if there is no "${selectedEnvIndexKey}" key present in localStorage where the fallback of "null" is chosen`, async () => {
        window.localStorage.removeItem(selectedEnvIndexKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(selectedEnvIndexKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(selectedEnvIndexKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )
      })

      it(`sets it to the store if there is a value associated with the "${selectedEnvIndexKey}" key in localStorage`, async () => {
        const selectedEnvIndex = SELECTED_ENV_INDEX_MOCK

        await setStoreItem(selectedEnvIndexKey, selectedEnvIndex)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(selectedEnvIndexKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(selectedEnvIndexKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(setSelectedEnvironmentIndex).toHaveBeenCalledWith(
          selectedEnvIndex
        )
        expect(selectedEnvironmentIndex$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })

      it(`sets it to "NO_ENV_SELECTED" if there is no value associated with the "${selectedEnvIndexKey}" in localStorage`, async () => {
        window.localStorage.removeItem(selectedEnvIndexKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(selectedEnvIndexKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(selectedEnvIndexKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(setSelectedEnvironmentIndex).toHaveBeenCalledWith({
          type: "NO_ENV_SELECTED",
        })
        expect(selectedEnvironmentIndex$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })
    })

    describe("setup secret Environments persistence", () => {
      // Key read from localStorage across test cases
      const secretEnvironmentsKey = `${STORE_NAMESPACE}:${STORE_KEYS.SECRET_ENVIRONMENTS}`

      const loadSecretEnvironmentsFromPersistedStateFn = vi.fn()
      const mock = {
        loadSecretEnvironmentsFromPersistedState:
          loadSecretEnvironmentsFromPersistedStateFn,
      }

      it(`shows an error and sets the entry as a backup in localStorage if "${secretEnvironmentsKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `secretEnvironments`
        const secretEnvironments = {
          clryz7ir7002al4162bsj0azg: {
            key: "ENV_KEY",
            value: "ENV_VALUE",
          },
        }

        await setStoreItem(secretEnvironmentsKey, secretEnvironments)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(secretEnvironmentsKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(secretEnvironmentsKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${secretEnvironmentsKey}-backup`,
          expect.stringContaining(JSON.stringify(secretEnvironments))
        )
      })

      it("loads secret environments from the state persisted in localStorage and sets watcher for `persistableSecretEnvironment`", async () => {
        const secretEnvironment = SECRET_ENVIRONMENTS_MOCK
        await setStoreItem(secretEnvironmentsKey, secretEnvironment)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence({
          mockSecretEnvironmentsService: true,
          mock,
        })

        expect(getItemSpy).toHaveBeenCalledWith(secretEnvironmentsKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(secretEnvironmentsKey)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(loadSecretEnvironmentsFromPersistedStateFn).toHaveBeenCalledWith(
          secretEnvironment
        )
        expect(watchDebounced).toHaveBeenCalled()
      })

      it(`skips schema parsing and the loading of persisted secret environments if there is no "${secretEnvironmentsKey}" key present in localStorage`, async () => {
        window.localStorage.removeItem(secretEnvironmentsKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence({
          mockSecretEnvironmentsService: true,
          mock,
        })

        expect(getItemSpy).toHaveBeenCalledWith(secretEnvironmentsKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(secretEnvironmentsKey)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(watchDebounced).toHaveBeenCalled()
      })

      it("logs an error to the console on failing to parse persisted secret environments", async () => {
        await setStoreItem(secretEnvironmentsKey, "invalid-json")

        console.error = vi.fn()
        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(secretEnvironmentsKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(secretEnvironmentsKey)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(console.error).toHaveBeenCalledWith(
          `Failed parsing persisted SECRET_ENVIRONMENTS:`,
          await getStoreItem(secretEnvironmentsKey)
        )

        expect(watchDebounced).toHaveBeenCalledWith(
          expect.any(Object),
          expect.any(Function),
          { debounce: 500 }
        )
      })
    })

    describe("setup WebSocket persistence", () => {
      // Key read from localStorage across test cases
      const wsRequestKey = `${STORE_NAMESPACE}:${STORE_KEYS.WEBSOCKET}`

      it(`shows an error and sets the entry as a backup in localStorage if "${wsRequestKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `WebsocketRequest`
        const request = {
          ...WEBSOCKET_REQUEST_MOCK,
          // `protocols` -> `[]`
          protocols: {},
        }

        await setStoreItem(wsRequestKey, request)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(wsRequestKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(wsRequestKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${wsRequestKey}-backup`,
          expect.stringContaining(JSON.stringify(request))
        )
      })

      it(`schema parsing succeeds if there is no "${wsRequestKey}" key present in localStorage where the fallback of "null" is chosen`, async () => {
        window.localStorage.removeItem(wsRequestKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(wsRequestKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(wsRequestKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )
      })

      it(`reads the "${wsRequestKey}" entry from localStorage, sets it as the new request, subscribes to the "WSSessionStore" and updates localStorage entries`, async () => {
        vi.mock("~/newstore/WebSocketSession", () => {
          return {
            setWSRequest: vi.fn(),
            WSRequest$: {
              subscribe: vi.fn(),
            },
          }
        })

        const request = WEBSOCKET_REQUEST_MOCK
        await setStoreItem(wsRequestKey, request)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(wsRequestKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(wsRequestKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(setWSRequest).toHaveBeenCalledWith(request)
        expect(WSRequest$.subscribe).toHaveBeenCalledWith(expect.any(Function))
      })
    })

    describe("setup Socket.IO persistence", () => {
      // Key read from localStorage across test cases
      const sioRequestKey = `${STORE_NAMESPACE}:${STORE_KEYS.SOCKETIO}`

      it(`shows an error and sets the entry as a backup in localStorage if "${sioRequestKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `SocketIORequest`
        const request = {
          ...SOCKET_IO_REQUEST_MOCK,
          // `v` -> `version: v4`
          v: "4",
        }

        await setStoreItem(sioRequestKey, request)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(sioRequestKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(sioRequestKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${sioRequestKey}-backup`,
          expect.stringContaining(JSON.stringify(request))
        )
      })

      it(`schema parsing succeeds if there is no "${sioRequestKey}" key present in localStorage where the fallback of "null" is chosen`, async () => {
        window.localStorage.removeItem(sioRequestKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(sioRequestKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(sioRequestKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )
      })

      it(`reads the "${sioRequestKey}" entry from localStorage, sets it as the new request, subscribes to the "SIOSessionStore" and updates localStorage entries`, async () => {
        vi.mock("~/newstore/SocketIOSession", () => {
          return {
            setSIORequest: vi.fn(),
            SIORequest$: {
              subscribe: vi.fn(),
            },
          }
        })

        const request = SOCKET_IO_REQUEST_MOCK
        await setStoreItem(sioRequestKey, request)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(sioRequestKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(sioRequestKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(setSIORequest).toHaveBeenCalledWith(request)
        expect(SIORequest$.subscribe).toHaveBeenCalledWith(expect.any(Function))
      })
    })

    describe("setup SSE persistence", () => {
      // Key read from localStorage across test cases
      const sseRequestKey = `${STORE_NAMESPACE}:${STORE_KEYS.SSE}`

      it(`shows an error and sets the entry as a backup in localStorage if "${sseRequestKey}" read from localStorage doesn't match the versioned schema`, async () => {
        // Invalid shape for `SSERequest`
        const request = {
          ...SSE_REQUEST_MOCK,
          // `url` -> `endpoint`
          url: "https://express-eventsource.herokuapp.com/events",
        }

        await setStoreItem(sseRequestKey, request)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(sseRequestKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(sseRequestKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${sseRequestKey}-backup`,
          expect.stringContaining(JSON.stringify(request))
        )
      })

      it(`schema parsing succeeds if there is no "${sseRequestKey}" key present in localStorage where the fallback of "null" is chosen`, async () => {
        window.localStorage.removeItem(sseRequestKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(sseRequestKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(sseRequestKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )
      })

      it(`reads the "${sseRequestKey}" entry from localStorage, sets it as the new request, subscribes to the "SSESessionStore" and updates localStorage entries`, async () => {
        vi.mock("~/newstore/SSESession", () => {
          return {
            setSSERequest: vi.fn(),
            SSERequest$: {
              subscribe: vi.fn(),
            },
          }
        })

        const request = SSE_REQUEST_MOCK
        await setStoreItem(sseRequestKey, request)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(sseRequestKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(sseRequestKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(setSSERequest).toHaveBeenCalledWith(request)
        expect(SSERequest$.subscribe).toHaveBeenCalledWith(expect.any(Function))
      })
    })

    describe("setup MQTT persistence", () => {
      // Key read from localStorage across test cases
      const mqttRequestKey = `${STORE_NAMESPACE}:${STORE_KEYS.MQTT}`

      it(`shows an error and sets the entry as a backup in localStorage if "${mqttRequestKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `MQTTRequest`
        const request = {
          ...MQTT_REQUEST_MOCK,
          // `url` -> `endpoint`
          url: "wss://test.mosquitto.org:8081",
        }

        await setStoreItem(mqttRequestKey, request)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(mqttRequestKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(mqttRequestKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${mqttRequestKey}-backup`,
          expect.stringContaining(JSON.stringify(request))
        )
      })

      it(`schema parsing succeeds if there is no "${mqttRequestKey}" key present in localStorage where the fallback of "null" is chosen`, async () => {
        window.localStorage.removeItem(mqttRequestKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(mqttRequestKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(mqttRequestKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )
      })

      it(`reads the ${mqttRequestKey}" entry from localStorage, sets it as the new request, subscribes to the "MQTTSessionStore" and updates localStorage entries`, async () => {
        vi.mock("~/newstore/MQTTSession", () => {
          return {
            setMQTTRequest: vi.fn(),
            MQTTRequest$: {
              subscribe: vi.fn(),
            },
          }
        })

        const request = MQTT_REQUEST_MOCK
        await setStoreItem(mqttRequestKey, request)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(mqttRequestKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(mqttRequestKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(setMQTTRequest).toHaveBeenCalledWith(request)
        expect(MQTTRequest$.subscribe).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })
    })

    describe("setup global environments persistence", () => {
      // Key read from localStorage across test cases
      const globalEnvKey = `${STORE_NAMESPACE}:${STORE_KEYS.GLOBAL_ENV}`

      it(`shows an error and sets the entry as a backup in localStorage if "${globalEnvKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `globalEnv`
        const globalEnv = [
          {
            // `key` -> `string`
            key: 1,
            value: "test-value",
          },
        ]

        await setStoreItem(globalEnvKey, globalEnv)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(globalEnvKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(globalEnvKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${globalEnvKey}-backup`,
          expect.stringContaining(JSON.stringify(globalEnv))
        )
      })

      it(`schema parsing succeeds if there is no "${globalEnvKey}" key present in localStorage where the fallback of "[]" is chosen`, async () => {
        window.localStorage.removeItem(globalEnvKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(globalEnvKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(globalEnvKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )
      })

      it(`reads the "globalEnv" entry from localStorage, dispatches the new value, subscribes to the "environmentsStore" and updates localStorage entries`, async () => {
        const globalEnv = GLOBAL_ENV_MOCK
        await setStoreItem(globalEnvKey, globalEnv)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(globalEnvKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(globalEnvKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringContaining('"schemaVersion":1')
        )

        expect(setGlobalEnvVariables).toHaveBeenCalledWith(globalEnv)
        expect(globalEnv$.subscribe).toHaveBeenCalledWith(expect.any(Function))
      })
    })

    describe("setup GQL tabs persistence", () => {
      // Key read from localStorage across test cases
      const gqlTabStateKey = `${STORE_NAMESPACE}:${STORE_KEYS.GQL_TABS}`

      const loadTabsFromPersistedStateFn = vi.fn()
      const mock = { loadTabsFromPersistedState: loadTabsFromPersistedStateFn }

      it(`shows an error and sets the entry as a backup in localStorage if "${gqlTabStateKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `gqlTabState`
        // `lastActiveTabID` -> `string`
        const gqlTabState = { ...GQL_TAB_STATE_MOCK, lastActiveTabID: 1234 }

        await setStoreItem(gqlTabStateKey, gqlTabState)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(gqlTabStateKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(gqlTabStateKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${gqlTabStateKey}-backup`,
          expect.stringContaining(JSON.stringify(gqlTabState))
        )
      })

      it(`skips schema parsing and the loading of persisted tabs if there is no "${gqlTabStateKey}" key present in localStorage`, async () => {
        window.localStorage.removeItem(gqlTabStateKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence({ mockGQLTabService: true, mock })

        expect(getItemSpy).toHaveBeenCalledWith(gqlTabStateKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(gqlTabStateKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )

        expect(loadTabsFromPersistedStateFn).not.toHaveBeenCalled()

        expect(watchDebounced).toHaveBeenCalled()
      })

      it("loads tabs from the state persisted in localStorage and sets watcher for `persistableTabState`", async () => {
        const tabState = GQL_TAB_STATE_MOCK
        await setStoreItem(gqlTabStateKey, tabState)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence({ mockGQLTabService: true, mock })

        expect(getItemSpy).toHaveBeenCalledWith(gqlTabStateKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(gqlTabStateKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )

        expect(loadTabsFromPersistedStateFn).toHaveBeenCalledWith(tabState)
        expect(watchDebounced).toHaveBeenCalledWith(
          expect.any(Object),
          expect.any(Function),
          { debounce: 500, deep: true }
        )
      })

      it("logs an error to the console on failing to parse persisted gql tab state", async () => {
        await setStoreItem(gqlTabStateKey, "invalid-json")

        console.error = vi.fn()
        const getItemSpy = spyOnGetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(gqlTabStateKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(gqlTabStateKey)

        expect(console.error).toHaveBeenCalledWith(
          `Failed parsing persisted GQL_TABS:`,
          await getStoreItem(gqlTabStateKey)
        )
        expect(watchDebounced).toHaveBeenCalledWith(
          expect.any(Object),
          expect.any(Function),
          { debounce: 500, deep: true }
        )
      })
    })

    describe("setup REST tabs persistence", () => {
      // Key read from localStorage across test cases
      const restTabStateKey = `${STORE_NAMESPACE}:${STORE_KEYS.REST_TABS}`

      const loadTabsFromPersistedStateFn = vi.fn()
      const mock = { loadTabsFromPersistedState: loadTabsFromPersistedStateFn }

      it(`shows an error and sets the entry as a backup in localStorage if "${restTabStateKey}" read from localStorage doesn't match the schema`, async () => {
        // Invalid shape for `restTabState`
        // `lastActiveTabID` -> `string`
        const restTabState = { ...REST_TAB_STATE_MOCK, lastActiveTabID: 1234 }

        await setStoreItem(restTabStateKey, restTabState)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(restTabStateKey)

        expect(toastErrorFn).toHaveBeenCalledWith(
          expect.stringContaining(restTabStateKey)
        )
        expect(setItemSpy).toHaveBeenCalledWith(
          `${restTabStateKey}-backup`,
          expect.stringContaining(JSON.stringify(restTabState))
        )
      })

      it(`skips schema parsing and the loading of persisted tabs if there is no "${restTabStateKey}" key present in localStorage`, async () => {
        window.localStorage.removeItem(restTabStateKey)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence({ mockRESTTabService: true, mock })

        expect(getItemSpy).toHaveBeenCalledWith(restTabStateKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(restTabStateKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )
        expect(loadTabsFromPersistedStateFn).not.toHaveBeenCalled()

        expect(watchDebounced).toHaveBeenCalled()
      })

      it("loads tabs from the state persisted in localStorage and sets watcher for `persistableTabState`", async () => {
        const tabState = REST_TAB_STATE_MOCK
        await setStoreItem(restTabStateKey, tabState)

        const getItemSpy = spyOnGetItem()
        const setItemSpy = spyOnSetItem()

        await invokeSetupLocalPersistence({ mockRESTTabService: true, mock })

        expect(getItemSpy).toHaveBeenCalledWith(restTabStateKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(restTabStateKey)
        expect(setItemSpy).toHaveBeenCalledTimes(1)
        expect(setItemSpy).toHaveBeenCalledWith(
          schemaVersionKey,
          expect.stringMatching(/"schemaVersion":1/)
        )

        expect(loadTabsFromPersistedStateFn).toHaveBeenCalledWith(tabState)
        expect(watchDebounced).toHaveBeenCalledWith(
          expect.any(Object),
          expect.any(Function),
          { debounce: 500, deep: true }
        )
      })

      it("logs an error to the console on failing to parse persisted rest tab state", async () => {
        await setStoreItem(restTabStateKey, "invalid-json")

        console.error = vi.fn()
        const getItemSpy = spyOnGetItem()

        await invokeSetupLocalPersistence()

        expect(getItemSpy).toHaveBeenCalledWith(restTabStateKey)

        expect(toastErrorFn).not.toHaveBeenCalledWith(restTabStateKey)

        expect(console.error).toHaveBeenCalledWith(
          `Failed parsing persisted REST_TABS:`,
          await getStoreItem(restTabStateKey)
        )
        expect(watchDebounced).toHaveBeenCalledWith(
          expect.any(Object),
          expect.any(Function),
          { debounce: 500, deep: true }
        )
      })
    })
  })

  it("`setLocalConfig` method sets a value in localStorage", async () => {
    const testKey = "test-key"
    const testValue = "test-value"

    const setItemSpy = spyOnSetItem()

    const service = bindPersistenceService()

    await service.setLocalConfig(testKey, testValue)
    expect(setItemSpy).toHaveBeenCalledWith(
      `${STORE_NAMESPACE}:${testKey}`,
      expect.stringContaining(testValue)
    )
  })

  it("`getLocalConfig` method gets a value from localStorage", async () => {
    const testKey = "test-key"
    const testValue = "test-value"

    const setItemSpy = spyOnSetItem()
    const getItemSpy = spyOnGetItem()

    const service = bindPersistenceService()

    await service.setLocalConfig(testKey, testValue)
    const retrievedValue = await service.getLocalConfig(testKey)

    expect(setItemSpy).toHaveBeenCalledWith(
      `${STORE_NAMESPACE}:${testKey}`,
      expect.stringContaining(testValue)
    )
    expect(getItemSpy).toHaveBeenCalledWith(`${STORE_NAMESPACE}:${testKey}`)
    expect(retrievedValue).toBe(testValue)
  })

  it("`removeLocalConfig` method clears a value in localStorage", async () => {
    const testKey = "test-key"
    const testValue = "test-value"

    const setItemSpy = spyOnSetItem()
    const removeItemSpy = spyOnRemoveItem()

    const service = bindPersistenceService()

    await service.setLocalConfig(testKey, testValue)
    await service.removeLocalConfig(testKey)

    expect(setItemSpy).toHaveBeenCalledWith(
      `${STORE_NAMESPACE}:${testKey}`,
      expect.stringContaining(testValue)
    )
    expect(removeItemSpy).toHaveBeenCalledWith(`${STORE_NAMESPACE}:${testKey}`)
  })
})
