UNPKG

jointjs

Version:

JavaScript diagramming library

706 lines (634 loc) 35.5 kB
QUnit.module('joint.dia.Paper', function(hooks) { var Paper = joint.dia.Paper; var paper; var paperEl; var graph; function cellNodesCount(paper) { return V(paper.cells).children().length; } function addCells(graph) { var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); var link = new joint.shapes.standard.Link(); rect1.resize(100, 100); rect2.resize(100, 100); rect1.position(-100, -100); rect2.position(100, 100); link.source(rect1); link.target(rect2); link.vertices([{ x: 0, y: 300 }]); rect1.addTo(graph); rect2.addTo(graph); link.addTo(graph); } hooks.beforeEach(function() { var fixtureEl = document.getElementById('qunit-fixture') || document.createElement('div'); paperEl = document.createElement('div'); fixtureEl.id = 'qunit-fixture'; fixtureEl.appendChild(paperEl); document.body.appendChild(fixtureEl); graph = new joint.dia.Graph; }); hooks.afterEach(function() { if (paper) paper.remove(); graph = null; paper = null; paperEl = null; }); QUnit.test('sanity', function(assert) { paper = new Paper({ el: paperEl }); assert.ok(paper.svg.id); }); QUnit.module('async = FALSE', function(hooks) { hooks.beforeEach(function() { paper = new Paper({ el: paperEl, model: graph, async: false }); }); QUnit.module('getContentArea() > options > useModelGeometry', function() { QUnit.test('useModelGeometry = FALSE', function(assert) { var area = paper.getContentArea(); assert.ok(area instanceof g.Rect); assert.deepEqual(area.toJSON(), { x: 0, y: 0, width: 0, height: 0 }); paper.freeze(); addCells(graph); area = paper.getContentArea(); assert.ok(area instanceof g.Rect); assert.deepEqual(area.toJSON(), { x: 0, y: 0, width: 0, height: 0 }); paper.unfreeze(); area = paper.getContentArea(); assert.deepEqual(area.toJSON(), { x: -100, y: -100, width: 300, height: 400 }); }); QUnit.test('useModelGeometry = TRUE', function(assert) { var area = paper.getContentArea({ useModelGeometry: true }); assert.ok(area instanceof g.Rect); assert.deepEqual(area.toJSON(), { x: 0, y: 0, width: 0, height: 0 }); paper.freeze(); addCells(graph); area = paper.getContentArea({ useModelGeometry: true }); assert.ok(area instanceof g.Rect); assert.deepEqual(area.toJSON(), { x: -100, y: -100, width: 300, height: 400 }); paper.unfreeze(); area = paper.getContentArea({ useModelGeometry: true }); assert.deepEqual(area.toJSON(), { x: -100, y: -100, width: 300, height: 400 }); }); }); QUnit.module('fitToContent() > options > useModelGeometry', function() { [0.5, 1, 2].forEach(function(scale) { QUnit.test('scale = ' + scale + ' > useModelGeometry = TRUE', function(assert) { paper.scale(scale); //scale = 1; var expected; var area = paper.fitToContent({ useModelGeometry: true }); assert.ok(area instanceof g.Rect); expected = { x: 0, y: 0, width: 1 / scale, height: 1 / scale }; assert.deepEqual(area.toJSON(), expected); assert.deepEqual(paper.getArea().toJSON(), expected); addCells(graph); area = paper.fitToContent({ useModelGeometry: true }); expected = { x: 0, y: 0, width: 200, height: 300 }; assert.deepEqual(area.toJSON(), expected); assert.deepEqual(paper.getArea().toJSON(), expected); area = paper.fitToContent({ useModelGeometry: true, allowNewOrigin: 'any' }); expected = { x: -100, y: -100, width: 300, height: 400 }; assert.deepEqual(area.toJSON(), expected); assert.deepEqual(paper.getArea().toJSON(), expected); var padding = 20; area = paper.fitToContent({ useModelGeometry: true, allowNewOrigin: 'any', padding: padding }); expected = { x: -100 - padding / scale, y: - 100 - padding / scale, width: 300 + 2 * padding / scale, height: 400 + 2 * padding / scale }; assert.deepEqual(area.toJSON(), expected); assert.deepEqual(paper.getArea().toJSON(), expected); }); }); }); Object.keys(Paper.sorting).forEach(function(sortingType) { QUnit.module('sorting = ' + sortingType, function(hooks) { hooks.beforeEach(function() { paper.options.sorting = Paper.sorting[sortingType]; }); QUnit.module('options', function() { QUnit.module('sorting', function() { QUnit.test('sanity', function(assert) { var rect1 = new joint.shapes.standard.Rectangle({ z: 0 }); var rect2 = new joint.shapes.standard.Rectangle({ z: 2 }); var rect3 = new joint.shapes.standard.Rectangle({ z: 1 }); var sortViewsExactSpy = sinon.spy(paper, 'sortViewsExact'); // RESET CELLS graph.resetCells([rect1, rect2, rect3]); var rect1View = rect1.findView(paper); var rect2View = rect2.findView(paper); var rect3View = rect3.findView(paper); assert.equal(rect1View.el.previousElementSibling, null); assert.equal(rect2View.el.previousElementSibling, rect3View.el); assert.equal(rect3View.el.previousElementSibling, rect1View.el); assert.equal(sortViewsExactSpy.callCount, paper.options.sorting === Paper.sorting.EXACT ? 1 : 0); // CHANGE Z rect3.toFront(); assert.equal(sortViewsExactSpy.callCount, paper.options.sorting === Paper.sorting.EXACT ? 2 : 0); if (paper.options.sorting === Paper.sorting.NONE) { assert.equal(rect1View.el.previousElementSibling, null); assert.equal(rect2View.el.previousElementSibling, rect3View.el); assert.equal(rect3View.el.previousElementSibling, rect1View.el); } else { assert.equal(rect1View.el.previousElementSibling, null); assert.equal(rect2View.el.previousElementSibling, rect1View.el); assert.equal(rect3View.el.previousElementSibling, rect2View.el); } sortViewsExactSpy.resetHistory(); rect3.translate(10, 10); assert.ok(sortViewsExactSpy.notCalled); // ADD CELLS graph.clear(); graph.addCells([rect1, rect2, rect3]); assert.equal(sortViewsExactSpy.callCount, paper.options.sorting === Paper.sorting.EXACT ? 1 : 0); if (paper.options.sorting !== Paper.sorting.NONE) { rect1View = rect1.findView(paper); rect2View = rect2.findView(paper); rect3View = rect3.findView(paper); assert.equal(rect1View.el.previousElementSibling, null); assert.equal(rect2View.el.previousElementSibling, rect1View.el); assert.equal(rect3View.el.previousElementSibling, rect2View.el); } }); QUnit.test('frozen', function(assert) { paper.freeze(); var rect1 = new joint.shapes.standard.Rectangle({ z: 0 }); var rect2 = new joint.shapes.standard.Rectangle({ z: 2 }); var rect3 = new joint.shapes.standard.Rectangle({ z: 1 }); var sortViewsExactSpy = sinon.spy(paper, 'sortViewsExact'); graph.resetCells([rect1, rect2, rect3]); var rect1View = rect1.findView(paper); var rect2View = rect2.findView(paper); var rect3View = rect3.findView(paper); rect3.toFront(); assert.ok(sortViewsExactSpy.notCalled); paper.unfreeze(); assert.equal(sortViewsExactSpy.callCount, paper.options.sorting === Paper.sorting.EXACT ? 1 : 0); if (paper.options.sorting !== Paper.sorting.NONE) { assert.equal(rect1View.el.previousElementSibling, null); assert.equal(rect2View.el.previousElementSibling, rect1View.el); assert.equal(rect3View.el.previousElementSibling, rect2View.el); } sortViewsExactSpy.resetHistory(); paper.freeze(); rect3.translate(10, 10); paper.unfreeze(); assert.ok(sortViewsExactSpy.notCalled); }); }); QUnit.module('viewport', function() { QUnit.test('sanity', function(assert) { var visible = true; var viewportSpy = sinon.spy(function() { return visible; }); paper.options.viewport = viewportSpy; var rect = new joint.shapes.standard.Rectangle(); rect.addTo(graph); var rectView = rect.findView(paper); assert.ok(viewportSpy.calledOnce); // TODO: is false ok? assert.ok(viewportSpy.calledWithExactly(rectView, false, paper)); assert.ok(viewportSpy.calledOn(paper)); assert.equal(rectView.el.parentNode, paper.cells); viewportSpy.resetHistory(); visible = false; rect.translate(10, 0); assert.ok(viewportSpy.calledOnce); assert.ok(viewportSpy.calledWithExactly(rectView, false, paper)); viewportSpy.resetHistory(); rect.translate(10, 0); assert.ok(viewportSpy.calledOnce); assert.ok(viewportSpy.calledWithExactly(rectView, true, paper)); assert.notOk(rectView.el.parentNode); }); }); QUnit.module('onViewUpdate', function() { QUnit.test('sanity', function(assert) { var onViewUpdateSpy = sinon.spy(); paper.options.onViewUpdate = onViewUpdateSpy; var rect = new joint.shapes.standard.Rectangle(); rect.addTo(graph, { test1: true }); var rectView = rect.findView(paper); assert.ok(onViewUpdateSpy.calledOnce); assert.ok(onViewUpdateSpy.calledWithExactly(rectView, sinon.match.number, sinon.match({ test1: true }), paper)); assert.ok(onViewUpdateSpy.calledOn(paper)); onViewUpdateSpy.resetHistory(); rect.translate(10, 0, { test2: true }); assert.ok(onViewUpdateSpy.calledOnce); assert.ok(onViewUpdateSpy.calledWithExactly(rectView, sinon.match.number, sinon.match({ test2: true }), paper)); }); QUnit.test('update connected links', function(assert) { var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); var link1 = new joint.shapes.standard.Link(); var link2 = new joint.shapes.standard.Link(); link1.source(rect1); link1.target(rect2); link2.target(link1); rect1.addTo(graph); rect2.addTo(graph); link1.addTo(graph); link2.addTo(graph); var onViewUpdateSpy = sinon.spy(paper.options, 'onViewUpdate'); rect1.translate(10, 0, { test: true }); assert.ok(onViewUpdateSpy.calledThrice); assert.ok(onViewUpdateSpy.calledWithExactly(link1.findView(paper), sinon.match.number, sinon.match({ test: true }), paper)); assert.ok(onViewUpdateSpy.calledWithExactly(link2.findView(paper), sinon.match.number, sinon.match({ test: true }), paper)); assert.ok(onViewUpdateSpy.calledWithExactly(rect1.findView(paper), sinon.match.number, sinon.match({ test: true }), paper)); }); }); QUnit.module('onViewPostponed', function() { QUnit.test('sanity', function(assert) { var leftoverFlag = 1; var onViewPostponedSpy = sinon.spy(function() { leftoverFlag = 0; return true; }); paper.options.onViewPostponed = onViewPostponedSpy; paper.options.elementView = joint.dia.ElementView.extend({ confirmUpdate: function() { return leftoverFlag; } }); var rect = new joint.shapes.standard.Rectangle(); rect.addTo(graph); var rectView = rect.findView(paper); assert.ok(onViewPostponedSpy.calledOnce); assert.ok(onViewPostponedSpy.calledWithExactly(rectView, sinon.match.number, paper)); assert.ok(onViewPostponedSpy.calledOn(paper)); onViewPostponedSpy.resetHistory(); rect.translate(10, 0); assert.ok(onViewPostponedSpy.notCalled); }); QUnit.test('force postponed view update', function(assert) { paper.options.viewport = function(view) { return view.model.isLink(); }; var onViewPostponedSpy = sinon.spy(paper.options, 'onViewPostponed'); var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); var link = new joint.shapes.standard.Link(); link.source(rect1); link.target(rect2); paper.freeze(); link.addTo(graph); rect1.addTo(graph); rect2.addTo(graph); paper.unfreeze(); assert.ok(onViewPostponedSpy.calledOnce); assert.ok(onViewPostponedSpy.calledWithExactly(link.findView(paper), sinon.match.number, paper)); assert.equal(cellNodesCount(paper), 3); }); }); }); QUnit.module('prototype', function() { QUnit.module('updateViews()', function() { QUnit.module('options', function() { QUnit.test('batchSize', function(assert) { paper.freeze(); var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); rect1.addTo(graph); rect2.addTo(graph); var res = paper.updateViews({ batchSize: 1 }); assert.deepEqual(res, { batches: 2, updated: 2, priority: 0 }); assert.equal(cellNodesCount(paper), 2); }); QUnit.test('viewport', function(assert) { paper.freeze(); var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); rect1.addTo(graph); rect2.addTo(graph); var viewportSpy = sinon.spy(function() { return true; }); var res = paper.updateViews({ viewport: viewportSpy }); assert.deepEqual(res, { batches: 1, updated: 2, priority: 0 }); assert.equal(cellNodesCount(paper), 2); assert.ok(viewportSpy.calledTwice); // Unmount a view because it's not in the viewport and update views with a different viewport paper.checkViewport({ viewport: function() { return false; } }); rect1.translate(10, 0); paper.updateViews({ viewport: function() { return true; } }); assert.equal(cellNodesCount(paper), 1); }); }); }); QUnit.test('dumpViews()', function(assert) { var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); var link = new joint.shapes.standard.Link(); rect1.resize(100, 100); rect2.resize(100, 100); rect2.position(200, 0); link.source(rect1); link.target(rect2); paper.options.viewport = function(view) { return view.model === rect1; }; rect1.addTo(graph); rect2.addTo(graph); link.addTo(graph); assert.equal(cellNodesCount(paper), 1); paper.dumpViews(); assert.equal(cellNodesCount(paper), 3); assert.checkBbox(paper, rect1, 0, 0, 100, 100); assert.checkBbox(paper, rect2, 200, 0, 100, 100); assert.checkBbox(paper, link, 100, 50, 100, 0); }); QUnit.test('checkViewport()', function(assert) { var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); var rect3 = new joint.shapes.standard.Rectangle(); var rectNever = new joint.shapes.standard.Rectangle(); var rectAlways = new joint.shapes.standard.Rectangle(); paper.options.viewport = function(view) { return [rect1, rectAlways].indexOf(view.model) > -1; }; paper.freeze(); rect1.addTo(graph); rect2.addTo(graph); rect3.addTo(graph); rectNever.addTo(graph); rectAlways.addTo(graph); paper.unfreeze(); var rect1View = rect1.findView(paper); var rect2View = rect2.findView(paper); var rect3View = rect3.findView(paper); var rectAlwaysView = rectAlways.findView(paper); paper.options.viewport = function(view) { return [rect2, rect3, rectAlways].indexOf(view.model) > -1; }; assert.equal(cellNodesCount(paper), 2); assert.equal(rect1View.el.parentNode, paper.cells); assert.equal(rectAlwaysView.el.parentNode, paper.cells); var res1 = paper.checkViewport(); assert.deepEqual(res1, { mounted: 2, unmounted: 1 }); paper.updateViews(); assert.equal(cellNodesCount(paper), 3); assert.equal(rect2View.el.parentNode, paper.cells); assert.equal(rect3View.el.parentNode, paper.cells); assert.equal(rectAlwaysView.el.parentNode, paper.cells); paper.options.viewport = function(view) { return [rect1, rectAlways].indexOf(view.model) > -1; }; var res2 = paper.checkViewport(); assert.deepEqual(res2, { mounted: 1, unmounted: 2 }); paper.updateViews(); assert.equal(cellNodesCount(paper), 2); assert.equal(rect1.findView(paper).el.parentNode, paper.cells); assert.equal(rectAlwaysView.el.parentNode, paper.cells); }); QUnit.test('requireView()', function(assert) { assert.equal(paper.requireView(), null); paper.options.viewport = function() { return false; }; var rect = new joint.shapes.standard.Rectangle(); rect.translate(201, 202); rect.resize(101, 102); rect.addTo(graph); var rectView = rect.findView(paper); assert.notOk(rectView.el.parentNode); rectView = paper.requireView(rect); assert.ok(rectView.el.parentNode, paper.cells); assert.checkBbox(paper, rect, 201, 202, 101, 102); }); QUnit.module('freeze(), unfreeze(), isFrozen()', function() { QUnit.test('sanity', function(assert) { assert.equal(cellNodesCount(paper), 0); assert.notOk(paper.isFrozen()); paper.freeze(); assert.ok(paper.isFrozen()); var rect = new joint.shapes.standard.Rectangle(); rect.addTo(graph); assert.ok(paper.isFrozen()); assert.equal(cellNodesCount(paper), 0); paper.unfreeze(); assert.notOk(paper.isFrozen()); assert.equal(cellNodesCount(paper), 1); }); QUnit.test('add+remove+change+add while frozen', function(assert) { paper.freeze(); var rect = new joint.shapes.standard.Rectangle(); rect.resize(50, 50); rect.position(0, 0); rect.addTo(graph); rect.remove(); rect.resize(101, 102); rect.translate(201, 202); rect.addTo(graph); paper.unfreeze(); assert.equal(cellNodesCount(paper), 1); assert.checkBbox(paper, rect, 201, 202, 101, 102); rect.remove(); assert.equal(cellNodesCount(paper), 0); }); QUnit.test('keep frozen on reset views', function(assert) { paper.freeze(); var rect = new joint.shapes.standard.Rectangle(); rect.resize(101, 102); rect.position(201, 202); graph.resetCells([rect]); assert.equal(cellNodesCount(paper), 0); assert.ok(paper.isFrozen()); paper.unfreeze(); assert.notOk(paper.isFrozen()); assert.equal(cellNodesCount(paper), 1); assert.checkBbox(paper, rect, 201, 202, 101, 102); }); QUnit.module('options', function() { QUnit.module('key', function() { QUnit.test('keep unfrozen', function(assert) { assert.notOk(paper.isFrozen()); paper.freeze({ key: 'test1' }); assert.ok(paper.isFrozen()); paper.unfreeze({ key: 'test2' }); assert.ok(paper.isFrozen()); paper.unfreeze({ key: 'test1' }); assert.notOk(paper.isFrozen()); }); QUnit.test('keep frozen', function(assert) { paper.freeze(); assert.ok(paper.isFrozen()); paper.freeze({ key: 'test1' }); assert.ok(paper.isFrozen()); paper.unfreeze({ key: 'test2' }); assert.ok(paper.isFrozen()); paper.unfreeze({ key: 'test1' }); assert.ok(paper.isFrozen()); }); QUnit.test('keep unfrozen - nested', function(assert) { assert.notOk(paper.isFrozen()); // UNFROZEN paper.freeze({ key: 'test1' }); assert.ok(paper.isFrozen()); // < nested paper.freeze({ key: 'test2' }); assert.ok(paper.isFrozen()); paper.unfreeze({ key: 'test2' }); assert.ok(paper.isFrozen()); // nested > paper.unfreeze({ key: 'test1' }); assert.notOk(paper.isFrozen()); }); QUnit.test('keep frozen - nested', function(assert) { paper.freeze(); assert.ok(paper.isFrozen()); // FROZEN paper.freeze({ key: 'test1' }); assert.ok(paper.isFrozen()); // < nested paper.freeze({ key: 'test2' }); assert.ok(paper.isFrozen()); paper.unfreeze({ key: 'test2' }); assert.ok(paper.isFrozen()); // nested > paper.unfreeze({ key: 'test1' }); assert.ok(paper.isFrozen()); }); }); }); }); }); }); }); }); QUnit.module('async = TRUE, frozen = TRUE', function(hooks) { hooks.beforeEach(function() { addCells(graph); paper = new Paper({ el: paperEl, model: graph, async: true, frozen: true, sorting: Paper.sorting.APPROX }); }); QUnit.test('sanity', function(assert) { assert.ok(paper.isFrozen()); assert.ok(paper.isAsync()); assert.equal(cellNodesCount(paper), 0); }); QUnit.test('unfreeze existing cells', function(assert) { var done = assert.async(); paper.on('render:done', function() { assert.equal(cellNodesCount(paper), 3); done(); }); paper.unfreeze(); }); QUnit.test('dumping existing cells', function(assert) { paper.dumpViews(); assert.equal(cellNodesCount(paper), 3); }); }); QUnit.module('async = TRUE, frozen = FALSE', function(hooks) { hooks.beforeEach(function() { paper = new Paper({ el: paperEl, model: graph, async: true, frozen: false, sorting: Paper.sorting.APPROX }); }); QUnit.test('sanity', function(assert) { assert.notOk(paper.isFrozen()); assert.ok(paper.isAsync()); }); QUnit.module('prototype', function() { QUnit.module('freeze(), unfreeze(), isFrozen()', function() { QUnit.test('sanity', function(assert) { var done = assert.async(); assert.expect(5); paper.on('render:done', function() { assert.notOk(paper.isFrozen()); assert.equal(cellNodesCount(paper), 1); done(); }); assert.notOk(paper.isFrozen()); paper.freeze(); assert.ok(paper.isFrozen()); var rect = new joint.shapes.standard.Rectangle(); rect.addTo(graph); paper.unfreeze(); assert.equal(cellNodesCount(paper), 0); }); }); QUnit.module('options', function() { QUnit.test('progress + batchSize', function(assert) { var done = assert.async(); assert.expect(11); var progressCounter = 0; var progressSpy = sinon.spy(function(finished, processed, total) { assert.equal(processed, ++progressCounter); assert.equal(total, graph.getCells().length); if (finished) { assert.ok(paper.isFrozen()); assert.notOk(paper._updates.id); done(); } }); paper.on('render:done', function() { assert.equal(progressSpy.callCount, 3); progressSpy.alwaysCalledWith(sinon.match.boolean, sinon.match.number, sinon.match.number /* stats */); progressSpy.alwaysCalledOn(paper); progressSpy.resetHistory(); paper.freeze(); }); paper.freeze(); graph.resetCells([ new joint.shapes.standard.Rectangle(), new joint.shapes.standard.Rectangle(), new joint.shapes.standard.Rectangle(), new joint.shapes.standard.Rectangle() ]); paper.unfreeze({ batchSize: 1, progress: progressSpy }); }); }); }); QUnit.module('events', function() { QUnit.module('render:done', function() { QUnit.test('unfrozen', function(assert) { paper.freeze(); paper.unfreeze(); var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); var done = assert.async(); var renderDoneSpy = sinon.spy(function() { rect2.addTo(graph); }); paper.on('render:done', renderDoneSpy); graph.resetCells([rect1]); assert.expect(1); setTimeout(function() { assert.equal(renderDoneSpy.callCount, 2); done(); }, 100); }); QUnit.test('frozen', function(assert) { paper.unfreeze(); paper.freeze(); var rect1 = new joint.shapes.standard.Rectangle(); var rect2 = new joint.shapes.standard.Rectangle(); var done = assert.async(); var renderDoneSpy = sinon.spy(function() { rect2.addTo(graph); }); assert.expect(1); paper.on('render:done', renderDoneSpy); graph.resetCells([rect1]); setTimeout(function() { assert.equal(renderDoneSpy.callCount, 0); done(); }, 100); }); }); }); }); });