2023-11-29 17:10:26 +00:00
/* 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 { afterAll , 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 } 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 ,
2024-02-08 16:28:42 +00:00
SECRET_ENVIRONMENTS_MOCK ,
2023-11-29 17:10:26 +00:00
SELECTED_ENV_INDEX_MOCK ,
SOCKET_IO_REQUEST_MOCK ,
SSE_REQUEST_MOCK ,
VUEX_DATA_MOCK ,
WEBSOCKET_REQUEST_MOCK ,
} from "./__mocks__"
2024-02-08 16:28:42 +00:00
import { SecretEnvironmentService } from "~/services/secret-environment.service"
2023-11-29 17:10:26 +00:00
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 bindPersistenceService = ( {
mockGQLTabService = false ,
mockRESTTabService = false ,
2024-02-08 16:28:42 +00:00
mockSecretEnvironmentsService = false ,
2023-11-29 17:10:26 +00:00
mock = { } ,
} : {
mockGQLTabService? : boolean
mockRESTTabService? : boolean
2024-02-08 16:28:42 +00:00
mockSecretEnvironmentsService? : boolean
2023-11-29 17:10:26 +00:00
mock? : Record < string , unknown >
} = { } ) = > {
const container = new TestContainer ( )
if ( mockGQLTabService ) {
container . bindMock ( GQLTabService , mock )
}
if ( mockRESTTabService ) {
container . bindMock ( RESTTabService , mock )
}
2024-02-08 16:28:42 +00:00
if ( mockSecretEnvironmentsService ) {
container . bindMock ( SecretEnvironmentService , mock )
}
2023-11-29 17:10:26 +00:00
container . bind ( PersistenceService )
const service = container . bind ( PersistenceService )
return service
}
const invokeSetupLocalPersistence = (
serviceBindMock? : Record < string , unknown >
) = > {
const service = bindPersistenceService ( serviceBindMock )
service . setupLocalPersistence ( )
}
describe ( "PersistenceService" , ( ) = > {
afterAll ( ( ) = > {
// Clear all mocks
vi . clearAllMocks ( )
// Restore the original implementation for any spied functions
vi . restoreAllMocks ( )
} )
describe ( "setupLocalPersistence" , ( ) = > {
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"
it ( ` sets the selected environment index type as "NO_ENV" in localStorage if the value retrieved for ${ selectedEnvIndexKey } is "-1" ` , ( ) = > {
window . localStorage . setItem ( selectedEnvIndexKey , "-1" )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( setItemSpy ) . toHaveBeenCalledWith (
selectedEnvIndexKey ,
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" ` , ( ) = > {
window . localStorage . setItem ( selectedEnvIndexKey , "1" )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( setItemSpy ) . toHaveBeenCalledWith (
selectedEnvIndexKey ,
JSON . stringify ( {
type : "MY_ENV" ,
index : 1 ,
} )
)
} )
it ( ` skips schema parsing and setting other properties if ${ vuexKey } read from localStorage is an empty entity ` , ( ) = > {
window . localStorage . setItem ( vuexKey , JSON . stringify ( { } ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( vuexKey )
expect ( toastErrorFn ) . not . toHaveBeenCalled ( )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ vuexKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// 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 ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( vuexKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( vuexKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ vuexKey } -backup ` ,
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 ` , ( ) = > {
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 ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( vuexKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( themeColorKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ themeColorKey } -backup ` ,
themeColorValue
)
expect ( applySetting ) . 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 ` , ( ) = > {
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 ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( vuexKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( nuxtColorModeKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ nuxtColorModeKey } -backup ` ,
nuxtColorModeValue
)
expect ( applySetting ) . toHaveBeenCalledWith (
bgColorKey ,
nuxtColorModeValue
)
expect ( removeItemSpy ) . toHaveBeenCalledWith ( nuxtColorModeKey )
} )
it ( ` extracts individual properties from the key " ${ vuexKey } " and sets them in localStorage ` , ( ) = > {
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 ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( vuexKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( nuxtColorModeKey )
expect ( setItemSpy ) . not . toHaveBeenCalledWith (
` ${ nuxtColorModeKey } -backup `
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
"settings" ,
JSON . stringify ( vuexData . postwoman . settings )
)
const { postwoman } = vuexData
delete postwoman . settings
expect ( setItemSpy ) . toHaveBeenCalledWith (
vuexKey ,
JSON . stringify ( vuexData )
)
// Excluding `settings`
expect ( setItemSpy ) . toHaveBeenCalledWith (
"collections" ,
JSON . stringify ( postwoman . collections )
)
delete postwoman . collections
// Excluding `settings` & `collections`
expect ( setItemSpy ) . toHaveBeenCalledWith (
vuexKey ,
JSON . stringify ( vuexData )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
"collectionsGraphql" ,
JSON . stringify ( postwoman . collectionsGraphql )
)
delete postwoman . collectionsGraphql
// Excluding `settings, `collections` & `collectionsGraphql`
expect ( setItemSpy ) . toHaveBeenCalledWith (
vuexKey ,
JSON . stringify ( vuexData )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
"environments" ,
JSON . stringify ( postwoman . environments )
)
delete postwoman . environments
// Excluding `settings, `collections`, `collectionsGraphql` & `environments`
expect ( setItemSpy ) . toHaveBeenCalledWith (
vuexKey ,
JSON . stringify ( vuexData )
)
expect ( getItemSpy ) . toHaveBeenCalledWith ( themeColorKey )
expect ( applySetting ) . toHaveBeenCalledWith ( themeColorKey , themeColor )
expect ( removeItemSpy ) . toHaveBeenCalledWith ( themeColorKey )
expect ( window . localStorage . getItem ( themeColorKey ) ) . toBe ( null )
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 = "localState"
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" ` , ( ) = > {
const localStateData = {
REMEMBERED_TEAM_ID : null ,
}
window . localStorage . setItem (
localStateKey ,
JSON . stringify ( localStateData )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( localStateKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( localStateKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ localStateKey } -backup ` ,
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 ` , ( ) = > {
const localStateData = {
INVALID_KEY : null ,
}
window . localStorage . setItem (
localStateKey ,
JSON . stringify ( localStateData )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( localStateKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( localStateKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ localStateKey } -backup ` ,
JSON . stringify ( localStateData )
)
} )
it ( ` schema parsing succeeds if there is no " ${ localStateKey } " key present in localStorage where the fallback of "{}" is chosen ` , ( ) = > {
window . localStorage . removeItem ( localStateKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( localStateKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( localStateKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` reads the value for " ${ localStateKey } " key from localStorage, invokes "bulkApplyLocalState" function if a value is yielded and subscribes to "localStateStore" updates ` , ( ) = > {
vi . mock ( "~/newstore/localstate" , ( ) = > {
return {
bulkApplyLocalState : vi.fn ( ) ,
localStateStore : {
subject $ : {
subscribe : vi.fn ( ) ,
} ,
} ,
}
} )
const localStateData = {
REMEMBERED_TEAM_ID : "test-id" ,
}
window . localStorage . setItem (
localStateKey ,
JSON . stringify ( localStateData )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( localStateKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( localStateKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 = "settings"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ settingsKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `settings`
// Expected value are booleans
const settings = {
EXTENSIONS_ENABLED : "true" ,
PROXY_ENABLED : "true" ,
}
window . localStorage . setItem ( settingsKey , JSON . stringify ( settings ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( settingsKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( settingsKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ settingsKey } -backup ` ,
JSON . stringify ( settings )
)
} )
it ( ` schema parsing succeeds if there is no " ${ settingsKey } " key present in localStorage where the fallback of "{}" is chosen ` , ( ) = > {
window . localStorage . removeItem ( settingsKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( settingsKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( settingsKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` reads the value for " ${ settingsKey } " from localStorage, invokes "performSettingsDataMigrations" and "bulkApplySettings" functions as required and subscribes to "settingsStore" updates ` , ( ) = > {
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
window . localStorage . setItem ( settingsKey , JSON . stringify ( settings ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
// toastErrorFn = vi.fn()
expect ( getItemSpy ) . toHaveBeenCalledWith ( settingsKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( settingsKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 = "history"
const graphqlHistoryKey = "graphqlHistory"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ historyKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `history`
// `v` -> `number`
const restHistoryData = [ { . . . REST_HISTORY_MOCK , v : "1" } ]
window . localStorage . setItem ( historyKey , JSON . stringify ( restHistoryData ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( historyKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( historyKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ historyKey } -backup ` ,
JSON . stringify ( restHistoryData )
)
} )
it ( ` REST history schema parsing succeeds if there is no " ${ historyKey } " key present in localStorage where the fallback of "[]" is chosen ` , ( ) = > {
window . localStorage . removeItem ( historyKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( historyKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( historyKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ graphqlHistoryKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `graphqlHistory`
// `v` -> `number`
const graphqlHistoryData = [ { . . . GQL_HISTORY_MOCK , v : "1" } ]
window . localStorage . setItem (
graphqlHistoryKey ,
JSON . stringify ( graphqlHistoryData )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( graphqlHistoryKey )
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ graphqlHistoryKey } -backup ` ,
JSON . stringify ( graphqlHistoryData )
)
} )
it ( ` GQL history schema parsing succeeds if there is no " ${ graphqlHistoryKey } " key present in localStorage where the fallback of "[]" is chosen ` , ( ) = > {
window . localStorage . removeItem ( graphqlHistoryKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( graphqlHistoryKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( graphqlHistoryKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
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" , ( ) = > {
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 stringifiedRestHistory = JSON . stringify ( REST_HISTORY_MOCK )
const stringifiedGqlHistory = JSON . stringify ( GQL_HISTORY_MOCK )
window . localStorage . setItem ( historyKey , stringifiedRestHistory )
window . localStorage . setItem ( graphqlHistoryKey , stringifiedGqlHistory )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( historyKey )
expect ( getItemSpy ) . toHaveBeenCalledWith ( graphqlHistoryKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith (
historyKey ,
graphqlHistoryKey
)
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( translateToNewRESTHistory ) . toHaveBeenCalled ( )
expect ( translateToNewGQLHistory ) . toHaveBeenCalled ( )
// This ensures `updatedOn` field is treated as a `string`
const parsedRestHistory = JSON . parse ( stringifiedRestHistory )
const parsedGqlHistory = JSON . parse ( stringifiedGqlHistory )
expect ( setRESTHistoryEntries ) . toHaveBeenCalledWith ( parsedRestHistory )
expect ( setGraphqlHistoryEntries ) . toHaveBeenCalledWith ( parsedGqlHistory )
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 collectionsKey = "collections"
const collectionsGraphqlKey = "collectionsGraphql"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ collectionsKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `collections`
// `v` -> `number`
const restCollectionsData = [ { . . . REST_COLLECTIONS_MOCK , v : "1" } ]
window . localStorage . setItem (
collectionsKey ,
JSON . stringify ( restCollectionsData )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( collectionsKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( collectionsKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ collectionsKey } -backup ` ,
JSON . stringify ( restCollectionsData )
)
} )
it ( ` REST collections schema parsing succeeds if there is no " ${ collectionsKey } " key present in localStorage where the fallback of "[]" is chosen ` , ( ) = > {
window . localStorage . removeItem ( collectionsKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( collectionsKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( collectionsKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ collectionsGraphqlKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `collectionsGraphql`
// `v` -> `number`
const graphqlCollectionsData = [ { . . . GQL_COLLECTIONS_MOCK , v : "1" } ]
window . localStorage . setItem (
collectionsGraphqlKey ,
JSON . stringify ( graphqlCollectionsData )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( collectionsGraphqlKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( collectionsGraphqlKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ collectionsGraphqlKey } -backup ` ,
JSON . stringify ( graphqlCollectionsData )
)
} )
it ( ` GQL history schema parsing succeeds if there is no " ${ collectionsGraphqlKey } " key present in localStorage where the fallback of "[]" is chosen ` , ( ) = > {
window . localStorage . removeItem ( collectionsGraphqlKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( collectionsGraphqlKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( collectionsGraphqlKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
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" , ( ) = > {
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
window . localStorage . setItem (
collectionsKey ,
JSON . stringify ( restCollections )
)
window . localStorage . setItem (
collectionsGraphqlKey ,
JSON . stringify ( gqlCollections )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( collectionsKey )
expect ( getItemSpy ) . toHaveBeenCalledWith ( collectionsGraphqlKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith (
collectionsKey ,
collectionsGraphqlKey
)
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 = "environments"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ environmentsKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `environments`
const environments = [
// `entries` -> `variables`
2024-02-08 16:28:42 +00:00
{
v : 1 ,
id : "ENV_1" ,
name : "Test" ,
entries : [ { key : "test-key" , value : "test-value" , secret : false } ] ,
} ,
2023-11-29 17:10:26 +00:00
]
window . localStorage . setItem (
environmentsKey ,
JSON . stringify ( environments )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( environmentsKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( environmentsKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ environmentsKey } -backup ` ,
JSON . stringify ( environments )
)
} )
it ( ` separates "globals" entries from " ${ environmentsKey } ", subscribes to the "environmentStore" and updates localStorage entries ` , ( ) = > {
const environments = cloneDeep ( ENVIRONMENTS_MOCK )
window . localStorage . setItem (
"environments" ,
JSON . stringify ( environments )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
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 ) . toHaveBeenCalledWith (
environmentsKey ,
JSON . stringify ( environments )
)
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 = "selectedEnvIndex"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ selectedEnvIndexKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `selectedEnvIndex`
// `index` -> `number`
const selectedEnvIndex = { . . . SELECTED_ENV_INDEX_MOCK , index : "1" }
window . localStorage . setItem (
selectedEnvIndexKey ,
JSON . stringify ( selectedEnvIndex )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( selectedEnvIndexKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ selectedEnvIndexKey } -backup ` ,
JSON . stringify ( selectedEnvIndex )
)
} )
it ( ` schema parsing succeeds if there is no " ${ selectedEnvIndexKey } " key present in localStorage where the fallback of "null" is chosen ` , ( ) = > {
window . localStorage . removeItem ( selectedEnvIndexKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` sets it to the store if there is a value associated with the " ${ selectedEnvIndexKey } " key in localStorage ` , ( ) = > {
const selectedEnvIndex = SELECTED_ENV_INDEX_MOCK
window . localStorage . setItem (
selectedEnvIndexKey ,
JSON . stringify ( selectedEnvIndex )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 ` , ( ) = > {
window . localStorage . removeItem ( selectedEnvIndexKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( selectedEnvIndexKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( setSelectedEnvironmentIndex ) . toHaveBeenCalledWith ( {
type : "NO_ENV_SELECTED" ,
} )
expect ( selectedEnvironmentIndex $ . subscribe ) . toHaveBeenCalledWith (
expect . any ( Function )
)
} )
} )
2024-02-08 16:28:42 +00:00
describe ( "Setup secret Environments persistence" , ( ) = > {
// Key read from localStorage across test cases
const secretEnvironmentsKey = "secretEnvironments"
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 ` , ( ) = > {
// Invalid shape for `secretEnvironments`
const secretEnvironments = {
clryz7ir7002al4162bsj0azg : {
key : "ENV_KEY" ,
value : "ENV_VALUE" ,
} ,
}
window . localStorage . setItem (
secretEnvironmentsKey ,
JSON . stringify ( secretEnvironments )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( secretEnvironmentsKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( secretEnvironmentsKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ secretEnvironmentsKey } -backup ` ,
JSON . stringify ( secretEnvironments )
)
} )
it ( "loads secret environments from the state persisted in localStorage and sets watcher for `persistableSecretEnvironment`" , ( ) = > {
const secretEnvironment = SECRET_ENVIRONMENTS_MOCK
window . localStorage . setItem (
secretEnvironmentsKey ,
JSON . stringify ( secretEnvironment )
)
const getItemSpy = spyOnGetItem ( )
invokeSetupLocalPersistence ( {
mockSecretEnvironmentsService : true ,
mock ,
} )
expect ( getItemSpy ) . toHaveBeenCalledWith ( secretEnvironmentsKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( secretEnvironmentsKey )
expect ( loadSecretEnvironmentsFromPersistedStateFn ) . toHaveBeenCalledWith (
secretEnvironment
)
expect ( watchDebounced ) . toHaveBeenCalledWith (
expect . any ( Object ) ,
expect . any ( Function ) ,
{ debounce : 500 }
)
} )
it ( ` skips schema parsing and the loading of persisted secret environments if there is no " ${ secretEnvironmentsKey } " key present in localStorage ` , ( ) = > {
window . localStorage . removeItem ( secretEnvironmentsKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( {
mockSecretEnvironmentsService : true ,
mock ,
} )
expect ( getItemSpy ) . toHaveBeenCalledWith ( secretEnvironmentsKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( secretEnvironmentsKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( watchDebounced ) . toHaveBeenCalled ( )
} )
it ( "logs an error to the console on failing to parse persisted secret environments" , ( ) = > {
window . localStorage . setItem ( secretEnvironmentsKey , "invalid-json" )
console . error = vi . fn ( )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( secretEnvironmentsKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( secretEnvironmentsKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( console . error ) . toHaveBeenCalledWith (
` Failed parsing persisted secret environment, state: ` ,
window . localStorage . getItem ( secretEnvironmentsKey )
)
expect ( watchDebounced ) . toHaveBeenCalledWith (
expect . any ( Object ) ,
expect . any ( Function ) ,
{ debounce : 500 }
)
} )
} )
2023-11-29 17:10:26 +00:00
describe ( "setup WebSocket persistence" , ( ) = > {
// Key read from localStorage across test cases
const wsRequestKey = "WebsocketRequest"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ wsRequestKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `WebsocketRequest`
const request = {
. . . WEBSOCKET_REQUEST_MOCK ,
// `protocols` -> `[]`
protocols : { } ,
}
window . localStorage . setItem ( wsRequestKey , JSON . stringify ( request ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( wsRequestKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( wsRequestKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ wsRequestKey } -backup ` ,
JSON . stringify ( request )
)
} )
it ( ` schema parsing succeeds if there is no " ${ wsRequestKey } " key present in localStorage where the fallback of "null" is chosen ` , ( ) = > {
window . localStorage . removeItem ( wsRequestKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( wsRequestKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( wsRequestKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` reads the " ${ wsRequestKey } " entry from localStorage, sets it as the new request, subscribes to the "WSSessionStore" and updates localStorage entries ` , ( ) = > {
vi . mock ( "~/newstore/WebSocketSession" , ( ) = > {
return {
setWSRequest : vi.fn ( ) ,
WSRequest $ : {
subscribe : vi.fn ( ) ,
} ,
}
} )
const request = WEBSOCKET_REQUEST_MOCK
window . localStorage . setItem ( wsRequestKey , JSON . stringify ( request ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( wsRequestKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( wsRequestKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 = "SocketIORequest"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ sioRequestKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `SocketIORequest`
const request = {
. . . SOCKET_IO_REQUEST_MOCK ,
// `v` -> `version: v4`
v : "4" ,
}
window . localStorage . setItem ( sioRequestKey , JSON . stringify ( request ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( sioRequestKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( sioRequestKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ sioRequestKey } -backup ` ,
JSON . stringify ( request )
)
} )
it ( ` schema parsing succeeds if there is no " ${ sioRequestKey } " key present in localStorage where the fallback of "null" is chosen ` , ( ) = > {
window . localStorage . removeItem ( sioRequestKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( sioRequestKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( sioRequestKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` reads the " ${ sioRequestKey } " entry from localStorage, sets it as the new request, subscribes to the "SIOSessionStore" and updates localStorage entries ` , ( ) = > {
vi . mock ( "~/newstore/SocketIOSession" , ( ) = > {
return {
setSIORequest : vi.fn ( ) ,
SIORequest $ : {
subscribe : vi.fn ( ) ,
} ,
}
} )
const request = SOCKET_IO_REQUEST_MOCK
window . localStorage . setItem ( sioRequestKey , JSON . stringify ( request ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( sioRequestKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( sioRequestKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( setSIORequest ) . toHaveBeenCalledWith ( request )
expect ( SIORequest $ . subscribe ) . toHaveBeenCalledWith ( expect . any ( Function ) )
} )
} )
describe ( "setup SSE Persistence" , ( ) = > {
// Key read from localStorage across test cases
const sseRequestKey = "SSERequest"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ sseRequestKey } " read from localStorage doesn't match the versioned schema ` , ( ) = > {
// Invalid shape for `SSERequest`
const request = {
. . . SSE_REQUEST_MOCK ,
// `url` -> `endpoint`
url : "https://express-eventsource.herokuapp.com/events" ,
}
window . localStorage . setItem ( sseRequestKey , JSON . stringify ( request ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( sseRequestKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( sseRequestKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ sseRequestKey } -backup ` ,
JSON . stringify ( request )
)
} )
it ( ` schema parsing succeeds if there is no " ${ sseRequestKey } " key present in localStorage where the fallback of "null" is chosen ` , ( ) = > {
window . localStorage . removeItem ( sseRequestKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( sseRequestKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( sseRequestKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` reads the " ${ sseRequestKey } " entry from localStorage, sets it as the new request, subscribes to the "SSESessionStore" and updates localStorage entries ` , ( ) = > {
vi . mock ( "~/newstore/SSESession" , ( ) = > {
return {
setSSERequest : vi.fn ( ) ,
SSERequest $ : {
subscribe : vi.fn ( ) ,
} ,
}
} )
const request = SSE_REQUEST_MOCK
window . localStorage . setItem ( sseRequestKey , JSON . stringify ( request ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( sseRequestKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( sseRequestKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( setSSERequest ) . toHaveBeenCalledWith ( request )
expect ( SSERequest $ . subscribe ) . toHaveBeenCalledWith ( expect . any ( Function ) )
} )
} )
describe ( "setup MQTT Persistence" , ( ) = > {
// Key read from localStorage across test cases
const mqttRequestKey = "MQTTRequest"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ mqttRequestKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `MQTTRequest`
const request = {
. . . MQTT_REQUEST_MOCK ,
// `url` -> `endpoint`
url : "wss://test.mosquitto.org:8081" ,
}
window . localStorage . setItem ( mqttRequestKey , JSON . stringify ( request ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( mqttRequestKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( mqttRequestKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ mqttRequestKey } -backup ` ,
JSON . stringify ( request )
)
} )
it ( ` schema parsing succeeds if there is no " ${ mqttRequestKey } " key present in localStorage where the fallback of "null" is chosen ` , ( ) = > {
window . localStorage . removeItem ( mqttRequestKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( mqttRequestKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( mqttRequestKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` reads the ${ mqttRequestKey } " entry from localStorage, sets it as the new request, subscribes to the "MQTTSessionStore" and updates localStorage entries ` , ( ) = > {
vi . mock ( "~/newstore/MQTTSession" , ( ) = > {
return {
setMQTTRequest : vi.fn ( ) ,
MQTTRequest $ : {
subscribe : vi.fn ( ) ,
} ,
}
} )
const request = MQTT_REQUEST_MOCK
window . localStorage . setItem ( mqttRequestKey , JSON . stringify ( request ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( mqttRequestKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( mqttRequestKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 = "globalEnv"
it ( ` shows an error and sets the entry as a backup in localStorage if " ${ globalEnvKey } " read from localStorage doesn't match the schema ` , ( ) = > {
// Invalid shape for `globalEnv`
const globalEnv = [
{
. . . GLOBAL_ENV_MOCK [ 0 ] ,
// `key` -> `string`
key : 1 ,
} ,
]
window . localStorage . setItem ( globalEnvKey , JSON . stringify ( globalEnv ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( globalEnvKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( globalEnvKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ globalEnvKey } -backup ` ,
JSON . stringify ( globalEnv )
)
} )
it ( ` schema parsing succeeds if there is no " ${ globalEnvKey } " key present in localStorage where the fallback of "[]" is chosen ` , ( ) = > {
window . localStorage . removeItem ( globalEnvKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( globalEnvKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( globalEnvKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
} )
it ( ` reads the "globalEnv" entry from localStorage, dispatches the new value, subscribes to the "environmentsStore" and updates localStorage entries ` , ( ) = > {
const globalEnv = GLOBAL_ENV_MOCK
window . localStorage . setItem ( globalEnvKey , JSON . stringify ( globalEnv ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( globalEnvKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( globalEnvKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 = "gqlTabState"
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 ` , ( ) = > {
// Invalid shape for `gqlTabState`
// `lastActiveTabID` -> `string`
const gqlTabState = { . . . GQL_TAB_STATE_MOCK , lastActiveTabID : 1234 }
window . localStorage . setItem ( gqlTabStateKey , JSON . stringify ( gqlTabState ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( gqlTabStateKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( gqlTabStateKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ gqlTabStateKey } -backup ` ,
JSON . stringify ( gqlTabState )
)
} )
it ( ` skips schema parsing and the loading of persisted tabs if there is no " ${ gqlTabStateKey } " key present in localStorage ` , ( ) = > {
window . localStorage . removeItem ( gqlTabStateKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( { mockGQLTabService : true , mock } )
expect ( getItemSpy ) . toHaveBeenCalledWith ( gqlTabStateKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( gqlTabStateKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( loadTabsFromPersistedStateFn ) . not . toHaveBeenCalled ( )
expect ( watchDebounced ) . toHaveBeenCalled ( )
} )
it ( "loads tabs from the state persisted in localStorage and sets watcher for `persistableTabState`" , ( ) = > {
const tabState = GQL_TAB_STATE_MOCK
window . localStorage . setItem ( gqlTabStateKey , JSON . stringify ( tabState ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( { mockGQLTabService : true , mock } )
expect ( getItemSpy ) . toHaveBeenCalledWith ( gqlTabStateKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( gqlTabStateKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 tab state" , ( ) = > {
window . localStorage . setItem ( gqlTabStateKey , "invalid-json" )
console . error = vi . fn ( )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( gqlTabStateKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( gqlTabStateKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( console . error ) . toHaveBeenCalledWith (
` Failed parsing persisted tab state, state: ` ,
window . localStorage . getItem ( 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 = "restTabState"
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 ` , ( ) = > {
// Invalid shape for `restTabState`
// `lastActiveTabID` -> `string`
const restTabState = { . . . REST_TAB_STATE_MOCK , lastActiveTabID : 1234 }
window . localStorage . setItem (
restTabStateKey ,
JSON . stringify ( restTabState )
)
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( restTabStateKey )
expect ( toastErrorFn ) . toHaveBeenCalledWith (
expect . stringContaining ( restTabStateKey )
)
expect ( setItemSpy ) . toHaveBeenCalledWith (
` ${ restTabStateKey } -backup ` ,
JSON . stringify ( restTabState )
)
} )
it ( ` skips schema parsing and the loading of persisted tabs if there is no " ${ restTabStateKey } " key present in localStorage ` , ( ) = > {
window . localStorage . removeItem ( restTabStateKey )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( { mockRESTTabService : true , mock } )
expect ( getItemSpy ) . toHaveBeenCalledWith ( restTabStateKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( restTabStateKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( loadTabsFromPersistedStateFn ) . not . toHaveBeenCalled ( )
expect ( watchDebounced ) . toHaveBeenCalled ( )
} )
it ( "loads tabs from the state persisted in localStorage and sets watcher for `persistableTabState`" , ( ) = > {
const tabState = REST_TAB_STATE_MOCK
window . localStorage . setItem ( restTabStateKey , JSON . stringify ( tabState ) )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( { mockRESTTabService : true , mock } )
expect ( getItemSpy ) . toHaveBeenCalledWith ( restTabStateKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( restTabStateKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
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 tab state" , ( ) = > {
window . localStorage . setItem ( restTabStateKey , "invalid-json" )
console . error = vi . fn ( )
const getItemSpy = spyOnGetItem ( )
const setItemSpy = spyOnSetItem ( )
invokeSetupLocalPersistence ( )
expect ( getItemSpy ) . toHaveBeenCalledWith ( restTabStateKey )
expect ( toastErrorFn ) . not . toHaveBeenCalledWith ( restTabStateKey )
expect ( setItemSpy ) . not . toHaveBeenCalled ( )
expect ( console . error ) . toHaveBeenCalledWith (
` Failed parsing persisted tab state, state: ` ,
window . localStorage . getItem ( restTabStateKey )
)
expect ( watchDebounced ) . toHaveBeenCalledWith (
expect . any ( Object ) ,
expect . any ( Function ) ,
{ debounce : 500 , deep : true }
)
} )
} )
} )
it ( "`setLocalConfig` method sets a value in localStorage" , ( ) = > {
const testKey = "test-key"
const testValue = "test-value"
const setItemSpy = spyOnSetItem ( )
const service = bindPersistenceService ( )
service . setLocalConfig ( testKey , testValue )
expect ( setItemSpy ) . toHaveBeenCalledWith ( testKey , testValue )
} )
it ( "`getLocalConfig` method gets a value from localStorage" , ( ) = > {
const testKey = "test-key"
const testValue = "test-value"
const setItemSpy = spyOnSetItem ( )
const getItemSpy = spyOnGetItem ( )
const service = bindPersistenceService ( )
service . setLocalConfig ( testKey , testValue )
const retrievedValue = service . getLocalConfig ( testKey )
expect ( setItemSpy ) . toHaveBeenCalledWith ( testKey , testValue )
expect ( getItemSpy ) . toHaveBeenCalledWith ( testKey )
expect ( retrievedValue ) . toBe ( testValue )
} )
it ( "`removeLocalConfig` method clears a value in localStorage" , ( ) = > {
const testKey = "test-key"
const testValue = "test-value"
const setItemSpy = spyOnSetItem ( )
const removeItemSpy = spyOnRemoveItem ( )
const service = bindPersistenceService ( )
service . setLocalConfig ( testKey , testValue )
service . removeLocalConfig ( testKey )
expect ( setItemSpy ) . toHaveBeenCalledWith ( testKey , testValue )
expect ( removeItemSpy ) . toHaveBeenCalledWith ( testKey )
} )
} )