diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67446d22180ea9ef38664aee86e288ab13becdc8..c2802f2a004cb839bffcd816537bbb7a24769699 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ## [Unreleased]
 
 ### Added (for new features, dependecies etc.)
+
+- The versioning model has a new styling and can show and tsv-export the full
+  version history now.
 - Module `ext_bookmarks` which allows users to bookmark entities, store them in
   a link or export them to TSV.
 - table previews in the bottom line module
diff --git a/misc/versioning_test_data.py b/misc/versioning_test_data.py
index eaa83e46f61ea2f20263b487e4bb42c37678c94f..5ec7073aeaffc894916ee8a6c4cfdc82bc25a4f1 100755
--- a/misc/versioning_test_data.py
+++ b/misc/versioning_test_data.py
@@ -91,3 +91,8 @@ else:
                              str(rec1.id),
                              str(rec1.id)])
 rec4.insert()
+
+for i in range(4,11):
+    rec1.name = f"TestRecord1-{i}thVersion"
+    rec1.description = f"This is the {i}th version."
+    rec1.update()
diff --git a/src/core/css/webcaosdb.css b/src/core/css/webcaosdb.css
index 57399e5787c28a6ecdf0c5fe7ce505b3d23f90d5..69a700376423a44bcb28a9920f1f3d15ef9a3b90 100644
--- a/src/core/css/webcaosdb.css
+++ b/src/core/css/webcaosdb.css
@@ -27,6 +27,35 @@ body {
     flex-direction: column;
 }
 
+
+div.export-data {
+    display: none;
+}
+
+tr:not(:hover) .caosdb-v-entity-version-hint-cur {
+    color: #DDD;
+}
+
+tr:hover .caosdb-v-entity-version-hint {
+    color: unset;
+}
+
+.caosdb-v-entity-version-hint {
+    color: #DDD;
+}
+
+tbody:not(:hover) tr .caosdb-v-entity-version-hint-cur {
+    color: unset;
+}
+
+.caosdb-v-entity-version-no-related {
+    color: #DDD;
+}
+
+.caosdb-v-entity-version-no-related:hover {
+    color: unset;
+}
+
 #top-navbar>ul>li>a {
     margin: 8px 0px;
     padding: 6px 12px;
diff --git a/src/core/js/caosdb.js b/src/core/js/caosdb.js
index 7fe4e9441822bf6c706a09c95aa65f0a2fef06a8..76d8a904e4806c0cdadf37ff453b13f452f376ff 100644
--- a/src/core/js/caosdb.js
+++ b/src/core/js/caosdb.js
@@ -286,6 +286,32 @@ function input2caosdbDate(date, time) {
     return date + "T" + time;
 }
 
