Skip to content

Commit

Permalink
feat: #739 The Cloud Apps should be testable in "Desktop Mode" (#784)
Browse files Browse the repository at this point in the history
* feat: #739 cloud apps now testable in desktop mode
  • Loading branch information
Cuong Vu authored Apr 3, 2020
1 parent c8c3fb2 commit 4640dfc
Show file tree
Hide file tree
Showing 31 changed files with 291 additions and 22 deletions.
2 changes: 2 additions & 0 deletions packages/aml-checklist/src/core/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import resultSagas from '@/sagas/result'
import authSagas from '@/sagas/auth'
import checklistDetailSagas from '@/sagas/checklist-detail'
import identityTypesSagas from '@/sagas/identity-types'
import { injectSwitchModeToWindow } from '@reapit/elements'

export class Store {
static _instance: Store
Expand Down Expand Up @@ -59,6 +60,7 @@ export class Store {
reduxStore: ReduxStore<ReduxState>

constructor() {
injectSwitchModeToWindow()
const composed = Store.composeEnhancers(applyMiddleware(Store.sagaMiddleware))

this.reduxStore = createStore(Store.reducers, composed)
Expand Down
2 changes: 1 addition & 1 deletion packages/aml-checklist/src/tests/badges/badge-lines.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/cognito-auth/src/tests/badges/badge-branches.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/cognito-auth/src/tests/badges/badge-lines.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions packages/cognito-auth/src/utils/cognito.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ describe('Session utils', () => {
it('should get a session from the cookie if it exists', () => {
const stringifiedSession = JSON.stringify({
refreshToken: mockLoginSession.refreshToken,
mode: 'DESKTOP',
loginType: mockLoginSession.loginType,
userName: mockLoginSession.userName,
})

document.cookie = `${COOKIE_SESSION_KEY}=${stringifiedSession}`

expect(getSessionCookie()).toEqual(JSON.parse(stringifiedSession))
})

it('should return with mode WEB if dont have global object', () => {
;(getMarketplaceGlobalsByKey as jest.Mock).mockImplementation(() => undefined)
const stringifiedSession = JSON.stringify({
refreshToken: mockLoginSession.refreshToken,
mode: 'WEB',
loginType: mockLoginSession.loginType,
userName: mockLoginSession.userName,
})
Expand Down
4 changes: 3 additions & 1 deletion packages/cognito-auth/src/utils/cognito.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export const getSessionCookie = (identifier: string = COOKIE_SESSION_KEY): Refre
try {
const session = hardtack.get(identifier)
if (session) {
return JSON.parse(session) as RefreshParams
const marketplaceGlobalObject = getMarketplaceGlobalsByKey()
const mode = marketplaceGlobalObject ? 'DESKTOP' : 'WEB'
return { ...JSON.parse(session), mode } as RefreshParams
}
return null
} catch {
Expand Down
109 changes: 108 additions & 1 deletion packages/elements/src/components/DynamicLinks/__tests__/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import { getMarketplaceGlobalsByKey, GLOBAL_KEY } from '../utils'
import {
getMarketplaceGlobalsByKey,
GLOBAL_KEY,
LOCALSTORAGE_KEY,
setMarketplaceGlobalsByKey,
clearMarkeplaceGlobals,
restoreGlobalObjectFromLS,
injectSwitchModeToWindow,
} from '../utils'
import { storageAvailable } from '../../../utils/local-storage/local-storage-check'

jest.mock('../../../utils/local-storage/local-storage-check', () => ({
storageAvailable: jest.fn(() => true),
}))
;(global as any).console = { log: jest.fn() }
let oldWindow = (global as any).window

beforeAll(() => {
Expand Down Expand Up @@ -28,3 +41,97 @@ describe('getMarketplaceGlobalsByKey', () => {
expect(getMarketplaceGlobalsByKey('key1')).toEqual('value')
})
})

describe('setMarketplaceGlobalsByKey', () => {
afterAll(() => {
;(storageAvailable as jest.Mocked<any>).mockImplementation(() => true)
})

it('should return correct object if localStorage available', () => {
;(global as any).window.localStorage.getItem = jest.fn(() => JSON.stringify({ key: 'value' }))
;(global as any).window.location.reload = jest.fn()
const result = setMarketplaceGlobalsByKey({ key2: 'value2' })
expect(result).toEqual({ key: 'value', key2: 'value2' })
})

it('should return correct object if localStorage available and pass in undefined', () => {
;(global as any).window.localStorage.getItem = jest.fn(() => JSON.stringify({ key: 'value' }))
;(global as any).window.location.reload = jest.fn()
const result = setMarketplaceGlobalsByKey()
expect(result).toEqual({ key: 'value' })
})

it('should return correct object if localStorage available and pass in undefined and getItem return null', () => {
;(global as any).window.localStorage.getItem = jest.fn(() => null)
;(global as any).window.location.reload = jest.fn()
const result = setMarketplaceGlobalsByKey()
expect(result).toEqual({})
})

it('should return undefined if localStorage unavailable', () => {
;(storageAvailable as jest.Mocked<any>).mockImplementation(() => false)
;(global as any).window.localStorage.getItem = jest.fn(() => null)
;(global as any).window.location.reload = jest.fn()
const result = setMarketplaceGlobalsByKey()
expect(result).toEqual(undefined)
})
})

describe('clearMarkeplaceGlobals', () => {
afterAll(() => {
;(storageAvailable as jest.Mocked<any>).mockImplementation(() => true)
})
it('should clear LocalStorage if it is available', () => {
;(global as any).window.localStorage.removeItem = jest.fn()
;(global as any).window.location.reload = jest.fn()
const result = clearMarkeplaceGlobals()
const spyRemove = jest.spyOn(window.localStorage, 'removeItem')
const spyReload = jest.spyOn(window.location, 'reload')
expect(spyRemove).toHaveBeenCalledWith(LOCALSTORAGE_KEY)
expect(spyReload).toHaveBeenCalled()
expect(result).toBe(true)
})
it('should reload if LocalStorage is unavailable', () => {
;(storageAvailable as jest.Mocked<any>).mockImplementation(() => false)
;(global as any).window.location.reload = jest.fn()
const result = clearMarkeplaceGlobals()
const spyReload = jest.spyOn(window.location, 'reload')
expect(spyReload).toHaveBeenCalled()
expect(result).toBe(true)
})
})

describe('restoreGlobalObjectFromLS', () => {
afterAll(() => {
;(storageAvailable as jest.Mocked<any>).mockImplementation(() => true)
})

it('should return correct object if storageAvailable', () => {
;(global as any).window.localStorage.getItem = jest.fn(() => JSON.stringify({ key: 'value' }))
;(global as any).window.localStorage.setItem = jest.fn()
const result = restoreGlobalObjectFromLS()
expect(result).toEqual({ key: 'value' })
})

it('should return false if getItem return non-object', () => {
;(global as any).window.localStorage.getItem = jest.fn(() => false)
;(global as any).window.localStorage.setItem = jest.fn()
const result = restoreGlobalObjectFromLS()
expect(result).toEqual(false)
})

it('should return null if LS unavailable', () => {
;(storageAvailable as jest.Mocked<any>).mockImplementation(() => false)
const result = restoreGlobalObjectFromLS()
expect(result).toBe(null)
})
})

describe('injectSwitchModeToWindow', () => {
it('should call correctly', () => {
Object.defineProperty = jest.fn()
const spyDefineProperty = window.spyOn(Object, 'defineProperty')
injectSwitchModeToWindow()
expect(spyDefineProperty).toHaveBeenCalledTimes(2)
})
})
75 changes: 75 additions & 0 deletions packages/elements/src/components/DynamicLinks/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { storageAvailable } from '../../utils/local-storage/local-storage-check'
export const GLOBAL_KEY = '__REAPIT_MARKETPLACE_GLOBALS__'
export const LOCALSTORAGE_KEY = '__REAPIT_MARKETPLACE_GLOBALS__'

/**
* If key is undefined, then return entire object,
Expand All @@ -13,3 +15,76 @@ export const getMarketplaceGlobalsByKey = (key?: string) => {
}
return window[GLOBAL_KEY][key]
}

/**
* Used to set data into window.__REAPIT_MARKETPLACE_GLOBALS__ via localStorage and return that object,
* Append to current existingObject and Overwrite if key is existed
*/
export const setMarketplaceGlobalsByKey = (
keyValueObject: { [key: string]: string } = {},
): { [key: string]: string } | undefined => {
if (storageAvailable('localStorage')) {
const existingObject = JSON.parse(window.localStorage.getItem(LOCALSTORAGE_KEY) as string)
const globalsObject =
typeof existingObject === 'object' && existingObject !== null
? { ...existingObject, ...keyValueObject }
: { ...keyValueObject }
window.localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(globalsObject))
window[GLOBAL_KEY] = globalsObject
window.location.reload()
return globalsObject
}
console.log("Your browser doesn't support localStorage")
return
}

/**
* Used to clear localStorage and window globalsObject
*/
export const clearMarkeplaceGlobals = () => {
if (storageAvailable('localStorage')) {
window.localStorage.removeItem(LOCALSTORAGE_KEY)
}
window[GLOBAL_KEY] = undefined
window.location.reload()
return true
}

/**
* To check if localStorage has globalObject data
* If has, restore it, otherwise, skip
*/
export const restoreGlobalObjectFromLS = (): { [key: string]: string } | boolean | null => {
if (storageAvailable('localStorage')) {
const localStorageObject = JSON.parse(window.localStorage.getItem(LOCALSTORAGE_KEY) as string)
if (typeof localStorageObject === 'object' && localStorageObject !== null) {
const globalsObject = { ...localStorageObject }
window[GLOBAL_KEY] = globalsObject
console.log(`window.${GLOBAL_KEY} is set to`, JSON.parse(JSON.stringify(globalsObject)))
return globalsObject
}
// Clear storage if it's non-object
window.localStorage.removeItem(LOCALSTORAGE_KEY)
window[GLOBAL_KEY] = undefined
return false
}
console.log("Your browser doesn't support localStorage")
return null
}

/**
* Used to inject window.desktopMode and window.webMode functions used to switch between mode
* Call this before initializing state related to LoginMode
* E.g. If you're using Redux, call this before initializing store,
* If you're using React without Redux, call this in index.js
*/
export const injectSwitchModeToWindow = () => {
Object.defineProperty(window, 'desktopMode', {
value: setMarketplaceGlobalsByKey,
})
Object.defineProperty(window, 'webMode', {
value: clearMarkeplaceGlobals,
})

restoreGlobalObjectFromLS()
}
Loading

0 comments on commit 4640dfc

Please sign in to comment.