jointjs
Version:
JavaScript diagramming library
1,127 lines (859 loc) • 47.7 kB
JavaScript
'use strict';
QUnit.module('util', function(hooks) {
QUnit.test('util.interpolate', function(assert) {
var values = [0, .25, .5, .75, 1];
var numberInterpolation = joint.util.interpolate.number(0, 100);
var objectInterpolation = joint.util.interpolate.object({ x: 100, y: 200 }, { x: 200, y: 0 });
var hexColorInterpolation = joint.util.interpolate.hexColor('#FFFFFF', '#00FF77');
var unitInterpolation = joint.util.interpolate.unit('1em', '0.50em');
var numberArray = _.map(values, numberInterpolation);
var objectArray = _.map(values, objectInterpolation);
var hexColorArray = _.map(values, hexColorInterpolation);
var unitArray = _.map(values, unitInterpolation);
assert.deepEqual(numberArray, [
0, 25, 50, 75, 100
], 'Numbers interpolated.');
assert.deepEqual(objectArray, [
{ x: 100, y: 200 }, { x: 125, y: 150 }, { x: 150, y: 100 }, { x: 175, y: 50 }, { x: 200, y: 0 }
], 'Objects interpolated.');
assert.deepEqual(hexColorArray, [
'#ffffff', '#bfffdd', '#7fffbb', '#3fff99', '#00ff77'
], 'String hex colors interpolated.');
assert.deepEqual(unitArray, [
'1.00em', '0.88em', '0.75em', '0.63em', '0.50em'
], 'Numbers with units interpolated.');
});
QUnit.test('util.isPercentage', function(assert) {
assert.equal(joint.util.isPercentage(undefined), false, 'undefined => false');
assert.equal(joint.util.isPercentage(null), false, 'null => false');
assert.equal(joint.util.isPercentage(true), false, 'true => false');
assert.equal(joint.util.isPercentage(false), false, 'false => false');
assert.equal(joint.util.isPercentage(0), false, '0 => false');
assert.equal(joint.util.isPercentage(10), false, '10 => false');
assert.equal(joint.util.isPercentage(''), false, '\'\' => false');
assert.equal(joint.util.isPercentage('10'), false, '\'10\' => false');
assert.equal(joint.util.isPercentage('%'), true, '\'%\' => true');
assert.equal(joint.util.isPercentage('10%'), true, '\'10%\' => true');
assert.equal(joint.util.isPercentage('-10%'), true, '\'-10%\' => true');
});
QUnit.test('util.format.number', function(assert) {
var res = {
'5.00': ['.2f', 5],
'005': ['03d', 5],
'05.02': ['05.2f', 5.02],
'20.5%': ['.1%', .205],
'****5****': ['*^9', '5'],
'5********': ['*<9', '5'],
'********5': ['*>9', '5'],
'+3.14': ['+.f', 3.14],
'3.14': ['.f', 3.14],
'-3.14': ['+.f', -3.14],
'a': ['x', 10],
'A': ['X', 10],
'C0': ['02X', 192],
'1,234,567,890': [',', 1234567890]
};
_.each(res, function(input, output) {
assert.equal(joint.util.format.number(input[0], input[1]), output, 'number(' + input[0] + ', ' + input[1] + ') = ' + output);
});
});
QUnit.module('util.breakText', function(assert) {
// tests can't compare exact results as they may vary in different browsers
// This ensures that the tests will be more deterministic.
// For example, some browsers might have a different default font size/family.
var styles = {
'font-size': '12px',
'font-family': 'Courier New'
};
var text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
QUnit.test('sanity', function(assert) {
assert.equal(joint.util.breakText('', { width: 100 }, styles), '', 'An empty text was correctly broken.');
assert.equal(joint.util.breakText(text, { width: 0, height: 0 }, styles), '', 'A text was correctly broken when zero width and height provided.');
assert.ok(_.includes(joint.util.breakText(text, { width: 100 }, styles), '\n'),
'A text was broken when width A specified.');
assert.ok(_.includes(joint.util.breakText(text, { width: 15 }, styles), '\n'), 'A text was broken when width B specified.');
var brokenText = joint.util.breakText(text, { width: 100, height: 40 }, styles);
assert.ok(_.includes(brokenText, 'Lorem') && !_.includes(brokenText, 'elit.'), 'A text was trimmed when width & height specified.');
brokenText = joint.util.breakText(text, { width: 100, height: 50 }, _.extend({}, styles, { 'font-size': '18px' }));
assert.ok(_.includes(brokenText, '\n') || !_.includes(brokenText, 'elit.'), 'A text was broken when style specified.');
assert.throws(function() {
joint.util.breakText(text, { width: 100, height: 50 }, _.extend({}, styles, { 'font-size': '18px' }), { svgDocument: 'not-svg' });
}, /appendChild|undefined/, 'A custom svgDocument provided was recognized.');
});
function measureText(text, styles) {
var vText = V('text').text(text).attr(styles || {});
var svgDoc = V('svg').append(vText);
document.body.appendChild(svgDoc.node);
var bbox = vText.getBBox();
svgDoc.remove();
return bbox;
}
QUnit.test('ellipsis', function(assert) {
var WIDTH = 100;
var HEIGHT = 20;
var ELLIPSIS = '\u2026';
var t, r;
t = text;
r = joint.util.breakText(t, { width: WIDTH, height: HEIGHT }, styles, { ellipsis: false });
assert.ok(r.indexOf(ELLIPSIS) === -1);
assert.ok(measureText(r, styles).width < WIDTH);
assert.ok(measureText(r, styles).height < HEIGHT);
r = joint.util.breakText(t, { width: WIDTH, height: HEIGHT }, styles, { ellipsis: true });
assert.ok(r.indexOf(ELLIPSIS) === r.length - ELLIPSIS.length);
assert.ok(measureText(r, styles).width < WIDTH);
assert.ok(measureText(r, styles).height < HEIGHT);
var customEllipsis = 'CUSTOM';
r = joint.util.breakText(t, { width: WIDTH, height: HEIGHT }, styles, { ellipsis: customEllipsis });
assert.ok(r.indexOf(customEllipsis) === r.length - customEllipsis.length);
assert.ok(measureText(r, styles).width < WIDTH);
assert.ok(measureText(r, styles).height < HEIGHT);
// '...' vs ' ...'
[WIDTH, WIDTH - 3, WIDTH - 6, WIDTH - 9, WIDTH -12].forEach(function(w, i) {
t = 'NoSpacesNoSpacesNoSpaces';
r = joint.util.breakText(t, { width: w, height: HEIGHT }, styles, { ellipsis: true });
assert.notOk(r[r.length - 1 - ELLIPSIS.length] === ' ');
t = 'S P A C E S S P A C E S';
r = joint.util.breakText(t, { width: w, height: HEIGHT }, styles, { ellipsis: true });
assert.ok(r[r.length - 1 - ELLIPSIS.length] === ' ');
});
});
QUnit.test('hyphen', function(assert) {
var WIDTH = 50;
var t, r;
t = 'test-hyphen';
r = joint.util.breakText(t, { width: 2 * WIDTH }, styles);
assert.equal(r, 'test-hyphen');
r = joint.util.breakText(t, { width: WIDTH }, styles);
assert.equal(r, 'test-\nhyphen');
r = joint.util.breakText(t, { width: WIDTH }, styles, { hyphen: '-' });
assert.equal(r, 'test-\nhyphen');
r = joint.util.breakText(t, { width: WIDTH }, styles, { hyphen: 'h' });
assert.equal(r, 'test-h\nyphen');
r = joint.util.breakText(t, { width: WIDTH }, styles, { hyphen: /h/ });
assert.equal(r, 'test-h\nyphen');
});
});
QUnit.test('util.parseCssNumeric', function(assert) {
assert.equal(joint.util.parseCssNumeric('auto'), null, 'no number to parse');
assert.deepEqual(joint.util.parseCssNumeric(1.1), { value: 1.1, unit: '' });
assert.deepEqual(joint.util.parseCssNumeric('1.1'), { value: 1.1, unit: '' });
assert.deepEqual(joint.util.parseCssNumeric('1.1px'), { value: 1.1, unit: 'px' });
assert.deepEqual(joint.util.parseCssNumeric(1.1, ''), { value: 1.1, unit: '' });
assert.deepEqual(joint.util.parseCssNumeric('1.1', ''), { value: 1.1, unit: '' });
assert.equal(joint.util.parseCssNumeric('1.1px', ''), null, '\'px\' found, expects no unit');
assert.equal(joint.util.parseCssNumeric(1.1, 'px'), null, 'no unit found, expects \'px\'');
assert.equal(joint.util.parseCssNumeric('1.1', 'px'), null, 'no unit found, expects \'px\'');
assert.deepEqual(joint.util.parseCssNumeric('1.1px', 'px'), { value: 1.1, unit: 'px' });
assert.equal(joint.util.parseCssNumeric('1.1em', 'px'), null, '\'em\' found, expects \'px\'');
assert.equal(joint.util.parseCssNumeric(1.1, []), null, 'always return null');
assert.equal(joint.util.parseCssNumeric('1.1', []), null, 'always return null');
assert.equal(joint.util.parseCssNumeric('1.1px', []), null, 'always return null');
assert.deepEqual(joint.util.parseCssNumeric(1.1, ['']), { value: 1.1, unit: '' });
assert.deepEqual(joint.util.parseCssNumeric('1.1', ['']), { value: 1.1, unit: '' });
assert.equal(joint.util.parseCssNumeric('1.1px', ['']), null, '\'px\' found, expects no unit');
assert.equal(joint.util.parseCssNumeric(1.1, ['px']), null, 'no unit found, expects \'px\'');
assert.equal(joint.util.parseCssNumeric('1.1', ['px']), null, 'no unit found, expects \'px\'');
assert.deepEqual(joint.util.parseCssNumeric('1.1px', ['px']), { value: 1.1, unit: 'px' });
assert.equal(joint.util.parseCssNumeric('1.1em', ['px']), null, '\'em\' found, expects \'px\'');
assert.equal(joint.util.parseCssNumeric('1.1', ['px', 'em']), null, 'no unit found, expects \'px\' or \'em\'');
assert.deepEqual(joint.util.parseCssNumeric('1.1px', ['px', 'em']), { value: 1.1, unit: 'px' });
assert.deepEqual(joint.util.parseCssNumeric('1.1em', ['px', 'em']), { value: 1.1, unit: 'em' });
assert.deepEqual(joint.util.parseCssNumeric('1.1', ['', 'px']), { value: 1.1, unit: '' });
assert.deepEqual(joint.util.parseCssNumeric('1.1px', ['', 'px']), { value: 1.1, unit: 'px' });
assert.equal(joint.util.parseCssNumeric('1.1em', ['', 'px']), null, '\'em\' found, expects no unit or \'px\'');
});
QUnit.test('util.getByPath()', function(assert) {
var obj = {
a: 1,
b: {
c: 2,
d: 3
},
f: {},
g: [],
h: [null, 4, {
i: { j: 6 }
}],
'a/b/c': { d: 'abcd' }
};
assert.deepEqual(joint.util.getByPath(obj, 'none'), undefined, 'non-existing property is undefined');
assert.equal(joint.util.getByPath(obj, 'a'), 1, 'existing property is a number');
assert.deepEqual(joint.util.getByPath(obj, 'b'), { c: 2, d: 3 }, 'existing property is an object');
assert.equal(joint.util.getByPath(obj, 'b/c'), 2, 'nested property is a number');
assert.deepEqual(joint.util.getByPath(obj, 'b/none'), undefined, 'non-existing nested property is undefined');
assert.deepEqual(joint.util.getByPath(obj, 'f'), {}, 'property is an empty object');
assert.deepEqual(joint.util.getByPath(obj, 'g'), [], 'property is an empty array');
assert.deepEqual(joint.util.getByPath(obj, 'g/0'), undefined, 'first item of an empty array is undefined');
assert.deepEqual(joint.util.getByPath(obj, 'h/0'), null, 'first item of an array is null');
assert.deepEqual(joint.util.getByPath(obj, 'h/0/none'), undefined, 'nested property in null is undefined');
assert.equal(joint.util.getByPath(obj, 'h/1'), 4, 'nth item of an array is number');
assert.deepEqual(joint.util.getByPath(obj, 'h/1/none'), undefined, 'non-existing property of nth item of an array is undefined');
assert.equal(joint.util.getByPath(obj, 'h/2/i/j'), 6, 'nested property of nth item of an array is number');
assert.equal(joint.util.getByPath(obj, 'h.2.i.j', '.'), 6, 'same but this time with a custom delimiter');
assert.equal(joint.util.getByPath(obj, ['h', '2', 'i', 'j']), 6, 'path as array');
assert.equal(joint.util.getByPath(obj, ['a/b/c', 'd']), 'abcd', 'path as array, separator in name');
});
QUnit.test('util.setByPath()', function(assert) {
assert.deepEqual(joint.util.setByPath({}, 'property', 1), { property: 1 }, 'non-existing property in an obj set as a number');
assert.deepEqual(joint.util.setByPath({ property: 2 }, 'property', 3), { property: 3 }, 'existing property in an obj set as a number');
assert.deepEqual(joint.util.setByPath([], '0', 4), [4], 'add an item to an empty array');
assert.deepEqual(joint.util.setByPath([5, 6], '1', 7), [5, 7], 'change an item in an array');
assert.deepEqual(joint.util.setByPath({}, 'first/second/third', 8), { first: { second: { third: 8 }}}, 'populate an empty object with nested objects');
assert.deepEqual(joint.util.setByPath({}, 'first.second.third', 9, '.'), { first: { second: { third: 9 }}}, 'same but this time with a custom delimiter');
assert.deepEqual(joint.util.setByPath([null], '0/property', 10), [{ property: 10 }], 'replace null item with an object');
assert.deepEqual(joint.util.setByPath({ array: [] }, 'array/1', 'index'), { array: [undefined, 'index'] }, 'define array');
assert.deepEqual(joint.util.setByPath({ object: {}}, 'object/1', 'property'), { object: { '1': 'property' }}, 'define property');
});
QUnit.module('util.unsetByPath', function(hooks) {
QUnit.test('path defined as string', function(assert) {
var obj = {
a: 1,
b: {
c: 2,
d: 3
}
};
joint.util.unsetByPath(obj, 'b/c', '/');
assert.deepEqual(obj, { a: 1, b: { d: 3 }}, 'A nested attribute was removed.');
joint.util.unsetByPath(obj, 'b');
assert.deepEqual(obj, { a: 1 }, 'A primitive attribute was removed.');
joint.util.unsetByPath(obj, 'c/d');
assert.deepEqual(obj, { a: 1 }, 'Attempt to delete non-existing attribute doesn\'t affect object.');
});
QUnit.test('path defined as array - remove from objects and arrays', function(assert) {
var obj = {
object: { 1: 'property', 2: 'property2', 3: 'property3' },
array: ['a', 'b', 'c'],
objectArray: [{ a: 'a_value', b: 'b_value' }, { c: 'c_value', d: 'd_value' }]
};
joint.util.unsetByPath(obj, ['object', 1]);
assert.deepEqual(obj.object, { 2: 'property2', 3: 'property3' });
joint.util.unsetByPath(obj, ['object', 2]);
assert.deepEqual(obj.object, { 3: 'property3' });
joint.util.unsetByPath(obj, ['array', 1]);
assert.deepEqual(obj.array, ['a', undefined, 'c']);
joint.util.unsetByPath(obj, ['array', 2]);
assert.deepEqual(obj.array, ['a', undefined, undefined]);
joint.util.unsetByPath(obj, ['objectArray', 1, 'c']);
assert.deepEqual(obj.objectArray, [{ a: 'a_value', b: 'b_value' }, { d: 'd_value' }]);
joint.util.unsetByPath(obj, ['objectArray', '1', 'd']);
assert.deepEqual(obj.objectArray, [{ a: 'a_value', b: 'b_value' }, {}]);
});
QUnit.test('path defined as array', function(assert) {
var obj = {
a: 1,
b: {
c: 2,
d: 3
}
};
joint.util.unsetByPath(obj, ['b', 'c'], '/');
assert.deepEqual(obj, { a: 1, b: { d: 3 }}, 'A nested attribute was removed.');
joint.util.unsetByPath(obj, ['b']);
assert.deepEqual(obj, { a: 1 }, 'A primitive attribute was removed.');
joint.util.unsetByPath(obj, ['c', 'd']);
assert.deepEqual(obj, { a: 1 }, 'Attempt to delete non-existing attribute doesn\'t affect object.');
});
});
QUnit.test('util.normalizeSides()', function(assert) {
assert.deepEqual(joint.util.normalizeSides(undefined), { top: 0, right: 0, bottom: 0, left: 0 },
'Undefined becomes 0');
assert.deepEqual(joint.util.normalizeSides(null), { top: 0, right: 0, bottom: 0, left: 0 },
'Null becomes 0');
assert.deepEqual(joint.util.normalizeSides(''), { top: 0, right: 0, bottom: 0, left: 0 },
'Empty string becomes 0');
assert.deepEqual(joint.util.normalizeSides('a'), { top: 0, right: 0, bottom: 0, left: 0 },
'String becomes 0');
assert.deepEqual(joint.util.normalizeSides('5'), { top: 5, right: 5, bottom: 5, left: 5 },
'String number becomes number');
assert.deepEqual(joint.util.normalizeSides('Infinity'), { top: 0, right: 0, bottom: 0, left: 0 },
'Infinity becomes 0');
assert.deepEqual(joint.util.normalizeSides('NaN'), { top: 0, right: 0, bottom: 0, left: 0 },
'NaN becomes 0');
assert.deepEqual(joint.util.normalizeSides(Infinity), { top: 0, right: 0, bottom: 0, left: 0 },
'Infinity becomes 0');
assert.deepEqual(joint.util.normalizeSides(NaN), { top: 0, right: 0, bottom: 0, left: 0 },
'NaN becomes 0');
assert.deepEqual(joint.util.normalizeSides({ left: undefined }), { top: 0, right: 0, bottom: 0, left: 0 },
'Specific undefined becomes 0');
assert.deepEqual(joint.util.normalizeSides({ left: null }), { top: 0, right: 0, bottom: 0, left: 0 },
'Specific null becomes 0');
assert.deepEqual(joint.util.normalizeSides({ left: '' }), { top: 0, right: 0, bottom: 0, left: 0 },
'Specific empty string becomes 0');
assert.deepEqual(joint.util.normalizeSides({ left: 'a' }), { top: 0, right: 0, bottom: 0, left: 0 },
'Specific string becomes 0');
assert.deepEqual(joint.util.normalizeSides({ left: '5' }), { top: 0, right: 0, bottom: 0, left: 5 },
'Specific string number becomes number');
assert.deepEqual(joint.util.normalizeSides({ left: 'Infinity' }), { top: 0, right: 0, bottom: 0, left: 0 },
'Specific string Infinity becomes 0');
assert.deepEqual(joint.util.normalizeSides({ left: 'NaN' }), { top: 0, right: 0, bottom: 0, left: 0 },
'Specific string NaN becomes 0');
assert.deepEqual(joint.util.normalizeSides({ left: Infinity }), { top: 0, right: 0, bottom: 0, left: 0 },
'Specific Infinity becomes 0');
assert.deepEqual(joint.util.normalizeSides({ left: NaN }), { top: 0, right: 0, bottom: 0, left: 0 },
'Specific NaN becomes 0');
assert.deepEqual(joint.util.normalizeSides(), { top: 0, right: 0, bottom: 0, left: 0 },
'Returns sides defaulted to 0 if called without an argument.');
assert.deepEqual(joint.util.normalizeSides(5), { top: 5, right: 5, bottom: 5, left: 5 },
'Returns sides equaled to a number if called with this number as an argument.');
assert.deepEqual(joint.util.normalizeSides({ horizontal: 5 }), { top: 0, right: 5, bottom: 0, left: 5 },
'If called with an object, horizontal sides are applied to right and left and the rest is defaulted to 0.');
assert.deepEqual(joint.util.normalizeSides({ left: 5 }), { top: 0, right: 0, bottom: 0, left: 5 },
'If called with an object, the existing sides are copied from the object and the rest is defaulted to 0.');
assert.deepEqual(joint.util.normalizeSides({ horizontal: 10, left: 5 }), { top: 0, right: 10, bottom: 0, left: 5 },
'If called with an object, horizontal sides are overriden by more specific sides from the object and the rest is defaulted to 0.');
assert.deepEqual(joint.util.normalizeSides({ horizontal: 5, left: 0 }), { top: 0, right: 5, bottom: 0, left: 0 },
'If called with an object, horizontal sides are overriden by more specific sides from the object and the rest is defaulted to 0.');
});
QUnit.module('util.normalizeEvent()', function() {
QUnit.test('correspondingUseElement', function(assert) {
var useElement = V('use').node;
var event = new $.Event('mouseover', { target: { correspondingUseElement: useElement }});
assert.equal(joint.util.normalizeEvent(event).target, useElement);
});
});
QUnit.test('util.merge', function(assert) {
var types = joint.util.merge({ a: [99] }, { a: { b: 1 }});
assert.deepEqual(types, { a: { b: 1 }}, 'array is not merged with object');
var custom = joint.util.merge({ a: [99] }, { a: { b: 1 }}, function(a) {
return 'x';
});
assert.deepEqual(custom, { a: 'x' });
});
QUnit.test('joint.setTheme()', function(assert) {
assert.ok(typeof joint.setTheme === 'function', 'should be a function');
var theme = 'set-global-theme-test';
var view1 = new joint.mvc.View();
var view2 = new joint.mvc.View();
joint.setTheme(theme);
assert.ok(view1.theme === theme && view2.theme === theme, 'should set the theme for all views');
assert.equal(joint.mvc.View.prototype.defaultTheme, theme, 'should update the default theme on the view prototype');
var view3 = new joint.mvc.View();
assert.equal(view3.theme, theme, 'newly created views should use the updated theme');
var localTheme = 'local-theme';
joint.mvc.View.extend({
options: {
theme: localTheme
}
});
var view4 = new joint.mvc.View({
theme: localTheme
});
joint.setTheme(theme);
assert.ok(view4.theme === localTheme, 'by default, should not override local theme settings');
joint.setTheme(theme, { override: true });
assert.ok(view4.theme === theme, 'when "override" set to true, should override local theme settings');
});
QUnit.module('template(html)', function(hooks) {
QUnit.test('should be a function', function(assert) {
assert.equal(typeof joint.util.template, 'function');
});
QUnit.test('should correctly render the sample HTML templates', function(assert) {
var samples = [
{
html: '<p>No embedded data in this template.</p>',
data: {},
expectedOutput: '<p>No embedded data in this template.</p>'
},
{
html: '<p>no data!</p>',
data: null,
expectedOutput: '<p>no data!</p>'
},
{
html: [
'<p>Some simple text with a value: <%= someValue %></p>',
'<p>Another line with another value: <%= anotherValue %></p>'
].join(''),
data: {
someValue: 12345,
anotherValue: 678
},
expectedOutput: [
'<p>Some simple text with a value: 12345</p>',
'<p>Another line with another value: 678</p>'
].join('')
},
{
html: '<p>With a complex data attribute <%= some.value %></p>',
data: {
some: {
value: 123
}
},
expectedOutput: '<p>With a complex data attribute 123</p>'
},
{
html: '<p>With a more <%= some.value.text %> data attribute</p>',
data: {
some: {
value: {
text: 'complex'
}
}
},
expectedOutput: '<p>With a more complex data attribute</p>'
},
{
html: '<p>Alternative syntax #${num}</p>',
data: {
num: 1
},
expectedOutput: '<p>Alternative syntax #1</p>'
},
{
html: '<p>Alternative syntax #${ num }</p>',
data: {
num: 2
},
expectedOutput: '<p>Alternative syntax #2</p>'
},
{
html: '<p>Alternative syntax #{{num}}</p>',
data: {
num: 3
},
expectedOutput: '<p>Alternative syntax #3</p>'
}
];
_.each(samples, function(sample) {
var template = joint.util.template(sample.html);
var actualOutput = template(sample.data);
assert.equal(actualOutput, sample.expectedOutput, 'should return expected output');
});
});
});
QUnit.module('addClassNamePrefix', function(hooks) {
QUnit.test('should be a function', function(assert) {
assert.equal(typeof joint.util.addClassNamePrefix, 'function');
});
QUnit.test('falsey value provided', function(assert) {
assert.equal(joint.util.addClassNamePrefix(null), null);
assert.equal(joint.util.addClassNamePrefix(undefined), undefined);
assert.equal(joint.util.addClassNamePrefix(0), 0);
assert.equal(joint.util.addClassNamePrefix(''), '');
assert.ok(_.isNaN(joint.util.addClassNamePrefix(NaN)));
});
QUnit.test('non-string value provided', function(assert) {
assert.equal(joint.util.addClassNamePrefix(1), joint.config.classNamePrefix + '1');
});
QUnit.test('one class name', function(assert) {
assert.equal(joint.util.addClassNamePrefix('some-class'), joint.config.classNamePrefix + 'some-class');
});
QUnit.test('multiple class names', function(assert) {
assert.equal(joint.util.addClassNamePrefix('some-class some-other-class'), joint.config.classNamePrefix + 'some-class ' + joint.config.classNamePrefix + 'some-other-class');
});
});
QUnit.module('removeClassNamePrefix', function(hooks) {
QUnit.test('should be a function', function(assert) {
assert.equal(typeof joint.util.removeClassNamePrefix, 'function');
});
QUnit.test('falsey value provided', function(assert) {
assert.equal(joint.util.removeClassNamePrefix(null), null);
assert.equal(joint.util.removeClassNamePrefix(undefined), undefined);
assert.equal(joint.util.removeClassNamePrefix(0), 0);
assert.equal(joint.util.removeClassNamePrefix(''), '');
assert.ok(_.isNaN(joint.util.removeClassNamePrefix(NaN)));
});
QUnit.test('non-string value provided', function(assert) {
assert.equal(joint.util.removeClassNamePrefix(1), '1');
});
QUnit.test('one prefixed class name', function(assert) {
assert.equal(joint.util.removeClassNamePrefix(joint.config.classNamePrefix + 'some-class'), 'some-class');
});
QUnit.test('multiple prefixed class names', function(assert) {
assert.equal(joint.util.removeClassNamePrefix(joint.config.classNamePrefix + 'some-class ' + joint.config.classNamePrefix + 'some-other-class'), 'some-class some-other-class');
});
QUnit.test('mix of prefixed and non-prefixed class names', function(assert) {
assert.equal(joint.util.removeClassNamePrefix(joint.config.classNamePrefix + 'some-class without-prefix'), 'some-class without-prefix');
});
});
QUnit.module('wrapWith', function(hooks) {
QUnit.test('wraps object\'s methods with wrapper function', function(assert) {
var someObject = {
someFunction: function() {
},
someOtherFunction: function() {
},
yetAnotherFunction: function() {
}
};
var methods = ['someFunction', 'someOtherFunction'];
var innerWrapper = function() { };
var wrapper = function() {
return innerWrapper;
};
joint.util.wrapWith(someObject, methods, wrapper);
_.each(someObject, function(fn, method) {
if (_.includes(methods, method)) {
// Should be wrapped.
assert.equal(someObject[method], innerWrapper);
} else {
// Should not be wrapped.
assert.equal(someObject[method], fn);
}
});
});
QUnit.test('can specify wrapper method by name', function(assert) {
var someObject = {
someFunction: function() {
}
};
var methods = ['someFunction'];
var wrapper = 'someWrapper';
var innerWrapper = function() { };
joint.util.wrappers[wrapper] = function() {
return innerWrapper;
};
joint.util.wrapWith(someObject, methods, wrapper);
_.each(someObject, function(fn, method) {
if (_.includes(methods, method)) {
// Should be wrapped.
assert.equal(someObject[method], innerWrapper);
} else {
// Should not be wrapped.
assert.equal(someObject[method], fn);
}
});
// Clean up.
delete joint.util.wrappers[wrapper];
});
});
QUnit.module('wrappers', function(hooks) {
QUnit.module('cells', function(hooks) {
var expected;
hooks.beforeEach(function() {
expected = {
cells: [
new joint.dia.Cell,
new joint.dia.Cell,
new joint.dia.Cell
],
opt: {
someOption: 'testing',
anotherOption: 50
}
};
});
QUnit.test('fn([cell, cell, cell], opt)', function(assert) {
var fn = joint.util.wrappers.cells(function(cells, opt) {
assert.ok(_.isArray(cells), 'cells is an array');
assert.ok(_.isEqual(cells, expected.cells), 'cells is as expected');
assert.ok(_.isObject(opt), 'opt is an object');
assert.ok(_.isEqual(opt, expected.opt), 'opt is as expected');
});
fn(expected.cells, expected.opt);
});
QUnit.test('fn([cell, cell, cell])', function(assert) {
var fn = joint.util.wrappers.cells(function(cells, opt) {
assert.ok(_.isArray(cells), 'cells is an array');
assert.ok(_.isEqual(cells, expected.cells), 'cells is as expected');
assert.ok(_.isObject(opt), 'opt is an object');
assert.ok(_.isEqual(opt, {}), 'opt is an empty object');
});
fn(expected.cells);
});
QUnit.test('fn(cell, cell, cell)', function(assert) {
var fn = joint.util.wrappers.cells(function(cells, opt) {
assert.ok(_.isArray(cells), 'cells is an array');
assert.ok(_.isEqual(cells, expected.cells), 'cells is as expected');
assert.ok(_.isObject(opt), 'opt is an object');
assert.ok(_.isEqual(opt, {}), 'opt is an empty object');
});
fn.apply(undefined, expected.cells);
});
QUnit.test('fn(cell, cell, cell, opt)', function(assert) {
var fn = joint.util.wrappers.cells(function(cells, opt) {
assert.ok(_.isArray(cells), 'cells is an array');
assert.ok(_.isEqual(cells, expected.cells), 'cells is as expected');
assert.ok(_.isObject(opt), 'opt is an object');
assert.ok(_.isEqual(opt, expected.opt), 'opt is as expected');
});
fn.apply(undefined, [].concat(expected.cells, [expected.opt]));
});
QUnit.test('fn(cell)', function(assert) {
var cell = _.first(expected.cells);
var fn = joint.util.wrappers.cells(function(cells, opt) {
assert.ok(_.isArray(cells), 'cells is an array');
assert.ok(_.isEqual(cells, [cell]), 'cells is as expected');
assert.ok(_.isObject(opt), 'opt is an object');
assert.ok(_.isEqual(opt, {}), 'opt is an empty object');
});
fn(cell);
});
});
});
QUnit.module('getElementBBox', function(hooks) {
QUnit.module('html', function(hooks) {
var $htmlElement;
hooks.beforeEach(function() {
$htmlElement = $('<div/>').css({
position: 'absolute',
top: 10,
left: 20,
width: 50,
height: 60
});
$htmlElement.appendTo(document.body);
});
hooks.afterEach(function() {
$htmlElement.remove();
});
QUnit.test('html element', function(assert) {
var bBox = joint.util.getElementBBox($htmlElement[0]);
assert.equal(bBox.x, 20);
assert.equal(bBox.y, 10);
assert.equal(bBox.width, 50);
assert.equal(bBox.height, 60);
});
QUnit.test('possible input argument types', function(assert) {
assert.ok(joint.util.getElementBBox('html'));
assert.ok(joint.util.getElementBBox($htmlElement));
assert.ok(joint.util.getElementBBox($htmlElement[0]));
assert.throws(function() {
joint.util.getElementBBox('xxx');
});
assert.throws(function() {
joint.util.getElementBBox();
});
});
});
QUnit.module('svg', function(hooks) {
hooks.beforeEach(function() {
this.svgDoc = V(V.createSvgDocument()).attr('style', 'position:absolute;top:50px;left:60px');
V($('body')[0]).append(this.svgDoc);
});
hooks.afterEach(function() {
this.svgDoc.remove();
});
QUnit.test('simple element', function(assert) {
var svgElement = V('<rect width="70" height="80"/>');
this.svgDoc.append(svgElement);
var bBox = joint.util.getElementBBox(svgElement.node);
assert.equal(bBox.x, 60);
assert.equal(bBox.y, 50);
assert.equal(bBox.width, 70);
assert.equal(bBox.height, 80);
});
QUnit.test('with position, with stroke', function(assert) {
// firefox measures differently - includes the stroke as well.
// joint.util.getElementBBox should return consistent values across all browsers.
var svgElement = V('<rect width="70" height="80" x="50" y="50" stroke-width="10" stroke="red"/>');
this.svgDoc.append(svgElement);
var bBox = joint.util.getElementBBox(svgElement.node);
assert.equal(bBox.x, 60 + 50);
assert.equal(bBox.y, 50 + 50);
assert.equal(bBox.width, 70);
assert.equal(bBox.height, 80);
});
});
});
QUnit.module('parseDOMJSON', function(hooks) {
var util = joint.util;
QUnit.test('sanity', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'rect' }], V.namespace.xmls);
assert.ok(res.fragment instanceof DocumentFragment);
assert.equal(Object(res.selectors), res.selectors);
});
QUnit.module('tagName', function() {
QUnit.test('required', function(assert) {
assert.throws(function() {
util.parseDOMJSON([{ /* tagName missing */ }]);
});
});
QUnit.test('svg', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'rect' }], V.namespace.xmls);
var node = res.fragment.firstChild;
assert.ok(node instanceof SVGRectElement);
});
QUnit.test('html', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'div' }], V.namespace.xhtml);
var node = res.fragment.firstChild;
assert.ok(node instanceof HTMLDivElement);
});
});
QUnit.module('attributes', function() {
QUnit.test('svg', function(assert) {
var res = util.parseDOMJSON([{
tagName: 'rect',
attributes: { 'fill': 'red', 'xlink:href': '#test' }
}]);
var node = res.fragment.firstChild;
assert.equal(node.attributes.getNamedItem('fill').value, 'red');
assert.equal(node.attributes.getNamedItemNS(V.namespace.xlink, 'href').value, '#test');
});
QUnit.test('html', function(assert) {
var res = util.parseDOMJSON([{
tagName: 'div',
attributes: { 'title': 'test' }
}], V.namespace.xhtml);
var node = res.fragment.firstChild;
assert.equal(node.attributes.getNamedItem('title').value, 'test');
});
});
QUnit.module('style', function() {
QUnit.test('svg', function(assert) {
var res = util.parseDOMJSON([{
tagName: 'rect',
style: { 'fill': 'red' }
}]);
var node = res.fragment.firstChild;
assert.ok(/fill:/.test(node.attributes.getNamedItem('style').value));
});
QUnit.test('html', function(assert) {
var res = util.parseDOMJSON([{
tagName: 'div',
style: { 'color': 'red' }
}], V.namespace.xhtml);
var node = res.fragment.firstChild;
assert.ok(/color:/.test(node.attributes.getNamedItem('style').value));
});
});
QUnit.module('className', function() {
QUnit.test('svg', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'rect', className: 'test' }]);
var node = res.fragment.firstChild;
assert.equal(node.className.baseVal, 'test');
});
QUnit.test('html', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'div', className: 'test' }], V.namespace.xhtml);
var node = res.fragment.firstChild;
assert.equal(node.className, 'test');
});
});
QUnit.module('textContent', function() {
QUnit.test('svg', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'text', textContent: 'test' }]);
var node = res.fragment.firstChild;
assert.equal(node.textContent, 'test');
});
QUnit.test('html', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'div', textContent: 'test' }], V.namespace.xhtml);
var node = res.fragment.firstChild;
assert.equal(node.textContent, 'test');
});
});
QUnit.module('selector', function() {
QUnit.test('svg', function(assert) {
var res = util.parseDOMJSON([
{ tagName: 'rect', selector: 'test1' },
{ tagName: 'circle', selector: 'test2' }
]);
assert.ok(res.selectors.test1 instanceof SVGRectElement);
assert.ok(res.selectors.test2 instanceof SVGCircleElement);
assert.equal(res.selectors.test1.getAttribute('joint-selector'), 'test1');
assert.equal(res.selectors.test2.getAttribute('joint-selector'), 'test2');
});
QUnit.test('html', function(assert) {
var res = util.parseDOMJSON([
{ tagName: 'div', selector: 'test1' },
{ tagName: 'img', selector: 'test2' },
], V.namespace.xhtml);
assert.ok(res.selectors.test1 instanceof HTMLDivElement);
assert.ok(res.selectors.test2 instanceof HTMLImageElement);
assert.equal(res.selectors.test1.getAttribute('joint-selector'), 'test1');
assert.equal(res.selectors.test2.getAttribute('joint-selector'), 'test2');
});
QUnit.test('uniqueness', function(assert) {
assert.throws(function() {
util.parseDOMJSON([
{ tagName: 'rect', selector: 'test' },
{ tagName: 'circle', selector: 'test' },
]);
});
});
});
QUnit.module('groupSelector', function() {
QUnit.test('svg - string', function(assert) {
var res = util.parseDOMJSON([
{ tagName: 'rect', groupSelector: 'test' },
{ tagName: 'circle' },
{ tagName: 'ellipse', groupSelector: 'test' }
]);
assert.deepEqual(Object.keys(res.groupSelectors), ['test']);
assert.equal(res.groupSelectors.test.length, 2);
assert.ok(res.groupSelectors.test[0] instanceof SVGRectElement);
assert.ok(res.groupSelectors.test[1] instanceof SVGEllipseElement);
});
QUnit.test('html - string', function(assert) {
var res = util.parseDOMJSON([
{ tagName: 'div', groupSelector: 'test' },
{ tagName: 'img' },
{ tagName: 'p', groupSelector: 'test' },
], V.namespace.xhtml);
assert.deepEqual(Object.keys(res.groupSelectors), ['test']);
assert.equal(res.groupSelectors.test.length, 2);
assert.ok(res.groupSelectors.test[0] instanceof HTMLDivElement);
assert.ok(res.groupSelectors.test[1] instanceof HTMLParagraphElement);
});
QUnit.test('svg - array', function(assert) {
var res = util.parseDOMJSON([
{ tagName: 'rect', groupSelector: ['test0', 'test1'] },
{ tagName: 'circle', groupSelector: ['test1', 'test2'] },
{ tagName: 'ellipse', groupSelector: ['test0', 'test2'] }
]);
assert.deepEqual(Object.keys(res.groupSelectors).sort(), ['test0', 'test1', 'test2']);
assert.equal(res.groupSelectors.test0.length, 2);
assert.equal(res.groupSelectors.test1.length, 2);
assert.equal(res.groupSelectors.test2.length, 2);
assert.ok(res.groupSelectors.test0[0] instanceof SVGRectElement);
assert.ok(res.groupSelectors.test0[1] instanceof SVGEllipseElement);
assert.ok(res.groupSelectors.test1[0] instanceof SVGRectElement);
assert.ok(res.groupSelectors.test1[1] instanceof SVGCircleElement);
assert.ok(res.groupSelectors.test2[0] instanceof SVGCircleElement);
assert.ok(res.groupSelectors.test2[1] instanceof SVGEllipseElement);
});
QUnit.test('html - array', function(assert) {
var res = util.parseDOMJSON([
{ tagName: 'div', groupSelector: ['test0', 'test1'] },
{ tagName: 'img', groupSelector: ['test1', 'test2'] },
{ tagName: 'p', groupSelector: ['test0', 'test2'] },
], V.namespace.xhtml);
assert.deepEqual(Object.keys(res.groupSelectors).sort(), ['test0', 'test1', 'test2']);
assert.equal(res.groupSelectors.test0.length, 2);
assert.equal(res.groupSelectors.test1.length, 2);
assert.equal(res.groupSelectors.test2.length, 2);
assert.ok(res.groupSelectors.test0[0] instanceof HTMLDivElement);
assert.ok(res.groupSelectors.test0[1] instanceof HTMLParagraphElement);
assert.ok(res.groupSelectors.test1[0] instanceof HTMLDivElement);
assert.ok(res.groupSelectors.test1[1] instanceof HTMLImageElement);
assert.ok(res.groupSelectors.test2[0] instanceof HTMLImageElement);
assert.ok(res.groupSelectors.test2[1] instanceof HTMLParagraphElement);
});
});
QUnit.module('namespaceURI', function() {
QUnit.test('svg', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'rect', namespaceURI: V.namespace.svg }]);
var node = res.fragment.firstChild;
assert.ok(node instanceof SVGRectElement);
});
QUnit.test('html', function(assert) {
var res = util.parseDOMJSON([{ tagName: 'div', namespaceURI: V.namespace.xhtml }]);
var node = res.fragment.firstChild;
assert.ok(node instanceof HTMLDivElement);
});
});
QUnit.module('children', function() {
QUnit.test('svg', function(assert) {
var res = util.parseDOMJSON([{
tagName: 'g',
children: [{ tagName: 'rect' }, { tagName: 'circle' }]
}]);
var group = res.fragment.firstChild;
assert.ok(group instanceof SVGGElement);
assert.ok(group.firstChild instanceof SVGRectElement);
assert.ok(group.lastChild instanceof SVGCircleElement);
});
QUnit.test('html', function(assert) {
var res = util.parseDOMJSON([{
tagName: 'div',
children: [{ tagName: 'p' }, { tagName: 'img' }]
}], V.namespace.xhtml);
var div = res.fragment.firstChild;
assert.ok(div instanceof HTMLDivElement);
assert.ok(div.firstChild instanceof HTMLParagraphElement);
assert.ok(div.lastChild instanceof HTMLImageElement);
});
});
});
});