Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/setup-state-persistence #26

Merged
merged 15 commits into from
Feb 9, 2019
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
7 changes: 7 additions & 0 deletions app/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import { init } from '@state/actions/app'
import { apiInit } from '@state/actions/api'
import store from '@state/store'
import OnboardingStackNavigation from '@navigation/onboarding-stack'
import { setTopLevelNavigator } from '@state/middlewares/navigation/navigation'
Expand All @@ -13,5 +15,10 @@ export default class App extends Component {
)
}

componentDidMount() {
store.dispatch(init())
store.dispatch(apiInit())
}

goToNextScreen = () => console.log('goToNextScreen')
}
127 changes: 127 additions & 0 deletions app/persistence-api/__tests__/persistence-api.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// import PersistenceApi from '@persistence-api/persistence-api'

describe('persistence-api', () => {
describe('getState', () => {
describe('state exists in storage', () => {
let PersistenceApi
beforeEach(() => {
jest.resetAllMocks()
jest.mock('react-native', () => ({
AsyncStorage: {
getItem: jest.fn(() =>
new Promise(resolve =>
resolve('{"mockedData": "mockedData"}')
)
),
setItem: jest.fn()
}
}))
PersistenceApi = require('@persistence-api/persistence-api').default
})

it('should return state from storage', async () => {
const state = await PersistenceApi.getState()

expect(state).toEqual({
mockedData: 'mockedData'
})
})
})

describe('state does not exist in storage', () => {
let PersistenceApi
beforeEach(() => {
jest.resetAllMocks()
jest.doMock('react-native', () => ({
AsyncStorage: {
getItem: jest.fn(() => {
return new Promise(resolve =>
resolve('{}')
)
}),
setItem: jest.fn()
}
}))
PersistenceApi = require('@persistence-api/persistence-api').default
})

it('should return `undefined`', async () => {
const state = await PersistenceApi.getState()

expect(state).toEqual(undefined)
})
})
})

describe('saveState', () => {
let PersistenceApi, AsyncStorage, state
beforeEach(() => {
jest.resetAllMocks()
jest.mock('react-native', () => ({
AsyncStorage: {
getItem: jest.fn(),
setItem: jest.fn((key, state) =>
new Promise(resolve =>
resolve(undefined)
)
)
}
}))
PersistenceApi = require('@persistence-api/persistence-api').default
AsyncStorage = require('react-native').AsyncStorage
})

describe('state is serializable', () => {
beforeEach(() => {
state = {
someState: 'some state'
}
})

it('should save state as string', async () => {
await PersistenceApi.saveState(state)

expect(AsyncStorage.setItem).toHaveBeenCalledWith('STORAGE:STATE', '{\"someState\":\"some state\"}')
})
})

describe('state is not serializable', () => {
let state
beforeEach(() => {
state = {};
state.myself = state;
})

it('should throw error', async done => {
try {
await PersistenceApi.saveState(state)
fail()
}
catch (err) {
done()
}
})
})

describe('Storage fails to save', () => {
let state
beforeEach(() => {
AsyncStorage.setItem = jest.fn(() =>
new Promise((_, reject) =>
reject()
)
)
})

it('should throw error', async done => {
try {
await PersistenceApi.saveState(state)
fail()
}
catch (err) {
done()
}
})
})
})
})
3 changes: 3 additions & 0 deletions app/persistence-api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import persistenceApi from './persistence-api'

export default persistenceApi
3 changes: 3 additions & 0 deletions app/persistence-api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "@persistence-api"
}
20 changes: 20 additions & 0 deletions app/persistence-api/persistence-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AsyncStorage } from 'react-native'

const STORAGE_KEY_STATE = 'STORAGE:STATE'

export default class PersistenceApi {
static getState = async () => {
const result = await AsyncStorage.getItem(STORAGE_KEY_STATE)
try {
return JSON.parse(result)
}
catch (_) {
return undefined
}
}

static saveState = async (state) => {
const stateString = JSON.stringify(state)
await AsyncStorage.setItem(STORAGE_KEY_STATE, stateString)
}
}
8 changes: 8 additions & 0 deletions app/state/actions/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const INIT = 'INIT'

export const init = () => {
return {
type: INIT,
payload: {}
}
}
57 changes: 57 additions & 0 deletions app/state/actions/persistence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
export const PERSISTENCE_LOAD_STATE_REQUEST = 'PERSISTENCE:LOAD_STATE_REQUEST'
export const PERSISTENCE_LOAD_STATE_SUCCESS = 'PERSISTENCE:LOAD_STATE_SUCCESS'
export const PERSISTENCE_LOAD_STATE_FAILURE = 'PERSISTENCE:LOAD_STATE_FAILURE'

export const PERSISTENCE_SAVE_STATE_REQUEST = 'PERSISTENCE:SAVE_STATE_REQUEST'
export const PERSISTENCE_SAVE_STATE_SUCCESS = 'PERSISTENCE:SAVE_STATE_SUCCESS'
export const PERSISTENCE_SAVE_STATE_FAILURE = 'PERSISTENCE:SAVE_STATE_FAILURE'

export const loadStateRequest = () => {
return {
type: PERSISTENCE_LOAD_STATE_REQUEST,
payload: {}
}
}

export const loadStateSuccess = (state) => {
return {
type: PERSISTENCE_LOAD_STATE_SUCCESS,
payload: {
state
}
}
}

export const loadStateFailure = (error) => {
return {
type: PERSISTENCE_LOAD_STATE_FAILURE,
payload: {
error
}
}
}

export const saveStateRequest = (state) => {
return {
type: PERSISTENCE_SAVE_STATE_REQUEST,
payload: {
state
}
}
}

export const saveStateSuccess = () => {
return {
type: PERSISTENCE_SAVE_STATE_SUCCESS,
payload: {}
}
}

export const saveStateFailure = (error) => {
return {
type: PERSISTENCE_SAVE_STATE_FAILURE,
payload: {
error
}
}
}
7 changes: 7 additions & 0 deletions app/state/middlewares/logger/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default store => next => action => {
console.log('prevState', store.getState())
console.log('action', action)
const nextAction = next(action)
console.log('nextState', store.getState())
return nextAction
}
Loading