diff --git a/forum-network/.eslintrc.js b/forum-network/.eslintrc.js index 3a4f0e3..6f3bea1 100644 --- a/forum-network/.eslintrc.js +++ b/forum-network/.eslintrc.js @@ -37,6 +37,7 @@ module.exports = { 'no-multi-assign': ['off'], 'no-constant-condition': ['off'], 'no-await-in-loop': ['off'], + 'no-underscore-dangle': ['off'], }, globals: { _: 'readonly', @@ -44,5 +45,6 @@ module.exports = { sinon: 'readonly', sinonChai: 'readonly', should: 'readonly', + mocha: 'readonly', }, }; diff --git a/forum-network/src/classes/display/box.js b/forum-network/src/classes/display/box.js index faacf17..46f49f6 100644 --- a/forum-network/src/classes/display/box.js +++ b/forum-network/src/classes/display/box.js @@ -2,16 +2,20 @@ import { DisplayValue } from './display-value.js'; import { randomID } from '../../util.js'; export class Box { - constructor(name, parentEl, elementType = 'div') { + constructor(name, parentEl, options = {}) { this.name = name; - this.el = document.createElement(elementType); + this.el = document.createElement('div'); this.el.id = `box_${randomID()}`; this.el.classList.add('box'); if (name) { this.el.setAttribute('box-name', name); } if (parentEl) { - parentEl.appendChild(this.el); + if (options.prepend) { + parentEl.prepend(this.el); + } else { + parentEl.appendChild(this.el); + } } } @@ -35,8 +39,8 @@ export class Box { return this; } - addBox(name, elementType) { - const box = new Box(name, this.el, elementType); + addBox(name) { + const box = new Box(name, this.el); return box; } diff --git a/forum-network/src/classes/display/controls.js b/forum-network/src/classes/display/controls.js new file mode 100644 index 0000000..4911456 --- /dev/null +++ b/forum-network/src/classes/display/controls.js @@ -0,0 +1,52 @@ +class Button { + constructor(innerHTML, onclick) { + this.el = document.createElement('button'); + this.el.innerHTML = innerHTML; + this.el.onclick = onclick; + } +} + +export class Controls { + constructor(parentBox) { + this.disableAutoplayButton = new Button('Disable Auto-play', () => { + const url = new URL(window.location.href); + url.searchParams.set('auto', 'false'); + window.location.href = url.href; + }); + this.enableAutoplayButton = new Button('Enable Auto-play', () => { + const url = new URL(window.location.href); + url.searchParams.delete('auto'); + window.location.href = url.href; + }); + this.stepButton = new Button('Next Action', () => { + console.log('Next Action button clicked'); + document.dispatchEvent(new Event('next-action')); + }); + + if (window.autoPlay) { + parentBox.el.appendChild(this.disableAutoplayButton.el); + } else { + parentBox.el.appendChild(this.enableAutoplayButton.el); + parentBox.el.appendChild(this.stepButton.el); + // Disable `stepButton` when test is complete + setInterval(() => { + this.stepButton.el.disabled = mocha._state !== 'running'; + }, 200); + } + } +} + +export async function delayOrWait(delayMs) { + if (window.autoPlay) { + await new Promise((resolve) => { + setTimeout(resolve, delayMs); + }); + } else { + await new Promise((resolve) => { + document.addEventListener('next-action', () => { + console.log('next-action event received'); + resolve(); + }, { once: true }); + }); + } +} diff --git a/forum-network/src/classes/display/scene.js b/forum-network/src/classes/display/scene.js index e455421..f0e76b3 100644 --- a/forum-network/src/classes/display/scene.js +++ b/forum-network/src/classes/display/scene.js @@ -4,6 +4,8 @@ import { MermaidDiagram } from './mermaid.js'; import { SequenceDiagram } from './sequence.js'; import { Table } from './table.js'; import { Flowchart } from './flowchart.js'; +import { Controls } from './controls.js'; +import { Box } from './box.js'; export class Scene { constructor(name, rootBox) { @@ -24,6 +26,14 @@ export class Scene { this.options = { edgeNodeColor: '#4d585c', }; + + window.autoPlay = new URL(window.location.href).searchParams.get('auto') !== 'false'; + + if (!window.disableSceneControls) { + this.topRail = new Box('Top rail', document.body, { prepend: true }).addClass('top-rail'); + this.controlsBox = this.topRail.addBox('Controls').addClass('controls'); + this.controls = new Controls(this.controlsBox); + } } withSequenceDiagram() { diff --git a/forum-network/src/index.css b/forum-network/src/index.css index 1c71ee9..1ff9007 100644 --- a/forum-network/src/index.css +++ b/forum-network/src/index.css @@ -36,6 +36,17 @@ a:visited { .padded { padding: 20px; } +.top-rail { + position: sticky; + top: 0; + left: 0; + width: 100%; + height: 0; +} +.controls { + position: relative; + left: 150px; +} svg { width: 800px; } @@ -49,3 +60,14 @@ td { .edge > rect { fill: #216262 !important; } +button { + margin: 5px; + margin-top: 1em; + background-color: #c6f4ff; + border-color: #b6b6b6; + border-radius: 5px; +} +button:disabled { + background-color: #2a535e; + color: #919191; +} diff --git a/forum-network/src/tests/all.test.html b/forum-network/src/tests/all.test.html index 82baba7..7f89e7c 100644 --- a/forum-network/src/tests/all.test.html +++ b/forum-network/src/tests/all.test.html @@ -12,6 +12,9 @@
+ @@ -32,12 +35,6 @@ - diff --git a/forum-network/src/tests/availability.test.html b/forum-network/src/tests/availability.test.html index a6bdbaf..3efa0df 100644 --- a/forum-network/src/tests/availability.test.html +++ b/forum-network/src/tests/availability.test.html @@ -26,12 +26,6 @@ - diff --git a/forum-network/src/tests/business.test.html b/forum-network/src/tests/business.test.html index 9a117eb..fe8bb01 100644 --- a/forum-network/src/tests/business.test.html +++ b/forum-network/src/tests/business.test.html @@ -25,12 +25,6 @@ - diff --git a/forum-network/src/tests/debounce.test.html b/forum-network/src/tests/debounce.test.html index 219c100..b45f7eb 100644 --- a/forum-network/src/tests/debounce.test.html +++ b/forum-network/src/tests/debounce.test.html @@ -25,12 +25,6 @@ - diff --git a/forum-network/src/tests/forum-network.test.html b/forum-network/src/tests/forum-network.test.html index ce233ab..488950b 100644 --- a/forum-network/src/tests/forum-network.test.html +++ b/forum-network/src/tests/forum-network.test.html @@ -26,12 +26,6 @@ - diff --git a/forum-network/src/tests/forum1.test.html b/forum-network/src/tests/forum1.test.html index 7af331d..4e338af 100644 --- a/forum-network/src/tests/forum1.test.html +++ b/forum-network/src/tests/forum1.test.html @@ -21,12 +21,6 @@ - diff --git a/forum-network/src/tests/forum2.test.html b/forum-network/src/tests/forum2.test.html index ff4d512..29af18a 100644 --- a/forum-network/src/tests/forum2.test.html +++ b/forum-network/src/tests/forum2.test.html @@ -21,12 +21,6 @@ - diff --git a/forum-network/src/tests/forum3.test.html b/forum-network/src/tests/forum3.test.html index 97a8df0..d9e41ed 100644 --- a/forum-network/src/tests/forum3.test.html +++ b/forum-network/src/tests/forum3.test.html @@ -21,12 +21,6 @@ - diff --git a/forum-network/src/tests/forum4.test.html b/forum-network/src/tests/forum4.test.html index 2b451d1..262977e 100644 --- a/forum-network/src/tests/forum4.test.html +++ b/forum-network/src/tests/forum4.test.html @@ -21,12 +21,6 @@ - diff --git a/forum-network/src/tests/forum5.test.html b/forum-network/src/tests/forum5.test.html index 142e468..f99f35e 100644 --- a/forum-network/src/tests/forum5.test.html +++ b/forum-network/src/tests/forum5.test.html @@ -21,12 +21,6 @@ - diff --git a/forum-network/src/tests/mocha.test.html b/forum-network/src/tests/mocha.test.html index 54287d7..174b492 100644 --- a/forum-network/src/tests/mocha.test.html +++ b/forum-network/src/tests/mocha.test.html @@ -20,7 +20,6 @@ mocha.setup({ ui: 'bdd', }); - mocha.checkLeaks(); chai.should(); diff --git a/forum-network/src/tests/scripts/availability.test.js b/forum-network/src/tests/scripts/availability.test.js index 5824672..556da23 100644 --- a/forum-network/src/tests/scripts/availability.test.js +++ b/forum-network/src/tests/scripts/availability.test.js @@ -1,10 +1,11 @@ import { Box } from '../../classes/display/box.js'; import { Scene } from '../../classes/display/scene.js'; import { Expert } from '../../classes/actors/expert.js'; -import { delay } from '../../util.js'; import { DAO } from '../../classes/dao/dao.js'; import { Public } from '../../classes/actors/public.js'; import { PostContent } from '../../classes/util/post-content.js'; +import { delayOrWait } from '../../classes/display/controls.js'; +import { mochaRun } from '../../util.js'; const DELAY_INTERVAL = 100; const POOL_DURATION = 200; @@ -43,7 +44,7 @@ const setup = async () => { await newExpert(); requestor = new Public('Public', scene); - await delay(DELAY_INTERVAL); + await delayOrWait(DELAY_INTERVAL); // Experts gain initial reputation by submitting a post with fee const { postId: postId1, pool: pool1 } = await experts[0].submitPostWithFee( @@ -54,10 +55,10 @@ const setup = async () => { tokenLossRatio: 1, }, ); - await delay(POOL_DURATION); + await delayOrWait(POOL_DURATION); await pool1.evaluateWinningConditions(); - await delay(DELAY_INTERVAL); + await delayOrWait(DELAY_INTERVAL); dao.reputation.valueOwnedBy(experts[0].reputationPublicKey).should.equal(10); @@ -71,10 +72,10 @@ const setup = async () => { tokenLossRatio: 1, }, ); - await delay(POOL_DURATION); + await delayOrWait(POOL_DURATION); await pool2.evaluateWinningConditions(); - await delay(DELAY_INTERVAL); + await delayOrWait(DELAY_INTERVAL); dao.reputation.valueOwnedBy(experts[0].reputationPublicKey).should.equal(15); dao.reputation.valueOwnedBy(experts[1].reputationPublicKey).should.equal(5); @@ -106,7 +107,9 @@ const voteForWorkEvidence = async (worker, pool) => { } }; -describe('Availability + Business', () => { +describe('Availability + Business', function tests() { + this.timeout(0); + before(async () => { await setup(); }); @@ -122,7 +125,7 @@ describe('Availability + Business', () => { it('Experts can register their availability for some duration', async () => { await experts[0].registerAvailability(1, 10000); await experts[1].registerAvailability(1, 10000); - await delay(DELAY_INTERVAL); + await delayOrWait(DELAY_INTERVAL); }); it('Public can submit a work request', async () => { @@ -131,7 +134,7 @@ describe('Availability + Business', () => { { fee: 100 }, { please: 'do some work' }, ); - await delay(DELAY_INTERVAL); + await delayOrWait(DELAY_INTERVAL); }); it('Expert can submit work evidence', async () => { @@ -153,11 +156,11 @@ describe('Availability + Business', () => { await voteForWorkEvidence(worker, pool3); // Wait for validation pool duration to elapse - await delay(POOL_DURATION); + await delayOrWait(POOL_DURATION); // Distribute reputation awards and fees await pool3.evaluateWinningConditions(); - await delay(DELAY_INTERVAL); + await delayOrWait(DELAY_INTERVAL); // This should throw an exception since the pool is already resolved try { @@ -167,3 +170,5 @@ describe('Availability + Business', () => { } }).timeout(10000); }); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/business.test.js b/forum-network/src/tests/scripts/business.test.js index ce87e31..dd3a524 100644 --- a/forum-network/src/tests/scripts/business.test.js +++ b/forum-network/src/tests/scripts/business.test.js @@ -1,8 +1,10 @@ -import { Business } from '../../classes/actors/business.js'; +import { Business } from '../../classes/dao/business.js'; import { Scene } from '../../classes/display/scene.js'; import { Box } from '../../classes/display/box.js'; +import { mochaRun } from '../../util.js'; -describe('Business', () => { +describe('Business', function tests() { + this.timeout(0); let scene; before(async () => { const rootElement = document.getElementById('scene'); @@ -14,3 +16,5 @@ describe('Business', () => { should.exist(business); }); }); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/debounce.test.js b/forum-network/src/tests/scripts/debounce.test.js index 286d310..b0de18e 100644 --- a/forum-network/src/tests/scripts/debounce.test.js +++ b/forum-network/src/tests/scripts/debounce.test.js @@ -2,7 +2,7 @@ import { Box } from '../../classes/display/box.js'; import { Scene } from '../../classes/display/scene.js'; import { Action } from '../../classes/display/action.js'; import { Actor } from '../../classes/display/actor.js'; -import { debounce, delay } from '../../util.js'; +import { debounce, delay, mochaRun } from '../../util.js'; describe('Debounce', () => { let scene; @@ -70,3 +70,5 @@ describe('Debounce', () => { await scene.sequence.endSection(); }); }); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/forum-network.test.js b/forum-network/src/tests/scripts/forum-network.test.js index d1737c8..5cbe692 100644 --- a/forum-network/src/tests/scripts/forum-network.test.js +++ b/forum-network/src/tests/scripts/forum-network.test.js @@ -4,9 +4,12 @@ import { PostContent } from '../../classes/util/post-content.js'; import { Expert } from '../../classes/actors/expert.js'; import { ForumNode } from '../../classes/forum-network/forum-node.js'; import { Network } from '../../classes/forum-network/network.js'; -import { delay, randomID } from '../../util.js'; +import { mochaRun, randomID } from '../../util.js'; +import { delayOrWait } from '../../classes/display/controls.js'; + +describe('Forum Network', function tests() { + this.timeout(0); -describe('Forum Network', () => { let scene; let author1; let author2; @@ -58,19 +61,21 @@ describe('Forum Network', () => { 1.0, ); - await delay(1000); + await delayOrWait(1000); await author1.submitPostViaNetwork( forumNode1, post1, 50, ); - await delay(1000); + await delayOrWait(1000); await author2.submitPostViaNetwork( forumNode2, post2, 100, ); - await delay(1000); + await delayOrWait(1000); }).timeout(10000); }); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/forum/forum.test-util.js b/forum-network/src/tests/scripts/forum/forum.test-util.js index 0ce352a..fea2e8a 100644 --- a/forum-network/src/tests/scripts/forum/forum.test-util.js +++ b/forum-network/src/tests/scripts/forum/forum.test-util.js @@ -2,9 +2,9 @@ import { Box } from '../../../classes/display/box.js'; import { Scene } from '../../../classes/display/scene.js'; import { Expert } from '../../../classes/actors/expert.js'; import { PostContent } from '../../../classes/util/post-content.js'; -import { delay } from '../../../util.js'; import params from '../../../params.js'; import { DAO } from '../../../classes/dao/dao.js'; +import { delayOrWait } from '../../../classes/display/controls.js'; export class ForumTest { constructor(options) { @@ -38,10 +38,10 @@ export class ForumTest { }, ); this.posts.push(postId); - await delay(this.options.poolDurationMs); + await delayOrWait(this.options.poolDurationMs); await pool.evaluateWinningConditions(); await this.scene.sequence.endSection(); - await delay(this.options.defaultDelayMs); + await delayOrWait(this.options.defaultDelayMs); return postId; } diff --git a/forum-network/src/tests/scripts/forum/forum1.test.js b/forum-network/src/tests/scripts/forum/forum1.test.js index 77d52a4..2800972 100644 --- a/forum-network/src/tests/scripts/forum/forum1.test.js +++ b/forum-network/src/tests/scripts/forum/forum1.test.js @@ -1,6 +1,9 @@ +import { mochaRun } from '../../../util.js'; import { ForumTest } from './forum.test-util.js'; -describe('Forum', () => { +describe('Forum', function tests() { + this.timeout(0); + const forumTest = new ForumTest(); before(async () => { @@ -37,3 +40,5 @@ describe('Forum', () => { // await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]); // await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/forum/forum2.test.js b/forum-network/src/tests/scripts/forum/forum2.test.js index b4737a3..6c76676 100644 --- a/forum-network/src/tests/scripts/forum/forum2.test.js +++ b/forum-network/src/tests/scripts/forum/forum2.test.js @@ -1,6 +1,9 @@ +import { mochaRun } from '../../../util.js'; import { ForumTest } from './forum.test-util.js'; -describe('Forum', () => { +describe('Forum', function tests() { + this.timeout(0); + const forumTest = new ForumTest(); before(async () => { @@ -37,3 +40,5 @@ describe('Forum', () => { // await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]); // await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/forum/forum3.test.js b/forum-network/src/tests/scripts/forum/forum3.test.js index e5d5038..ce849ed 100644 --- a/forum-network/src/tests/scripts/forum/forum3.test.js +++ b/forum-network/src/tests/scripts/forum/forum3.test.js @@ -1,6 +1,9 @@ +import { mochaRun } from '../../../util.js'; import { ForumTest } from './forum.test-util.js'; -describe('Forum', () => { +describe('Forum', function tests() { + this.timeout(0); + const forumTest = new ForumTest(); before(async () => { @@ -40,3 +43,5 @@ describe('Forum', () => { // await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]); // await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/forum/forum4.test.js b/forum-network/src/tests/scripts/forum/forum4.test.js index c4c3c55..2349110 100644 --- a/forum-network/src/tests/scripts/forum/forum4.test.js +++ b/forum-network/src/tests/scripts/forum/forum4.test.js @@ -1,6 +1,9 @@ +import { mochaRun } from '../../../util.js'; import { ForumTest } from './forum.test-util.js'; -describe('Forum', () => { +describe('Forum', function tests() { + this.timeout(0); + const forumTest = new ForumTest(); before(async () => { @@ -68,3 +71,5 @@ describe('Forum', () => { // await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]); // await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/forum/forum5.test.js b/forum-network/src/tests/scripts/forum/forum5.test.js index 2274d57..52e819b 100644 --- a/forum-network/src/tests/scripts/forum/forum5.test.js +++ b/forum-network/src/tests/scripts/forum/forum5.test.js @@ -1,6 +1,9 @@ +import { mochaRun } from '../../../util.js'; import { ForumTest } from './forum.test-util.js'; -describe('Forum', () => { +describe('Forum', function tests() { + this.timeout(0); + const forumTest = new ForumTest(); before(async () => { @@ -57,3 +60,5 @@ describe('Forum', () => { // await addPost(expert3, 'Post 4', 100, [{ postId: postId2, weight: -1 }]); // await addPost(expert1, 'Post 5', 100, [{ postId: postId3, weight: -1 }]); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/validation-pool.test.js b/forum-network/src/tests/scripts/validation-pool.test.js index 865fca0..3d1e8c4 100644 --- a/forum-network/src/tests/scripts/validation-pool.test.js +++ b/forum-network/src/tests/scripts/validation-pool.test.js @@ -2,8 +2,9 @@ import { Box } from '../../classes/display/box.js'; import { Scene } from '../../classes/display/scene.js'; import { Expert } from '../../classes/actors/expert.js'; import { PostContent } from '../../classes/util/post-content.js'; -import { delay } from '../../util.js'; import { DAO } from '../../classes/dao/dao.js'; +import { delayOrWait } from '../../classes/display/controls.js'; +import { mochaRun } from '../../util.js'; const POOL_DURATION_MS = 100; const DEFAULT_DELAY_MS = 100; @@ -35,10 +36,11 @@ async function setup() { await newExpert(); await newExpert(); - await delay(DEFAULT_DELAY_MS); + await delayOrWait(DEFAULT_DELAY_MS); } -describe('Validation Pool', () => { +describe('Validation Pool', function tests() { + this.timeout(0); before(async () => { await setup(); }); @@ -73,9 +75,9 @@ describe('Validation Pool', () => { } } await scene.sequence.endSection(); - await delay(POOL_DURATION_MS); + await delayOrWait(POOL_DURATION_MS); await pool.evaluateWinningConditions(); // Vote passes - await delay(DEFAULT_DELAY_MS); + await delayOrWait(DEFAULT_DELAY_MS); }); it('Failure example: second expert can not self-approve', async () => { @@ -85,9 +87,9 @@ describe('Validation Pool', () => { duration: POOL_DURATION_MS, tokenLossRatio: 1, }); - await delay(POOL_DURATION_MS); + await delayOrWait(POOL_DURATION_MS); await pool.evaluateWinningConditions(); // Quorum not met! - await delay(DEFAULT_DELAY_MS); + await delayOrWait(DEFAULT_DELAY_MS); } catch (e) { e.message.should.match(/Quorum is not met/); } @@ -104,8 +106,10 @@ describe('Validation Pool', () => { amount: 4, lockingTime: 0, }); - await delay(POOL_DURATION_MS); + await delayOrWait(POOL_DURATION_MS); await pool.evaluateWinningConditions(); // Stake passes - await delay(DEFAULT_DELAY_MS); + await delayOrWait(DEFAULT_DELAY_MS); }); }); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/vm.test.js b/forum-network/src/tests/scripts/vm.test.js index 93baac5..ffd1967 100644 --- a/forum-network/src/tests/scripts/vm.test.js +++ b/forum-network/src/tests/scripts/vm.test.js @@ -2,6 +2,7 @@ import { Actor } from '../../classes/display/actor.js'; import { Box } from '../../classes/display/box.js'; import { Scene } from '../../classes/display/scene.js'; import { VM } from '../../classes/supporting/vm.js'; +import { mochaRun } from '../../util.js'; const contractIds = ['contract-id-1', 'contract-id-2']; @@ -29,7 +30,9 @@ class Repeater extends Actor { } } -describe('VM', () => { +describe('VM', function tests() { + this.timeout(0); + let vm; let sender; let vmHandle; @@ -68,3 +71,5 @@ describe('VM', () => { .should.equal('Repeater world: good day'); }); }); + +mochaRun(); diff --git a/forum-network/src/tests/scripts/wdag.test.js b/forum-network/src/tests/scripts/wdag.test.js index 35f453b..4fd1243 100644 --- a/forum-network/src/tests/scripts/wdag.test.js +++ b/forum-network/src/tests/scripts/wdag.test.js @@ -1,12 +1,15 @@ import { Box } from '../../classes/display/box.js'; import { Scene } from '../../classes/display/scene.js'; import { WDAG } from '../../classes/supporting/wdag.js'; +import { mochaRun } from '../../util.js'; const rootElement = document.getElementById('scene'); const rootBox = new Box('rootBox', rootElement).flex(); window.scene = new Scene('WDAG test', rootBox); -describe('Query the graph', () => { +describe('Query the graph', function tests() { + this.timeout(0); + let graph; before(() => { @@ -43,3 +46,5 @@ describe('Query the graph', () => { ]); }); }); + +mochaRun(); diff --git a/forum-network/src/tests/validation-pool.test.html b/forum-network/src/tests/validation-pool.test.html index 7afaac2..4dbe0f1 100644 --- a/forum-network/src/tests/validation-pool.test.html +++ b/forum-network/src/tests/validation-pool.test.html @@ -25,12 +25,6 @@ - diff --git a/forum-network/src/tests/vm.test.html b/forum-network/src/tests/vm.test.html index 8aeff12..f78597e 100644 --- a/forum-network/src/tests/vm.test.html +++ b/forum-network/src/tests/vm.test.html @@ -21,12 +21,6 @@ - diff --git a/forum-network/src/tests/wdag.test.html b/forum-network/src/tests/wdag.test.html index 44190be..49eece4 100644 --- a/forum-network/src/tests/wdag.test.html +++ b/forum-network/src/tests/wdag.test.html @@ -21,13 +21,7 @@ - diff --git a/forum-network/src/util.js b/forum-network/src/util.js index b8a4ac8..2505b93 100644 --- a/forum-network/src/util.js +++ b/forum-network/src/util.js @@ -38,3 +38,9 @@ export const displayNumber = (value, decimals = 2) => (value.toString().length > : value); export const randomID = () => CryptoUtil.randomUUID().replaceAll('-', '').slice(0, 8); + +export const mochaRun = () => { + if (mocha._state !== 'running') { + mocha.run(); + } +};