Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,8 @@
},
"dependencies": {
"js-cookie": "^2.1.4"
},
"jest": {
"setupFiles": ["./test/browserMocks.js"]
}
}
4 changes: 2 additions & 2 deletions src/middleware.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import createLocalStorageStore from './storage/localStorage'
import createAdaptiveStore from './storage/adaptive'
import { AUTHENTICATE } from './actionTypes'
import {
authenticateFailed,
Expand All @@ -8,7 +8,7 @@ import {
} from './actions'

const createAuthMiddleware = (config = {}) => {
const storage = config.storage || createLocalStorageStore()
const storage = config.storage || createAdaptiveStore()
const authenticators = config.authenticators || []

const findAuthenticator = name =>
Expand Down
1 change: 1 addition & 0 deletions src/storage.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as createAdaptiveStore } from './storage/adaptive'
export { default as createLocalStorageStore } from './storage/localStorage'
export { default as createCookieStore } from './storage/cookie'
16 changes: 16 additions & 0 deletions src/storage/adaptive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import createCookieStore from './cookie'
import createLocalStorageStore from './localStorage'
import { isLocalStorageAvailable } from '../utils/localStorage'

const createAdaptiveStore = ({
localStorageKey: key,
cookieName: name,
cookieDomain: domain,
cookieExpires: expires,
cookieSecure: secure
} = {}) =>
isLocalStorageAvailable() ?
createLocalStorageStore({ key }) :
createCookieStore({ name, domain, expires, secure })

export default createAdaptiveStore
11 changes: 11 additions & 0 deletions src/utils/localStorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const LOCAL_STORAGE_TEST_KEY = '_redux-simple-auth-test'

export const isLocalStorageAvailable = () => {
try {
localStorage.setItem(LOCAL_STORAGE_TEST_KEY, true)
localStorage.removeItem(LOCAL_STORAGE_TEST_KEY)
return true
} catch (e) {
return false
}
}
19 changes: 19 additions & 0 deletions test/browserMocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const createLocalStorageMock = () => {
const store = {}

return {
setItem(key, value) {
store[key] = value.toString()
},
getItem(key) {
return store[key] || null
},
removeItem(key) {
delete store[key]
}
}
}

Object.defineProperty(window, 'localStorage', {
value: createLocalStorageMock()
})
91 changes: 91 additions & 0 deletions test/storage/adaptive.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { createAdaptiveStore } from '../../src/storage'
import Cookie from 'js-cookie'

describe('Adaptive store', () => {
describe('it builds a store', () => {
const store = createAdaptiveStore()

expect(store).toHaveProperty('persist')
expect(store).toHaveProperty('restore')
})

describe('when localStorage is available', () => {
it('builds localStorage store if available', () => {
const setItemSpy = jest.spyOn(localStorage, 'setItem')
const getItemSpy = jest.spyOn(localStorage, 'getItem')

const store = createAdaptiveStore()
store.persist({ key: 'value' })
store.restore()

expect(setItemSpy).toHaveBeenCalled()
expect(getItemSpy).toHaveBeenCalled()

setItemSpy.mockRestore()
getItemSpy.mockRestore()
})

it('honors local storage options', () => {
const setItemSpy = jest.spyOn(localStorage, 'setItem')
const getItemSpy = jest.spyOn(localStorage, 'getItem')

const store = createAdaptiveStore({ localStorageKey: 'my-custom-key' })
store.persist({ key: 'value' })
store.restore()

expect(setItemSpy).toHaveBeenCalledWith(
'my-custom-key',
JSON.stringify({ key: 'value' })
)
expect(getItemSpy).toHaveBeenCalledWith('my-custom-key')

setItemSpy.mockRestore()
getItemSpy.mockRestore()
})
})

describe('when local storage is not available', () => {
beforeEach(() => {
localStorage.setItem = jest.fn(() => { throw new Error })
})

it('builds cookie store', () => {
const setSpy = jest.spyOn(Cookie, 'set')
const getJSONSpy = jest.spyOn(Cookie, 'getJSON')

const store = createAdaptiveStore()
store.persist({ key: 'value' })
store.restore()

expect(setSpy).toHaveBeenCalled()
expect(getJSONSpy).toHaveBeenCalled()
})

it('honors cookie options', () => {
const setSpy = jest.spyOn(Cookie, 'set')
const getJSONSpy = jest.spyOn(Cookie, 'getJSON')

const store = createAdaptiveStore({
cookieName: 'my-custom-cookie',
cookieDomain: 'example.com',
cookiePath: '/',
cookieSecure: true,
cookieExpires: 120
})
store.persist({ key: 'value' })
store.restore()

expect(setSpy).toHaveBeenCalledWith(
'my-custom-cookie',
{ key: 'value' },
{
domain: 'example.com',
path: '/',
secure: true,
expires: expect.any(Date)
}
)
expect(getJSONSpy).toHaveBeenCalledWith('my-custom-cookie')
})
})
})
File renamed without changes.
20 changes: 20 additions & 0 deletions test/utils/localStorage.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { isLocalStorageAvailable } from '../../src/utils/localStorage'

describe('isLocalStorageAvailable', () => {
it('when local storage is available it returns true', () => {
const result = isLocalStorageAvailable()

expect(result).toBe(true)
})

it('when localStorage is not available it returns false', () => {
const originalSetItem = localStorage.setItem
localStorage.setItem = jest.fn(() => { throw new Error('') })

const result = isLocalStorageAvailable()

expect(result).toBe(false)

localStorage.setItem = originalSetItem
})
})