diff --git a/package-lock.json b/package-lock.json
index 16d0d127..e6c4a05e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4206,6 +4206,11 @@
         "string.prototype.codepointat": "0.2.0"
       }
     },
+    "utf8": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz",
+      "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY="
+    },
     "util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
diff --git a/package.json b/package.json
index 40cd2b1f..befd2203 100644
--- a/package.json
+++ b/package.json
@@ -64,6 +64,8 @@
     "tag-dist-files": "^0.1.6"
   },
   "dependencies": {
-    "debug": "^2.6.8"
+    "debug": "^2.6.8",
+    "utf-8": "^1.0.0",
+    "utf8": "^2.1.2"
   }
 }
diff --git a/rollup.test.js b/rollup.test.js
index e0dbe22d..8b2b604d 100644
--- a/rollup.test.js
+++ b/rollup.test.js
@@ -3,7 +3,7 @@ import commonjs from 'rollup-plugin-commonjs'
 import multiEntry from 'rollup-plugin-multi-entry'
 
 export default {
-  entry: 'test/*.js',
+  entry: 'test/{encode-decode,red-black-tree}.js',
   moduleName: 'y-tests',
   format: 'umd',
   plugins: [
diff --git a/src/Binary/Decoder.js b/src/Binary/Decoder.js
index 6cb11d1d..72c4453b 100644
--- a/src/Binary/Decoder.js
+++ b/src/Binary/Decoder.js
@@ -1,4 +1,4 @@
-import '../../node_modules/utf8/utf8.js'
+import utf8 from 'utf-8'
 
 export default class BinaryDecoder {
   constructor (buffer) {
diff --git a/src/Binary/Encoder.js b/src/Binary/Encoder.js
index 00fe7cca..dfa62a5f 100644
--- a/src/Binary/Encoder.js
+++ b/src/Binary/Encoder.js
@@ -1,4 +1,4 @@
-import '../../node_modules/utf8/utf8.js'
+import utf8 from 'utf-8'
 
 const bits7 = 0b1111111
 const bits8 = 0b11111111
diff --git a/src/MessageHandler/deleteSet.js b/src/MessageHandler/deleteSet.js
index 4a22f2be..555183ae 100644
--- a/src/MessageHandler/deleteSet.js
+++ b/src/MessageHandler/deleteSet.js
@@ -65,7 +65,7 @@ export function readDeleteSet (y, decoder) {
     }
     var pos = 0
     var d = dv[pos]
-    y.ds.iterate(this, [user, 0], [user, Number.MAX_VALUE], function (n) {
+    y.ds.iterate([user, 0], [user, Number.MAX_VALUE], function (n) {
       // cases:
       // 1. d deletes something to the right of n
       //  => go to next n (break)
diff --git a/src/MessageHandler/integrateRemoteStructs.js b/src/MessageHandler/integrateRemoteStructs.js
index c5b33e22..b969c737 100644
--- a/src/MessageHandler/integrateRemoteStructs.js
+++ b/src/MessageHandler/integrateRemoteStructs.js
@@ -1,4 +1,4 @@
-import { getStruct } from '../Util/StructReferences.js'
+import { getStruct } from '../Util/structReferences.js'
 import BinaryDecoder from '../Binary/Decoder.js'
 
 class MissingEntry {
diff --git a/src/MessageHandler/stateSet.js b/src/MessageHandler/stateSet.js
index 057d5518..88b5a577 100644
--- a/src/MessageHandler/stateSet.js
+++ b/src/MessageHandler/stateSet.js
@@ -14,7 +14,7 @@ export function writeStateSet (encoder) {
   let lenPosition = encoder.pos
   let len = 0
   encoder.writeUint32(0)
-  this.ss.iterate(this, null, null, function (n) {
+  this.ss.iterate(null, null, function (n) {
     encoder.writeVarUint(n.id[0])
     encoder.writeVarUint(n.clock)
     len++
diff --git a/src/MessageHandler/update.js b/src/MessageHandler/update.js
index 0f66a7df..85a64503 100644
--- a/src/MessageHandler/update.js
+++ b/src/MessageHandler/update.js
@@ -1,5 +1,5 @@
 
-import { getStruct } from '../Util/StructReferences.js'
+import { getStruct } from '../Util/structReferences.js'
 
 export function stringifyUpdate (decoder, strBuilder) {
   while (decoder.length !== decoder.pos) {
diff --git a/src/Util/ID.js b/src/Util/ID.js
index 2de00f6d..bfc1b666 100644
--- a/src/Util/ID.js
+++ b/src/Util/ID.js
@@ -10,7 +10,7 @@ export default class ID {
     return new ID(this.user, this.clock)
   }
   equals (id) {
-    return id !== null && id.user === this.user && id.clock === this.user
+    return id !== null && id.user === this.user && id.clock === this.clock
   }
   lessThan (id) {
     return this.user < id.user || (this.user === id.user && this.clock < id.clock)
diff --git a/src/Util/Tree.js b/src/Util/Tree.js
index 71b58842..0680bf77 100644
--- a/src/Util/Tree.js
+++ b/src/Util/Tree.js
@@ -232,11 +232,11 @@ export default class Tree {
   findNode (id) {
     var o = this.root
     if (o === null) {
-      return false
+      return null
     } else {
       while (true) {
         if (o === null) {
-          return false
+          return null
         }
         if (id.lessThan(o.val.id)) {
           o = o.left
@@ -249,9 +249,6 @@ export default class Tree {
     }
   }
   delete (id) {
-    if (id == null || id.constructor !== Array) {
-      throw new Error('id is expected to be an Array!')
-    }
     var d = this.findNode(id)
     if (d == null) {
       // throw new Error('Element does not exist!')
diff --git a/src/Y.js b/src/Y.js
index 1a859d88..9c33de87 100644
--- a/src/Y.js
+++ b/src/Y.js
@@ -1,11 +1,3 @@
-
-// import debug from 'debug'
-export function debug (namespace) {
-  return function log (message) {
-    console.log(namespace, message)
-  }
-}
-
 import DeleteStore from './Store/DeleteStore.js'
 import OperationStore from './Store/OperationStore.js'
 import StateStore from './Store/StateStore.js'
@@ -21,6 +13,8 @@ import YMap from './Type/YMap.js'
 import YText from './Type/YText.js'
 import YXml from './Type/YXml.js'
 
+import debug from 'debug'
+
 export default class Y {
   constructor (opts) {
     this.userID = generateUserID()
@@ -101,6 +95,8 @@ Y.Map = YMap
 Y.Text = YText
 Y.Xml = YXml
 
+export { default as debug } from 'debug'
+
 Y.debug = debug
 debug.formatters.Y = messageToString
 debug.formatters.y = messageToRoomname
diff --git a/test/encode-decode.js b/test/encode-decode.js
index 8e9b2ac2..576b3ebe 100644
--- a/test/encode-decode.js
+++ b/test/encode-decode.js
@@ -1,9 +1,9 @@
-import { test } from '../node_modules/cutest/cutest.js'
+import { test } from '../node_modules/cutest/cutest.mjs'
 import '../node_modules/chance/chance.js'
-import Y from '../src/y.js'
 import BinaryEncoder from '../src/Binary/Encoder.js'
 import BinaryDecoder from '../src/Binary/Decoder.js'
 import { generateUserID } from '../src/Util/generateUserID.js'
+import Chance from 'chance'
 
 function testEncoding (t, write, read, val) {
   let encoder = new BinaryEncoder()
diff --git a/test/red-black-tree.js b/test/red-black-tree.js
index 14a19164..299e85f0 100644
--- a/test/red-black-tree.js
+++ b/test/red-black-tree.js
@@ -1,4 +1,5 @@
-import Y from '../src/y.js'
+import RedBlackTree from '../src/Util/Tree.js'
+import ID from '../src/Util/ID.js'
 import Chance from 'chance'
 import { test, proxyConsole } from 'cutest'
 
@@ -53,23 +54,16 @@ function checkRootNodeIsBlack (t, tree) {
 }
 
 test('RedBlack Tree', async function redBlackTree (t) {
-  let memory = new Y.memory(null, { // eslint-disable-line
-    name: 'Memory',
-    gcTimeout: -1
-  })
-  let tree = memory.os
-  memory.requestTransaction(function () {
-    tree.put({id: [8433]})
-    tree.put({id: [12844]})
-    tree.put({id: [1795]})
-    tree.put({id: [30302]})
-    tree.put({id: [64287]})
-    tree.delete([8433])
-    tree.put({id: [28996]})
-    tree.delete([64287])
-    tree.put({id: [22721]})
-  })
-  await memory.whenTransactionsFinished()
+  let tree = new RedBlackTree()
+  tree.put({id: new ID(8433, 0)})
+  tree.put({id: new ID(12844, 0)})
+  tree.put({id: new ID(1795, 0)})
+  tree.put({id: new ID(30302, 0)})
+  tree.put({id: new ID(64287)})
+  tree.delete(new ID(8433, 0))
+  tree.put({id: new ID(28996)})
+  tree.delete(new ID(64287))
+  tree.put({id: new ID(22721)})
   checkRootNodeIsBlack(t, tree)
   checkBlackHeightOfSubTreesAreEqual(t, tree)
   checkRedNodesDoNotHaveBlackChildren(t, tree)
@@ -77,141 +71,122 @@ test('RedBlack Tree', async function redBlackTree (t) {
 
 test(`random tests (${numberOfRBTreeTests})`, async function random (t) {
   let chance = new Chance(t.getSeed() * 1000000000)
-  let memory = new Y.memory(null, { // eslint-disable-line
-    name: 'Memory',
-    gcTimeout: -1
-  })
-  let tree = memory.os
+  let tree = new RedBlackTree()
   let elements = []
-  memory.requestTransaction(function () {
-    for (var i = 0; i < numberOfRBTreeTests; i++) {
-      if (chance.bool({likelihood: 80})) {
-        // 80% chance to insert an element
-        let obj = [chance.integer({min: 0, max: numberOfRBTreeTests})]
-        let nodeExists = tree.find(obj)
-        if (!nodeExists) {
-          if (elements.some(e => e[0] === obj[0])) {
-            t.assert(false, 'tree and elements contain different results')
-          }
-          elements.push(obj)
-          tree.put({id: obj})
+  for (var i = 0; i < numberOfRBTreeTests; i++) {
+    if (chance.bool({likelihood: 80})) {
+      // 80% chance to insert an element
+      let obj = new ID(chance.integer({min: 0, max: numberOfRBTreeTests}), chance.integer({min: 0, max: 1}))
+      let nodeExists = tree.find(obj)
+      if (nodeExists === null) {
+        if (elements.some(e => e.equals(obj))) {
+          t.assert(false, 'tree and elements contain different results')
         }
-      } else if (elements.length > 0) {
-        // ~20% chance to delete an element
-        var elem = chance.pickone(elements)
-        elements = elements.filter(function (e) {
-          return !Y.utils.compareIds(e, elem)
-        })
-        tree.delete(elem)
+        elements.push(obj)
+        tree.put({id: obj})
       }
+    } else if (elements.length > 0) {
+      // ~20% chance to delete an element
+      var elem = chance.pickone(elements)
+      elements = elements.filter(function (e) {
+        return !e.equals(elem)
+      })
+      tree.delete(elem)
     }
-  })
-  await memory.whenTransactionsFinished()
+  }
   checkRootNodeIsBlack(t, tree)
   checkBlackHeightOfSubTreesAreEqual(t, tree)
   checkRedNodesDoNotHaveBlackChildren(t, tree)
-  memory.requestTransaction(function () {
-    let allNodesExist = true
-    for (let id of elements) {
-      let node = tree.find(id)
-      if (!Y.utils.compareIds(node.id, id)) {
-        allNodesExist = false
-      }
+  // TEST if all nodes exist
+  let allNodesExist = true
+  for (let id of elements) {
+    let node = tree.find(id)
+    if (!node.id.equals(id)) {
+      allNodesExist = false
     }
-    t.assert(allNodesExist, 'All inserted nodes exist')
-  })
-  memory.requestTransaction(function () {
-    let findAllNodesWithLowerBoundSerach = true
-    for (let id of elements) {
-      let node = tree.findWithLowerBound(id)
-      if (!Y.utils.compareIds(node.id, id)) {
-        findAllNodesWithLowerBoundSerach = false
-      }
+  }
+  t.assert(allNodesExist, 'All inserted nodes exist')
+  // TEST lower bound search
+  let findAllNodesWithLowerBoundSerach = true
+  for (let id of elements) {
+    let node = tree.findWithLowerBound(id)
+    if (!node.id.equals(id)) {
+      findAllNodesWithLowerBoundSerach = false
     }
-    t.assert(
-      findAllNodesWithLowerBoundSerach,
-      'Find every object with lower bound search'
-    )
-  })
-
-  memory.requestTransaction(function () {
-    let lowerBound = chance.pickone(elements)
-    let expectedResults = elements.filter((e, pos) =>
-      (Y.utils.smaller(lowerBound, e) || Y.utils.compareIds(e, lowerBound)) &&
-      elements.indexOf(e) === pos
-    ).length
-    let actualResults = 0
-    tree.iterate(this, lowerBound, null, function (val) {
-      if (val == null) {
-        t.assert(false, 'val is undefined!')
-      }
-      actualResults++
-    })
-    t.assert(
-      expectedResults === actualResults,
-      'Iterating over a tree with lower bound yields the right amount of results'
-    )
-  })
-
-  memory.requestTransaction(function () {
-    let expectedResults = elements.filter((e, pos) =>
-      elements.indexOf(e) === pos
-    ).length
-    let actualResults = 0
-    tree.iterate(this, null, null, function (val) {
-      if (val == null) {
-        t.assert(false, 'val is undefined!')
-      }
-      actualResults++
-    })
-    t.assert(
-      expectedResults === actualResults,
-      'iterating over a tree without bounds yields the right amount of results'
-    )
-  })
-
-  memory.requestTransaction(function () {
-    let upperBound = chance.pickone(elements)
-    let expectedResults = elements.filter((e, pos) =>
-      (Y.utils.smaller(e, upperBound) || Y.utils.compareIds(e, upperBound)) &&
-      elements.indexOf(e) === pos
-    ).length
-    let actualResults = 0
-    tree.iterate(this, null, upperBound, function (val) {
-      if (val == null) {
-        t.assert(false, 'val is undefined!')
-      }
-      actualResults++
-    })
-    t.assert(
-      expectedResults === actualResults,
-      'iterating over a tree with upper bound yields the right amount of results'
-    )
-  })
-
-  memory.requestTransaction(function () {
-    let upperBound = chance.pickone(elements)
-    let lowerBound = chance.pickone(elements)
-    if (Y.utils.smaller(upperBound, lowerBound)) {
-      [lowerBound, upperBound] = [upperBound, lowerBound]
+  }
+  t.assert(
+    findAllNodesWithLowerBoundSerach,
+    'Find every object with lower bound search'
+  )
+  // TEST iteration (with lower bound search)
+  let lowerBound = chance.pickone(elements)
+  let expectedResults = elements.filter((e, pos) =>
+    (lowerBound.lessThan(e) || e.equals(lowerBound)) &&
+    elements.indexOf(e) === pos
+  ).length
+  let actualResults = 0
+  tree.iterate(lowerBound, null, function (val) {
+    if (val == null) {
+      t.assert(false, 'val is undefined!')
     }
-    let expectedResults = elements.filter((e, pos) =>
-      (Y.utils.smaller(lowerBound, e) || Y.utils.compareIds(e, lowerBound)) &&
-      (Y.utils.smaller(e, upperBound) || Y.utils.compareIds(e, upperBound)) &&
-      elements.indexOf(e) === pos
-    ).length
-    let actualResults = 0
-    tree.iterate(this, lowerBound, upperBound, function (val) {
-      if (val == null) {
-        t.assert(false, 'val is undefined!')
-      }
-      actualResults++
-    })
-    t.assert(
-      expectedResults === actualResults,
-      'iterating over a tree with upper bound yields the right amount of results'
-    )
+    actualResults++
   })
+  t.assert(
+    expectedResults === actualResults,
+    'Iterating over a tree with lower bound yields the right amount of results'
+  )
 
-  await memory.whenTransactionsFinished()
+  expectedResults = elements.filter((e, pos) =>
+    elements.indexOf(e) === pos
+  ).length
+  actualResults = 0
+  tree.iterate(null, null, function (val) {
+    if (val == null) {
+      t.assert(false, 'val is undefined!')
+    }
+    actualResults++
+  })
+  t.assert(
+    expectedResults === actualResults,
+    'iterating over a tree without bounds yields the right amount of results'
+  )
+
+  let upperBound = chance.pickone(elements)
+  expectedResults = elements.filter((e, pos) =>
+    (e.lessThan(upperBound) || e.equals(upperBound)) &&
+    elements.indexOf(e) === pos
+  ).length
+  actualResults = 0
+  tree.iterate(null, upperBound, function (val) {
+    if (val == null) {
+      t.assert(false, 'val is undefined!')
+    }
+    actualResults++
+  })
+  t.assert(
+    expectedResults === actualResults,
+    'iterating over a tree with upper bound yields the right amount of results'
+  )
+
+  upperBound = chance.pickone(elements)
+  lowerBound = chance.pickone(elements)
+  if (upperBound.lessThan(lowerBound)) {
+    [lowerBound, upperBound] = [upperBound, lowerBound]
+  }
+  expectedResults = elements.filter((e, pos) =>
+    (lowerBound.lessThan(e) || e.equals(lowerBound)) &&
+    (e.lessThan(upperBound) || e.equals(upperBound)) &&
+    elements.indexOf(e) === pos
+  ).length
+  actualResults = 0
+  tree.iterate(lowerBound, upperBound, function (val) {
+    if (val == null) {
+      t.assert(false, 'val is undefined!')
+    }
+    actualResults++
+  })
+  t.assert(
+    expectedResults === actualResults,
+    'iterating over a tree with upper bound yields the right amount of results'
+  )
 })
diff --git a/tests-lib/helper.js b/tests-lib/helper.js
index de60e07f..ca4ceb73 100644
--- a/tests-lib/helper.js
+++ b/tests-lib/helper.js
@@ -1,13 +1,15 @@
 
-import _Y from '../../yjs/src/y.js'
+import _Y from '../src/Y.js'
 import yTest from './test-connector.js'
 
 import Chance from 'chance'
 
-export let Y = _Y
+export const Y = _Y
 
-export var database = { name: 'memory' }
-export var connector = { name: 'test', url: 'http://localhost:1234' }
+Y.extend(yTest)
+
+export const database = { name: 'memory' }
+export const connector = { name: 'test', url: 'http://localhost:1234' }
 
 function getStateSet (y) {
   let ss = {}
@@ -19,7 +21,7 @@ function getStateSet (y) {
 
 function getDeleteSet (y) {
   var ds = {}
-  y.ds.iterate(this, null, null, function (n) {
+  y.ds.iterate(null, null, function (n) {
     var user = n.id[0]
     var counter = n.id[1]
     var len = n.len
@@ -108,7 +110,7 @@ export async function compareUsers (t, users) {
   var data = users.forEach(u => {
     var data = {}
     let ops = []
-    y.os.iterate(null, null, function (op) {
+    u.os.iterate(null, null, function (op) {
       if (!op._deleted) {
         ops.push({
           left: op._left,
@@ -132,8 +134,7 @@ export async function compareUsers (t, users) {
   for (var i = 0; i < data.length - 1; i++) {
     await t.asyncGroup(async () => {
       t.compare(userArrayValues[i], userArrayValues[i + 1], 'array types')
-      t.compare(userMapOneValues[i], userMapOneValues[i + 1], 'map types (propery "one")')
-      t.compare(userMapTwoValues[i], userMapTwoValues[i + 1], 'map types (propery "two")')
+      t.compare(userMapValues[i], userMapValues[i + 1], 'map types')
       t.compare(userXmlValues[i], userXmlValues[i + 1], 'xml types')
       t.compare(data[i].os, data[i + 1].os, 'os')
       t.compare(data[i].ds, data[i + 1].ds, 'ds')