diff --git a/forum-network/src/classes/dao/forum.js b/forum-network/src/classes/dao/forum.js
index 2ac0d5b..e65dee2 100644
--- a/forum-network/src/classes/dao/forum.js
+++ b/forum-network/src/classes/dao/forum.js
@@ -1,4 +1,4 @@
-import { WDAG } from '../supporting/wdag.js';
+import { WeightedDirectedGraph } from '../supporting/wdg.js';
import { Action } from '../display/action.js';
import { Actor } from '../display/actor.js';
import { ReputationHolder } from '../reputation/reputation-holder.js';
@@ -51,7 +51,7 @@ export class Forum extends ReputationHolder {
super(name, scene);
this.dao = dao;
this.id = this.reputationPublicKey;
- this.graph = new WDAG(scene);
+ this.graph = new WeightedDirectedGraph(scene);
this.actions = {
propagate: new Action('propagate', scene),
confirm: new Action('confirm', scene),
diff --git a/forum-network/src/classes/display/document.js b/forum-network/src/classes/display/document.js
index 69545be..2726e18 100644
--- a/forum-network/src/classes/display/document.js
+++ b/forum-network/src/classes/display/document.js
@@ -2,8 +2,8 @@ import { Box } from './box.js';
import { Form } from './form.js';
export class Remark extends Box {
- constructor(doc, text, opts) {
- super('Remark', doc.el, opts);
+ constructor(doc, text, opts = {}) {
+ super('Remark', opts.parentEl ?? doc.el, opts);
this.setInnerHTML(text);
}
}
@@ -16,8 +16,10 @@ export class Remark extends Box {
* ```
*/
export class Document extends Box {
- form() {
- return this.addElement(new Form(this));
+ elements = [];
+
+ form(opts) {
+ return this.addElement(new Form(this, opts));
}
remark(text, opts) {
@@ -25,13 +27,17 @@ export class Document extends Box {
}
addElement(element) {
- this.elements = this.elements ?? [];
this.elements.push(element);
return this;
}
+ clear() {
+ this.el.innerHTML = '';
+ this.elements = [];
+ }
+
get lastElement() {
- if (!this.elements?.length) return null;
+ if (!this.elements.length) return null;
return this.elements[this.elements.length - 1];
}
}
diff --git a/forum-network/src/classes/display/form.js b/forum-network/src/classes/display/form.js
index 3f04d6c..9ad297b 100644
--- a/forum-network/src/classes/display/form.js
+++ b/forum-network/src/classes/display/form.js
@@ -4,13 +4,16 @@ import { Box } from './box.js';
const updateValuesOnEventTypes = ['keyup', 'mouseup'];
export class FormElement extends Box {
- constructor(name, parentEl, opts) {
+ constructor(name, form, opts) {
+ const parentEl = opts.parentEl ?? form.el;
super(name, parentEl, opts);
+ this.form = form;
this.id = opts.id ?? name;
+ this.includeInOutput = opts.includeInOutput ?? true;
const { cb } = opts;
if (cb) {
updateValuesOnEventTypes.forEach((eventType) => this.el.addEventListener(eventType, () => {
- cb(this);
+ cb(this, { initializing: false });
}));
cb(this, { initializing: true });
}
@@ -18,21 +21,26 @@ export class FormElement extends Box {
}
export class Button extends FormElement {
- constructor(name, parentEl, opts) {
- super(name, parentEl, opts);
+ constructor(name, form, opts) {
+ super(name, form, opts);
this.button = document.createElement('button');
this.button.setAttribute('type', 'button');
this.button.innerHTML = name;
+ this.button.disabled = !!opts.disabled;
this.el.appendChild(this.button);
}
}
export class TextField extends FormElement {
- constructor(name, parentEl, opts) {
- super(name, parentEl, opts);
+ constructor(name, form, opts) {
+ super(name, form, opts);
this.label = document.createElement('label');
- this.label.innerHTML = name;
+ this.labelDiv = document.createElement('div');
+ this.label.appendChild(this.labelDiv);
+ this.labelDiv.innerHTML = name;
this.input = document.createElement('input');
+ this.input.disabled = !!opts.disabled;
+ this.input.defaultValue = opts.defaultValue || '';
this.label.appendChild(this.input);
this.el.appendChild(this.label);
}
@@ -44,25 +52,83 @@ export class TextField extends FormElement {
export class TextArea extends FormElement { }
-export class Form {
+export class SubFormArray extends FormElement {
+ constructor(name, form, opts) {
+ super(name, form, opts);
+ this.subForms = [];
+ }
+
+ get value() {
+ return this.subForms.map((subForm) => subForm.value);
+ }
+
+ remove(subForm) {
+ const idx = this.subForms.findIndex((s) => s === subForm);
+ this.subForms.splice(idx, 1);
+ subForm.el.remove();
+ }
+}
+
+export class SubForm extends FormElement {
+ constructor(name, form, opts) {
+ const parentEl = opts.subFormArray ? opts.subFormArray.el : form.el;
+ const subForm = form.document.form({ name, parentEl }).lastElement;
+ super(name, form, { ...opts, parentEl });
+ this.subForm = subForm;
+ if (opts.subFormArray) {
+ opts.subFormArray.subForms.push(this);
+ this.includeInOutput = false;
+ }
+ }
+
+ get value() {
+ return this.subForm.value;
+ }
+}
+
+export class Form extends Box {
constructor(document, opts = {}) {
+ super(opts.name, opts.parentEl || document.el, opts);
this.document = document;
this.items = [];
this.id = opts.id ?? `form_${randomID()}`;
}
button(opts) {
- this.items.push(new Button(opts.name, this.document.el, opts));
+ this.items.push(new Button(opts.name, this, opts));
return this;
}
textField(opts) {
- this.items.push(new TextField(opts.name, this.document.el, opts));
+ this.items.push(new TextField(opts.name, this, opts));
return this;
}
textArea(opts) {
- this.items.push(new TextArea(opts.name, this.document.el, opts));
+ this.items.push(new TextArea(opts.name, this, opts));
return this;
}
+
+ subForm(opts) {
+ this.items.push(new SubForm(opts.name, this, opts));
+ return this;
+ }
+
+ subFormArray(opts) {
+ this.items.push(new SubFormArray(opts.name, this, opts));
+ return this;
+ }
+
+ get lastItem() {
+ return this.items[this.items.length - 1];
+ }
+
+ get value() {
+ return this.items.reduce((result, { id, value, includeInOutput }) => {
+ if (includeInOutput && value !== undefined) {
+ result[id] = value;
+ }
+ return result;
+ }, {});
+ }
}
diff --git a/forum-network/src/classes/display/mermaid.js b/forum-network/src/classes/display/mermaid.js
index 72f0171..201bba1 100644
--- a/forum-network/src/classes/display/mermaid.js
+++ b/forum-network/src/classes/display/mermaid.js
@@ -29,6 +29,8 @@ export class MermaidDiagram {
activationBkgColor: '#1d3f49',
activationBorderColor: '#569595',
},
+ securityLevel: 'loose', // 'loose' so that we can use click events
+ // logLevel: 'debug',
});
}
@@ -51,11 +53,16 @@ export class MermaidDiagram {
return debounce(async () => {
const text = this.getText();
try {
- const graph = await mermaid.mermaidAPI.render(
+ await mermaid.mermaidAPI.render(
this.element.getId(),
text,
+ (svgCode, bindFunctions) => {
+ this.renderBox.setInnerHTML(svgCode);
+ if (bindFunctions) {
+ bindFunctions(this.renderBox.el);
+ }
+ },
);
- this.renderBox.setInnerHTML(graph);
} catch (e) {
console.error(`render text:\n${text}`);
throw e;
diff --git a/forum-network/src/classes/display/scene.js b/forum-network/src/classes/display/scene.js
index 3b14ec6..e6a0130 100644
--- a/forum-network/src/classes/display/scene.js
+++ b/forum-network/src/classes/display/scene.js
@@ -21,6 +21,7 @@ export class Scene {
this.actors = new Set();
this.dateStart = new Date();
this.flowcharts = new Map();
+ this.documents = [];
MermaidDiagram.initializeAPI();
@@ -105,6 +106,10 @@ export class Scene {
return this.documents[this.documents.length - 1];
}
+ getDocument(name) {
+ return this.documents.find((doc) => doc.name === name);
+ }
+
registerActor(actor) {
this.actors.add(actor);
if (actor.options.announce) {
diff --git a/forum-network/src/classes/supporting/edge.js b/forum-network/src/classes/supporting/edge.js
new file mode 100644
index 0000000..ba82aa2
--- /dev/null
+++ b/forum-network/src/classes/supporting/edge.js
@@ -0,0 +1,119 @@
+export class Edge {
+ constructor(graph, type, from, to, weight, data, options = {}) {
+ this.graph = graph;
+ this.from = from;
+ this.to = to;
+ this.type = type;
+ this.weight = weight;
+ this.data = data;
+ this.options = options;
+ }
+
+ static getKey({
+ from, to, type,
+ }) {
+ return ['edge', from.id, to.id, type].join(':');
+ }
+
+ static getCombinedKey({ from, to }) {
+ return ['edge', from.id, to.id].join(':');
+ }
+
+ getComorphicEdges() {
+ return this.graph.getEdges(null, this.from, this.to);
+ }
+
+ getHtml() {
+ let html = '
';
+ for (const { type, weight } of this.getComorphicEdges()) {
+ html += `${type} | ${weight} |
`;
+ }
+ html += '
';
+ return html;
+ }
+
+ getFlowchartNode() {
+ return `${Edge.getCombinedKey(this)}(${this.getHtml()})`;
+ }
+
+ displayEdgeNode() {
+ if (this.options.hide) {
+ return;
+ }
+ this.graph.flowchart?.log(this.getFlowchartNode());
+ }
+
+ displayEdge() {
+ if (this.options.hide) {
+ return;
+ }
+ this.graph.flowchart?.log(`${this.from.id} --- ${this.getFlowchartNode()} --> ${this.to.id}`);
+ this.graph.flowchart?.log(`class ${Edge.getCombinedKey(this)} edge`);
+ if (this.graph.editable) {
+ this.graph.flowchart?.log(`click ${Edge.getCombinedKey(this)} WDGHandler${this.graph.index} "Edit Edge"`);
+ }
+ }
+
+ static prepareEditorDocument(graph, doc, from, to) {
+ doc.clear();
+ const form = doc.form({ name: 'editorForm' }).lastElement;
+ doc.remark('Edit Edge
', { parentEl: form.el });
+ form
+ .textField({
+ id: 'from', name: 'from', defaultValue: from, disabled: true,
+ })
+ .textField({
+ id: 'to', name: 'to', defaultValue: to, disabled: true,
+ });
+
+ const subFormArray = form.subFormArray({ id: 'edges', name: 'edges' }).lastItem;
+ const addEdgeForm = (edge) => {
+ const { subForm } = form.subForm({ name: 'subform', subFormArray }).lastItem;
+ doc.remark('
', { parentEl: subForm.el });
+ subForm.textField({ id: 'type', name: 'type', defaultValue: edge.type });
+ subForm.textField({ id: 'weight', name: 'weight', defaultValue: edge.weight });
+ subForm.button({
+ id: 'remove',
+ name: 'Remove Edge Type',
+ cb: (_, { initializing }) => {
+ if (initializing) return;
+ subFormArray.remove(subForm);
+ },
+ });
+ };
+
+ for (const edge of graph.getEdges(null, from, to)) {
+ addEdgeForm(edge);
+ }
+
+ form.button({
+ id: 'add',
+ name: 'Add Edge Type',
+ cb: (_, { initializing }) => {
+ if (initializing) return;
+ addEdgeForm(new Edge(graph, null, graph.getVertex(from), graph.getVertex(to)));
+ },
+ });
+
+ form.button({
+ id: 'save',
+ name: 'Save',
+ cb: ({ form: { value } }, { initializing }) => {
+ if (initializing) return;
+ console.log('graph before save', { ...graph });
+ // Handle additions and updates
+ for (const { type, weight } of value.edges) {
+ graph.setEdgeWeight(type, from, to, weight);
+ }
+ // Handle removals
+ for (const edgeType of graph.edgeTypes.values()) {
+ if (!value.edges.find((edge) => edge.type === edgeType)) {
+ graph.deleteEdge(edgeType, from, to);
+ }
+ }
+ console.log('graph after save', { ...graph });
+ // TODO: Redraw graph
+ },
+ });
+ }
+}
diff --git a/forum-network/src/classes/supporting/vertex.js b/forum-network/src/classes/supporting/vertex.js
new file mode 100644
index 0000000..0b86e9b
--- /dev/null
+++ b/forum-network/src/classes/supporting/vertex.js
@@ -0,0 +1,82 @@
+export class Vertex {
+ constructor(graph, type, id, data, options = {}) {
+ this.graph = graph;
+ this.type = type;
+ this._id = id;
+ this.data = data;
+ this.options = options;
+ this.edges = {
+ from: [],
+ to: [],
+ };
+ this.installedClickCallback = false;
+ }
+
+ set id(newId) {
+ this._id = newId;
+ }
+
+ get id() {
+ return this._id;
+ }
+
+ getEdges(type, away) {
+ return this.edges[away ? 'from' : 'to'].filter(
+ (edge) => edge.type === type,
+ );
+ }
+
+ setDisplayLabel(label) {
+ this.label = label;
+ this.displayVertex();
+ }
+
+ displayVertex() {
+ if (this.options.hide) {
+ return;
+ }
+ this.graph.flowchart?.log(`${this.id}[${this.label}]`);
+ if (this.graph.editable && !this.installedClickCallback) {
+ this.graph.flowchart?.log(`click ${this.id} WDGHandler${this.graph.index} "Edit Vertex"`);
+ this.installedClickCallback = true;
+ }
+ }
+
+ static prepareEditorDocument(graph, doc, vertexId) {
+ doc.clear();
+ const vertex = graph.getVertex(vertexId);
+ if (!vertex) {
+ throw new Error(`Could not find WDG Vertex ${vertexId}`);
+ }
+ doc.remark('Edit Vertex
');
+ const form = doc.form().lastElement;
+ form
+ .textField({
+ id: 'id', name: 'id', defaultValue: vertex.id, disabled: true,
+ })
+ .textField({ id: 'type', name: 'type', defaultValue: vertex.type })
+ .textField({ id: 'label', name: 'label', defaultValue: vertex.label })
+
+ .button({
+ id: 'save',
+ name: 'Save',
+ cb: ({ form: { value } }, { initializing }) => {
+ if (initializing) return;
+ if (value.id && value.id !== vertex.id) {
+ // TODO: When an ID changes we really need to wipe out and redraw!
+ // But we don't yet have a systematic approach for doing that.
+ // Everything is getting rendered as needed. Lacking abstraction.
+ // HMM we're not actually that far! Just wipe everything out and draw each vertex and edge :)
+ // for (const vertex of )
+ // for (const edge of [...vertex.edges.to, ...vertex.edges.from]) {
+ // edge.displayEdge();
+ // }
+ }
+ Object.assign(vertex, value);
+ vertex.displayVertex();
+ },
+ });
+
+ return doc;
+ }
+}
diff --git a/forum-network/src/classes/supporting/wdag.js b/forum-network/src/classes/supporting/wdg.js
similarity index 62%
rename from forum-network/src/classes/supporting/wdag.js
rename to forum-network/src/classes/supporting/wdg.js
index 15b6446..fe0984b 100644
--- a/forum-network/src/classes/supporting/wdag.js
+++ b/forum-network/src/classes/supporting/wdg.js
@@ -1,79 +1,34 @@
-const getEdgeKey = ({ from, to }) => btoa([from.id, to.id]).replaceAll(/[^A-Za-z0-9]+/g, '');
+import { Vertex } from './vertex.js';
+import { Edge } from './edge.js';
-export class Vertex {
- constructor(graph, type, id, data, options = {}) {
- this.graph = graph;
- this.type = type;
- this.id = id;
- this.data = data;
- this.options = options;
- this.edges = {
- from: [],
- to: [],
- };
+const graphs = [];
+
+const makeWDGHandler = (graph) => (vertexId) => {
+ // We want a document for editing this node, which may be a vertex or an edge
+ const editorDoc = graph.scene.getDocument('editorDocument')
+ ?? graph.scene.withDocument('editorDocument').lastDocument;
+ if (vertexId.startsWith('edge:')) {
+ const [, from, to] = vertexId.split(':');
+ Edge.prepareEditorDocument(graph, editorDoc, from, to);
+ } else {
+ Vertex.prepareEditorDocument(graph, editorDoc, vertexId);
}
+};
- getEdges(type, away) {
- return this.edges[away ? 'from' : 'to'].filter(
- (edge) => edge.type === type,
- );
- }
-
- setDisplayLabel(label) {
- if (this.options.hide) {
- return;
- }
- this.graph.flowchart?.log(`${this.id}[${label}]`);
- }
-}
-
-export class Edge {
- constructor(graph, type, from, to, weight, data, options = {}) {
- this.graph = graph;
- this.from = from;
- this.to = to;
- this.type = type;
- this.weight = weight;
- this.data = data;
- this.options = options;
- }
-
- getHtml() {
- let html = '';
- for (const { type, weight } of this.graph.getEdges(null, this.from, this.to)) {
- html += `${type} | ${weight} |
`;
- }
- html += '
';
- return html;
- }
-
- getFlowchartNode() {
- return `${getEdgeKey(this)}(${this.getHtml()})`;
- }
-
- displayEdgeNode() {
- if (this.options.hide) {
- return;
- }
- this.graph.flowchart?.log(this.getFlowchartNode());
- }
-
- displayEdge() {
- if (this.options.hide) {
- return;
- }
- this.graph.flowchart?.log(`${this.from.id} --- ${this.getFlowchartNode()} --> ${this.to.id}`);
- this.graph.flowchart?.log(`class ${getEdgeKey(this)} edge`);
- }
-}
-
-export class WDAG {
- constructor(scene) {
+export class WeightedDirectedGraph {
+ constructor(scene, options = {}) {
this.scene = scene;
this.vertices = new Map();
this.edgeTypes = new Map();
this.nextVertexId = 0;
this.flowchart = scene?.flowchart;
+ this.editable = options.editable;
+ this.index = graphs.length;
+ graphs.push(this);
+ // Mermaid supports a click callback, but we can't customize arguments; we just get the vertex ID.
+ // In order to provide the appropriate graph context for each callback, we create a separate callback
+ // function for each graph.
+ window[`WDGHandler${this.index}`] = makeWDGHandler(this);
}
withFlowchart() {
@@ -83,11 +38,12 @@ export class WDAG {
}
addVertex(type, id, data, label, options) {
- // Support simple case of auto-incremented numeric ids
+ // Supports simple case of auto-incremented numeric ids
if (typeof id === 'object') {
data = id;
id = this.nextVertexId++;
}
+ id = (typeof id === 'number') ? id.toString(10) : id;
if (this.vertices.has(id)) {
throw new Error(`Vertex already exists with id: ${id}`);
}
@@ -98,6 +54,7 @@ export class WDAG {
}
getVertex(id) {
+ id = (typeof id === 'number') ? id.toString(10) : id;
return this.vertices.get(id);
}
@@ -116,10 +73,23 @@ export class WDAG {
return undefined;
}
const edges = this.edgeTypes.get(type);
- const edgeKey = getEdgeKey({ from, to });
+ const edgeKey = Edge.getKey({ from, to, type });
return edges?.get(edgeKey);
}
+ deleteEdge(type, from, to) {
+ from = from instanceof Vertex ? from : this.getVertex(from);
+ to = to instanceof Vertex ? to : this.getVertex(to);
+ const edges = this.edgeTypes.get(type);
+ const edgeKey = Edge.getKey({ type, from, to });
+ if (!edges) return;
+ const edge = edges.get(edgeKey);
+ if (!edge) return;
+ to.edges.from.forEach((x, i) => (x === edge) && to.edges.from.splice(i, 1));
+ from.edges.to.forEach((x, i) => (x === edge) && from.edges.to.splice(i, 1));
+ edges.delete(edgeKey);
+ }
+
getEdgeWeight(type, from, to) {
return this.getEdge(type, from, to)?.weight;
}
@@ -133,7 +103,7 @@ export class WDAG {
edges = new Map();
this.edgeTypes.set(type, edges);
}
- const edgeKey = getEdgeKey(edge);
+ const edgeKey = Edge.getKey(edge);
edges.set(edgeKey, edge);
edge.displayEdgeNode();
return edge;
@@ -172,6 +142,4 @@ export class WDAG {
}
return Array.from(this.vertices.values()).filter((vertex) => vertex.type === type).length;
}
-
- // TODO: Add support for inputs to add/edit vertices and edges
}
diff --git a/forum-network/src/index.css b/forum-network/src/index.css
index 2826340..2db2c1b 100644
--- a/forum-network/src/index.css
+++ b/forum-network/src/index.css
@@ -79,3 +79,7 @@ label {
font-size: smaller;
color: #999999;
}
+label > div {
+ display: inline-block;
+ min-width: 50px;
+}
diff --git a/forum-network/src/index.html b/forum-network/src/index.html
index 1c198fb..8b95bbf 100644
--- a/forum-network/src/index.html
+++ b/forum-network/src/index.html
@@ -55,7 +55,7 @@
- Basic Sequencing
- Basic Sequencing 2
- - WDAG
+ - Weighted Directed Graph
- Debounce
- Flowchart
- Mocha
diff --git a/forum-network/src/tests/all.test.html b/forum-network/src/tests/all.test.html
index 10d7178..b28655c 100644
--- a/forum-network/src/tests/all.test.html
+++ b/forum-network/src/tests/all.test.html
@@ -25,7 +25,7 @@
-
+
diff --git a/forum-network/src/tests/scripts/input.test.js b/forum-network/src/tests/scripts/input.test.js
index 224c196..b3bf2ee 100644
--- a/forum-network/src/tests/scripts/input.test.js
+++ b/forum-network/src/tests/scripts/input.test.js
@@ -45,7 +45,7 @@ describe('Document > Form > Button', () => {
const form = doc.lastElement;
const dvMap = new Map();
let clicks = 0;
- const handleClick = ({ id, name }, { initializing = false } = {}) => {
+ const handleClick = ({ id, name }, { initializing }) => {
const dv = dvMap.get(id) ?? scene.addDisplayValue(name);
dvMap.set(id, dv);
if (!initializing) {
diff --git a/forum-network/src/tests/scripts/wdag.test.js b/forum-network/src/tests/scripts/wdg.test.js
similarity index 59%
rename from forum-network/src/tests/scripts/wdag.test.js
rename to forum-network/src/tests/scripts/wdg.test.js
index dfc15a3..44f8c6d 100644
--- a/forum-network/src/tests/scripts/wdag.test.js
+++ b/forum-network/src/tests/scripts/wdg.test.js
@@ -1,19 +1,19 @@
import { Box } from '../../classes/display/box.js';
import { Scene } from '../../classes/display/scene.js';
-import { WDAG } from '../../classes/supporting/wdag.js';
+import { WeightedDirectedGraph } from '../../classes/supporting/wdg.js';
import { mochaRun } from '../../util/helpers.js';
const rootElement = document.getElementById('scene');
const rootBox = new Box('rootBox', rootElement).flex();
-window.scene = new Scene('WDAG test', rootBox);
+window.scene = new Scene('WDG test', rootBox);
-describe('Query the graph', function tests() {
+describe('Weighted Directed Acyclic Graph', function tests() {
this.timeout(0);
let graph;
before(() => {
- graph = (window.graph = new WDAG()).withFlowchart();
+ graph = (window.graph = new WeightedDirectedGraph(window.scene)).withFlowchart();
graph.addVertex('v1', {});
graph.addVertex('v1', {});
@@ -34,17 +34,35 @@ describe('Query the graph', function tests() {
it('can query for all e1 edges from a particular vertex', () => {
const edges = graph.getEdges('e1', 2);
- edges.map(({ from, to, weight }) => [from.id, to.id, weight]).should.have.deep.members([[2, 1, 0.5]]);
+ edges.map(({ from, to, weight }) => [from.id, to.id, weight]).should.have.deep.members([[
+ '2', '1', 0.5,
+ ]]);
});
it('can query for all e1 edges to a particular vertex', () => {
const edges = graph.getEdges('e1', null, 1);
edges.map(({ from, to, weight }) => [from.id, to.id, weight]).should.have.deep.members([
- [0, 1, 1],
- [2, 1, 0.5],
- [3, 1, 0.25],
+ ['0', '1', 1],
+ ['2', '1', 0.5],
+ ['3', '1', 0.25],
]);
});
});
+describe('editable', () => {
+ let graph;
+
+ it('should be editable', () => {
+ graph = (window.graph2 = new WeightedDirectedGraph(window.scene, { editable: true })).withFlowchart();
+
+ graph.addVertex('v1', {});
+ graph.addVertex('v2', {});
+ graph.addVertex('v3', {});
+
+ graph.addEdge('e1', 2, 1, 1);
+ graph.addEdge('e2', 1, 0, 0.5);
+ graph.addEdge('e3', 2, 0, 0.25);
+ });
+});
+
mochaRun();
diff --git a/forum-network/src/tests/wdag.test.html b/forum-network/src/tests/wdg.test.html
similarity index 88%
rename from forum-network/src/tests/wdag.test.html
rename to forum-network/src/tests/wdg.test.html
index 49eece4..bc53e80 100644
--- a/forum-network/src/tests/wdag.test.html
+++ b/forum-network/src/tests/wdg.test.html
@@ -1,7 +1,7 @@
- WDAG test
+ Weighted Directed Graph test
@@ -24,4 +24,4 @@
});
chai.should();
-
+