@itrigger/dagre-d3
Version:
A D3-based renderer for Dagre
326 lines (257 loc) • 10.8 kB
JavaScript
var expect = chai.expect;
d3.select("body").append("link")
.attr("rel", "stylesheet")
.attr("href", "/base/test/bundle-test.css");
describe("dagreD3", function() {
var svg;
var g;
beforeEach(function() {
svg = d3.select("body").append("svg");
g = new dagreD3.graphlib.Graph()
.setGraph({})
.setDefaultNodeLabel(function() { return {}; })
.setDefaultEdgeLabel(function() { return {}; });
});
afterEach(function() {
svg.remove();
});
describe("exports", function() {
_.each(["graphlib", "dagre", "intersect", "util"], function(lib) {
it(lib, function() {
expect(dagreD3[lib]).to.be.an("object");
});
});
it("render", function() {
expect(dagreD3.render).to.be.a("function");
});
it("version", function() {
expect(dagreD3.version).to.be.a("string");
});
});
describe("DOM elements", function() {
it("are created for each node", function() {
g.setNode("a", { id: "a" });
g.setNode("b", { id: "b" });
dagreD3.render()(svg, g);
expect(d3.select("#a").datum()).to.equal("a");
expect(d3.select("#b").datum()).to.equal("b");
// We should also be able to get to the element from the node object.
expect(g.node("a").elem).to.equal(d3.select("#a").node());
expect(g.node("b").elem).to.equal(d3.select("#b").node());
});
it("are created for each node label", function() {
g.setNode("a", { labelId: "a-lab" });
g.setNode("b", { labelId: "b-lab" });
dagreD3.render()(svg, g);
expect(d3.select("#a-lab").datum()).to.equal("a");
expect(d3.select("#b-lab").datum()).to.equal("b");
});
it("are created for each edge", function() {
g.setNode("a", {});
g.setNode("b", {});
g.setEdge("a", "b", { id: "ab" });
dagreD3.render()(svg, g);
expect(d3.select("#ab").datum()).eqls({ v: "a", w: "b" });
// We should also be able to get to the element from the edge object.
expect(g.edge("a", "b").elem).to.equal(d3.select("#ab").node());
});
it("preserve link to the elem even after re-rendering", function() {
g.setNode("a", {});
g.setNode("b", {});
g.setEdge("a", "b", { id: "ab" });
dagreD3.render()(svg, g);
// Remove elem from edge object and re-render
g.setEdge("a", "b", { id: "ab" });
dagreD3.render()(svg, g);
expect(g.edge("a", "b").elem).to.equal(d3.select("#ab").node());
});
it("are created for each edge label", function() {
g.setNode("a", {});
g.setNode("b", {});
g.setEdge("a", "b", { labelId: "ab-lab" });
dagreD3.render()(svg, g);
expect(d3.select("#ab-lab").datum()).eqls({ v: "a", w: "b" });
});
});
it("uses node's width and height if specified", function() {
g.setNode("a", { id: "a", width: 1000, height: 2000, padding: 0 });
dagreD3.render()(svg, g);
expect(Math.round(d3.select("#a").node().getBBox().width)).to.equal(1000);
expect(Math.round(d3.select("#a").node().getBBox().height)).to.equal(2000);
});
it("does not grow node dimensions when re-rendering", function() {
g.setNode("a", { id: "a" });
dagreD3.render()(svg, g);
var bbox = svg.select("#a rect").node().getBBox();
dagreD3.render()(svg, g);
var bbox2 = svg.select("#a rect").node().getBBox();
expect(bbox.width).equals(bbox2.width);
expect(bbox.height).equals(bbox2.height);
});
it("does not grow edge dimensions when re-rendering", function() {
g.setNode("a");
g.setNode("b");
g.setEdge("a", "b", { labelId: "ab", label: "foo" });
dagreD3.render()(svg, g);
var bbox = svg.select("#ab").node().getBBox();
dagreD3.render()(svg, g);
var bbox2 = svg.select("#ab").node().getBBox();
expect(bbox.width).equals(bbox2.width);
expect(bbox.height).equals(bbox2.height);
});
describe("HTML labels", function() {
it("can be created for a node", function() {
g.setNode("a", { labelType: "html", label: "<p id='a-lab'>Hello</p>" });
dagreD3.render()(svg, g);
expect(d3.select("#a-lab").empty()).to.be.false;
expect(d3.select("#a-lab").text()).equals("Hello");
});
it("can use an existing DOM element", function() {
var elem = document.createElement("p");
elem.setAttribute("id", "a-lab");
elem.innerHTML = "Hello";
g.setNode("a", { id: "a", labelType: "html", label: elem });
dagreD3.render()(svg, g);
expect(d3.select("#a #a-lab").empty()).to.be.false;
expect(d3.select("#a #a-lab").text()).equals("Hello");
});
it("can use an function that returns a DOM element", function() {
var elem = document.createElement("p");
elem.setAttribute("id", "a-lab");
elem.innerHTML = "Hello";
g.setNode("a", { id: "a", labelType: "html", label: function() { return elem; } });
dagreD3.render()(svg, g);
expect(d3.select("#a #a-lab").empty()).to.be.false;
expect(d3.select("#a #a-lab").text()).equals("Hello");
});
it("can be created for an edge", function() {
g.setNode("a", {});
g.setNode("b", {});
g.setEdge("a", "b", { labelType: "html", label: "<p id='ab-lab'>Hello</p>" });
dagreD3.render()(svg, g);
expect(d3.select("#ab-lab").empty()).to.be.false;
expect(d3.select("#ab-lab").text()).equals("Hello");
});
});
describe("SVG labels", function() {
it("can be created for a node", function() {
link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://google.com/');
link.setAttribute('target', '_blank');
link.setAttribute('id', 'a-lab');
link.textContent = 'Google';
g.setNode("a", { labelType: "svg", label: link });
dagreD3.render()(svg, g);
expect(d3.select("#a-lab").empty()).to.be.false;
expect(d3.select("#a-lab").text()).equals("Google");
});
it("can be created for an edge", function() {
link = document.createElementNS('http://www.w3.org/2000/svg', 'a');
link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://yahoo.com/');
link.setAttribute('target', '_blank');
link.setAttribute('id', 'ab-lab');
link.textContent = 'Yahoo';
g.setNode("a", {});
g.setNode("b", {});
g.setEdge("a", "b", { labelType: "svg", label: link });
dagreD3.render()(svg, g);
expect(d3.select("#ab-lab").empty()).to.be.false;
expect(d3.select("#ab-lab").text()).equals("Yahoo");
});
});
describe("breaks label lines", function() {
it("on '\\n'", function() {
g.setNode("a", { id: "a", label: "multi\nline" });
dagreD3.render()(svg, g);
var text = d3.select("#a text");
expect(text.empty()).to.be.false;
expect(d3.select(text.selectAll("tspan").nodes()[0]).text()).equals("multi");
expect(d3.select(text.selectAll("tspan").nodes()[1]).text()).equals("line");
});
it("on '\\\\n'", function() {
g.setNode("a", { id: "a", label: "multi\\nline" });
dagreD3.render()(svg, g);
var text = d3.select("#a text");
expect(text.empty()).to.be.false;
expect(d3.select(text.selectAll("tspan").nodes()[0]).text()).equals("multi");
expect(d3.select(text.selectAll("tspan").nodes()[1]).text()).equals("line");
});
});
describe("styles", function() {
var canonicalRed;
beforeEach(function() {
// Each browser has a different way to represent colors canonically. We
// create a dummy object here to get the canonical representation for the
// color red.
canonicalRed = svg.append("rect").style("fill", "#ff0000").style("fill");
});
it("can be applied to a node", function() {
g.setNode("a", { id: "a", style: "fill: #ff0000", shape: "rect" });
dagreD3.render()(svg, g);
expect(d3.select("#a rect").style("fill")).to.equal(canonicalRed);
});
it("can be applied to a node label", function() {
g.setNode("a", { labelId: "a-lab", labelStyle: "stroke: #ff0000" });
dagreD3.render()(svg, g);
expect(d3.select("#a-lab text").style("stroke")).to.equal(canonicalRed);
});
it("can be applied to an edge", function() {
g.setNode("a", {});
g.setNode("b", {});
g.setEdge("a", "b", { id: "ab", style: "stroke: #ff0000" });
dagreD3.render()(svg, g);
expect(d3.select("#ab path").style("stroke")).to.equal(canonicalRed);
});
it("can be applied to an edge label", function() {
g.setNode("a", {});
g.setNode("b", {});
g.setEdge("a", "b", { labelId: "ab-lab", labelStyle: "stroke: #ff0000" });
dagreD3.render()(svg, g);
expect(d3.select("#ab-lab text").style("stroke")).to.equal(canonicalRed);
});
});
describe("shapes", function() {
it("include a rect", function() {
g.setNode("a", { id: "a", shape: "rect", width: 100, height: 200, padding: 0 });
dagreD3.render()(svg, g);
var rect = d3.select("#a rect");
expect(rect.empty()).to.be.false;
expect(rect.node().getBBox().width).to.equal(100);
expect(rect.node().getBBox().height).to.equal(200);
});
it("include a circle", function() {
g.setNode("a", { id: "a", shape: "circle", width: 100, height: 250, padding: 0 });
dagreD3.render()(svg, g);
var circle = d3.select("#a circle");
expect(circle.empty()).to.be.false;
// Should be half of greater of width, height
expect(circle.attr("r") * 2).to.equal(250);
});
it("include an ellipse", function() {
g.setNode("a", { id: "a", shape: "ellipse", width: 100, height: 250, padding: 0 });
dagreD3.render()(svg, g);
var ellipse = d3.select("#a ellipse");
expect(ellipse.empty()).to.be.false;
expect(ellipse.attr("rx") * 2).to.equal(100);
expect(ellipse.attr("ry") * 2).to.equal(250);
});
});
describe("class", function() {
it("can be set for nodes", function() {
g.setNode("a", { id: "a", class: function(d) { return d + "-class"; } });
g.setNode("b", { id: "b", class: "b-class" });
dagreD3.render()(svg, g);
expect(d3.select("#a").classed("a-class")).to.be.true;
expect(d3.select("#b").classed("b-class")).to.be.true;
});
it("can be set for edges", function() {
g.setNode("a", { id: "a" });
g.setNode("b", { id: "b" });
g.setEdge("a", "b", { id: "c", class: function(d) { return d.v + d.w + "-class"; } });
g.setEdge("b", "a", { id: "d", class: "d-class" });
dagreD3.render()(svg, g);
expect(d3.select("#c").classed("ab-class")).to.be.true;
expect(d3.select("#d").classed("d-class")).to.be.true;
});
});
});