diff --git a/package.json b/package.json
index 0d8796c48d7733c2c80deda635ff4c7344acfd1e..fe988f094d57f88d17eceed049a71fbbab0e349b 100755
--- a/package.json
+++ b/package.json
@@ -4,7 +4,8 @@
   "main": "index.js",
   "license": "AGPLv3",
   "scripts": {
-    "prepublish": "tsc"
+    "prepublish": "tsc",
+    "test": "mocha"
   },
   "dependencies": {
     "body-parser": "1.17.1",
@@ -21,8 +22,12 @@
   },
   "devDependencies": {
     "@types/node": "^11.9.3",
+    "@types/mocha": "^2.2.41",
     "duniter": "1.7.x",
-    "typescript": "^3.3.3"
+    "typescript": "^3.3.3",
+    "mocha": "^3.4.2",
+    "should": "*",
+    "ts-node": "^3.3.0"
   },
   "peerDependencies": {
     "duniter": "1.7.x"
diff --git a/test/indexing.ts b/test/indexing.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f5f94bc99c3515e03711f7e6f46863afe991b4f1
--- /dev/null
+++ b/test/indexing.ts
@@ -0,0 +1,97 @@
+// Source file from duniter: Crypto-currency software to manage libre currency such as Ğ1
+// Copyright (C) 2018  Cedric Moreau <cem.moreau@gmail.com>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+
+import {assertEqual, assertTrue, writeBasicTestWithConfAnd2Users} from "duniter/test/integration/tools/test-framework"
+import {CommonConstants} from "duniter/app/lib/common-libs/constants";
+import {DataFinder, initMonitDB} from "../lib/DataFinder";
+import {MonitDBBlock} from "../lib/SqliteBlockchain";
+
+describe('Indexing blockchain', () => writeBasicTestWithConfAnd2Users({
+  sigQty: 1,
+  medianTimeBlocks: 1,
+  forksize: 2,
+}, (test) => {
+
+  const now = 1500000000
+
+  before(() => {
+    CommonConstants.BLOCKS_IN_MEMORY_MAX = 3 // Must be > forkWindowSize
+  })
+
+  test('Duniter blockchain init', async (s1, cat, tac) => {
+    await cat.createIdentity()
+    await tac.createIdentity()
+    await cat.cert(tac)
+    await tac.cert(cat)
+    await cat.join()
+    await tac.join()
+    for (let i = 0; i < 6; i++) {
+      await s1.commit({ time: now })
+    }
+    const head = await s1.commit({ time: now })
+    assertEqual(head.number, 6);
+    (s1.dal.blockchainArchiveDAL as any)._chunkSize = 2 // Archive 2 blocks per file
+  })
+
+  test('first indexing by monit', async (s1) => {
+    // Simulate that archiving was called on Duniter once (during sync)
+    await s1.dal.archiveBlocks()
+    // Now test Monit
+    await initMonitDB(s1._server, true)
+    assertEqual(await DataFinder.getInstance().getHighestBlockNumber(), 6) // Current block in Monit = current in Duniter
+    assertEqual(await DataFinder.getInstance().getHighestArchivedBlockNumber(), 4) // Highest archived = current - forksize
+  })
+
+  test('second indexing by monit after adding some blocks to the blockchain', async (s1) => {
+    for (let i = 0; i < 3; i++) {
+      await s1.commit({ time: now })
+    }
+    // Now test Monit
+    await DataFinder.getInstance().index()
+    assertEqual(await DataFinder.getInstance().getHighestBlockNumber(), 9)
+    assertEqual(await DataFinder.getInstance().getHighestArchivedBlockNumber(), 7)
+  })
+
+  test('third indexing taking care of forks', async (s1) => {
+
+    // Make a #10 block
+    const b10v1Duniter = await s1.commit({ time: now })
+    await DataFinder.getInstance().index()
+    const b10v1Monit = await DataFinder.getInstance().getHighestBlock() as MonitDBBlock
+    assertEqual(await DataFinder.getInstance().getHighestBlockNumber(), 10)
+    assertEqual(b10v1Monit.number, 10)
+    assertEqual(b10v1Monit.hash, b10v1Duniter.hash)
+    assertEqual(await DataFinder.getInstance().getHighestArchivedBlockNumber(), 8) // Archived level = 10 - forksize
+
+    // Revert
+    await s1.revert()
+
+    // Re-commit
+    const b10v2Duniter = await s1.commit({ time: now + 1 })
+    await DataFinder.getInstance().index()
+    const b10v2Monit = await DataFinder.getInstance().getHighestBlock() as MonitDBBlock
+    assertEqual(await DataFinder.getInstance().getHighestBlockNumber(), 10)
+    assertEqual(b10v2Monit.number, 10)
+    assertEqual(b10v2Monit.hash, b10v2Duniter.hash)
+    assertEqual(await DataFinder.getInstance().getHighestArchivedBlockNumber(), 8) // Archived level = 10 - forksize
+
+    // assertions
+    assertTrue(b10v1Duniter.number === b10v2Duniter.number)
+    assertTrue(b10v1Duniter.hash !== b10v2Duniter.hash)
+    assertTrue(b10v1Monit.number === b10v2Monit.number)
+    assertTrue(b10v1Monit.hash !== b10v2Monit.hash)
+    assertTrue(b10v1Monit.hash === b10v1Duniter.hash)
+    assertTrue(b10v2Monit.hash === b10v2Duniter.hash)
+  })
+}))
+
diff --git a/test/mocha.opts b/test/mocha.opts
new file mode 100644
index 0000000000000000000000000000000000000000..21039253bb7916b4aff02e306631ef57795f1f0b
--- /dev/null
+++ b/test/mocha.opts
@@ -0,0 +1,8 @@
+--compilers ts-node/register
+--require source-map-support/register
+--full-trace
+--growl
+--timeout 60000
+--recursive
+-R spec
+test/
diff --git a/tsconfig.json b/tsconfig.json
index 5cad0e30a8a110973b49d9aabd086ad9c086f856..84a98f52f36aa28b8697d453fbb6581326774c2c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -15,7 +15,8 @@
   },
   "include": [
     "routes",
-    "lib"
+    "lib",
+    "test"
   ],
   "compileOnSave": true
 }