diff --git a/src/lib/Diff.ts b/src/lib/Diff.ts index a4c9cb6e4d..d21aa74c98 100644 --- a/src/lib/Diff.ts +++ b/src/lib/Diff.ts @@ -107,36 +107,59 @@ export default class Diff, item2: TItem, itemTree: Folder, cache: Record): boolean { + const cacheKey = 'contains:' + Mappings.mapId(mappingsSnapshot, item2, ItemLocation.LOCAL) + ':' + Mappings.mapId(mappingsSnapshot, item2, ItemLocation.SERVER) + + '-' + Mappings.mapId(mappingsSnapshot, item1, ItemLocation.LOCAL) + ':' + Mappings.mapId(mappingsSnapshot, item1, ItemLocation.SERVER) + if (typeof cache[cacheKey] !== 'undefined') { + return cache[cacheKey] + } + const item1InTree = itemTree.findItem(item1.type, Mappings.mapId(mappingsSnapshot, item1, itemTree.location)) + if ( + item1.findItem(ItemType.FOLDER, + Mappings.mapParentId(mappingsSnapshot, item2, item1.location)) || + (item1InTree && item1InTree.findItem(ItemType.FOLDER, Mappings.mapParentId(mappingsSnapshot, item2, itemTree.location))) || + String(Mappings.mapId(mappingsSnapshot, item1, item2.location)) === String(item2.parentId) || + String(Mappings.mapParentId(mappingsSnapshot, item2, item1.location)) === String(item1.id) + ) { + cache[cacheKey] = true + return true + } + cache[cacheKey] = false + return false + } + static findChain( mappingsSnapshot: MappingSnapshot, - actions: Action[], itemTree: Folder, + actions: Action[], + itemTree: Folder, currentItem: TItem, targetAction: Action, + cache: Record = {}, chain: Action[] = [] ): boolean { - const targetItemInTree = itemTree.findFolder(Mappings.mapId(mappingsSnapshot, targetAction.payload, itemTree.location)) - if ( - targetAction.payload.findItem(ItemType.FOLDER, - Mappings.mapParentId(mappingsSnapshot, currentItem, targetAction.payload.location)) || - (targetItemInTree && targetItemInTree.findFolder(Mappings.mapParentId(mappingsSnapshot, currentItem, itemTree.location))) - ) { + const currentItemLocalId = Mappings.mapId(mappingsSnapshot, currentItem, ItemLocation.LOCAL) + const currentItemServerId = Mappings.mapId(mappingsSnapshot, currentItem, ItemLocation.SERVER) + const targetPayloadLocalId = Mappings.mapId(mappingsSnapshot, targetAction.payload, ItemLocation.LOCAL) + const targetPayloadServerId = Mappings.mapId(mappingsSnapshot, targetAction.payload, ItemLocation.SERVER) + const cacheKey = `hasChain:${currentItemLocalId}:${currentItemServerId}-${targetPayloadLocalId}:${targetPayloadServerId}` + if (typeof cache[cacheKey] !== 'undefined') { + return cache[cacheKey] + } + if (Diff.containsParent(mappingsSnapshot, targetAction.payload, currentItem, itemTree, cache)) { + cache[cacheKey] = true return true } - const newCurrentActions = actions.filter(targetAction => - !chain.includes(targetAction) && ( - targetAction.payload.findItem(ItemType.FOLDER, Mappings.mapParentId(mappingsSnapshot, currentItem, targetAction.payload.location)) || - ( - itemTree.findFolder(Mappings.mapId(mappingsSnapshot, targetAction.payload, itemTree.location)) && - itemTree.findFolder(Mappings.mapId(mappingsSnapshot, targetAction.payload, itemTree.location)).findFolder(Mappings.mapParentId(mappingsSnapshot, currentItem, itemTree.location))) - ) + const newCurrentActions = actions.filter(newTargetAction => + !chain.includes(newTargetAction) && Diff.containsParent(mappingsSnapshot, newTargetAction.payload, currentItem, itemTree, cache) ) if (newCurrentActions.length) { for (const newCurrentAction of newCurrentActions) { - if (Diff.findChain(mappingsSnapshot, actions, itemTree, newCurrentAction.payload, targetAction, [...chain, newCurrentAction])) { + if (Diff.findChain(mappingsSnapshot, actions, itemTree, newCurrentAction.payload, targetAction, cache,[...chain, newCurrentAction])) { return true } } } + cache[cacheKey] = false return false } diff --git a/src/lib/Mappings.ts b/src/lib/Mappings.ts index 64bfd19400..5762a1042a 100644 --- a/src/lib/Mappings.ts +++ b/src/lib/Mappings.ts @@ -79,6 +79,13 @@ export default class Mappings { } } + static mapRawId(mappingsSnapshot:MappingSnapshot, id: string|number, type: TItemType, source: TItemLocation, target: TItemLocation) : string|number { + if (target === source) { + return id + } + return mappingsSnapshot[source + 'To' + target][type][id] + } + static mapId(mappingsSnapshot:MappingSnapshot, item: TItem, target: TItemLocation) : string|number { if (item.location === target) { return item.id @@ -94,10 +101,10 @@ export default class Mappings { } static mappable(mappingsSnapshot: MappingSnapshot, item1: TItem, item2: TItem) : boolean { - if (Mappings.mapId(mappingsSnapshot, item1, item2.location) === item2.id) { + if (String(Mappings.mapId(mappingsSnapshot, item1, item2.location)) === String(item2.id)) { return true } - if (Mappings.mapId(mappingsSnapshot, item2, item1.location) === item1.id) { + if (String(Mappings.mapId(mappingsSnapshot, item2, item1.location)) === String(item1.id)) { return true } return false diff --git a/src/lib/browser/BrowserTree.ts b/src/lib/browser/BrowserTree.ts index 67c94bc327..bd2c9d5a96 100644 --- a/src/lib/browser/BrowserTree.ts +++ b/src/lib/browser/BrowserTree.ts @@ -249,6 +249,10 @@ export default class BrowserTree implements IResource const [realTree] = await browser.bookmarks.getSubTree(id) try { for (let index = 0; index < order.length; index++) { + if (!realTree.children.find(item => String(item.id) === String(order[index].id))) { + Logger.log('(local)ORDERFOLDER: skipping item ', order[index]) + continue + } await browser.bookmarks.move(order[index].id, { parentId: id.toString(), index }) } } catch (e) { diff --git a/src/lib/strategies/Default.ts b/src/lib/strategies/Default.ts index 6a73547ce5..853b0c3db1 100644 --- a/src/lib/strategies/Default.ts +++ b/src/lib/strategies/Default.ts @@ -9,6 +9,7 @@ import { } from '../Tree' import Logger from '../Logger' import Diff, { + Action, ActionType, CreateAction, MoveAction, @@ -289,6 +290,10 @@ export default class SyncProcess { Logger.log('Executing local plan') await this.execute(this.localTree, this.localPlanStage2, ItemLocation.LOCAL, this.localDonePlan, this.localReorders) + // Remove mappings only after both plans have been executed + this.localDonePlan.REMOVE.getActions().forEach(action => this.removeMapping(this.localTree, action.payload)) + this.serverDonePlan.REMOVE.getActions().forEach(action => this.removeMapping(this.server, action.payload)) + if (this.canceled) { throw new CancelledSyncError() } @@ -296,8 +301,10 @@ export default class SyncProcess { if ('orderFolder' in this.server && !this.localReordersFinal) { // mappings have been updated, reload mappingsSnapshot = this.mappings.getSnapshot() - this.localReordersFinal = this.reconcileReorderings(this.localReorders, this.serverDonePlan, ItemLocation.LOCAL, mappingsSnapshot) - this.serverReorderFinal = this.reconcileReorderings(this.serverReorders, this.localDonePlan, ItemLocation.SERVER, mappingsSnapshot) + const localReorders = this.reconcileReorderings(this.localReorders, this.localDonePlan, ItemLocation.LOCAL, mappingsSnapshot) + const serverReorders = this.reconcileReorderings(this.serverReorders, this.serverDonePlan, ItemLocation.SERVER, mappingsSnapshot) + this.localReordersFinal = this.reconcileReorderings(localReorders, this.serverDonePlan, ItemLocation.LOCAL, mappingsSnapshot).map(mappingsSnapshot, ItemLocation.LOCAL) + this.serverReorderFinal = this.reconcileReorderings(serverReorders, this.localDonePlan, ItemLocation.SERVER, mappingsSnapshot).map(mappingsSnapshot, ItemLocation.SERVER) } if (this.canceled) { @@ -554,10 +561,11 @@ export default class SyncProcess { REORDER: new Diff(), } + const findChainCacheForRemovals = {} await Parallel.each(sourceScanResult.REMOVE.getActions(), async(action) => { const concurrentRemoval = targetRemovals.find(targetRemoval => (action.payload.type === targetRemoval.payload.type && Mappings.mappable(mappingsSnapshot, action.payload, targetRemoval.payload)) || - Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, targetTree, action.payload, targetRemoval)) + Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, targetTree, action.payload, targetRemoval, findChainCacheForRemovals)) if (concurrentRemoval) { // Already deleted on target, do nothing. return @@ -574,6 +582,7 @@ export default class SyncProcess { targetPlan.REMOVE.commit(action) }, ACTION_CONCURRENCY) + const findChainCacheForCreations = {} await Parallel.each(sourceScanResult.CREATE.getActions(), async(action) => { const concurrentCreation = targetCreations.find(a => ( action.payload.parentId === Mappings.mapParentId(mappingsSnapshot, a.payload, action.payload.location) && @@ -604,9 +613,10 @@ export default class SyncProcess { // TODO: subScanner may contain residual CREATE/REMOVE actions that need to be added to mappings return } + const concurrentRemoval = targetScanResult.REMOVE.getActions().find(targetRemoval => // target removal removed this creation's target (via some chain) - Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, targetRemoval) + Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, targetRemoval, findChainCacheForCreations) ) if (concurrentRemoval) { avoidTargetReorders[action.payload.parentId] = true @@ -622,24 +632,28 @@ export default class SyncProcess { const concurrentMove = targetMoves.find(a => action.payload.type === a.payload.type && Mappings.mappable(mappingsSnapshot, action.payload, a.payload)) if (concurrentMove) { - // Moved both on target and sourcely, source has precedence: do nothing sourcely + // Moved both on target and sourcely, master has precedence: do nothing on master return } } + let findChainCache = {} // FInd out if there's a removal in the target diff which already deletes this item (via some chain of MOVE|CREATEs) const complexTargetTargetRemoval = targetRemovals.find(targetRemoval => { - return Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, targetRemoval) + return Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, targetRemoval, findChainCache) }) + findChainCache = {} const concurrentTargetOriginRemoval = targetRemovals.find(targetRemoval => (action.payload.type === targetRemoval.payload.type && Mappings.mappable(mappingsSnapshot, action.payload, targetRemoval.payload)) || - Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.oldItem, targetRemoval) + Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.oldItem, targetRemoval, findChainCache) ) + findChainCache = {} const concurrentSourceOriginRemoval = sourceRemovals.find(sourceRemoval => { - return Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, targetTree, action.oldItem, sourceRemoval) + return Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, targetTree, action.oldItem, sourceRemoval, findChainCache) }) + findChainCache = {} const concurrentSourceTargetRemoval = sourceRemovals.find(sourceRemoval => // We pass an empty folder here, because we don't want direct deletions of the moved folder's parent to count, as it's moved away anyway - Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, new Folder({id: 0, location: targetLocation}), action.payload, sourceRemoval) + Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, new Folder({id: 0, location: targetLocation}), action.payload, sourceRemoval, findChainCache) ) if (complexTargetTargetRemoval) { // target already deleted by a target|source REMOVE (connected via source MOVE|CREATEs) @@ -690,15 +704,18 @@ export default class SyncProcess { } return } + let findChainCache1 = {}, findChainCache2 = {} // Find concurrent moves that form a hierarchy reversal together with this one const concurrentHierarchyReversals = targetMoves.filter(targetMove => { - return Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, targetMove) && - Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, targetTree, targetMove.payload, action) + return Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, targetMove, findChainCache1) && + Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, targetTree, targetMove.payload, action, findChainCache2) }) if (concurrentHierarchyReversals.length) { if (targetLocation !== this.masterLocation) { targetPlan.MOVE.commit(action) + findChainCache1 = {} + findChainCache2 = {} concurrentHierarchyReversals.forEach(a => { // moved sourcely but moved in reverse hierarchical order on target const payload = a.oldItem.copyWithLocation(false, action.payload.location) @@ -711,8 +728,8 @@ export default class SyncProcess { targetPlan.MOVE.getActions().find(move => String(move.payload.id) === String(payload.id)) || sourceMoves.find(move => String(move.payload.id) === String(payload.id)) || // Don't move back into removed territory - targetRemovals.find(remove => Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, remove)) || - sourceRemovals.find(remove => Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, targetTree, action.payload, remove)) + targetRemovals.find(remove => Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, remove, findChainCache)) || + sourceRemovals.find(remove => Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, targetTree, action.payload, remove, findChainCache)) ) { return } @@ -763,8 +780,10 @@ export default class SyncProcess { } } - const concurrentRemoval = targetRemovals.find(a => - a.payload.findItem('folder', action.payload.id)) + const findChainCache = {} + const concurrentRemoval = targetRemovals.find(targetRemoval => + Diff.findChain(mappingsSnapshot, allCreateAndMoveActions, sourceTree, action.payload, targetRemoval, findChainCache) + ) if (concurrentRemoval) { // Already deleted on target, do nothing. return @@ -1063,7 +1082,6 @@ export default class SyncProcess { } await action.payload.visitRemove(resource) - await this.removeMapping(resource, action.payload) diff.retract(action) donePlan.REMOVE.commit(action) this.updateProgress() @@ -1096,18 +1114,22 @@ export default class SyncProcess { reconcileReorderings( targetReorders: Diff>, - sourceDonePlan: PlanStage3, + targetOrSourceDonePlan: PlanStage3, targetLocation: L1, mappingSnapshot: MappingSnapshot - ) : Diff> { + ) : Diff> { Logger.log('Reconciling reorders to create a plan') - const sourceCreations = sourceDonePlan.CREATE.getActions() - const sourceRemovals = sourceDonePlan.REMOVE.getActions() - const sourceMoves = sourceDonePlan.MOVE.getActions() + const targetCreations = targetOrSourceDonePlan.CREATE.getActions() + const targetRemovals = targetOrSourceDonePlan.REMOVE.getActions() + const targetMoves = targetOrSourceDonePlan.MOVE.getActions() + const targetCreationsAndMoves : Action[] = (targetCreations as Action[]).concat(targetMoves) + const targetTree = targetLocation === ItemLocation.LOCAL ? this.localTreeRoot : this.serverTreeRoot const newReorders = new Diff> + const findChainCache = {} + targetReorders .getActions() // MOVEs have oldItem from cacheTree and payload now mapped to their corresponding target tree @@ -1116,22 +1138,27 @@ export default class SyncProcess { // clone action const reorderAction = {...oldReorderAction, order: oldReorderAction.order.slice()} - const removed = sourceRemovals - .filter(removal => removal.payload.findItem(reorderAction.payload.type, removal.payload.id)) + const removed = targetRemovals + .filter(removal => + removal.payload.findItem(reorderAction.payload.type, reorderAction.payload.id) || + Diff.findChain(mappingSnapshot, targetCreationsAndMoves, targetTree, reorderAction.payload, removal, findChainCache)) if (removed.length) { return } // Find Away-moves - const childAwayMoves = sourceMoves + const childAwayMoves = targetMoves .filter(move => - (String(reorderAction.payload.id) !== String(move.payload.parentId) && // reorder IDs are from localTree (source of this plan), move.oldItem IDs are from server tree (source of other plan) - reorderAction.order.find(item => String(item.id) === String(move.payload.id) && item.type === move.payload.type))// move.payload IDs are from localTree (target of the other plan + String(Mappings.mapId(mappingSnapshot, reorderAction.payload, move.payload.location)) !== String(move.payload.parentId) && + reorderAction.order.find(item => + String(Mappings.mapRawId(mappingSnapshot, item.id, item.type, reorderAction.payload.location, move.payload.location)) === String(move.payload.id) && item.type === move.payload.type) ) // Find removals - const concurrentRemovals = sourceRemovals - .filter(removal => reorderAction.order.find(item => String(item.id) === String(removal.payload.id) && item.type === removal.payload.type)) + const concurrentRemovals = targetRemovals + .filter(removal => + reorderAction.order.find(item => + String(Mappings.mapRawId(mappingSnapshot, item.id, item.type, reorderAction.payload.location, removal.payload.location)) === String(removal.payload.id) && item.type === removal.payload.type)) // Remove away-moves and removals reorderAction.order = reorderAction.order.filter(item => { @@ -1139,7 +1166,7 @@ export default class SyncProcess { if ( // eslint-disable-next-line no-cond-assign action = childAwayMoves.find(move => - String(item.id) === String(move.payload.id) && move.payload.type === item.type)) { + String(Mappings.mapRawId(mappingSnapshot, item.id, item.type, reorderAction.payload.location, move.payload.location)) === String(move.payload.id) && move.payload.type === item.type)) { Logger.log('ReconcileReorders: Removing moved item from order', {move: action, reorder: reorderAction}) return false } @@ -1147,7 +1174,7 @@ export default class SyncProcess { if ( // eslint-disable-next-line no-cond-assign action = concurrentRemovals.find(removal => - String(item.id) === String(removal.payload.id) && removal.payload.type === item.type) + String(Mappings.mapRawId(mappingSnapshot, item.id, item.type, reorderAction.payload.location, removal.payload.location)) === String(removal.payload.id) && removal.payload.type === item.type) ) { Logger.log('ReconcileReorders: Removing removed item from order', {item, reorder: reorderAction, removal: action}) return false @@ -1156,7 +1183,7 @@ export default class SyncProcess { }) // Find and insert creations - const concurrentCreations = sourceCreations + const concurrentCreations = targetCreations .filter(creation => String(reorderAction.payload.id) === String(creation.payload.parentId)) concurrentCreations .forEach(a => { @@ -1165,7 +1192,7 @@ export default class SyncProcess { }) // Find and insert moves at move target - const moves = sourceMoves + const moves = targetMoves .filter(move => String(reorderAction.payload.id) === String(move.payload.parentId) && !reorderAction.order.find(item => String(item.id) === String(move.payload.id) && item.type === move.payload.type) @@ -1178,7 +1205,7 @@ export default class SyncProcess { newReorders.commit(reorderAction) }) - return newReorders.map(mappingSnapshot, targetLocation) + return newReorders } async executeReorderings(resource:OrderFolderResource, reorderings:Diff>):Promise { @@ -1337,11 +1364,11 @@ export default class SyncProcess { mappingsSnapshot: MappingSnapshot, sourceReorders:Diff>, oldItem: TItem) { - const parentReorder = sourceReorders.getActions().find(action => Mappings.mapId(mappingsSnapshot, action.payload, oldItem.location) === oldItem.parentId) + const parentReorder = sourceReorders.getActions().find(action => String(Mappings.mapId(mappingsSnapshot, action.payload, oldItem.location)) === String(oldItem.parentId)) if (!parentReorder) { return } - parentReorder.order = parentReorder.order.filter(item => !(item.type === oldItem.type && Mappings.mapId(mappingsSnapshot, oldItem, parentReorder.payload.location) === item.id)) + parentReorder.order = parentReorder.order.filter(item => !(item.type === oldItem.type && String(Mappings.mapId(mappingsSnapshot, oldItem, parentReorder.payload.location)) === String(item.id))) } toJSON(): ISerializedSyncProcess { diff --git a/src/lib/strategies/Merge.ts b/src/lib/strategies/Merge.ts index 2158bc11d5..3bac4ccb6b 100644 --- a/src/lib/strategies/Merge.ts +++ b/src/lib/strategies/Merge.ts @@ -175,11 +175,11 @@ export default class MergeSyncProcess extends DefaultSyncProcess { reconcileReorderings( targetReorders: Diff>, - sourceDonePlan: PlanStage3, + targetOrSourceDonePlan: PlanStage3, targetLocation: L1, mappingSnapshot: MappingSnapshot - ) : Diff> { - return super.reconcileReorderings(targetReorders, sourceDonePlan, targetLocation, mappingSnapshot) + ) : Diff> { + return super.reconcileReorderings(targetReorders, targetOrSourceDonePlan, targetLocation, mappingSnapshot) } async loadChildren(serverTreeRoot: Folder):Promise { diff --git a/src/lib/strategies/Unidirectional.ts b/src/lib/strategies/Unidirectional.ts index b254661dd4..43f67b8e88 100644 --- a/src/lib/strategies/Unidirectional.ts +++ b/src/lib/strategies/Unidirectional.ts @@ -181,6 +181,12 @@ export default class UnidirectionalSyncProcess extends DefaultStrategy { await this.executeRevert(target, this.revertPlan, this.direction, this.revertDonePlan, sourceScanResult.REORDER) + if (this.direction === ItemLocation.LOCAL) { + this.revertDonePlan.REMOVE.getActions().forEach(action => this.removeMapping(this.localTree, action.payload)) + } else { + this.revertDonePlan.REMOVE.getActions().forEach(action => this.removeMapping(this.server, action.payload)) + } + if ('orderFolder' in this.server && !this.revertReorders) { const mappingsSnapshot = this.mappings.getSnapshot() Logger.log('Mapping reorderings') diff --git a/src/test/test.js b/src/test/test.js index 66dec2742a..f907d137b4 100644 --- a/src/test/test.js +++ b/src/test/test.js @@ -30,11 +30,15 @@ let expectTreeEqualRec = function(tree1, tree2, recDepth, ignoreEmptyFolders, ch tree2.children.sort((a, b) => { if (a.title < b.title) return -1 if (a.title > b.title) return 1 + if ((a.url || '') < (b.url || '')) return -1 + if ((a.url || '') > (b.url || '')) return 1 return 0 }) tree1.children.sort((a, b) => { if (a.title < b.title) return -1 if (a.title > b.title) return 1 + if ((a.url || '') < (b.url || '')) return -1 + if ((a.url || '') > (b.url || '')) return 1 return 0 }) } @@ -5321,15 +5325,18 @@ describe('Floccus', function() { const tree2AfterThirdSync = await account2.localTree.getBookmarksTree( true ) + console.log('Checking local tree of acc2') expectTreeEqual( tree2AfterThirdSync, tree2BeforeThirdSync, false ) - serverTreeAfterThirdSync.title = tree2AfterThirdSync.title + console.log('All good') + console.log('Checking server tree') + serverTreeAfterThirdSync.title = tree2BeforeThirdSync.title expectTreeEqual( serverTreeAfterThirdSync, - tree2AfterThirdSync, + tree2BeforeThirdSync, false ) console.log('Second round second half ok') @@ -6585,7 +6592,7 @@ describe('Floccus', function() { beforeEach('set up accounts', async function() { let _expectTreeEqual = expectTreeEqual - expectTreeEqual = (tree1, tree2, ignoreEmptyFolders, checkOrder) => _expectTreeEqual(tree1, tree2, ignoreEmptyFolders, !!checkOrder) + expectTreeEqual = (tree1, tree2, ignoreEmptyFolders, checkOrder) => _expectTreeEqual(tree1, tree2, ignoreEmptyFolders, false) // reset random seed random.use(seedrandom(SEED)) @@ -7174,8 +7181,8 @@ describe('Floccus', function() { .filter(item => item.id !== tree2AfterFirstSync.id) } - await randomlyManipulateTree(account1, folders1, bookmarks1, 20) - await randomlyManipulateTree(account2, folders2, bookmarks2, 20) + await randomlyManipulateTree(account1, folders1, bookmarks1, RANDOM_MANIPULATION_ITERATIONS) + await randomlyManipulateTree(account2, folders2, bookmarks2, RANDOM_MANIPULATION_ITERATIONS) console.log(' acc1: Moved items') @@ -7300,7 +7307,7 @@ describe('Floccus', function() { } }) - it('should handle fuzzed changes with deletions from two clients', async function() { + it('should handle fuzzed changes with deletions from two clients (normal)', async function() { const localRoot = account1.getData().localRoot let bookmarks1 = [] let folders1 = []