this.handleColorPickerClose() } />
+ {this.state.folder.showColumnPicker
+ ?
+
this.handleColorPickerClose()}
+ />
this.handleColorChange(color) }
- onChangeComplete={ (color) => this.handleColorChange(color) } />
+ onChange={(color) => this.handleColorChange(color)}
+ onChangeComplete={(color) => this.handleColorChange(color)}
+ />
- : null }
+ : null
+ }
{
+ .deleteFolder(storage.key, folder.key)
+ .then((data) => {
store.dispatch({
- type: 'REMOVE_FOLDER',
- key: folder.key,
- storage: storage
+ type: 'DELETE_FOLDER',
+ storage: data.storage,
+ folderKey: data.folderKey
})
})
}
@@ -254,10 +256,10 @@ class StorageItem extends React.Component {
}
dataApi.createFolder(storage.key, input)
- .then((storage) => {
+ .then((data) => {
store.dispatch({
- type: 'ADD_FOLDER',
- storage: storage
+ type: 'UPDATE_FOLDER',
+ storage: data.storage
})
})
.catch((err) => {
@@ -276,11 +278,11 @@ class StorageItem extends React.Component {
.then(() => {
store.dispatch({
type: 'REMOVE_STORAGE',
- key: storage.key
+ storageKey: storage.key
})
})
.catch((err) => {
- console.error(err)
+ throw err
})
}
diff --git a/browser/main/modals/PreferencesModal/StoragesTab.js b/browser/main/modals/PreferencesModal/StoragesTab.js
index ead759ba..f0609e6e 100644
--- a/browser/main/modals/PreferencesModal/StoragesTab.js
+++ b/browser/main/modals/PreferencesModal/StoragesTab.js
@@ -51,14 +51,13 @@ class StoragesTab extends React.Component {
}
renderList () {
- let { storages, boundingBox } = this.props
+ let { data, boundingBox } = this.props
if (!boundingBox) { return null }
- let storageList = storages.map((storage) => {
+ let storageList = data.storageMap.map((storage) => {
return
})
diff --git a/browser/main/modals/PreferencesModal/index.js b/browser/main/modals/PreferencesModal/index.js
index fead28f4..0f8382e1 100644
--- a/browser/main/modals/PreferencesModal/index.js
+++ b/browser/main/modals/PreferencesModal/index.js
@@ -33,8 +33,8 @@ class Preferences extends React.Component {
}
renderContent () {
- const { boundingBox } = this.state;
- let { dispatch, config, storages } = this.props
+ const { boundingBox } = this.state
+ let { dispatch, config, data } = this.props
switch (this.state.currentTab) {
case 'INFO':
@@ -51,7 +51,7 @@ class Preferences extends React.Component {
return (
)
@@ -66,7 +66,7 @@ class Preferences extends React.Component {
getContentBoundingBox () {
const node = ReactDOM.findDOMNode(this.refs.content)
- return node.getBoundingClientRect();
+ return node.getBoundingClientRect()
}
render () {
diff --git a/browser/main/store.js b/browser/main/store.js
index b1c2e68b..8b778939 100644
--- a/browser/main/store.js
+++ b/browser/main/store.js
@@ -1,95 +1,449 @@
import { combineReducers, createStore } from 'redux'
import { routerReducer } from 'react-router-redux'
import ConfigManager from 'browser/main/lib/ConfigManager'
+import { Map, Set } from 'browser/lib/Mutable'
+import _ from 'lodash'
-function storages (state = [], action) {
- console.info('REDUX >> ', action)
- switch (action.type) {
- case 'INIT_ALL':
- return action.storages
- case 'ADD_STORAGE':
- {
- let storages = state.slice()
-
- storages.push(action.storage)
-
- return storages
- }
- case 'ADD_FOLDER':
- case 'REMOVE_FOLDER':
- case 'UPDATE_STORAGE':
- case 'RENAME_STORAGE':
- {
- let storages = state.slice()
- storages = storages
- .filter((storage) => storage.key !== action.storage.key)
- storages.push(action.storage)
-
- return storages
- }
- case 'REMOVE_STORAGE':
- {
- let storages = state.slice()
- storages = storages
- .filter((storage) => storage.key !== action.key)
-
- return storages
- }
+function defaultDataMap () {
+ return {
+ storageMap: new Map(),
+ noteMap: new Map(),
+ starredSet: new Set(),
+ storageNoteMap: new Map(),
+ folderNoteMap: new Map(),
+ tagNoteMap: new Map()
}
- return state
}
-function notes (state = [], action) {
+function data (state = defaultDataMap(), action) {
switch (action.type) {
case 'INIT_ALL':
- return action.notes
- case 'ADD_STORAGE':
- {
- let notes = state.concat(action.notes)
- return notes
- }
- case 'REMOVE_STORAGE':
- {
- let notes = state.slice()
- notes = notes
- .filter((note) => note.storage !== action.key)
+ state = defaultDataMap()
- return notes
- }
- case 'REMOVE_FOLDER':
- {
- let notes = state.slice()
- notes = notes
- .filter((note) => note.storage !== action.storage.key || note.folder !== action.key)
+ action.storages.forEach((storage) => {
+ state.storageMap.set(storage.key, storage)
+ })
- return notes
- }
- case 'CREATE_NOTE':
- {
- let notes = state.slice()
- notes.push(action.note)
- return notes
- }
+ action.notes.forEach((note) => {
+ let uniqueKey = note.storage + '-' + note.key
+ let folderKey = note.storage + '-' + note.folder
+ state.noteMap.set(uniqueKey, note)
+
+ if (note.isStarred) {
+ state.starredSet.add(uniqueKey)
+ }
+
+ let storageNoteList = state.storageNoteMap.get(note.storage)
+ if (storageNoteList == null) {
+ storageNoteList = new Set(storageNoteList)
+ state.storageNoteMap.set(note.storage, storageNoteList)
+ }
+ storageNoteList.add(uniqueKey)
+
+ let folderNoteSet = state.folderNoteMap.get(folderKey)
+ if (folderNoteSet == null) {
+ folderNoteSet = new Set(folderNoteSet)
+ state.folderNoteMap.set(folderKey, folderNoteSet)
+ }
+ folderNoteSet.add(uniqueKey)
+
+ note.tags.forEach((tag) => {
+ let tagNoteList = state.tagNoteMap.get(tag)
+ if (tagNoteList == null) {
+ tagNoteList = new Set(tagNoteList)
+ state.tagNoteMap.set(tag, tagNoteList)
+ }
+ tagNoteList.add(uniqueKey)
+ })
+ })
+ return state
case 'UPDATE_NOTE':
{
- let notes = state.slice()
- notes = notes.filter((note) => note.key !== action.note.key || note.folder !== action.note.folder || note.storage !== action.note.storage)
- notes.push(action.note)
- return notes
+ let note = action.note
+ let uniqueKey = note.storage + '-' + note.key
+ let folderKey = note.storage + '-' + note.folder
+ let oldNote = state.noteMap.get(uniqueKey)
+
+ state = Object.assign({}, state)
+ state.noteMap = new Map(state.noteMap)
+ state.noteMap.set(uniqueKey, note)
+
+ if (oldNote == null || oldNote.isStarred !== note.isStarred) {
+ state.starredSet = new Set(state.starredSet)
+ if (note.isStarred) {
+ state.starredSet.add(uniqueKey)
+ } else {
+ state.starredSet.delete(uniqueKey)
+ }
+ }
+
+ // Update storageNoteMap if oldNote doesn't exist
+ if (oldNote == null) {
+ state.storageNoteMap = new Map(state.storageNoteMap)
+ let storageNoteSet = state.storageNoteMap.get(note.storage)
+ storageNoteSet = new Set(storageNoteSet)
+ storageNoteSet.add(uniqueKey)
+ state.storageNoteMap.set(note.storage, storageNoteSet)
+ }
+
+ // Update foldermap if folder changed or post created
+ if (oldNote == null || oldNote.folder !== note.folder) {
+ state.folderNoteMap = new Map(state.folderNoteMap)
+ let folderNoteSet = state.folderNoteMap.get(folderKey)
+ folderNoteSet = new Set(folderNoteSet)
+ folderNoteSet.add(uniqueKey)
+ state.folderNoteMap.set(folderKey, folderNoteSet)
+
+ if (oldNote != null) {
+ let oldFolderKey = oldNote.storage + '-' + oldNote.folder
+ let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey)
+ oldFolderNoteList = new Set(oldFolderNoteList)
+ oldFolderNoteList.delete(uniqueKey)
+ state.folderNoteMap.set(oldFolderKey, oldFolderNoteList)
+ }
+ }
+
+ if (oldNote != null) {
+ let discardedTags = _.difference(oldNote.tags, note.tags)
+ let addedTags = _.difference(note.tags, oldNote.tags)
+ if (discardedTags.length + addedTags.length > 0) {
+ state.tagNoteMap = new Map(state.tagNoteMap)
+
+ discardedTags.forEach((tag) => {
+ let tagNoteList = state.tagNoteMap.get(tag)
+ if (tagNoteList != null) {
+ tagNoteList = new Set(tagNoteList)
+ tagNoteList.delete(uniqueKey)
+ state.tagNoteMap.set(tag, tagNoteList)
+ }
+ })
+ addedTags.forEach((tag) => {
+ let tagNoteList = state.tagNoteMap.get(tag)
+ tagNoteList = new Set(tagNoteList)
+ tagNoteList.add(uniqueKey)
+
+ state.tagNoteMap.set(tag, tagNoteList)
+ })
+ }
+ } else {
+ state.tagNoteMap = new Map(state.tagNoteMap)
+ note.tags.forEach((tag) => {
+ let tagNoteList = state.tagNoteMap.get(tag)
+ if (tagNoteList == null) {
+ tagNoteList = new Set(tagNoteList)
+ state.tagNoteMap.set(tag, tagNoteList)
+ }
+ tagNoteList.add(uniqueKey)
+ })
+ }
+
+ return state
}
case 'MOVE_NOTE':
{
- let notes = state.slice()
- notes = notes.filter((note) => note.key !== action.note.key || note.folder !== action.note.folder || note.storage !== action.note.storage)
- notes.push(action.newNote)
- return notes
+ let originNote = action.originNote
+ let originKey = originNote.storage + '-' + originNote.key
+ let note = action.note
+ let uniqueKey = note.storage + '-' + note.key
+ let folderKey = note.storage + '-' + note.folder
+ let oldNote = state.noteMap.get(uniqueKey)
+
+ state = Object.assign({}, state)
+ state.noteMap = new Map(state.noteMap)
+ state.noteMap.delete(originKey)
+ state.noteMap.set(uniqueKey, note)
+
+ // If storage chanced, origin key must be discarded
+ if (originKey !== uniqueKey) {
+ console.log('diffrent storage')
+ // From isStarred
+ if (originNote.isStarred) {
+ state.starredSet = new Set(state.starredSet)
+ state.starredSet.delete(originKey)
+ }
+
+ // From storageNoteMap
+ state.storageNoteMap = new Map(state.storageNoteMap)
+ let noteSet = state.storageNoteMap.get(originNote.storage)
+ noteSet = new Set(noteSet)
+ noteSet.delete(originKey)
+ state.storageNoteMap.set(originNote.storage, noteSet)
+
+ // From folderNoteMap
+ state.folderNoteMap = new Map(state.folderNoteMap)
+ let originFolderKey = originNote.storage + '-' + originNote.folder
+ let originFolderList = state.folderNoteMap.get(originFolderKey)
+ originFolderList = new Set(originFolderList)
+ originFolderList.delete(originKey)
+ state.folderNoteMap.set(originFolderKey, originFolderList)
+
+ // From tagMap
+ if (originNote.tags.length > 0) {
+ state.tagNoteMap = new Map(state.tagNoteMap)
+ originNote.tags.forEach((tag) => {
+ let noteSet = state.tagNoteMap.get(tag)
+ noteSet = new Set(noteSet)
+ noteSet.delete(originKey)
+ state.tagNoteMap.set(tag, noteSet)
+ })
+ }
+ }
+
+ if (oldNote == null || oldNote.isStarred !== note.isStarred) {
+ state.starredSet = new Set(state.starredSet)
+ if (note.isStarred) {
+ state.starredSet.add(uniqueKey)
+ } else {
+ state.starredSet.delete(uniqueKey)
+ }
+ }
+
+ // Update storageNoteMap if oldNote doesn't exist
+ if (oldNote == null) {
+ state.storageNoteMap = new Map(state.storageNoteMap)
+ let noteSet = state.storageNoteMap.get(note.storage)
+ noteSet = new Set(noteSet)
+ noteSet.add(uniqueKey)
+ state.folderNoteMap.set(folderKey, noteSet)
+ }
+
+ // Update foldermap if folder changed or post created
+ if (oldNote == null || oldNote.folder !== note.folder) {
+ state.folderNoteMap = new Map(state.folderNoteMap)
+ let folderNoteList = state.folderNoteMap.get(folderKey)
+ folderNoteList = new Set(folderNoteList)
+ folderNoteList.add(uniqueKey)
+ state.folderNoteMap.set(folderKey, folderNoteList)
+
+ if (oldNote != null) {
+ let oldFolderKey = oldNote.storage + '-' + oldNote.folder
+ let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey)
+ oldFolderNoteList = new Set(oldFolderNoteList)
+ oldFolderNoteList.delete(uniqueKey)
+ state.folderNoteMap.set(oldFolderKey, oldFolderNoteList)
+ }
+ }
+
+ // Remove from old folder map
+ if (oldNote != null) {
+ let discardedTags = _.difference(oldNote.tags, note.tags)
+ let addedTags = _.difference(note.tags, oldNote.tags)
+ if (discardedTags.length + addedTags.length > 0) {
+ state.tagNoteMap = new Map(state.tagNoteMap)
+
+ discardedTags.forEach((tag) => {
+ let tagNoteList = state.tagNoteMap.get(tag)
+ if (tagNoteList != null) {
+ tagNoteList = new Set(tagNoteList)
+ tagNoteList.delete(uniqueKey)
+ state.tagNoteMap.set(tag, tagNoteList)
+ }
+ })
+ addedTags.forEach((tag) => {
+ let tagNoteList = state.tagNoteMap.get(tag)
+ tagNoteList = new Set(tagNoteList)
+ tagNoteList.add(uniqueKey)
+
+ state.tagNoteMap.set(tag, tagNoteList)
+ })
+ }
+ } else {
+ state.tagNoteMap = new Map(state.tagNoteMap)
+ note.tags.forEach((tag) => {
+ let tagNoteList = state.tagNoteMap.get(tag)
+ if (tagNoteList == null) {
+ tagNoteList = new Set(tagNoteList)
+ state.tagNoteMap.set(tag, tagNoteList)
+ }
+ tagNoteList.add(uniqueKey)
+ })
+ }
+
+ return state
}
- case 'REMOVE_NOTE':
+ case 'DELETE_NOTE':
{
- let notes = state.slice()
- notes = notes.filter((note) => note.key !== action.note.key || note.folder !== action.note.folder || note.storage !== action.note.storage)
- return notes
+ let uniqueKey = action.storageKey + '-' + action.noteKey
+ let targetNote = state.noteMap.get(uniqueKey)
+
+ state = Object.assign({}, state)
+
+ // From storageNoteMap
+ state.storageNoteMap = new Map(state.storageNoteMap)
+ let noteSet = state.storageNoteMap.get(targetNote.storage)
+ noteSet = new Set(noteSet)
+ noteSet.delete(uniqueKey)
+ state.storageNoteMap.set(targetNote.storage, noteSet)
+
+ if (targetNote != null) {
+ // From isStarred
+ if (targetNote.isStarred) {
+ state.starredSet = new Set(state.starredSet)
+ state.starredSet.delete(uniqueKey)
+ }
+
+ // From folderNoteMap
+ let folderKey = targetNote.storage + '-' + targetNote.folder
+ state.folderNoteMap = new Map(state.folderNoteMap)
+ let folderSet = state.folderNoteMap.get(folderKey)
+ folderSet = new Set(folderSet)
+ folderSet.delete(uniqueKey)
+ state.folderNoteMap.set(folderKey, folderSet)
+
+ // From tagMap
+ if (targetNote.tags.length > 0) {
+ state.tagNoteMap = new Map(state.tagNoteMap)
+ targetNote.tags.forEach((tag) => {
+ let noteSet = state.tagNoteMap.get(tag)
+ noteSet = new Set(noteSet)
+ noteSet.delete(uniqueKey)
+ state.tagNoteMap.set(tag, noteSet)
+ })
+ }
+ }
+ state.noteMap = new Map(state.noteMap)
+ state.noteMap.delete(uniqueKey)
+ return state
}
+ case 'UPDATE_FOLDER':
+ {
+ state = Object.assign({}, state)
+ state.storageMap = new Map(state.storageMap)
+ state.storageMap.set(action.storage.key, action.storage)
+ }
+ return state
+ case 'DELETE_FOLDER':
+ {
+ state = Object.assign({}, state)
+ state.storageMap = new Map(state.storageMap)
+ state.storageMap.set(action.storage.key, action.storage)
+
+ // Get note list from folder-note map
+ // and delete note set from folder-note map
+ let folderKey = action.storage.key + '-' + action.folderKey
+ let noteSet = state.folderNoteMap.get(folderKey)
+ state.folderNoteMap = new Map(state.folderNoteMap)
+ state.folderNoteMap.delete(folderKey)
+
+ state.noteMap = new Map(state.noteMap)
+ state.storageNoteMap = new Map(state.storageNoteMap)
+ let storageNoteSet = state.storageNoteMap.get(action.storage.key)
+ storageNoteSet = new Set(storageNoteSet)
+ state.storageNoteMap.set(action.storage.key, storageNoteSet)
+ noteSet.forEach(function handleNoteKey (noteKey) {
+ // Get note from noteMap
+ let note = state.noteMap.get(noteKey)
+ if (note != null) {
+ state.noteMap.delete(noteKey)
+
+ // From storageSet
+ storageNoteSet.delete(noteKey)
+
+ // From starredSet
+ if (note.isStarred) {
+ state.starredSet = new Set(state.starredSet)
+ state.starredSet.delete(noteKey)
+ }
+
+ // Delete key from tag map
+ state.tagNoteMap = new Map(state.tagNoteMap)
+ note.tags.forEach((tag) => {
+ let tagNoteSet = state.tagNoteMap.get(tag)
+ tagNoteSet = new Set(tagNoteSet)
+ state.tagNoteMap.set(tag, tagNoteSet)
+ tagNoteSet.delete(noteKey)
+ })
+ }
+ })
+ }
+ return state
+ case 'ADD_STORAGE':
+ state = Object.assign({}, state)
+ state.storageMap = new Map(state.storageMap)
+ state.storageMap.set(action.storage.key, action.storage)
+
+ state.noteMap = new Map(state.noteMap)
+ state.storageNoteMap = new Map(state.storageNoteMap)
+ state.storageNoteMap.set(action.storage.key, new Set())
+ state.folderNoteMap = new Map(state.folderNoteMap)
+ state.tagNoteMap = new Map(state.tagNoteMap)
+ action.notes.forEach((note) => {
+ let uniqueKey = note.storage + '-' + note.key
+ let folderKey = note.storage + '-' + note.folder
+ state.noteMap.set(uniqueKey, note)
+
+ if (note.isStarred) {
+ state.starredSet.add(uniqueKey)
+ }
+
+ let storageNoteList = state.storageNoteMap.get(note.storage)
+ if (storageNoteList == null) {
+ storageNoteList = new Set(storageNoteList)
+ state.storageNoteMap.set(note.storage, storageNoteList)
+ }
+ storageNoteList.add(uniqueKey)
+
+ let folderNoteSet = state.folderNoteMap.get(folderKey)
+ if (folderNoteSet == null) {
+ folderNoteSet = new Set(folderNoteSet)
+ state.folderNoteMap.set(folderKey, folderNoteSet)
+ }
+ folderNoteSet.add(uniqueKey)
+
+ note.tags.forEach((tag) => {
+ let tagNoteSet = state.tagNoteMap.get(tag)
+ if (tagNoteSet == null) {
+ tagNoteSet = new Set(tagNoteSet)
+ state.tagNoteMap.set(tag, tagNoteSet)
+ }
+ tagNoteSet.add(uniqueKey)
+ })
+ })
+ return state
+ case 'REMOVE_STORAGE':
+ state = Object.assign({}, state)
+ let storage = state.storageMap.get(action.storageKey)
+ state.storageMap = new Map(state.storageMap)
+ state.storageMap.delete(action.storageKey)
+
+ // Remove folders from folderMap
+ if (storage != null) {
+ state.folderMap = new Map(state.folderMap)
+ storage.folders.forEach((folder) => {
+ let folderKey = storage.key + '-' + folder.key
+ state.folderMap.delete(folderKey)
+ })
+ }
+
+ // Remove notes from noteMap and tagNoteMap
+ let storageNoteSet = state.storageNoteMap.get(action.storageKey)
+ state.storageNoteMap = new Map(state.storageNoteMap)
+ state.storageNoteMap.delete(action.storageKey)
+ if (storageNoteSet != null) {
+ let notes = storageNoteSet
+ .map((noteKey) => state.noteMap.get(noteKey))
+ .filter((note) => note != null)
+
+ state.noteMap = new Map(state.noteMap)
+ state.tagNoteMap = new Map(state.tagNoteMap)
+ state.starredSet = new Set(state.starredSet)
+ notes.forEach((note) => {
+ let noteKey = storage.key + '-' + note.key
+ state.noteMap.delete(noteKey)
+ state.starredSet.delete(noteKey)
+ note.tags.forEach((tag) => {
+ let tagNoteSet = state.tagNoteMap.get(tag)
+ tagNoteSet = new Set(tagNoteSet)
+ tagNoteSet.delete(noteKey)
+ })
+ })
+ }
+ return state
+ case 'RENAME_STORAGE':
+ state = Object.assign({}, state)
+ state.storageMap = new Map(state.storageMap)
+ state.storageMap.set(action.storage.key, action.storage)
+ return state
}
return state
}
@@ -116,8 +470,7 @@ function config (state = defaultConfig, action) {
}
let reducer = combineReducers({
- storages,
- notes,
+ data,
config,
routing: routerReducer
})
diff --git a/package.json b/package.json
index 29f4d696..039d179e 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
"electron-gh-releases": "^2.0.2",
"font-awesome": "^4.3.0",
"highlight.js": "^9.3.0",
+ "immutable": "^3.8.1",
"lodash": "^4.11.1",
"markdown-it": "^6.0.1",
"markdown-it-checkbox": "^1.1.0",
@@ -76,6 +77,7 @@
"dom-storage": "^2.0.2",
"electron-packager": "^6.0.0",
"electron-prebuilt": "^1.2.8",
+ "faker": "^3.1.0",
"grunt": "^0.4.5",
"grunt-electron-installer": "^1.2.0",
"history": "^1.17.0",
diff --git a/tests/dataApi/addStorage.js b/tests/dataApi/addStorage.js
index 26d24fe9..1ca10c54 100644
--- a/tests/dataApi/addStorage.js
+++ b/tests/dataApi/addStorage.js
@@ -8,86 +8,65 @@ global.navigator = window.navigator
const Storage = require('dom-storage')
const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
const path = require('path')
+const TestDummy = require('../fixtures/TestDummy')
const sander = require('sander')
const _ = require('lodash')
+const os = require('os')
+const CSON = require('season')
-function copyFile (filePath, targetPath) {
- return sander.readFile(filePath)
- .then(function writeFile (data) {
- return sander.writeFile(targetPath, data.toString())
- })
-}
+const v1StoragePath = path.join(os.tmpdir(), 'test/addStorage-v1-storage')
+// const legacyStoragePath = path.join(os.tmpdir(), 'test/addStorage-legacy-storage')
+// const emptyDirPath = path.join(os.tmpdir(), 'test/addStorage-empty-storage')
-test('add a initialized storage', (t) => {
- const dummyStoragePath = path.join(__dirname, '../dummy/dummyStorage')
- const targetPath = path.join(__dirname, '../sandbox/test-add-storage1')
+test.beforeEach((t) => {
+ t.context.v1StorageData = TestDummy.dummyStorage(v1StoragePath)
+ // t.context.legacyStorageData = TestDummy.dummyLegacyStorage(legacyStoragePath)
+
+ localStorage.setItem('storages', JSON.stringify([]))
+})
+
+test.serial('Add Storage', (t) => {
const input = {
type: 'FILESYSTEM',
- name: 'test-add-storage1',
- path: targetPath
+ name: 'add-storage1',
+ path: v1StoragePath
}
return Promise.resolve()
- .then(function before () {
- localStorage.setItem('storages', JSON.stringify([]))
-
- sander.rimrafSync(targetPath)
- return copyFile(path.join(dummyStoragePath, 'boostnote.json'), path.join(targetPath, 'boostnote.json'))
- .then(() => {
- return copyFile(path.join(dummyStoragePath, 'fc6ba88e8ecf/data.json'), path.join(targetPath, 'fc6ba88e8ecf/data.json'))
- })
- })
- .then(function doTest (data) {
+ .then(function doTest () {
return addStorage(input)
})
.then(function validateResult (data) {
- const { storage, notes } = data
+ let { storage, notes } = data
+ // Check data.storage
t.true(_.isString(storage.key))
- t.is(storage.name, 'test-add-storage1')
- t.true(_.isArray(storage.folders))
- t.is(storage.folders.length, 1)
- t.true(_.isArray(notes))
- t.is(notes.length, 2)
- t.is(notes[0].folder, 'fc6ba88e8ecf')
- t.is(notes[0].storage, storage.key)
- })
- .then(function after () {
- localStorage.clear()
- sander.rimrafSync(targetPath)
+ t.is(storage.name, input.name)
+ t.is(storage.type, input.type)
+ t.is(storage.path, input.path)
+ t.is(storage.version, '1.0')
+ t.is(storage.folders.length, t.context.v1StorageData.json.folders.length)
+
+ // Check data.notes
+ t.is(notes.length, t.context.v1StorageData.notes.length)
+ notes.forEach(function validateNote (note) {
+ t.is(note.storage, storage.key)
+ })
+
+ // Check localStorage
+ let cacheData = _.find(JSON.parse(localStorage.getItem('storages')), {key: data.storage.key})
+ t.is(cacheData.name, input.name)
+ t.is(cacheData.type, input.type)
+ t.is(cacheData.path, input.path)
+
+ // Check boostnote.json
+ let jsonData = CSON.readFileSync(path.join(storage.path, 'boostnote.json'))
+ t.true(_.isArray(jsonData.folders))
+ t.is(jsonData.version, '1.0')
+ t.is(jsonData.folders.length, t.context.v1StorageData.json.folders.length)
})
})
-test('add a fresh storage', (t) => {
- const targetPath = path.join(__dirname, '../sandbox/test-add-storage2')
- const input = {
- type: 'FILESYSTEM',
- name: 'test-add-storage2',
- path: targetPath
- }
- return Promise.resolve()
- .then(function before () {
- localStorage.setItem('storages', JSON.stringify([]))
-
- sander.rimrafSync(targetPath)
- })
- .then(function doTest (data) {
- return addStorage(input)
- })
- .then(function validateResult (data) {
- const { storage, notes } = data
-
- t.true(_.isString(storage.key))
- t.is(storage.name, 'test-add-storage2')
- t.true(_.isArray(storage.folders))
- t.is(storage.folders.length, 0)
-
- t.true(_.isArray(notes))
- t.is(notes.length, 0)
-
- t.true(sander.statSync(path.join(targetPath, 'boostnote.json')).isFile())
- })
- .then(function after () {
- localStorage.clear()
- sander.rimrafSync(targetPath)
- })
+test.after.always(() => {
+ localStorage.clear()
+ sander.rimrafSync(v1StoragePath)
})
diff --git a/tests/dataApi/createFolder.js b/tests/dataApi/createFolder.js
new file mode 100644
index 00000000..986123b0
--- /dev/null
+++ b/tests/dataApi/createFolder.js
@@ -0,0 +1,45 @@
+const test = require('ava')
+const createFolder = require('browser/main/lib/dataApi/createFolder')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const _ = require('lodash')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('season')
+
+const storagePath = path.join(os.tmpdir(), 'test/create-folder')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Create a folder', (t) => {
+ const storageKey = t.context.storage.cache.key
+ const input = {
+ name: 'created',
+ color: '#ff5555'
+ }
+ return Promise.resolve()
+ .then(function doTest () {
+ return createFolder(storageKey, input)
+ })
+ .then(function assert (data) {
+ t.true(_.find(data.storage.folders, input) != null)
+ let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
+ console.log(path.join(data.storage.path, 'boostnote.json'))
+ t.true(_.find(jsonData.folders, input) != null)
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dataApi/createNote.js b/tests/dataApi/createNote.js
new file mode 100644
index 00000000..7a983fef
--- /dev/null
+++ b/tests/dataApi/createNote.js
@@ -0,0 +1,89 @@
+const test = require('ava')
+const createNote = require('browser/main/lib/dataApi/createNote')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('season')
+const faker = require('faker')
+
+const storagePath = path.join(os.tmpdir(), 'test/create-note')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Create a note', (t) => {
+ const storageKey = t.context.storage.cache.key
+ const folderKey = t.context.storage.json.folders[0].key
+
+ const input1 = {
+ type: 'SNIPPET_NOTE',
+ description: faker.lorem.lines(),
+ snippets: [{
+ name: faker.system.fileName(),
+ mode: 'text',
+ content: faker.lorem.lines()
+ }],
+ tags: faker.lorem.words().split(' '),
+ folder: folderKey
+ }
+ input1.title = input1.description.split('\n').shift()
+
+ const input2 = {
+ type: 'MARKDOWN_NOTE',
+ content: faker.lorem.lines(),
+ tags: faker.lorem.words().split(' '),
+ folder: folderKey
+ }
+ input2.title = input2.content.split('\n').shift()
+
+ return Promise.resolve()
+ .then(function doTest () {
+ return Promise.all([
+ createNote(storageKey, input1),
+ createNote(storageKey, input2)
+ ])
+ })
+ .then(function assert (data) {
+ let data1 = data[0]
+ let data2 = data[1]
+
+ t.is(storageKey, data1.storage)
+ let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
+ t.is(input1.title, data1.title)
+ t.is(input1.title, jsonData1.title)
+ t.is(input1.description, data1.description)
+ t.is(input1.description, jsonData1.description)
+ t.is(input1.tags.length, data1.tags.length)
+ t.is(input1.tags.length, jsonData1.tags.length)
+ t.is(input1.snippets.length, data1.snippets.length)
+ t.is(input1.snippets.length, jsonData1.snippets.length)
+ t.is(input1.snippets[0].content, data1.snippets[0].content)
+ t.is(input1.snippets[0].content, jsonData1.snippets[0].content)
+ t.is(input1.snippets[0].name, data1.snippets[0].name)
+ t.is(input1.snippets[0].name, jsonData1.snippets[0].name)
+
+ t.is(storageKey, data2.storage)
+ let jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
+ t.is(input2.title, data2.title)
+ t.is(input2.title, jsonData2.title)
+ t.is(input2.content, data2.content)
+ t.is(input2.content, jsonData2.content)
+ t.is(input2.tags.length, data2.tags.length)
+ t.is(input2.tags.length, jsonData2.tags.length)
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dataApi/deleteFolder.js b/tests/dataApi/deleteFolder.js
new file mode 100644
index 00000000..f760c819
--- /dev/null
+++ b/tests/dataApi/deleteFolder.js
@@ -0,0 +1,45 @@
+const test = require('ava')
+const deleteFolder = require('browser/main/lib/dataApi/deleteFolder')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const _ = require('lodash')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('season')
+
+const storagePath = path.join(os.tmpdir(), 'test/delete-folder')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Delete a folder', (t) => {
+ const storageKey = t.context.storage.cache.key
+ const folderKey = t.context.storage.json.folders[0].key
+
+ return Promise.resolve()
+ .then(function doTest () {
+ return deleteFolder(storageKey, folderKey)
+ })
+ .then(function assert (data) {
+ t.true(_.find(data.storage.folders, {key: folderKey}) == null)
+ let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
+
+ t.true(_.find(jsonData.folders, {key: folderKey}) == null)
+ let notePaths = sander.readdirSync(data.storage.path, 'notes')
+ t.is(notePaths.length, t.context.storage.notes.filter((note) => note.folder !== folderKey).length)
+ })
+})
+
+test.after.always(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dataApi/deleteNote.js b/tests/dataApi/deleteNote.js
new file mode 100644
index 00000000..b22e5de2
--- /dev/null
+++ b/tests/dataApi/deleteNote.js
@@ -0,0 +1,62 @@
+const test = require('ava')
+const createNote = require('browser/main/lib/dataApi/createNote')
+const deleteNote = require('browser/main/lib/dataApi/deleteNote')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('season')
+const faker = require('faker')
+
+const storagePath = path.join(os.tmpdir(), 'test/delete-note')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Delete a note', (t) => {
+ const storageKey = t.context.storage.cache.key
+ const folderKey = t.context.storage.json.folders[0].key
+
+ const input1 = {
+ type: 'SNIPPET_NOTE',
+ description: faker.lorem.lines(),
+ snippets: [{
+ name: faker.system.fileName(),
+ mode: 'text',
+ content: faker.lorem.lines()
+ }],
+ tags: faker.lorem.words().split(' '),
+ folder: folderKey
+ }
+ input1.title = input1.description.split('\n').shift()
+
+ return Promise.resolve()
+ .then(function doTest () {
+ return createNote(storageKey, input1)
+ .then(function (data) {
+ return deleteNote(storageKey, data.key)
+ })
+ })
+ .then(function assert (data) {
+ try {
+ CSON.readFileSync(path.join(storagePath, 'notes', data.noteKey + '.cson'))
+ t.fail('note cson must be deleted.')
+ } catch (err) {
+ t.is(err.code, 'ENOENT')
+ }
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dataApi/init.js b/tests/dataApi/init.js
index 2d47a904..81ef38a4 100644
--- a/tests/dataApi/init.js
+++ b/tests/dataApi/init.js
@@ -8,68 +8,58 @@ global.navigator = window.navigator
const Storage = require('dom-storage')
const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
const path = require('path')
-const crypto = require('crypto')
+const TestDummy = require('../fixtures/TestDummy')
+const keygen = require('browser/lib/keygen')
+const sander = require('sander')
+const _ = require('lodash')
+const os = require('os')
-test.serial('Fetch storages and notes', (t) => {
- const dummyStoragePath = path.join(__dirname, '..', 'dummy/dummyStorage')
- const dummyRawStorage = {
- name: 'test1',
- key: crypto.randomBytes(6).toString('hex'),
- path: dummyStoragePath
+const v1StoragePath = path.join(os.tmpdir(), 'test/init-v1-storage')
+const legacyStoragePath = path.join(os.tmpdir(), 'test/init-legacy-storage')
+const emptyDirPath = path.join(os.tmpdir(), 'test/init-empty-storage')
+
+test.beforeEach((t) => {
+ localStorage.clear()
+ // Prepare 3 types of dir
+ t.context.v1StorageData = TestDummy.dummyStorage(v1StoragePath, {cache: {name: 'v1'}})
+ t.context.legacyStorageData = TestDummy.dummyLegacyStorage(legacyStoragePath, {cache: {name: 'legacy'}})
+ t.context.emptyStorageData = {
+ cache: {
+ type: 'FILESYSTEM',
+ name: 'empty',
+ key: keygen(),
+ path: emptyDirPath
+ }
}
- const dummyFolderKey = 'fc6ba88e8ecf'
+ localStorage.setItem('storages', JSON.stringify([t.context.v1StorageData.cache, t.context.legacyStorageData.cache, t.context.emptyStorageData.cache]))
+})
+
+test.serial('Initialize All Storages', (t) => {
+ const { v1StorageData, legacyStorageData, emptyStorageData } = t.context
return Promise.resolve()
- .then(function before () {
- localStorage.setItem('storages', JSON.stringify([dummyRawStorage]))
- })
.then(function test () {
return init()
})
.then(function assert (data) {
t.true(Array.isArray(data.storages))
- var targetStorage = data.storages.filter((storage) => storage.key === dummyRawStorage.key)[0]
- t.not(targetStorage, null)
- t.is(targetStorage.name, dummyRawStorage.name)
- t.is(targetStorage.key, dummyRawStorage.key)
- t.is(targetStorage.path, dummyRawStorage.path)
- t.is(data.notes.length, 2)
- data.notes.forEach((note) => {
- t.is(note.folder, dummyFolderKey)
+ t.is(data.notes.length, v1StorageData.notes.length + legacyStorageData.notes.length)
+ t.is(data.storages.length, 3)
+ data.storages.forEach(function assertStorage (storage) {
+ t.true(_.isString(storage.key))
+ t.true(_.isString(storage.name))
+ t.true(storage.type === 'FILESYSTEM')
+ t.true(_.isString(storage.path))
})
-
- t.true(Array.isArray(data.notes))
})
.then(function after () {
localStorage.clear()
})
})
-test.serial('If storage path is a empty folder, return metadata with empty folder array and empty note array.', (t) => {
- const emptyFolderPath = path.join(__dirname, '..', 'dummy/empty')
- const dummyRawStorage = {
- name: 'test2',
- key: crypto.randomBytes(6).toString('hex'),
- path: emptyFolderPath
- }
- return Promise.resolve()
- .then(function before () {
- localStorage.setItem('storages', JSON.stringify([dummyRawStorage]))
- })
- .then(function test () {
- return init()
- })
- .then(function assert (data) {
- t.true(Array.isArray(data.storages))
- var targetStorage = data.storages.filter((storage) => storage.key === dummyRawStorage.key)[0]
- t.not(targetStorage, null)
- t.is(targetStorage.name, dummyRawStorage.name)
- t.is(targetStorage.key, dummyRawStorage.key)
- t.is(targetStorage.path, dummyRawStorage.path)
-
- t.true(Array.isArray(data.notes))
- })
- .then(function after () {
- localStorage.clear()
- })
+test.after.always(() => {
+ localStorage.clear()
+ sander.rimrafSync(v1StoragePath)
+ sander.rimrafSync(legacyStoragePath)
+ sander.rimrafSync(emptyDirPath)
})
diff --git a/tests/dataApi/migrateFromV6Storage.js b/tests/dataApi/migrateFromV6Storage.js
new file mode 100644
index 00000000..f10e3ff6
--- /dev/null
+++ b/tests/dataApi/migrateFromV6Storage.js
@@ -0,0 +1,64 @@
+const test = require('ava')
+const migrateFromV6Storage = require('browser/main/lib/dataApi/migrateFromV6Storage')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const CSON = require('season')
+const _ = require('lodash')
+const os = require('os')
+
+const dummyStoragePath = path.join(os.tmpdir(), 'test/migrate-test-storage')
+
+test.beforeEach((t) => {
+ let dummyData = t.context.dummyData = TestDummy.dummyLegacyStorage(dummyStoragePath)
+ console.log('init count', dummyData.notes.length)
+ localStorage.setItem('storages', JSON.stringify([dummyData.cache]))
+})
+
+test.serial('Migrate legacy storage into v1 storage', (t) => {
+ return Promise.resolve()
+ .then(function test () {
+ return migrateFromV6Storage(dummyStoragePath)
+ })
+ .then(function assert (data) {
+ // Check the result. It must be true if succeed.
+ t.true(data)
+
+ // Check all notes migrated.
+ let dummyData = t.context.dummyData
+ let noteDirPath = path.join(dummyStoragePath, 'notes')
+ let fileList = sander.readdirSync(noteDirPath)
+ t.is(dummyData.notes.length, fileList.length)
+ let noteMap = fileList
+ .map((filePath) => {
+ return CSON.readFileSync(path.join(noteDirPath, filePath))
+ })
+ dummyData.notes
+ .forEach(function (targetNote) {
+ t.true(_.find(noteMap, {title: targetNote.title, folder: targetNote.folder}) != null)
+ })
+
+ // Check legacy folder directory is removed
+ dummyData.json.folders
+ .forEach(function (folder) {
+ try {
+ sander.statSync(dummyStoragePath, folder.key)
+ t.fail('Folder still remains. ENOENT error must be occured.')
+ } catch (err) {
+ t.is(err.code, 'ENOENT')
+ }
+ })
+ })
+})
+
+test.after.always(function () {
+ localStorage.clear()
+ sander.rimrafSync(dummyStoragePath)
+})
diff --git a/tests/dataApi/moveNote.js b/tests/dataApi/moveNote.js
new file mode 100644
index 00000000..595b46ed
--- /dev/null
+++ b/tests/dataApi/moveNote.js
@@ -0,0 +1,66 @@
+const test = require('ava')
+const moveNote = require('browser/main/lib/dataApi/moveNote')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('season')
+const faker = require('faker')
+
+const storagePath = path.join(os.tmpdir(), 'test/move-note')
+const storagePath2 = path.join(os.tmpdir(), 'test/move-note2')
+
+test.beforeEach((t) => {
+ t.context.storage1 = TestDummy.dummyStorage(storagePath)
+ t.context.storage2 = TestDummy.dummyStorage(storagePath2)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage1.cache, t.context.storage2.cache]))
+})
+
+test.serial('Move a note', (t) => {
+ const storageKey1 = t.context.storage1.cache.key
+ const folderKey1 = t.context.storage1.json.folders[0].key
+ const note1 = t.context.storage1.notes[0]
+ const note2 = t.context.storage1.notes[1]
+ const storageKey2 = t.context.storage2.cache.key
+ const folderKey2 = t.context.storage2.json.folders[0].key
+
+ return Promise.resolve()
+ .then(function doTest () {
+ return Promise.all([
+ moveNote(storageKey1, note1.key, storageKey1, folderKey1),
+ moveNote(storageKey1, note2.key, storageKey2, folderKey2)
+ ])
+ })
+ .then(function assert (data) {
+ let data1 = data[0]
+ let data2 = data[1]
+
+ let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
+
+ t.is(jsonData1.folder, folderKey1)
+ t.is(jsonData1.title, note1.title)
+
+ let jsonData2 = CSON.readFileSync(path.join(storagePath2, 'notes', data2.key + '.cson'))
+ t.is(jsonData2.folder, folderKey2)
+ t.is(jsonData2.title, note2.title)
+ try {
+ CSON.readFileSync(path.join(storagePath, 'notes', note2.key + '.cson'))
+ t.fail('The old note should be deleted.')
+ } catch (err) {
+ t.is(err.code, 'ENOENT')
+ }
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+ sander.rimrafSync(storagePath2)
+})
diff --git a/tests/dataApi/removeStorage.js b/tests/dataApi/removeStorage.js
new file mode 100644
index 00000000..33541df1
--- /dev/null
+++ b/tests/dataApi/removeStorage.js
@@ -0,0 +1,36 @@
+const test = require('ava')
+const removeStorage = require('browser/main/lib/dataApi/removeStorage')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+
+const storagePath = path.join(os.tmpdir(), 'test/remove-storage')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test('Remove a storage', (t) => {
+ const storageKey = t.context.storage.cache.key
+ return Promise.resolve()
+ .then(function doTest () {
+ return removeStorage(storageKey)
+ })
+ .then(function assert (data) {
+ t.is(JSON.parse(localStorage.getItem('storages')).length, 0)
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dataApi/renameStorage.js b/tests/dataApi/renameStorage.js
new file mode 100644
index 00000000..b898d6f1
--- /dev/null
+++ b/tests/dataApi/renameStorage.js
@@ -0,0 +1,38 @@
+const test = require('ava')
+const renameStorage = require('browser/main/lib/dataApi/renameStorage')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const _ = require('lodash')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+
+const storagePath = path.join(os.tmpdir(), 'test/rename-storage')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Rename a storage', (t) => {
+ const storageKey = t.context.storage.cache.key
+ return Promise.resolve()
+ .then(function doTest () {
+ return renameStorage(storageKey, 'changed')
+ })
+ .then(function assert (data) {
+ let cachedStorageList = JSON.parse(localStorage.getItem('storages'))
+ t.true(_.find(cachedStorageList, {key: storageKey}).name === 'changed')
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dataApi/updateFolder.js b/tests/dataApi/updateFolder.js
new file mode 100644
index 00000000..9ebbdc9f
--- /dev/null
+++ b/tests/dataApi/updateFolder.js
@@ -0,0 +1,46 @@
+const test = require('ava')
+const updateFolder = require('browser/main/lib/dataApi/updateFolder')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const _ = require('lodash')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('season')
+
+const storagePath = path.join(os.tmpdir(), 'test/update-folder')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Update a folder', (t) => {
+ const storageKey = t.context.storage.cache.key
+ const folderKey = t.context.storage.json.folders[0].key
+ const input = {
+ name: 'changed',
+ color: '#FF0000'
+ }
+ return Promise.resolve()
+ .then(function doTest () {
+ return updateFolder(storageKey, folderKey, input)
+ })
+ .then(function assert (data) {
+ t.true(_.find(data.storage.folders, input) != null)
+ let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
+ console.log(path.join(data.storage.path, 'boostnote.json'))
+ t.true(_.find(jsonData.folders, input) != null)
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dataApi/updateNote.js b/tests/dataApi/updateNote.js
new file mode 100644
index 00000000..63b74dbb
--- /dev/null
+++ b/tests/dataApi/updateNote.js
@@ -0,0 +1,116 @@
+const test = require('ava')
+const createNote = require('browser/main/lib/dataApi/createNote')
+const updateNote = require('browser/main/lib/dataApi/updateNote')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('season')
+const faker = require('faker')
+
+const storagePath = path.join(os.tmpdir(), 'test/update-note')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Update a note', (t) => {
+ const storageKey = t.context.storage.cache.key
+ const folderKey = t.context.storage.json.folders[0].key
+
+ const input1 = {
+ type: 'SNIPPET_NOTE',
+ description: faker.lorem.lines(),
+ snippets: [{
+ name: faker.system.fileName(),
+ mode: 'text',
+ content: faker.lorem.lines()
+ }],
+ tags: faker.lorem.words().split(' '),
+ folder: folderKey
+ }
+ input1.title = input1.description.split('\n').shift()
+
+ const input2 = {
+ type: 'MARKDOWN_NOTE',
+ content: faker.lorem.lines(),
+ tags: faker.lorem.words().split(' '),
+ folder: folderKey
+ }
+ input2.title = input2.content.split('\n').shift()
+
+ const input3 = {
+ type: 'SNIPPET_NOTE',
+ description: faker.lorem.lines(),
+ snippets: [{
+ name: faker.system.fileName(),
+ mode: 'text',
+ content: faker.lorem.lines()
+ }],
+ tags: faker.lorem.words().split(' ')
+ }
+ input3.title = input3.description.split('\n').shift()
+
+ const input4 = {
+ type: 'MARKDOWN_NOTE',
+ content: faker.lorem.lines(),
+ tags: faker.lorem.words().split(' ')
+ }
+ input4.title = input4.content.split('\n').shift()
+
+ return Promise.resolve()
+ .then(function doTest () {
+ return Promise
+ .all([
+ createNote(storageKey, input1),
+ createNote(storageKey, input2)
+ ])
+ .then(function updateNotes (data) {
+ let data1 = data[0]
+ let data2 = data[1]
+ return Promise.all([
+ updateNote(data1.storage, data1.key, input3),
+ updateNote(data1.storage, data2.key, input4)
+ ])
+ })
+ })
+ .then(function assert (data) {
+ let data1 = data[0]
+ let data2 = data[1]
+
+ let jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
+ t.is(input3.title, data1.title)
+ t.is(input3.title, jsonData1.title)
+ t.is(input3.description, data1.description)
+ t.is(input3.description, jsonData1.description)
+ t.is(input3.tags.length, data1.tags.length)
+ t.is(input3.tags.length, jsonData1.tags.length)
+ t.is(input3.snippets.length, data1.snippets.length)
+ t.is(input3.snippets.length, jsonData1.snippets.length)
+ t.is(input3.snippets[0].content, data1.snippets[0].content)
+ t.is(input3.snippets[0].content, jsonData1.snippets[0].content)
+ t.is(input3.snippets[0].name, data1.snippets[0].name)
+ t.is(input3.snippets[0].name, jsonData1.snippets[0].name)
+
+ let jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
+ t.is(input4.title, data2.title)
+ t.is(input4.title, jsonData2.title)
+ t.is(input4.content, data2.content)
+ t.is(input4.content, jsonData2.content)
+ t.is(input4.tags.length, data2.tags.length)
+ t.is(input4.tags.length, jsonData2.tags.length)
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/tests/dummy/dummyStorage/boostnote.json b/tests/dummy/dummyStorage/boostnote.json
deleted file mode 100644
index ae4e4df4..00000000
--- a/tests/dummy/dummyStorage/boostnote.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "folders": [
- {
- "key": "fc6ba88e8ecf",
- "name": "test",
- "color": "#FF5555"
- }
- ]
-}
diff --git a/tests/dummy/dummyStorage/fc6ba88e8ecf/data.json b/tests/dummy/dummyStorage/fc6ba88e8ecf/data.json
deleted file mode 100644
index 08e002c1..00000000
--- a/tests/dummy/dummyStorage/fc6ba88e8ecf/data.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "notes": [
- {
- "tags": [],
- "title": "Footnote test",
- "content": "# Footnote test\n\ntest test",
- "type": "MARKDOWN_NOTE",
- "key": "93c6ac2a7953",
- "isStarred": false,
- "createdAt": "2016-07-25T16:19:55.620Z",
- "updatedAt": "2016-07-26T08:00:11.326Z"
- },
- {
- "tags": [],
- "title": "Checkbox test",
- "content": "# Checkbox test\n\n- [x] Task1\n- [ ] Task2\n- [ ] Task3\n\n",
- "type": "MARKDOWN_NOTE",
- "key": "4568d84331d9",
- "isStarred": false,
- "createdAt": "2016-07-25T16:58:43.685Z",
- "updatedAt": "2016-08-21T06:14:50.381Z"
- }
- ]
-}
diff --git a/tests/fixtures/TestDummy.js b/tests/fixtures/TestDummy.js
new file mode 100644
index 00000000..19cfa9c5
--- /dev/null
+++ b/tests/fixtures/TestDummy.js
@@ -0,0 +1,179 @@
+const faker = require('faker')
+const keygen = require('browser/lib/keygen')
+const _ = require('lodash')
+const sander = require('sander')
+const CSON = require('season')
+const path = require('path')
+
+function dummyFolder (override = {}) {
+ var data = {
+ name: faker.lorem.word(),
+ color: faker.internet.color()
+ }
+ if (override.key == null) data.key = keygen()
+
+ Object.assign(data, override)
+
+ return data
+}
+
+function dummyBoostnoteJSONData (override = {}, isLegacy = false) {
+ var data = {}
+ if (override.folders == null) {
+ data.folders = []
+
+ var folderCount = Math.floor((Math.random() * 5)) + 1
+ for (var i = 0; i < folderCount; i++) {
+ var key = keygen()
+ while (data.folders.some((folder) => folder.key === key)) {
+ key = keygen()
+ }
+
+ data.folders.push(dummyFolder({
+ key
+ }))
+ }
+ }
+ if (!isLegacy) data.version = '1.0'
+
+ Object.assign(data, override)
+
+ return data
+}
+
+function dummyNote (override = {}) {
+ var data = Math.random() > 0.5
+ ? {
+ type: 'MARKDOWN_NOTE',
+ content: faker.lorem.lines()
+ }
+ : {
+ type: 'SNIPPET_NOTE',
+ description: faker.lorem.lines(),
+ snippets: [{
+ name: faker.system.fileName(),
+ mode: 'text',
+ content: faker.lorem.lines()
+ }]
+ }
+ data.title = data.type === 'MARKDOWN_NOTE'
+ ? data.content.split('\n').shift()
+ : data.description.split('\n').shift()
+ data.createdAt = faker.date.past()
+ data.updatedAt = faker.date.recent()
+ data.isStarred = false
+ data.tags = faker.lorem.words().split(' ')
+
+ if (override.key == null) data.key = keygen()
+ if (override.folder == null) data.folder = keygen()
+ Object.assign(data, override)
+
+ return data
+}
+
+/**
+ * @param {String}
+ * @param {Object}
+ * ```
+ * {
+ * json: {
+ * folders: []
+ * version: String(enum:'1.0')
+ * },
+ * cache: {
+ * key: String,
+ * name: String,
+ * type: String(enum:'FILESYSTEM'),
+ * path: String
+ * },
+ * notes: []
+ * }
+ * ```
+ * @return {[type]}
+ */
+function dummyStorage (storagePath, override = {}) {
+ var jsonData = override.json != null
+ ? override.json
+ : dummyBoostnoteJSONData()
+ var cacheData = override.cache != null
+ ? override.cache
+ : {}
+ if (cacheData.key == null) cacheData.key = keygen()
+ if (cacheData.name == null) cacheData.name = faker.random.word()
+ if (cacheData.type == null) cacheData.type = 'FILESYSTEM'
+ cacheData.path = storagePath
+
+ sander.writeFileSync(path.join(storagePath, 'boostnote.json'), JSON.stringify(jsonData))
+ var notesData = []
+ var noteCount = Math.floor((Math.random() * 15)) + 1
+ for (var i = 0; i < noteCount; i++) {
+ var key = keygen()
+ while (notesData.some((note) => note.key === key)) {
+ key = keygen()
+ }
+
+ var noteData = dummyNote({
+ key,
+ folder: jsonData.folders[Math.floor(Math.random() * jsonData.folders.length)].key
+ })
+
+ notesData.push(noteData)
+ }
+ notesData.forEach(function saveNoteCSON (note) {
+ CSON.writeFileSync(path.join(storagePath, 'notes', note.key + '.cson'), _.omit(note, ['key']))
+ })
+
+ return {
+ json: jsonData,
+ cache: cacheData,
+ notes: notesData
+ }
+}
+
+function dummyLegacyStorage (storagePath, override = {}) {
+ var jsonData = override.json != null
+ ? override.json
+ : dummyBoostnoteJSONData({}, true)
+ var cacheData = override.cache != null
+ ? override.cache
+ : {}
+ if (cacheData.key == null) cacheData.key = keygen()
+ if (cacheData.name == null) cacheData.name = faker.random.word()
+ if (cacheData.type == null) cacheData.type = 'FILESYSTEM'
+ cacheData.path = storagePath
+
+ sander.writeFileSync(path.join(storagePath, 'boostnote.json'), JSON.stringify(jsonData))
+
+ var notesData = []
+ for (var j = 0; j < jsonData.folders.length; j++) {
+ var folderNotes = []
+ var noteCount = Math.floor((Math.random() * 5)) + 1
+ for (var i = 0; i < noteCount; i++) {
+ var key = keygen(6)
+ while (folderNotes.some((note) => note.key === key)) {
+ key = keygen(6)
+ }
+
+ var noteData = dummyNote({
+ key,
+ folder: jsonData.folders[j].key
+ })
+ folderNotes.push(noteData)
+ }
+ notesData = notesData.concat(folderNotes)
+ CSON.writeFileSync(path.join(storagePath, jsonData.folders[j].key, 'data.json'), {notes: folderNotes.map((note) => _.omit(note, ['folder']))})
+ }
+
+ return {
+ json: jsonData,
+ cache: cacheData,
+ notes: notesData
+ }
+}
+
+module.exports = {
+ dummyFolder,
+ dummyBoostnoteJSONData,
+ dummyStorage,
+ dummyLegacyStorage
+}
diff --git a/webpack.config.js b/webpack.config.js
index 7a1768f1..dfde7e85 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -24,7 +24,7 @@ var config = Object.assign({}, skeleton, {
publicPath: 'http://localhost:8080/assets/'
},
debug: true,
- devtool: 'eval-source-map'
+ devtool: 'cheap-module-eval-source-map'
})
module.exports = config