+/**
+ * Return true if the current user has the given permission for the given
+ * entity.
+ *
+ * @param {HTMLElement} entity
+ * @return {boolean}
+ */
+var hasEntityPermission = function (entity, permission) {
+    if (userHasRole("administration")) {
+        // administration is a special role. It has * permissions.
+      return true;
+    }
+    const permissions = getAllEntityPermissions(entity);
+    return permissions.indexOf(permission.toUpperCase()) > -1;
+}
+
+/**
+ * Get all permissions the current user has for this entity.
+ * @param {HTMLElement} entity
+ * @return {string[]} array of permissions.
+ */
+var getAllEntityPermissions = function (entity) {
+    const permissions = $(entity).find("[data-permission]").toArray().map(x => x.getAttribute("data-permission"));
+    return permissions;
+}
+
 /**
  * Take a datetime from caosdb and return a date and a time
  * suitable for html inputs.
diff --git a/src/core/js/ext_bookmarks.js b/src/core/js/ext_bookmarks.js
index 07de3014825de6c64040e98e3da143d4ad5b8228..569d19a09ff72a4f6174bba36a83bf0a3ca18be6 100644
--- a/src/core/js/ext_bookmarks.js
+++ b/src/core/js/ext_bookmarks.js
@@ -217,6 +217,8 @@ var ext_bookmarks = function ($, logger, config) {
      * Generate the TSV data for the export callback with all current
      * bookmarks.
      *
+     * TODO merge with caosdb_utils.create_tsv_table.
+     *
      * @param {string[]} bookmarks - array of ids.
      */
     const get_export_table = async function (bookmarks, preamble, tab, newline) {
diff --git a/src/core/js/ext_xls_download.js b/src/core/js/ext_xls_download.js
index fbedd0c6cd10c75c3d0b2914de1a1eef9cb7b1f0..03fba88b0920dc94b17caccf4b4ed365a9c64e15 100644
--- a/src/core/js/ext_xls_download.js
+++ b/src/core/js/ext_xls_download.js
@@ -113,6 +113,8 @@ var caosdb_table_export = new function () {
     /**
      * Convert all entities to an encoded tsv string with the given columns.
      *
+     * TODO merge with caosdb_utils.create_tsv_table.
+     *
      * @param {HTMLElement[]} entities - entities which are converted to rows
      *     of the tsv string.
      * @param {string[]} columns - array of property names.
diff --git a/src/core/js/webcaosdb.js b/src/core/js/webcaosdb.js
index ac4d908bca32e0f8bf0f0645a6f4d5bc9d628ada..509abee58bd66bd938788527f4f0e459ceb36e6d 100644
--- a/src/core/js/webcaosdb.js
+++ b/src/core/js/webcaosdb.js
@@ -327,6 +327,30 @@ this.caosdb_utils = new function () {
         }
         throw new TypeError(name + " is expected to be an array, was " + typeof obj);
     }
+
+    /**
+     * Create a tsv table as string.
+     *
+     * The data must be appropriately encoded (e.g. urlencoded).
+     *
+     * With `tab=","` it is also possible to create csv tables.
+     *
+     * @param {string[][]} data - An array of rows which contain arrays of
+     *     cells.
+     * @param {string} [preamble="data:text/csv;charset=utf-8,"] - a prefix for
+     *     the the resulting string. The default is suitable for creating
+     *     downloadable href attributes of links.
+     * @param {string} [tab="%09"] - the cell separator.
+     * @param {string} [newline="%0A"] - the row separator.
+     * @return {string} a tsv table as a string.
+     */
+    this.create_tsv_table = function(data, preamble, tab, newline) {
+        preamble = ((typeof preamble == 'undefined') ? "data:text/csv;charset=utf-8,": preamble);
+        tab = tab || "%09";
+        newline = newline || "%0A";
+        const rows = data.map(x => x.join(tab))
+        return `${preamble}${rows.join(newline)}`;
+    }
 }
 
 /**
@@ -651,7 +675,7 @@ this.transaction = new function () {
      */
     this.retrieveEntitiesById = async function _rEBIs(entityIds) {
         const response = await connection.get(this.generateEntitiesUri(entityIds));
-        return $(response).find('Response [id]').toArray();
+        return $(response).find('Response > [id]').toArray();
     }
 
     /** Sends a PUT request with an xml representation of entities and
@@ -964,6 +988,117 @@ this.transaction = new function () {
     }
 }
 
+/**
+ * This module provides the functionality to load the full version history (for
+ * privileged users) and export it to tsv.
+ */
+var version_history = new function () {
+
+    this._get = connection.get;
+    /**
+     * Retrieve the version history of an entity and return a table with the
+     * history.
+     *
+     * @param {string} entity - the entity id with or without version id.
+     * @return {HTMLElement} A table with the version history.
+     */
+    this.retrieve_history = async function(entity) {
+        const xml = this._get(transaction
+            .generateEntitiesUri([entity]) + "?H");
+        const html = (await transformation.transformEntities(xml))[0];
+        const history_table = $(html).find(".caosdb-f-entity-version-history");
+        return history_table[0];
+    }
+
+    /**
+     * Initalize the buttons for loading the version history.
+     *
+     * The buttons are visible when the entity has only the normal version info
+     * attached and the current user has the permissions to retrieve the
+     * version history.
+     *
+     * The buttons trigger the retrieval of the version history and append the
+     * version history to the version info modal.
+     */
+    this.init_load_history_buttons = function () {
+        for (let entity of $(".caosdb-entity-panel")) {
+            const is_permitted = hasEntityPermission(entity, "RETRIEVE:HISTORY");
+            if (!is_permitted) {
+                continue;
+            }
+            const entity_id_version = getEntityIdVersion(entity);
+            const version_info = $(entity)
+                .find(".caosdb-f-entity-version-info");
+            const button = $(version_info)
+                .find(".caosdb-f-entity-version-load-history-btn");
+            button.show();
+            button
+                .click(async () => {
+                    button.prop("disabled", true);
+                    const wait = createWaitingNotification("Retrieving full history. Please wait.");
+                    const sparse = $(version_info)
+                        .find(".caosdb-f-entity-version-history");
+                    sparse.find(".modal-body *").replaceWith(wait);
+
+                    const history_table = await version_history
+                        .retrieve_history(entity_id_version);
+                    sparse.replaceWith(history_table);
+                    version_history.init_export_history_buttons(entity);
+                });
+        }
+    }
+
+    /**
+     * Transform the HTML table with the version history to tsv.
+     *
+     * @param {HTMLElement} history_table - the HTML representation of the
+     *     version history.
+     * @return {string} the version history as downloadable tsv string,
+     *     suitable for the href attribute of a link or window.location.
+     */
+    this.get_history_tsv = function (history_table) {
+        const rows = [];
+        for (let row of $(history_table).find("tr")) {
+          const cells = $(row).find(".export-data").toArray().map(x => x.textContent);
+          rows.push(cells);
+        }
+        return caosdb_utils.create_tsv_table(rows);
+    }
+
+    /**
+     * Initialize the export buttons of `entity`.
+     *
+     * The buttons are only visible when the version history is visible and
+     * trigger a download of a tsv file which contains the version history.
+     *
+     * The buttons trigger the download of a tsv file with the version history.
+     *
+     * @param {HTMLElement} [entity] - if undefined, the export buttons of all
+     *     page entities are initialized.
+     */
+    this.init_export_history_buttons = function (entity) {
+        entity = entity || $(".caosdb-entity-panel");
+        for (let version_info of $(entity)
+            .find(".caosdb-f-entity-version-info")) {
+            $(version_info).find(".caosdb-f-entity-version-export-history-btn")
+                .click(async () => {
+                    const html_table = $(version_info).find("table")[0];
+                    const history_tsv = this.get_history_tsv(html_table);
+                    version_history._download_tsv(history_tsv);
+                });
+        }
+    }
+
+    this._download_tsv = function(tsv_link) {
+        window.location.href = tsv_link;
+    }
+
+
+    this.init = function () {
+        this.init_load_history_buttons();
+        this.init_export_history_buttons();
+    }
+}
 
 var paging = new function () {
 
@@ -1602,6 +1737,7 @@ function initOnDocumentReady() {
     }
     caosdb_modules.init();
     navbar.init();
+    version_history.init();
 
 }
 
diff --git a/src/core/xsl/entity.xsl b/src/core/xsl/entity.xsl
index 826961b9e3f748daf73017715348fa3682bcbb1a..f9216f0b7b9e56d40f2ea2761712eef9b11d04f7 100644
--- a/src/core/xsl/entity.xsl
+++ b/src/core/xsl/entity.xsl
@@ -103,6 +103,7 @@
       <xsl:attribute name="data-entity-id">
         <xsl:value-of select="@id"/>
       </xsl:attribute>
+      <xsl:apply-templates mode="entity-permissions" select="Permissions"/>
       <!-- A page-unique ID for this entity -->
       <xsl:variable name="entityid" select="concat('entity_',generate-id())"/>
       <div class="panel-heading caosdb-entity-panel-heading">
@@ -524,78 +525,197 @@
       </xsl:attribute>
       <span class="glyphicon glyphicon-time"/>
     </button>
+
     <!-- the following div.modal is the window that pops up when the user clicks on the clock button -->
     <div class="caosdb-f-entity-version-info modal fade" tabindex="-1" role="dialog">
       <xsl:attribute name="id"><xsl:value-of select="$versionModalId"/></xsl:attribute>
+      <xsl:attribute name="data-entity-versioned-id"><xsl:value-of select="concat($entityId, '@', @id)"/></xsl:attribute>
       <div class="modal-dialog modal-lg" role="document">
         <div class="modal-content text-left">
+          <!-- modal-header start -->
           <div>
             <xsl:attribute name="class">
               modal-header
-              <xsl:if test="Successor">
+              <xsl:if test="not(@head='true')">
                 <!-- indicate old version by color -->
                 <xsl:value-of select="' bg-danger'"/>
               </xsl:if>
             </xsl:attribute>
             <button type="button" class="close" data-dismiss="modal" aria-label="Close" title="Close"><span aria-hidden="true">×</span></button>
             <h4 class="modal-title">Version Info</h4>
-            <p class="caosdb-entity-heading-attr">
+              <p class="caosdb-entity-heading-attr">
               <em class="caosdb-entity-heading-attr-name">
               This is
-              <xsl:if test="Successor"><b>not</b></xsl:if>
+              <xsl:if test="not(@head='true')"><b>not</b></xsl:if>
               the latest version of this entity.
+              <xsl:apply-templates mode="entity-version-modal-head" select="Successor">
+                <xsl:with-param name="entityId" select="$entityId"/>
+              </xsl:apply-templates>
               </em>
             </p>
           </div>
-          <div class="modal-body">
-            <xsl:apply-templates mode="entity-version-modal-head" select="Successor">
+          <!-- modal-header end -->
+          <div class="caosdb-f-entity-version-history">
+            <!-- modal-body and modal-footer are added by this template -->
+            <xsl:apply-templates select="." mode="entity-version-history-table">
               <xsl:with-param name="entityId" select="$entityId"/>
             </xsl:apply-templates>
-            <xsl:apply-templates mode="entity-version-modal-successor" select="Successor">
+          </div>
+        </div>
+      </div>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="Version[@completeHistory='true']" mode="entity-version-history-table">
+    <!-- contains the table of the full version history -->
+    <xsl:param name="entityId"/>
+    <div class="modal-body">
+      <table class="table table-hover">
+        <thead>
+          <tr><div class="export-data">Entity ID</div><th/>
+            <th class="export-data">Version ID</th>
+            <th class="export-data">Date</th>
+            <th class="export-data">User</th>
+            <div class="export-data">URI</div>
+          </tr></thead>
+        <tbody>
+          <xsl:apply-templates mode="entity-version-modal-successor" select="Successor">
+            <xsl:with-param name="entityId" select="$entityId"/>
+          </xsl:apply-templates>
+          <tr>
+            <div class="export-data"><xsl:value-of select="$entityId"/></div>
+            <td class="caosdb-v-entity-version-hint caosdb-v-entity-version-hint-cur">This Version</td>
+            <td><xsl:apply-templates select="@id" mode="entity-version-id"/>
+            </td><td>
+              <xsl:apply-templates select="@date" mode="entity-version-date"/>
+            </td><td class="export-data">
+              <xsl:value-of select="@username"/>@<xsl:value-of select="@realm"/>
+            </td>
+            <div class="export-data"><xsl:value-of select="concat($entitypath, $entityId, '@', @id)"/></div>
+          </tr>
+          <xsl:apply-templates mode="entity-version-modal-predecessor" select="Predecessor">
+            <xsl:with-param name="entityId" select="$entityId"/>
+          </xsl:apply-templates>
+        </tbody>
+      </table>
+    </div>
+    <div class="modal-footer">
+      <button type="button" class="caosdb-f-entity-version-export-history-btn btn btn-default">Export history</button>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="Version[not(@completeHistory='true')]" mode="entity-version-history-table">
+    <!-- contains the table of the simple version info (not the full history)-->
+    <xsl:param name="entityId"/>
+    <div class="modal-body">
+      <table class="table">
+        <thead><tr><th>Previous Version</th><th>This Version</th><th>Next Version</th></tr></thead>
+        <tbody>
+          <tr>
+          <td>
+            <xsl:if test="not(Predecessor)">
+              <div class="caosdb-v-entity-version-no-related">No predecessor</div>
+            </xsl:if>
+            <xsl:apply-templates select="Predecessor/@id" mode="entity-version-link-to-other-version">
               <xsl:with-param name="entityId" select="$entityId"/>
             </xsl:apply-templates>
-            <p class="caosdb-entity-heading-attr">
-              <em class="caosdb-entity-heading-attr-name">This version:</em>
-              <xsl:value-of select="@id"/> (<xsl:value-of select="@date"/>)
-            </p>
-            <xsl:apply-templates mode="entity-version-modal-predecessor" select="Predecessor">
+          </td>
+          <td>
+            <xsl:apply-templates select="@id" mode="entity-version-id"/>
+          </td>
+          <td>
+            <xsl:if test="not(Successor)">
+              <div class="caosdb-v-entity-version-no-related">No successor</div>
+            </xsl:if>
+            <xsl:apply-templates select="Successor/@id" mode="entity-version-link-to-other-version">
               <xsl:with-param name="entityId" select="$entityId"/>
             </xsl:apply-templates>
-          </div>
-        </div>
-      </div>
+          </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <div class="modal-footer">
+      <button type="button" style="display: none" class="caosdb-f-entity-version-load-history-btn btn btn-default">Load full history</button>
     </div>
   </xsl:template>
+
+  <xsl:template match="@id" mode="entity-version-id">
+    <!-- a versions'id (abbreviated) -->
+    <xsl:attribute name="title">Full Version ID: <xsl:value-of select="."/></xsl:attribute>
+    <xsl:value-of select="substring(.,1,8)"/>
+    <div class="export-data"><xsl:value-of select="."/></div>
+  </xsl:template>
+
+  <xsl:template match="@date" mode="entity-version-date">
+    <!-- a version's date (abbreviated)-->
+    <xsl:attribute name="title"><xsl:value-of select="."/></xsl:attribute>
+    <xsl:value-of select="substring(.,0,11)"/>
+    <xsl:value-of select="' '"/>
+    <xsl:value-of select="substring(.,12,8)"/>
+    <div class="export-data"><xsl:value-of select="."/></div>
+  </xsl:template>
+
+  <xsl:template match="Predecessor|Successor" mode="entity-version-modal-single-history-item">
+    <!-- a single row of the version history table -->
+    <xsl:param name="entityId"/>
+    <xsl:param name="hint"/>
+    <tr>
+      <div class="export-data"><xsl:value-of select="$entityId"/></div>
+      <td class="caosdb-v-entity-version-hint"><xsl:value-of select="$hint"/></td>
+      <td>
+        <xsl:apply-templates select="@id" mode="entity-version-link-to-other-version">
+          <xsl:with-param name="entityId" select="$entityId"/>
+        </xsl:apply-templates>
+      </td><td>
+        <xsl:apply-templates select="@date" mode="entity-version-date"/>
+      </td><td class="export-data">
+        <xsl:value-of select="@username"/>@<xsl:value-of select="@realm"/>
+      </td>
+      <div class="export-data"><xsl:value-of select="concat($entitypath, $entityId, '@', @id)"/></div>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="@id" mode="entity-version-link-to-other-version">
+    <!-- link to other version (used by both version tables)-->
+    <xsl:param name="entityId"/>
+    <a><xsl:attribute name="href"><xsl:value-of select="$entityId"/>@<xsl:value-of select="."/></xsl:attribute>
+      <xsl:apply-templates select="." mode="entity-version-id"/></a>
+  </xsl:template>
+
   <xsl:template match="Predecessor" mode="entity-version-modal-predecessor">
-    <!-- content of the versioning window -->
+    <!-- content of the versioning info (not the full history) -->
     <xsl:param name="entityId"/>
-    <p class="caosdb-entity-heading-attr">
-      <em class="caosdb-entity-heading-attr-name">Previous version:</em>
-      <a><xsl:attribute name="href"><xsl:value-of select="$entityId"/>@<xsl:value-of select="@id"/></xsl:attribute>
-        <xsl:value-of select="@id"/> (<xsl:value-of select="@date"/>)
-      </a>
-    </p>
+    <xsl:apply-templates mode="entity-version-modal-single-history-item" select=".">
+      <xsl:with-param name="entityId" select="$entityId"/>
+      <xsl:with-param name="hint" select="'Older Version'"/>
+    </xsl:apply-templates>
+    <xsl:apply-templates mode="entity-version-modal-predecessor" select="Predecessor">
+      <xsl:with-param name="entityId" select="$entityId"/>
+    </xsl:apply-templates>
   </xsl:template>
+
   <xsl:template match="Successor" mode="entity-version-modal-head">
-    <!-- content of the versioning window -->
+    <!-- content of the versioning modal's header (if a newer version exists) -->
     <xsl:param name="entityId"/>
-    <p class="caosdb-entity-heading-attr">
-      <em class="caosdb-entity-heading-attr-name">Newest version:</em>
-      <a><xsl:attribute name="href"><xsl:value-of select="$entityId"/>@HEAD</xsl:attribute>
-        <xsl:value-of select="$entityId"/>@HEAD
-      </a>
-    </p>
+    View the newest version here:
+    <a><xsl:attribute name="href"><xsl:value-of select="$entityId"/>@HEAD</xsl:attribute>
+      <xsl:value-of select="$entityId"/>@HEAD
+    </a>
   </xsl:template>
+
   <xsl:template match="Successor" mode="entity-version-modal-successor">
-    <!-- content of the versioning window -->
+    <!-- content of the versioning info (not the full history) -->
     <xsl:param name="entityId"/>
-    <p class="caosdb-entity-heading-attr">
-      <em class="caosdb-entity-heading-attr-name">Next version:</em>
-      <a><xsl:attribute name="href"><xsl:value-of select="$entityId"/>@<xsl:value-of select="@id"/></xsl:attribute>
-        <xsl:value-of select="@id"/> (<xsl:value-of select="@date"/>)
-      </a>
-    </p>
+    <xsl:apply-templates mode="entity-version-modal-successor" select="Successor">
+      <xsl:with-param name="entityId" select="$entityId"/>
+    </xsl:apply-templates>
+    <xsl:apply-templates mode="entity-version-modal-single-history-item" select=".">
+      <xsl:with-param name="entityId" select="$entityId"/>
+      <xsl:with-param name="hint" select="'Newer Version'"/>
+    </xsl:apply-templates>
   </xsl:template>
+
   <xsl:template match="Version/Successor" mode="entity-action-panel-version">
     <!-- clickable warning message in the entity actions panel when there exists a newer version -->
     <xsl:param name="entityId"/>
@@ -604,13 +724,15 @@
       <strong>Warning</strong> A newer version exists!
     </a>
   </xsl:template>
+
   <xsl:template match="Version" mode="entity-version-marker">
     <!-- content of the data-version-id attribute -->
     <xsl:attribute name="data-version-id">
-        <xsl:value-of select="@id"/>
+      <xsl:value-of select="@id"/>
     </xsl:attribute>
     <xsl:apply-templates select="Successor" mode="entity-version-marker"/>
   </xsl:template>
+
   <xsl:template match="Successor" mode="entity-version-marker">
     <!-- content of the data-version-successor attribute
          This data-attribute marks entities which have a newer version.
@@ -619,4 +741,17 @@
       <xsl:value-of select="@id"/>
     </xsl:attribute>
   </xsl:template>
+
+  <!-- PERMISSIONS -->
+  <xsl:template match="Permissions" mode="entity-permissions">
+    <div style="display: none">
+      <xsl:apply-templates select="Permission" mode="entity-permissions"/>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="Permission" mode="entity-permissions">
+    <div>
+      <xsl:attribute name="data-permission"><xsl:value-of select="@name"/></xsl:attribute>
+    </div>
+  </xsl:template>
 </xsl:stylesheet>
diff --git a/test/core/js/modules/entity.xsl.js b/test/core/js/modules/entity.xsl.js
index 91a6c18c2f0bee58c272461fe4b4fe595508110c..59a2f8a6f9a03cf4990fe11bfd751d437a3ffc3e 100644
--- a/test/core/js/modules/entity.xsl.js
+++ b/test/core/js/modules/entity.xsl.js
@@ -264,6 +264,48 @@ QUnit.test("data-version-successor attribute", function(assert) {
     assert.equal($(html).find("div.caosdb-entity-panel[data-version-successor]").length, 0, "data-version-successor attribute not present");
 });
 
+QUnit.test("version full history", function (assert) {
+    var xmlstr = `
+    <Response username="user1" realm="Realm1" srid="31ce8ea1-6c9b-4a82-82ec-9f6f3edd2622" timestamp="1606225647516" baseuri="https://localhost:10443" count="1">
+  <Record id="3373" name="TestRecord1-10thVersion" description="This is the 10th version.">
+    <Permissions>
+      <Permission name="RETRIEVE:HISTORY" />
+    </Permissions>
+    <Version id="vid6" username="user1" realm="Realm1" date="date6" completeHistory="true">
+      <Predecessor id="vid5" username="user1" realm="Realm1" date="date5">
+        <Predecessor id="vid4" username="user1" realm="Realm1" date="date4">
+          <Predecessor id="vid3" username="user1" realm="Realm1" date="date3">
+            <Predecessor id="vid2" username="user1" realm="Realm1" date="date2">
+              <Predecessor id="vid1" username="user1" realm="Realm1" date="date1" />
+            </Predecessor>
+          </Predecessor>
+        </Predecessor>
+      </Predecessor>
+      <Successor id="vid7" username="user1" realm="Realm1" date="date7">
+        <Successor id="vid8" username="user1" realm="Realm1" date="date8">
+          <Successor id="vid9" username="user1" realm="Realm1" date="date9">
+            <Successor id="vid10" username="user1" realm="Realm1" date="date10" />
+          </Successor>
+        </Successor>
+      </Successor>
+    </Version>
+    <Parent id="3372" name="TestRT" />
+  </Record>
+</Response>
+`;
+    var xml = str2xml(xmlstr);
+    var html = applyTemplates(xml, this.entityXSL, "entities", "*");
+    var version_info = $(html).find(".caosdb-f-entity-version-info");
+    var table_elem = $(version_info).find("table");
+
+    var TAB = "%09", NEWL = "%0A", usr = "user1@Realm1",
+      path = "/entitypath/3373";
+    var export_table = `data:text/csv;charset=utf-8,Entity ID${TAB}Version ID${TAB}Date${TAB}User${TAB}URI${NEWL}3373${TAB}vid10${TAB}date10${TAB}${usr}${TAB}${path}@vid10${NEWL}3373${TAB}vid9${TAB}date9${TAB}${usr}${TAB}${path}@vid9${NEWL}3373${TAB}vid8${TAB}date8${TAB}${usr}${TAB}${path}@vid8${NEWL}3373${TAB}vid7${TAB}date7${TAB}${usr}${TAB}${path}@vid7${NEWL}3373${TAB}vid6${TAB}date6${TAB}${usr}${TAB}${path}@vid6${NEWL}3373${TAB}vid5${TAB}date5${TAB}${usr}${TAB}${path}@vid5${NEWL}3373${TAB}vid4${TAB}date4${TAB}${usr}${TAB}${path}@vid4${NEWL}3373${TAB}vid3${TAB}date3${TAB}${usr}${TAB}${path}@vid3${NEWL}3373${TAB}vid2${TAB}date2${TAB}${usr}${TAB}${path}@vid2${NEWL}3373${TAB}vid1${TAB}date1${TAB}${usr}${TAB}${path}@vid1`
+    assert.equal(version_info.length, 1);
+    assert.equal(table_elem.length, 1);
+    assert.equal(version_history.get_history_tsv(table_elem[0]), export_table);
+});
+
 QUnit.test("Transforming abstract properties", function (assert) {
     var xmlstr = `<Property id="3842" name="reftotestrt" datatype="TestRT">
     <Version id="04ad505da057603a9177a1fcf6c9efd5f3690fe4" date="2020-11-23T10:38:02.936+0100" />
diff --git a/test/core/js/modules/webcaosdb.js.js b/test/core/js/modules/webcaosdb.js.js
index 5b43d2c1dcd2be0a9cac710b5749d13c631c76ed..7b3f7abf404f261668c18690df337b73794dd8bd 100644
--- a/test/core/js/modules/webcaosdb.js.js
+++ b/test/core/js/modules/webcaosdb.js.js
@@ -957,10 +957,6 @@ QUnit.test("createCarouselNav", function(assert) {
     let original_get = connection.get;
     ref_property_elem.find('div').append(refLinks);
 
-    const sleep = function sleep(ms) {
-      return new Promise(resolve => setTimeout(resolve, ms));
-    }
-
     QUnit.test("initProperty", async function(assert) {
         var done = assert.async(2);
         assert.ok(preview.initProperty, "function available");
@@ -1939,3 +1935,80 @@ QUnit.test("toolbox example", function(assert) {
     assert.equal($('.caosdb-f-navbar-toolbox[data-toolbox-name="Tools"]').length, 1, "one 'Tools' toolbox");
     assert.equal($('.caosdb-f-navbar-toolbox[data-toolbox-name="Tools"] button').length, 3, "three 'Tools' buttons");
 });
+
+QUnit.module("webcaosdb.js - version_history", {
+    before: function(assert) {
+        connection._init();
+    },
+    after: function(assert) {
+        connection._init();
+    },
+});
+
+QUnit.test("available", function (assert) {
+    assert.equal(typeof version_history.init, "function");
+    assert.equal(typeof version_history.get_history_tsv, "function");
+    assert.equal(typeof version_history.init_export_history_buttons, "function");
+    assert.equal(typeof version_history.init_load_history_buttons, "function");
+    assert.equal(typeof version_history.retrieve_history, "function");
+})
+
+QUnit.test("init_load_history_buttons and init_load_history_buttons", async function (assert) {
+    var xml_str = `<Response username="user1" realm="Realm1" srid="bc2f8f6b-71d6-49ca-890c-eebea3e38e18" timestamp="1606253365632" baseuri="https://localhost:10443" count="1">
+  <UserInfo username="user1" realm="Realm1">
+    <Roles>
+      <Role>role1</Role>
+    </Roles>
+  </UserInfo>
+  <Record id="8610" name="TestRecord1-6thVersion" description="This is the 6th version.">
+    <Permissions>
+      <Permission name="RETRIEVE:HISTORY" />
+    </Permissions>
+    <Version id="efa5ac7126c722b3f43284e150d070d6deac0ba6">
+      <Predecessor id="f09114b227d88f23d4e23645ae471d688b1e82f7" />
+      <Successor id="5759d2bccec3662424db5bb005acea4456a299ef" />
+    </Version>
+    <Parent id="8609" name="TestRT" />
+  </Record>
+</Response>
+`;
+    var done = assert.async(2);
+    var xml = str2xml(xml_str);
+    version_history._get = async function (entity) {
+        assert.equal(entity, "Entity/8610@efa5ac7126c722b3f43284e150d070d6deac0ba6?H");
+        done();
+        $(xml).find("Version").attr("completeHistory", "true");
+        return xml;
+    }
+    var html = await transformation.transformEntities(xml);
+    var load_button = $(html).find(".caosdb-f-entity-version-load-history-btn");
+    $("body").append(html);
+
+    assert.notOk(load_button.is(":visible"), "load_button hidden");
+    load_button.click(); // nothing happens
+
+    version_history.init_load_history_buttons();
+    assert.ok(load_button.is(":visible"), "load_button is not hidden anymore");
+
+    // load_button triggers retrieval of history
+    load_button.click();
+    await sleep(200);
+
+    var gone_button = $(html).find(".caosdb-f-entity-version-load-history-btn");
+    assert.equal(gone_button.length, 0, "button is gone");
+
+    export_button = $(html).find(".caosdb-f-entity-version-export-history-btn");
+    assert.ok(export_button.is(":visible"), "export_button is visible");
+
+    version_history._download_tsv = function (tsv) {
+        assert.equal(tsv.indexOf("data:text/csv;charset=utf-8,Entity ID%09"), 0);
+        done();
+    }
+    export_button.click();
+
+    $(html).remove();
+});
+
+const sleep = function sleep(ms) {
+  return new Promise(resolve => setTimeout(resolve, ms));
+}