From 68e2edf6e70daada19059ebe8cf4d874a566e124 Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Mon, 10 Aug 2020 16:48:44 -0700 Subject: [PATCH 1/5] TST: Add initial barplot panel handler tests Also shuffled around the order of test JS modules in the index.html file -- looked like things got moved around, but i don't think it made a difference --- empress/support_files/js/barplot-layer.js | 105 +++++++++++++--------- tests/index.html | 9 +- 2 files changed, 67 insertions(+), 47 deletions(-) diff --git a/empress/support_files/js/barplot-layer.js b/empress/support_files/js/barplot-layer.js index 7c30508e7..cab04bbc0 100644 --- a/empress/support_files/js/barplot-layer.js +++ b/empress/support_files/js/barplot-layer.js @@ -33,9 +33,14 @@ define(["jquery", "underscore", "spectrum", "Colorer", "util"], function ( this.layerContainer = layerContainer; this.num = num; + this.fmAvailable = this.fmCols.length > 0; + // This should be "fm" if the barplot is for feature metadata; "sm" if - // the barplot is for sample metadata - this.barplotType = "fm"; + // the barplot is for sample metadata. (The default is to use feature + // metadata barplots, but if no feature metadata was passed to Empress + // then we have no choice but to just draw sample metadata barplots for + // everything.) + this.barplotType = this.fmAvailable ? "fm" : "sm"; // Various properties of the barplot layer state for feature metadata this.initialDefaultColorHex = Colorer.getQIIMEColor(this.num - 1); @@ -81,47 +86,55 @@ define(["jquery", "underscore", "spectrum", "Colorer", "util"], function ( this.updateHeader(); // Add UI elements for switching between feature and sample metadata - // barplots for this layer - var metadataChoiceP = this.layerDiv.appendChild( - document.createElement("p") - ); - var fmBtn = metadataChoiceP.appendChild( - document.createElement("button") - ); - var smBtn = metadataChoiceP.appendChild( - document.createElement("button") - ); - fmBtn.innerText = "Feature Metadata"; - smBtn.innerText = "Sample Metadata"; - // Center the feature and sample metadata buttons - fmBtn.setAttribute("style", "margin: 0 auto;"); - smBtn.setAttribute("style", "margin: 0 auto;"); - // Since we default to feature metadata barplot layers, we mark the - // feature metadata button as "selected" (a.k.a. we darken it a bit) - fmBtn.classList.add("selected-metadata-choice"); - - this.initFMDiv(); - this.initSMDiv(); - - fmBtn.onclick = function () { - if (scope.barplotType !== "fm") { - scope.smDiv.classList.add("hidden"); - scope.fmDiv.classList.remove("hidden"); - fmBtn.classList.add("selected-metadata-choice"); - smBtn.classList.remove("selected-metadata-choice"); - scope.barplotType = "fm"; - } - }; - smBtn.onclick = function () { - if (scope.barplotType !== "sm") { - scope.fmDiv.classList.add("hidden"); - scope.smDiv.classList.remove("hidden"); - smBtn.classList.add("selected-metadata-choice"); - fmBtn.classList.remove("selected-metadata-choice"); - scope.barplotType = "sm"; - } - }; + // barplots for this layer (only if feature metadata is available; + // otherwise, things will just default to sample metadata barplots.) + if (this.fmAvailable) { + var metadataChoiceP = this.layerDiv.appendChild( + document.createElement("p") + ); + var fmBtn = metadataChoiceP.appendChild( + document.createElement("button") + ); + var smBtn = metadataChoiceP.appendChild( + document.createElement("button") + ); + fmBtn.innerText = "Feature Metadata"; + smBtn.innerText = "Sample Metadata"; + // Center the feature and sample metadata buttons + fmBtn.setAttribute("style", "margin: 0 auto;"); + smBtn.setAttribute("style", "margin: 0 auto;"); + // Since we default to feature metadata barplot layers, we mark the + // feature metadata button as "selected" (a.k.a. we darken it a bit) + fmBtn.classList.add("selected-metadata-choice"); + + // We delay calling initFMDiv() (and initSMDiv(), although that + // isn't in this block because it doesn't depend on feature + // metadata being available) until after we create the + // "type switching" choice buttons above. This is so that the + // buttons are placed above the FM / SM divs in the page layout. + this.initFMDiv(); + + fmBtn.onclick = function () { + if (scope.barplotType !== "fm") { + scope.smDiv.classList.add("hidden"); + scope.fmDiv.classList.remove("hidden"); + fmBtn.classList.add("selected-metadata-choice"); + smBtn.classList.remove("selected-metadata-choice"); + scope.barplotType = "fm"; + } + }; + smBtn.onclick = function () { + if (scope.barplotType !== "sm") { + scope.fmDiv.classList.add("hidden"); + scope.smDiv.classList.remove("hidden"); + smBtn.classList.add("selected-metadata-choice"); + fmBtn.classList.remove("selected-metadata-choice"); + scope.barplotType = "sm"; + } + }; + } + this.initSMDiv(); // Add a row of UI elements that supports removing this layer var rmP = this.layerDiv.appendChild(document.createElement("p")); var rmLbl = rmP.appendChild(document.createElement("label")); @@ -144,6 +157,9 @@ define(["jquery", "underscore", "spectrum", "Colorer", "util"], function ( BarplotLayer.prototype.initFMDiv = function () { var scope = this; this.fmDiv = this.layerDiv.appendChild(document.createElement("div")); + if (this.barplotType !== "fm") { + this.fmDiv.classList.add("hidden"); + } // Add default color stuff var dfltColorP = document.createElement("p"); @@ -416,8 +432,9 @@ define(["jquery", "underscore", "spectrum", "Colorer", "util"], function ( BarplotLayer.prototype.initSMDiv = function () { var scope = this; this.smDiv = this.layerDiv.appendChild(document.createElement("div")); - // Hide this div by default - this.smDiv.classList.add("hidden"); + if (this.barplotType !== "sm") { + this.smDiv.classList.add("hidden"); + } var chgFieldP = this.smDiv.appendChild(document.createElement("p")); // Add a label diff --git a/tests/index.html b/tests/index.html index d5fb4cfcb..8c27e637e 100644 --- a/tests/index.html +++ b/tests/index.html @@ -103,7 +103,8 @@ 'testVectorOps' : './../tests/test-vector-ops', 'testEmpress' : './../tests/test-empress', 'testExport': './../tests/test-export', - 'testAnimationHandler': './../tests/test-animation-panel-handler' + 'testAnimationHandler': './../tests/test-animation-panel-handler', + 'testBarplotPanelHandler': './../tests/test-barplot-panel-handler' } }); @@ -134,8 +135,9 @@ 'testCircularLayoutComputation', 'testVectorOps', 'testEmpress', + 'testExport', 'testAnimationHandler', - 'testExport' + 'testBarplotPanelHandler', ], // start tests @@ -165,8 +167,9 @@ testCircularLayoutComputation, testVectorOps, testEmpress, + testExport, testAnimationHandler, - testExport + testBarplotPanelHandler ) { $(document).ready(function() { QUnit.start(); From f4ab79963d7cba21e9c9a2b5b97c090427c11ef9 Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Mon, 10 Aug 2020 17:47:01 -0700 Subject: [PATCH 2/5] TST: abstract tst Empress init code; add bpph tsts some problems with calling updateLayout() so testing that will have to wait for now, but this is nice --- tests/index.html | 5 + tests/test-barplot-panel-handler.js | 123 +++++++++++++++++++ tests/test-empress.js | 160 ++----------------------- tests/utilities-for-testing.js | 177 ++++++++++++++++++++++++++++ 4 files changed, 312 insertions(+), 153 deletions(-) create mode 100644 tests/test-barplot-panel-handler.js create mode 100644 tests/utilities-for-testing.js diff --git a/tests/index.html b/tests/index.html index 8c27e637e..65bb46f7c 100644 --- a/tests/index.html +++ b/tests/index.html @@ -92,6 +92,9 @@ 'CanvasEvents' : './support_files/js/canvas-events', 'SelectedNodeMenu' : './support_files/js/select-node-menu', + /* test utility code */ + 'UtilitiesForTesting' : './../tests/utilities-for-testing', + /* test paths */ 'testBPTree' : './../tests/test-bp-tree', 'testByteTree' : './../tests/test-byte-array', @@ -126,6 +129,7 @@ 'util', 'Empress', 'Legend', + 'UtilitiesForTesting', 'testBPTree', 'testByteTree', 'testBIOMTable', @@ -159,6 +163,7 @@ util, Empress, Legend, + UtilitiesForTesting, testBPTree, testByteTree, testCamera, diff --git a/tests/test-barplot-panel-handler.js b/tests/test-barplot-panel-handler.js new file mode 100644 index 000000000..f6cad95f0 --- /dev/null +++ b/tests/test-barplot-panel-handler.js @@ -0,0 +1,123 @@ +require(["jquery", "Empress", "UtilitiesForTesting"], function ( + $, + Empress, + UtilitiesForTesting +) { + module("Barplot Panel Handler", { + setup: function () { + this.testData = UtilitiesForTesting.getTestData(); + }, + }); + + test("Layout availability toggling: initialization", function () { + // The default layout should influence whether the barplot panel's + // "available" or "unavailable" content is shown. First, let's try the + // unrooted layout, which doesn't support barplots. + var empress = new Empress( + this.testData.tree, + this.testData.treeData, + this.testData.tdToInd, + this.testData.nameToKeys, + this.testData.layoutToCoordSuffix, + "Unrooted", + this.testData.yrscf, + this.testData.biom, + this.testData.fmCols, + this.testData.tm, + this.testData.im, + this.testData.canvas + ); + ok(empress._barplotPanel.availContent.classList.contains("hidden")); + notOk( + empress._barplotPanel.unavailContent.classList.contains("hidden") + ); + + // And now let's try starting out in the rectangular layout, which + // *does* support barplots. + var empress2 = new Empress( + this.testData.tree, + this.testData.treeData, + this.testData.tdToInd, + this.testData.nameToKeys, + this.testData.layoutToCoordSuffix, + "Rectangular", + this.testData.yrscf, + this.testData.biom, + this.testData.fmCols, + this.testData.tm, + this.testData.im, + this.testData.canvas + ); + notOk(empress2._barplotPanel.availContent.classList.contains("hidden")); + ok(empress2._barplotPanel.unavailContent.classList.contains("hidden")); + }); + // test("Layout availability toggling post-initialization", function () { + // var empress = new Empress( + // this.testData.tree, + // this.testData.treeData, + // this.testData.tdToInd, + // this.testData.nameToKeys, + // this.testData.layoutToCoordSuffix, + // "Unrooted", + // this.testData.yrscf, + // this.testData.biom, + // this.testData.fmCols, + // this.testData.tm, + // this.testData.im, + // this.testData.canvas + // ); + + // // After updating the layout to something that supports barplots, the + // // barplot "available content" should now be shown. + // // + // // NOTE: This fails in testing -- I get the following error: + // // TypeError: Cannot set property '0' of undefined + // // at Object.u (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/empress/support_files/vendor/gl-matrix.min.js:28:30362) + // // at Drawer.centerCameraOn (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/empress/support_files/js/drawer.js:466:17) + // // at Empress.centerLayoutAvgPoint (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/empress/support_files/js/empress.js:1929:22) + // // at Empress.updateLayout (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/empress/support_files/js/empress.js:1816:22) + // // at Object. (file:///home/marcus/Dropbox/Work/KnightLab/Empress/fedarko/empress/tests/test-barplot-panel-handler.js:68:17) + // empress.updateLayout("Rectangular"); + // notOk(empress._barplotPanel.availContent.classList.contains("hidden")); + // ok(empress._barplotPanel.unavailContent.classList.contains("hidden")); + + // // ... And going back to a not-compatible-with-barplots layout should + // // switch back to the unavailable content. + // empress.updateLayout("Unrooted"); + // notOk(empress._barplotPanel.availContent.classList.contains("hidden")); + // ok(empress._barplotPanel.unavailContent.classList.contains("hidden")); + // }); + test("Barplot layers default to feature metadata layers, but only if feature metadata is available", function () { + var empressWithFM = new Empress( + this.testData.tree, + this.testData.treeData, + this.testData.tdToInd, + this.testData.nameToKeys, + this.testData.layoutToCoordSuffix, + "Unrooted", + this.testData.yrscf, + this.testData.biom, + this.testData.fmCols, + this.testData.tm, + this.testData.im, + this.testData.canvas + ); + equal(empressWithFM._barplotPanel.layers[0].barplotType, "fm"); + + var empressWithNoFM = new Empress( + this.testData.tree, + this.testData.treeData, + this.testData.tdToInd, + this.testData.nameToKeys, + this.testData.layoutToCoordSuffix, + "Unrooted", + this.testData.yrscf, + this.testData.biom, + [], + {}, + {}, + this.testData.canvas + ); + equal(empressWithNoFM._barplotPanel.layers[0].barplotType, "sm"); + }); +}); diff --git a/tests/test-empress.js b/tests/test-empress.js index 8da47c379..72ac5eeb4 100644 --- a/tests/test-empress.js +++ b/tests/test-empress.js @@ -1,162 +1,16 @@ -require([ - "jquery", - "BPTree", - "Empress", - "BiomTable", - "util", - "chroma", -], function ($, BPTree, Empress, BiomTable, util, chroma) { +require(["jquery", "UtilitiesForTesting", "util", "chroma"], function ( + $, + UtilitiesForTesting, + util, + chroma +) { $(document).ready(function () { // Setup test variables // Note: This is ran for each test() so tests can modify bpArray // without affecting other tests. module("Empress", { setup: function () { - // tree comes from the following newick string - // ((1,(2,3)4)5,6)7; - var tree = new BPTree( - new Uint8Array([1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0]), - [ - "root", - "internal", - "1", - "internal", - "2", - "3", - "EmpressNode6", - ], - [7, 5, 1, 4, 2, 3, 6], - null - ); - var layoutToCoordSuffix = { - Rectangular: "r", - Circular: "c1", - Unrooted: "2", - }; - - var nameToKeys = { - root: [7], - EmpressNode6: [6], - internal: [5, 4], - "2": [2], - "3": [3], - "1": [1], - }; - // Note: the coordinates for each layout are "random". i.e. - // they will not make an actual tree. They were created to - // make testing easier. - - // see core.py for more details on the format of treeData - var treeData = [ - 0, // this is blank since empress uses 1-based index. This - // will be addressed with #223 - ["1", 29, 30, 1, 2, 15, 16, 0, 0, 0], - ["2", 31, 32, 3, 4, 17, 18, 0, 0, 0.5], - ["3", 33, 34, 5, 6, 19, 20, 0, 0, 1], - ["internal", 35, 36, 7, 8, 21, 22, 0, 0, 0], - ["internal", 37, 38, 9, 10, 23, 24, 0, 0, 0], - ["EmpressNode6", 39, 40, 11, 12, 25, 26, 0, 0, 0], - ["root", 41, 42, 13, 14, 27, 28, 0, 0, 0], - ]; - var tdToInd = { - name: 0, - x2: 1, - y2: 2, - xr: 3, - yr: 4, - xc1: 5, - yc1: 6, - xc0: 7, - yc0: 8, - angle: 9, - highestchildyr: 10, - lowestchildyr: 11, - arcx0: 12, - arcy0: 13, - arcstartangle: 14, - arcendangle: 15, - }; - - // data for the BiomTable object - // (These IDs / indices aren't assigned in any particular - // order; as long as it's consistent it doesn't matter. - // However, setting fIDs in this way is convenient b/c it means - // the index of feature "1" is 1, of "2" is 2, etc.) - var sIDs = ["s1", "s2", "s3", "s4", "s5", "s6", "s7"]; - var fIDs = ["EmpressNode6", "1", "2", "3"]; - var sID2Idx = { - s1: 0, - s2: 1, - s3: 2, - s4: 3, - s5: 4, - s6: 5, - s7: 6, - }; - var fID2Idx = { - EmpressNode6: 0, - "1": 1, - "2": 2, - "3": 3, - }; - // See test-biom-table.js for details on this format. Briefly, - // each inner array describes the feature indices present in a - // sample. - var tbl = [ - [1, 2, 3], - [2, 3], - [0, 1, 3], - [2], - [0, 1, 2, 3], - [1, 2, 3], - [0], - ]; - var smCols = ["f1", "grad", "traj"]; - var sm = [ - ["a", "1", "t1"], - ["a", "2", "t1"], - ["a", "1", "t2"], - ["b", "2", "t2"], - ["a", "3", "t3"], - ["a", "3", "t3"], - ["b", "4", "t4"], - ]; - var featureColumns = ["f1", "f2"]; - var tipMetadata = { - "1": ["2", "2"], - "2": ["1", "2"], - "3": ["1", "2"], - EmpressNode6: ["2", "2"], - }; - var intMetadata = { - internal: ["1", "1"], - }; - var biom = new BiomTable( - sIDs, - fIDs, - sID2Idx, - fID2Idx, - tbl, - smCols, - sm - ); - var canvas = document.createElement("canvas"); - this.empress = new Empress( - tree, - treeData, - tdToInd, - nameToKeys, - layoutToCoordSuffix, - "Unrooted", - // Rectangular layout y scaling factor - // equal to 4020 / (# leaves - 1) = 4020 / 3 = 1,340.0 - 1340.0, - biom, - featureColumns, - tipMetadata, - intMetadata, - canvas - ); + this.empress = UtilitiesForTesting.getTestData(true).empress; this.empress._drawer.initialize(); }, diff --git a/tests/utilities-for-testing.js b/tests/utilities-for-testing.js new file mode 100644 index 000000000..34c30f44d --- /dev/null +++ b/tests/utilities-for-testing.js @@ -0,0 +1,177 @@ +define(["Empress", "BPTree", "BiomTable"], function ( + Empress, + BPTree, + BiomTable +) { + /** + * Returns an Object containing test data that can be used to construct an + * instance of Empress. + * + * This function was cobbled together from the setup code in + * test-empress.js. It will likely need to be extended or modified to + * support further testing in the future. + * + * @param {Boolean} constructEmpress If truthy, this will actually create a + * new Empress instance and include this + * instance in the returned Object under + * the key "empress". If this is falsy, + * this will instead just set the value + * of the empress key to null. + * @return {Object} testData + */ + function getTestData(constructEmpress = false) { + // tree comes from the following newick string + // ((1,(2,3)4)5,6)7; + var tree = new BPTree( + new Uint8Array([1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0]), + ["root", "internal", "1", "internal", "2", "3", "EmpressNode6"], + [7, 5, 1, 4, 2, 3, 6], + null + ); + var layoutToCoordSuffix = { + Rectangular: "r", + Circular: "c1", + Unrooted: "2", + }; + + var nameToKeys = { + root: [7], + EmpressNode6: [6], + internal: [5, 4], + "2": [2], + "3": [3], + "1": [1], + }; + // Note: the coordinates for each layout are "random". i.e. + // they will not make an actual tree. They were created to + // make testing easier. + + // see core.py for more details on the format of treeData + var treeData = [ + 0, // this is blank since empress uses 1-based index. This + // will be addressed with #223 + ["1", 29, 30, 1, 2, 15, 16, 0, 0, 0], + ["2", 31, 32, 3, 4, 17, 18, 0, 0, 0.5], + ["3", 33, 34, 5, 6, 19, 20, 0, 0, 1], + ["internal", 35, 36, 7, 8, 21, 22, 0, 0, 0], + ["internal", 37, 38, 9, 10, 23, 24, 0, 0, 0], + ["EmpressNode6", 39, 40, 11, 12, 25, 26, 0, 0, 0], + ["root", 41, 42, 13, 14, 27, 28, 0, 0, 0], + ]; + var tdToInd = { + name: 0, + x2: 1, + y2: 2, + xr: 3, + yr: 4, + xc1: 5, + yc1: 6, + xc0: 7, + yc0: 8, + angle: 9, + highestchildyr: 10, + lowestchildyr: 11, + arcx0: 12, + arcy0: 13, + arcstartangle: 14, + arcendangle: 15, + }; + + // data for the BiomTable object + // (These IDs / indices aren't assigned in any particular + // order; as long as it's consistent it doesn't matter. + // However, setting fIDs in this way is convenient b/c it means + // the index of feature "1" is 1, of "2" is 2, etc.) + var sIDs = ["s1", "s2", "s3", "s4", "s5", "s6", "s7"]; + var fIDs = ["EmpressNode6", "1", "2", "3"]; + var sID2Idx = { + s1: 0, + s2: 1, + s3: 2, + s4: 3, + s5: 4, + s6: 5, + s7: 6, + }; + var fID2Idx = { + EmpressNode6: 0, + "1": 1, + "2": 2, + "3": 3, + }; + // See test-biom-table.js for details on this format. Briefly, + // each inner array describes the feature indices present in a + // sample. + var tbl = [ + [1, 2, 3], + [2, 3], + [0, 1, 3], + [2], + [0, 1, 2, 3], + [1, 2, 3], + [0], + ]; + var smCols = ["f1", "grad", "traj"]; + var sm = [ + ["a", "1", "t1"], + ["a", "2", "t1"], + ["a", "1", "t2"], + ["b", "2", "t2"], + ["a", "3", "t3"], + ["a", "3", "t3"], + ["b", "4", "t4"], + ]; + var featureColumns = ["f1", "f2"]; + var tipMetadata = { + "1": ["2", "2"], + "2": ["1", "2"], + "3": ["1", "2"], + EmpressNode6: ["2", "2"], + }; + var intMetadata = { + internal: ["1", "1"], + }; + var biom = new BiomTable(sIDs, fIDs, sID2Idx, fID2Idx, tbl, smCols, sm); + var canvas = document.createElement("canvas"); + + // Rectangular layout y scaling factor + // equal to 4020 / (# leaves - 1) = 4020 / 3 = 1,340.0 + var yrscf = 1340.0; + var empress; + if (constructEmpress) { + empress = new Empress( + tree, + treeData, + tdToInd, + nameToKeys, + layoutToCoordSuffix, + "Unrooted", + yrscf, + biom, + featureColumns, + tipMetadata, + intMetadata, + canvas + ); + } else { + empress = null; + } + + return { + empress: empress, + tree: tree, + treeData: treeData, + tdToInd: tdToInd, + nameToKeys: nameToKeys, + layoutToCoordSuffix: layoutToCoordSuffix, + yrscf: yrscf, + biom: biom, + fmCols: featureColumns, + tm: tipMetadata, + im: intMetadata, + canvas: canvas, + }; + } + + return { getTestData: getTestData }; +}); From 58ce1e7ebd49b7ba5497d4288ed628c9e9c3b890 Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Mon, 10 Aug 2020 18:03:21 -0700 Subject: [PATCH 3/5] TST: make the broken test less broken i mean it's still broken but now if we fix the gl stuff the test should work lol --- tests/test-barplot-panel-handler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-barplot-panel-handler.js b/tests/test-barplot-panel-handler.js index f6cad95f0..bf30ffe5a 100644 --- a/tests/test-barplot-panel-handler.js +++ b/tests/test-barplot-panel-handler.js @@ -84,8 +84,8 @@ require(["jquery", "Empress", "UtilitiesForTesting"], function ( // // ... And going back to a not-compatible-with-barplots layout should // // switch back to the unavailable content. // empress.updateLayout("Unrooted"); - // notOk(empress._barplotPanel.availContent.classList.contains("hidden")); - // ok(empress._barplotPanel.unavailContent.classList.contains("hidden")); + // ok(empress._barplotPanel.availContent.classList.contains("hidden")); + // notOk(empress._barplotPanel.unavailContent.classList.contains("hidden")); // }); test("Barplot layers default to feature metadata layers, but only if feature metadata is available", function () { var empressWithFM = new Empress( From dda82febfd0f7a0c464b05b04ff77ee1b7071994 Mon Sep 17 00:00:00 2001 From: Marcus Fedarko Date: Tue, 11 Aug 2020 14:29:12 -0700 Subject: [PATCH 4/5] TST: get remaining planned barplot test working --- tests/index.html | 22 ++++++++++ tests/test-barplot-panel-handler.js | 64 ++++++++++++++--------------- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/tests/index.html b/tests/index.html index 65bb46f7c..fbd2a421c 100644 --- a/tests/index.html +++ b/tests/index.html @@ -57,6 +57,28 @@ + +
+ + + + + + + + + + + + + +
+