UNPKG

jointjs

Version:

JavaScript diagramming library

631 lines (505 loc) 22.1 kB
'use strict'; QUnit.module('cellView', function(hooks) { var paper; var cellView; hooks.beforeEach(function() { // !! TODO !! // Should be able to create a CellView instance without the graph or paper. var $fixture = $('<div>', { id: 'qunit-fixture' }).appendTo(document.body); paper = new joint.dia.Paper; paper.render().$el.appendTo($fixture); var cell = new joint.dia.Element({ type: 'element', markup: '<rect/>' }); paper.model.addCell(cell); cellView = paper.findViewByModel(cell); }); hooks.afterEach(function() { paper.remove(); paper = null; cellView = null; }); QUnit.module('can(feature)', function(hooks) { QUnit.test('should be a function', function(assert) { assert.equal(typeof joint.dia.CellView.prototype.can, 'function'); }); QUnit.test('options.interactive = false', function(assert) { cellView.options.interactive = false; assert.notOk(cellView.can('someFeature')); }); QUnit.test('options.interactive = true', function(assert) { cellView.options.interactive = true; assert.ok(cellView.can('someFeature')); }); QUnit.test('options.interactive = { someFeature: false }', function(assert) { cellView.options.interactive = { someFeature: false }; assert.notOk(cellView.can('someFeature')); }); QUnit.test('options.interactive = { someFeature: true }', function(assert) { cellView.options.interactive = { someFeature: true }; assert.ok(cellView.can('someFeature')); }); QUnit.test('options.interactive = function(cellView) { }', function(assert) { var called = false; cellView.options.interactive = function(cellView) { called = true; return false; }; assert.notOk(cellView.can('someFeature')); assert.ok(called); }); }); QUnit.module('highlighting', function() { QUnit.test('default highlighter', function(assert) { paper.options.highlighting['default'] = { name: 'addClass' }; cellView.highlight(); assert.ok(cellView.$el.hasClass(joint.highlighters.addClass.className)); }); QUnit.test('highlighter specified by name only', function(assert) { cellView.highlight(null, { highlighter: 'addClass' }); assert.ok(cellView.$el.hasClass(joint.highlighters.addClass.className)); }); QUnit.module('addClass', function() { QUnit.test('default class name', function(assert) { cellView.highlight(null, { highlighter: { name: 'addClass' }}); assert.ok(cellView.$el.hasClass(joint.highlighters.addClass.className)); cellView.unhighlight(null, { highlighter: { name: 'addClass' }}); assert.notOk(cellView.$el.hasClass(joint.highlighters.addClass.className)); }); QUnit.test('with defined class name', function(assert) { cellView.highlight(null, { highlighter: { name: 'addClass', options: { className: 'xx' }}}); assert.ok(cellView.$el.hasClass('xx')); cellView.unhighlight(null, { highlighter: { name: 'addClass', options: { className: 'xx' }}}); assert.notOk(cellView.$el.hasClass('xx')); }); }); }); QUnit.module('Attributes', function(hooks) { var cell; hooks.beforeEach(function() { cell = cellView.model; cell.resize(100,100).position(0, 0); }); QUnit.module('Merging', function(hooks) { hooks.beforeEach(function() { cell.set('markup', [{ tagName: 'rect', selector: 'selector1', groupSelector: ['groupSelector', 'groupSelector1'] }, { tagName: 'rect', selector: 'selector2', groupSelector: ['groupSelector', 'groupSelector2'] }]); }); hooks.afterEach(function(assert) { assert.equal(cellView.el.querySelector('[joint-selector="selector1"]').getAttribute('test'), 'selector'); }); QUnit.test('selector, groupSelector(n > 1)', function() { cell.attr({ selector1: { test: 'selector' }, groupSelector: { test: 'groupSelector' } }); }); QUnit.test('groupSelector(n > 1), selector', function() { cell.attr({ groupSelector: { test: 'groupSelector' }, selector1: { test: 'selector' } }); }); QUnit.test('selector, groupSelector(n === 1)', function() { cell.attr({ selector1: { test: 'selector' }, groupSelector1: { test: 'groupSelector' } }); }); QUnit.test('groupSelector(n === 1), selector', function() { cell.attr({ groupSelector1: { test: 'groupSelector' }, selector1: { test: 'selector' } }); }); }); QUnit.module('Type: Set', function(hooks) { var rectA, rectB; hooks.beforeEach(function() { cell.set('markup', '<rect class="a"/><rect class="b"/>'); rectA = cellView.vel.findOne('.a'); rectB = cellView.vel.findOne('.b'); }); QUnit.test('Sanity', function(assert) { var spy = sinon.spy(); cell.constructor.attributes || (cell.constructor.attributes = {}); cell.constructor.attributes.setTestAttribute = { set: spy }; cell.attr('.a/setTestAttribute', 'value'); assert.ok(spy.calledOnce); assert.ok(spy.calledOn(cellView)); assert.ok(spy.calledWith( 'value', sinon.match.instanceOf(g.Rect), rectA.node, cell.attr('.a') )); delete cell.constructor.attributes.setTestAttribute; }); QUnit.test('Basics', function(assert) { cell.attr({ '.b': { fill: { type: 'radialGradient', stops: [ { offset: '95%', color: '#3498DB' }, { offset: '98%', color: '#9B59B6' } ] } } }); assert.notEqual(rectB.attr('fill'), null); }); }); QUnit.module('Type: Position', function(hooks) { var rectA, rectB; hooks.beforeEach(function() { cell.set('markup', '<rect class="a"/><rect class="b"/>'); rectA = cellView.vel.findOne('.a'); rectB = cellView.vel.findOne('.b'); }); QUnit.test('Sanity', function(assert) { var spy = sinon.spy(); cell.constructor.attributes || (cell.constructor.attributes = {}); cell.constructor.attributes.positionTestAttribute = { position: spy }; cell.attr('.a/positionTestAttribute', 'value'); assert.ok(spy.calledOnce); assert.ok(spy.calledOn(cellView)); assert.ok(spy.calledWith( 'value', sinon.match.instanceOf(g.Rect), rectA.node, cell.attr('.a') )); delete cell.constructor.attributes.positionTestAttribute; }), QUnit.test('Basics', function(assert) { cell.attr({ '.a': { refWidth: '100%', refHeight: '100%', refX: 0, refY: 10 }, '.b': { refWidth: '50%', refHeight: '50%', refX: '50%', refY: '50%' } }); assert.deepEqual(rectA.bbox().toString(), '0@10 100@110'); assert.deepEqual(rectB.bbox().toString(), '50@50 100@100'); // Attributes are not actually set on the DOM Element assert.equal(rectA.attr('refWidth'), null); assert.equal(rectA.attr('refHeight'), null); assert.equal(rectB.attr('refX'), null); assert.equal(rectB.attr('refY'), null); }); QUnit.test('With Ref', function(assert) { cell.attr({ '.a': { refWidth: '100%', refHeight: '100%', refX: 10, refY: 10 }, '.b': { ref: '.a', refWidth: '50%', refHeight: '50%', refX: '50%', refY: '50%' } }); assert.deepEqual(rectA.bbox().toString(), '10@10 110@110'); assert.deepEqual(rectB.bbox().toString(), '60@60 110@110'); }); QUnit.test('With Ref and Rotatable Group', function(assert) { var REF_DY = 10; var RECT_WIDTH = 50; cell.set('markup', [{ tagName: 'g', selector: 'rotatable', children: [{ tagName: 'rect', selector: '.a', className: 'a' }] }, { tagName: 'rect', selector: '.b', className: 'b' }, { tagName: 'rect', selector: '.c', className: 'c' }]); cell.attr({ '.a': { width: 100, height: 100, x: 0, y: 0 }, '.b': { width: RECT_WIDTH, height: 50, ref: '.a', refDy: REF_DY, refX: 0.5 }, '.c': { width: RECT_WIDTH, height: 50, ref: '.b', refDy: REF_DY, refX: 0.5 } }); cell.set('angle', 45); rectA = cellView.vel.findOne('.a'); rectB = cellView.vel.findOne('.b'); var rectC = cellView.vel.findOne('.c'); var bboxA = rectA.getBBox({ target: paper.svg }); var bboxB = rectB.getBBox({ target: paper.svg }); var bboxC = rectC.getBBox({ target: paper.svg }); assert.equal(Math.round(bboxB.y - bboxA.y - bboxA.height), REF_DY); assert.equal(Math.round(bboxC.y - bboxB.y - bboxB.height), REF_DY); assert.equal(Math.round(bboxC.x - bboxB.x), RECT_WIDTH / 2); }); QUnit.test('Position stacking', function(assert) { // Positin does not override the previous position. // The results are added up. cell.attr({ '.b': { refWidth: '50%', refHeight: '50%', refX: '50%', refX2: 20, refY: '50%', refY2: 20 } }); assert.deepEqual(rectB.bbox().toString(), '70@70 120@120'); }); QUnit.test('Position && Transform', function(assert) { cell.attr({ '.b': { refWidth: '50%', refHeight: '50%', refX: '50%', refY: '50%', transform: 'translate(10,10)' } }); assert.deepEqual(rectB.bbox().toString(), '60@60 110@110'); cell.attr({ '.b': { transform: 'scale(2,2)' } }); assert.deepEqual(rectB.bbox().toString(), '50@50 150@150'); cell.attr({ '.b': { transform: 'translate(10,10) scale(2,2)' } }); assert.deepEqual(rectB.bbox().toString(), '60@60 160@160'); }); }); QUnit.module('Type: Offset', function(hooks) { var rectA, rectB; hooks.beforeEach(function() { cell.set('markup', '<rect class="a"/><rect class="b"/>'); rectA = cellView.vel.findOne('.a'); rectB = cellView.vel.findOne('.b'); }); QUnit.test('Sanity', function(assert) { var spy = sinon.spy(); cell.constructor.attributes || (cell.constructor.attributes = {}); cell.constructor.attributes.offsetTestAttribute = { offset: spy }; cell.attr('.a/offsetTestAttribute', 'value'); // Rect has no dimension yet assert.notOk(spy.called); cell.attr({ '.a': { height: 100, width: 100 } }); assert.ok(spy.calledOnce); assert.ok(spy.calledOn(cellView)); assert.ok(spy.calledWith( 'value', sinon.match.instanceOf(g.Rect), rectA.node, cell.attr('.a') )); delete cell.constructor.attributes.offsetTestAttribute; }), QUnit.test('Basics', function(assert) { cell.attr({ '.b': { refWidth: '50%', refHeight: '50%', refX: '50%', refY: '50%', xAlignment: 'middle', yAlignment: 'middle' } }); assert.deepEqual(rectB.bbox().toString(), '25@25 75@75'); // Attributes are not actually set on the DOM Element assert.equal(rectB.attr('xAlignment'), null); assert.equal(rectB.attr('yAlignment'), null); }); QUnit.test('With Ref', function(assert) { cell.attr({ '.a': { refWidth: '100%', refHeight: '100%', refX: 10, refY: 10 }, '.b': { ref: '.a', refWidth: '50%', refHeight: '50%', refX: '50%', refY: '50%', xAlignment: 'middle', yAlignment: 'middle' } }); assert.deepEqual(rectA.bbox().toString(), '10@10 110@110'); assert.deepEqual(rectB.bbox().toString(), '35@35 85@85'); cell.attr({ '.a': { transform: 'scale(2,2)' } }); assert.deepEqual(rectA.bbox().toString(), '10@10 210@210'); assert.deepEqual(rectB.bbox().toString(), '60@60 160@160'); }); QUnit.test('Offset && Transform', function(assert) { cell.attr({ '.b': { transform: 'translate(10,10)', refWidth: '50%', refHeight: '50%', refX: '50%', refY: '50%', xAlignment: 'middle', yAlignment: 'middle' } }); assert.deepEqual(rectB.bbox().toString(), '35@35 85@85'); cell.attr({ '.b': { transform: 'scale(3,3)' } }); assert.deepEqual(rectB.bbox().toString(), '-25@-25 125@125'); cell.attr({ '.b': { transform: 'translate(10,10) scale(3,3)' } }); assert.deepEqual(rectB.bbox().toString(), '-15@-15 135@135'); }); }); QUnit.module('Backwards compatibility', function() { QUnit.test('inline transform attribute', function(assert) { cell.set('markup', '<rect class="a" transform="translate(10,10)"/>'); var rect = cellView.vel.findOne('.a'); cell.attr('rect/style', { fill: 'red' }); // set attribute assert.equal(rect.attr('transform'), 'translate(10,10)', 'inline attribute stays untouched'); cell.attr('rect/refX', 20); // position attribute assert.equal(rect.attr('transform'), 'matrix(1,0,0,1,20,0)', 'inline attribute is disregarder'); }); }); QUnit.module('Text', function(hooks) { hooks.beforeEach(function() { cell.set('markup', '<rect/><text/>'); }); QUnit.test('attribute "x"', function(assert) { var X = 23; function testTextOffset(offset) { var text = cellView.vel.findOne('text'); var tspans = text.find('tspan'); tspans.forEach(function(tspan) { assert.equal(tspan.bbox(false, cellView.el).x, offset, 'Offset of "' + tspan.node.textContent + '""'); }); } assert.expect(6); cell.attr({ text: { refX: null, x: X, text: 'single line - no refX and with x' }}, { dirty: true }); testTextOffset(X); cell.attr({ text: { refX: X, x: X, text: 'single line - with refX and x' }}, { dirty: true }); testTextOffset(X + X); cell.attr({ text: { refX: null, x: X, text: '1. line - no refX and with x\n2. line - no refX and with x' }}, { dirty: true }); testTextOffset(X); cell.attr({ text: { refX: X, x: X, text: '1. line - with refX and x\n2. line - with refX and x' }}, { dirty: true }); testTextOffset(X + X); }); }); QUnit.module('Event', function(hooks) { hooks.beforeEach(function() { cell.set('markup', '<g class="ab"><rect class="a"/><rect class="b"/></g><rect class="c"/>'); }); QUnit.test('sanity', function(assert) { var paperSpy = sinon.spy(); var cellViewSpy = sinon.spy(); cell.attr('.ab/event', 'test-event'); paper.on('test-event', paperSpy); cellView.on('test-event', cellViewSpy); // Event should be triggered simulate.mousedown({ el: cellView.el.querySelector('.ab') }); simulate.mouseup({ el: cellView.el.querySelector('.ab') }); simulate.mousedown({ el: cellView.el.querySelector('.a') }); simulate.mouseup({ el: cellView.el.querySelector('.a') }); simulate.mousedown({ el: cellView.el.querySelector('.b') }); simulate.mouseup({ el: cellView.el.querySelector('.b') }); assert.equal(paperSpy.callCount, 3); assert.equal(cellViewSpy.callCount, 3); assert.ok(paperSpy.alwaysCalledWith( cellView, sinon.match.instanceOf($.Event), sinon.match.number, sinon.match.number )); assert.ok(cellViewSpy.alwaysCalledWith( sinon.match.instanceOf($.Event), sinon.match.number, sinon.match.number )); // Event should not be triggered paperSpy.resetHistory(); cellViewSpy.resetHistory(); simulate.mousedown({ el: cellView.el.querySelector('.c') }); assert.notOk(paperSpy.called); assert.notOk(cellViewSpy.called); }); }); QUnit.module('resetOffset', function(hooks) { hooks.beforeEach(function() { cell.set('markup', 'path'); }); QUnit.test('sanity', function(assert) { cell.attr('path/d', 'M 10 10 20 20'); assert.equal(cellView.getBBox().toString(), '10@10 20@20'); cell.attr('path/resetOffset', true); assert.equal(cellView.getBBox().toString(), '0@0 10@10'); cell.attr('path/resetOffset', false); assert.equal(cellView.getBBox().toString(), '10@10 20@20'); }); }); }); });