- Testing: Migrate remaining HTML tests to Cypress
This commit is contained in:
21
.eslintrc.js
21
.eslintrc.js
@@ -3,8 +3,6 @@ module.exports = {
|
||||
parserOptions: {
|
||||
sourceType: "module"
|
||||
},
|
||||
// Need to make explicit here for processing by jsdoc/check-examples
|
||||
plugins: ["qunit"],
|
||||
env: {
|
||||
browser: true
|
||||
},
|
||||
@@ -87,7 +85,7 @@ module.exports = {
|
||||
"editor/redirect-on-no-module-support.js",
|
||||
"editor/extensions/imagelib/index.js",
|
||||
"editor/external/dom-polyfill/dom-polyfill.js",
|
||||
"test/all_tests.js", "screencasts/svgopen2010/script.js",
|
||||
"screencasts/svgopen2010/script.js",
|
||||
"opera-widget/handlers.js",
|
||||
"firefox-extension/handlers.js",
|
||||
"firefox-extension/content/svg-edit-overlay.js"
|
||||
@@ -96,12 +94,6 @@ module.exports = {
|
||||
"import/unambiguous": ["off"]
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['test/browser-bugs/**'],
|
||||
rules: {
|
||||
'no-var': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.html'],
|
||||
rules: {
|
||||
@@ -133,7 +125,7 @@ module.exports = {
|
||||
// Dis-apply Node rules mistakenly giving errors with browser files,
|
||||
// and treating Node global `root` as being present for shadowing
|
||||
{
|
||||
files: ["editor/**", "test/**", "screencasts/**"],
|
||||
files: ["editor/**", "screencasts/**"],
|
||||
globals: {
|
||||
root: "off"
|
||||
},
|
||||
@@ -141,14 +133,6 @@ module.exports = {
|
||||
"node/no-unsupported-features/node-builtins": "off"
|
||||
}
|
||||
},
|
||||
// We want console in tests!
|
||||
{
|
||||
extends: ["plugin:qunit/recommended"],
|
||||
files: ["test/**"],
|
||||
rules: {
|
||||
"no-console": ["off"]
|
||||
}
|
||||
},
|
||||
{
|
||||
// Node files
|
||||
files: [
|
||||
@@ -191,6 +175,7 @@ module.exports = {
|
||||
node: true
|
||||
},
|
||||
rules: {
|
||||
'no-console': 0,
|
||||
'import/unambiguous': 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
ignore
|
||||
screencasts
|
||||
test
|
||||
|
||||
.github/ISSUE_TEMPLATE/bug_report.md
|
||||
build
|
||||
|
||||
11
cypress/integration/browser-bugs.js
Normal file
11
cypress/integration/browser-bugs.js
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
describe('Browser bugs', function () {
|
||||
it('removeItem and setAttribute test (Chromium 843901; now fixed)', function () {
|
||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=843901
|
||||
const elem = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
elem.setAttribute('transform', 'matrix(1,0,0,1,0,0)');
|
||||
elem.transform.baseVal.removeItem(0);
|
||||
elem.removeAttribute('transform');
|
||||
assert.equal(elem.hasAttribute('transform'), false);
|
||||
});
|
||||
});
|
||||
59
cypress/integration/contextmenu.js
Normal file
59
cypress/integration/contextmenu.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
import * as contextmenu from '../../instrumented/contextmenu.js';
|
||||
|
||||
describe('contextmenu', function () {
|
||||
/**
|
||||
* Tear down tests, resetting custom menus.
|
||||
* @returns {void}
|
||||
*/
|
||||
afterEach(() => {
|
||||
contextmenu.resetCustomMenus();
|
||||
});
|
||||
|
||||
it('Test svgedit.contextmenu package', function () {
|
||||
assert.ok(contextmenu, 'contextmenu registered correctly');
|
||||
assert.ok(contextmenu.add, 'add registered correctly');
|
||||
assert.ok(contextmenu.hasCustomHandler, 'contextmenu hasCustomHandler registered correctly');
|
||||
assert.ok(contextmenu.getCustomHandler, 'contextmenu getCustomHandler registered correctly');
|
||||
});
|
||||
|
||||
it('Test svgedit.contextmenu does not add invalid menu item', function () {
|
||||
assert.throws(
|
||||
() => contextmenu.add({id: 'justanid'}),
|
||||
null, null,
|
||||
'menu item with just an id is invalid'
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => contextmenu.add({id: 'idandlabel', label: 'anicelabel'}),
|
||||
null, null,
|
||||
'menu item with just an id and label is invalid'
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => contextmenu.add({id: 'idandlabel', label: 'anicelabel', action: 'notafunction'}),
|
||||
null, null,
|
||||
'menu item with action that is not a function is invalid'
|
||||
);
|
||||
});
|
||||
|
||||
it('Test svgedit.contextmenu adds valid menu item', function () {
|
||||
const validItem = {id: 'valid', label: 'anicelabel', action () { /* */ }};
|
||||
contextmenu.add(validItem);
|
||||
|
||||
assert.ok(contextmenu.hasCustomHandler('valid'), 'Valid menu item is added.');
|
||||
assert.equal(contextmenu.getCustomHandler('valid'), validItem.action, 'Valid menu action is added.');
|
||||
});
|
||||
|
||||
it('Test svgedit.contextmenu rejects valid duplicate menu item id', function () {
|
||||
const validItem1 = {id: 'valid', label: 'anicelabel', action () { /**/ }};
|
||||
const validItem2 = {id: 'valid', label: 'anicelabel', action () { /**/ }};
|
||||
contextmenu.add(validItem1);
|
||||
|
||||
assert.throws(
|
||||
() => contextmenu.add(validItem2),
|
||||
null, null,
|
||||
'duplicate menu item is rejected.'
|
||||
);
|
||||
});
|
||||
});
|
||||
310
cypress/integration/coords.js
Normal file
310
cypress/integration/coords.js
Normal file
@@ -0,0 +1,310 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as utilities from '../../instrumented/utilities.js';
|
||||
import * as coords from '../../instrumented/coords.js';
|
||||
|
||||
describe('coords', function () {
|
||||
let elemId = 1;
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
const root = document.createElement('div');
|
||||
root.id = 'root';
|
||||
root.style.visibility = 'hidden';
|
||||
document.body.append(root);
|
||||
|
||||
/**
|
||||
* Set up tests with mock data.
|
||||
* @returns {void}
|
||||
*/
|
||||
beforeEach(function () {
|
||||
const svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot.id = 'svgroot';
|
||||
root.append(svgroot);
|
||||
this.svg = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot.append(this.svg);
|
||||
|
||||
// Mock out editor context.
|
||||
utilities.init(
|
||||
/**
|
||||
* @implements {module:utilities.EditorContext}
|
||||
*/
|
||||
{
|
||||
getSVGRoot: () => { return this.svg; },
|
||||
getDOMDocument () { return null; },
|
||||
getDOMContainer () { return null; }
|
||||
}
|
||||
);
|
||||
coords.init(
|
||||
/**
|
||||
* @implements {module:coords.EditorContext}
|
||||
*/
|
||||
{
|
||||
getGridSnapping () { return false; },
|
||||
getDrawing () {
|
||||
return {
|
||||
getNextId () { return String(elemId++); }
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tear down tests, removing elements.
|
||||
* @returns {void}
|
||||
*/
|
||||
afterEach(function () {
|
||||
while (this.svg.hasChildNodes()) {
|
||||
this.svg.firstChild.remove();
|
||||
}
|
||||
});
|
||||
|
||||
it('Test remapElement(translate) for rect', function () {
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('x', '200');
|
||||
rect.setAttribute('y', '150');
|
||||
rect.setAttribute('width', '250');
|
||||
rect.setAttribute('height', '120');
|
||||
this.svg.append(rect);
|
||||
|
||||
const attrs = {
|
||||
x: '200',
|
||||
y: '150',
|
||||
width: '125',
|
||||
height: '75'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(rect, attrs, m);
|
||||
|
||||
assert.equal(rect.getAttribute('x'), '300');
|
||||
assert.equal(rect.getAttribute('y'), '100');
|
||||
assert.equal(rect.getAttribute('width'), '125');
|
||||
assert.equal(rect.getAttribute('height'), '75');
|
||||
});
|
||||
|
||||
it('Test remapElement(scale) for rect', function () {
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('width', '250');
|
||||
rect.setAttribute('height', '120');
|
||||
this.svg.append(rect);
|
||||
|
||||
const attrs = {
|
||||
x: '0',
|
||||
y: '0',
|
||||
width: '250',
|
||||
height: '120'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 2; m.b = 0;
|
||||
m.c = 0; m.d = 0.5;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
coords.remapElement(rect, attrs, m);
|
||||
|
||||
assert.equal(rect.getAttribute('x'), '0');
|
||||
assert.equal(rect.getAttribute('y'), '0');
|
||||
assert.equal(rect.getAttribute('width'), '500');
|
||||
assert.equal(rect.getAttribute('height'), '60');
|
||||
});
|
||||
|
||||
it('Test remapElement(translate) for circle', function () {
|
||||
const circle = document.createElementNS(NS.SVG, 'circle');
|
||||
circle.setAttribute('cx', '200');
|
||||
circle.setAttribute('cy', '150');
|
||||
circle.setAttribute('r', '125');
|
||||
this.svg.append(circle);
|
||||
|
||||
const attrs = {
|
||||
cx: '200',
|
||||
cy: '150',
|
||||
r: '125'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(circle, attrs, m);
|
||||
|
||||
assert.equal(circle.getAttribute('cx'), '300');
|
||||
assert.equal(circle.getAttribute('cy'), '100');
|
||||
assert.equal(circle.getAttribute('r'), '125');
|
||||
});
|
||||
|
||||
it('Test remapElement(scale) for circle', function () {
|
||||
const circle = document.createElementNS(NS.SVG, 'circle');
|
||||
circle.setAttribute('cx', '200');
|
||||
circle.setAttribute('cy', '150');
|
||||
circle.setAttribute('r', '250');
|
||||
this.svg.append(circle);
|
||||
|
||||
const attrs = {
|
||||
cx: '200',
|
||||
cy: '150',
|
||||
r: '250'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 2; m.b = 0;
|
||||
m.c = 0; m.d = 0.5;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
coords.remapElement(circle, attrs, m);
|
||||
|
||||
assert.equal(circle.getAttribute('cx'), '400');
|
||||
assert.equal(circle.getAttribute('cy'), '75');
|
||||
// Radius is the minimum that fits in the new bounding box.
|
||||
assert.equal(circle.getAttribute('r'), '125');
|
||||
});
|
||||
|
||||
it('Test remapElement(translate) for ellipse', function () {
|
||||
const ellipse = document.createElementNS(NS.SVG, 'ellipse');
|
||||
ellipse.setAttribute('cx', '200');
|
||||
ellipse.setAttribute('cy', '150');
|
||||
ellipse.setAttribute('rx', '125');
|
||||
ellipse.setAttribute('ry', '75');
|
||||
this.svg.append(ellipse);
|
||||
|
||||
const attrs = {
|
||||
cx: '200',
|
||||
cy: '150',
|
||||
rx: '125',
|
||||
ry: '75'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(ellipse, attrs, m);
|
||||
|
||||
assert.equal(ellipse.getAttribute('cx'), '300');
|
||||
assert.equal(ellipse.getAttribute('cy'), '100');
|
||||
assert.equal(ellipse.getAttribute('rx'), '125');
|
||||
assert.equal(ellipse.getAttribute('ry'), '75');
|
||||
});
|
||||
|
||||
it('Test remapElement(scale) for ellipse', function () {
|
||||
const ellipse = document.createElementNS(NS.SVG, 'ellipse');
|
||||
ellipse.setAttribute('cx', '200');
|
||||
ellipse.setAttribute('cy', '150');
|
||||
ellipse.setAttribute('rx', '250');
|
||||
ellipse.setAttribute('ry', '120');
|
||||
this.svg.append(ellipse);
|
||||
|
||||
const attrs = {
|
||||
cx: '200',
|
||||
cy: '150',
|
||||
rx: '250',
|
||||
ry: '120'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 2; m.b = 0;
|
||||
m.c = 0; m.d = 0.5;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
coords.remapElement(ellipse, attrs, m);
|
||||
|
||||
assert.equal(ellipse.getAttribute('cx'), '400');
|
||||
assert.equal(ellipse.getAttribute('cy'), '75');
|
||||
assert.equal(ellipse.getAttribute('rx'), '500');
|
||||
assert.equal(ellipse.getAttribute('ry'), '60');
|
||||
});
|
||||
|
||||
it('Test remapElement(translate) for line', function () {
|
||||
const line = document.createElementNS(NS.SVG, 'line');
|
||||
line.setAttribute('x1', '50');
|
||||
line.setAttribute('y1', '100');
|
||||
line.setAttribute('x2', '120');
|
||||
line.setAttribute('y2', '200');
|
||||
this.svg.append(line);
|
||||
|
||||
const attrs = {
|
||||
x1: '50',
|
||||
y1: '100',
|
||||
x2: '120',
|
||||
y2: '200'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(line, attrs, m);
|
||||
|
||||
assert.equal(line.getAttribute('x1'), '150');
|
||||
assert.equal(line.getAttribute('y1'), '50');
|
||||
assert.equal(line.getAttribute('x2'), '220');
|
||||
assert.equal(line.getAttribute('y2'), '150');
|
||||
});
|
||||
|
||||
it('Test remapElement(scale) for line', function () {
|
||||
const line = document.createElementNS(NS.SVG, 'line');
|
||||
line.setAttribute('x1', '50');
|
||||
line.setAttribute('y1', '100');
|
||||
line.setAttribute('x2', '120');
|
||||
line.setAttribute('y2', '200');
|
||||
this.svg.append(line);
|
||||
|
||||
const attrs = {
|
||||
x1: '50',
|
||||
y1: '100',
|
||||
x2: '120',
|
||||
y2: '200'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 2; m.b = 0;
|
||||
m.c = 0; m.d = 0.5;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
coords.remapElement(line, attrs, m);
|
||||
|
||||
assert.equal(line.getAttribute('x1'), '100');
|
||||
assert.equal(line.getAttribute('y1'), '50');
|
||||
assert.equal(line.getAttribute('x2'), '240');
|
||||
assert.equal(line.getAttribute('y2'), '100');
|
||||
});
|
||||
|
||||
it('Test remapElement(translate) for text', function () {
|
||||
const text = document.createElementNS(NS.SVG, 'text');
|
||||
text.setAttribute('x', '50');
|
||||
text.setAttribute('y', '100');
|
||||
this.svg.append(text);
|
||||
|
||||
const attrs = {
|
||||
x: '50',
|
||||
y: '100'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = this.svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(text, attrs, m);
|
||||
|
||||
assert.equal(text.getAttribute('x'), '150');
|
||||
assert.equal(text.getAttribute('y'), '50');
|
||||
});
|
||||
});
|
||||
789
cypress/integration/draw.js
Normal file
789
cypress/integration/draw.js
Normal file
@@ -0,0 +1,789 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as draw from '../../instrumented/draw.js';
|
||||
import * as units from '../../instrumented/units.js';
|
||||
|
||||
describe('draw.Drawing', function () {
|
||||
const addOwnSpies = (obj) => {
|
||||
const methods = Object.keys(obj);
|
||||
methods.forEach((method) => {
|
||||
cy.spy(obj, method);
|
||||
});
|
||||
};
|
||||
|
||||
const LAYER_CLASS = draw.Layer.CLASS_NAME;
|
||||
const NONCE = 'foo';
|
||||
const LAYER1 = 'Layer 1';
|
||||
const LAYER2 = 'Layer 2';
|
||||
const LAYER3 = 'Layer 3';
|
||||
const PATH_ATTR = {
|
||||
// clone will convert relative to absolute, so the test for equality fails.
|
||||
// d: 'm7.38867,57.38867c0,-27.62431 22.37569,-50 50,-50c27.62431,0 50,22.37569 50,50c0,27.62431 -22.37569,50 -50,50c-27.62431,0 -50,-22.37569 -50,-50z',
|
||||
d: 'M7.389,57.389C7.389,29.764 29.764,7.389 57.389,7.389C85.013,7.389 107.389,29.764 107.389,57.389C107.389,85.013 85.013,107.389 57.389,107.389C29.764,107.389 7.389,85.013 7.389,57.389z',
|
||||
transform: 'rotate(45 57.388671875000036,57.388671874999986) ',
|
||||
'stroke-width': '5',
|
||||
stroke: '#660000',
|
||||
fill: '#ff0000'
|
||||
};
|
||||
|
||||
units.init(
|
||||
/**
|
||||
* @implements {module:units.ElementContainer}
|
||||
*/
|
||||
{
|
||||
// used by units.shortFloat - call path: cloneLayer -> copyElem -> convertPath -> pathDSegment -> shortFloat
|
||||
getRoundDigits () { return 3; }
|
||||
}
|
||||
);
|
||||
|
||||
// Simplifying from svgcanvas.js usage
|
||||
const idprefix = 'svg_';
|
||||
|
||||
const getCurrentDrawing = function () {
|
||||
return currentDrawing_;
|
||||
};
|
||||
const setCurrentGroup = (cg) => { /* */ };
|
||||
draw.init(
|
||||
/**
|
||||
* @implements {module:draw.DrawCanvasInit}
|
||||
*/
|
||||
{
|
||||
getCurrentDrawing,
|
||||
setCurrentGroup
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @param {module:utilities.SVGElementJSON} jsonMap
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function createSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
}
|
||||
|
||||
const setupSVGWith3Layers = function (svgElem) {
|
||||
const layer1 = document.createElementNS(NS.SVG, 'g');
|
||||
const layer1Title = document.createElementNS(NS.SVG, 'title');
|
||||
layer1Title.append(document.createTextNode(LAYER1));
|
||||
layer1.append(layer1Title);
|
||||
svgElem.append(layer1);
|
||||
|
||||
const layer2 = document.createElementNS(NS.SVG, 'g');
|
||||
const layer2Title = document.createElementNS(NS.SVG, 'title');
|
||||
layer2Title.append(document.createTextNode(LAYER2));
|
||||
layer2.append(layer2Title);
|
||||
svgElem.append(layer2);
|
||||
|
||||
const layer3 = document.createElementNS(NS.SVG, 'g');
|
||||
const layer3Title = document.createElementNS(NS.SVG, 'title');
|
||||
layer3Title.append(document.createTextNode(LAYER3));
|
||||
layer3.append(layer3Title);
|
||||
svgElem.append(layer3);
|
||||
|
||||
return [layer1, layer2, layer3];
|
||||
};
|
||||
|
||||
const createSomeElementsInGroup = function (group) {
|
||||
group.append(
|
||||
createSVGElement({
|
||||
element: 'path',
|
||||
attr: PATH_ATTR
|
||||
}),
|
||||
// createSVGElement({
|
||||
// element: 'path',
|
||||
// attr: {d: 'M0,1L2,3'}
|
||||
// }),
|
||||
createSVGElement({
|
||||
element: 'rect',
|
||||
attr: {x: '0', y: '1', width: '5', height: '10'}
|
||||
}),
|
||||
createSVGElement({
|
||||
element: 'line',
|
||||
attr: {x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
})
|
||||
);
|
||||
|
||||
const g = createSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(createSVGElement({
|
||||
element: 'rect',
|
||||
attr: {x: '0', y: '1', width: '5', height: '10'}
|
||||
}));
|
||||
group.append(g);
|
||||
return 4;
|
||||
};
|
||||
|
||||
const cleanupSVG = function (svgElem) {
|
||||
while (svgElem.firstChild) { svgElem.firstChild.remove(); }
|
||||
};
|
||||
|
||||
let sandbox, currentDrawing_, svg, svgN;
|
||||
beforeEach(() => {
|
||||
sandbox = document.createElement('div');
|
||||
sandbox.id = 'sandbox';
|
||||
sandbox.style.visibility = 'hidden';
|
||||
|
||||
svg = document.createElementNS(NS.SVG, 'svg');
|
||||
// Firefox throws exception in getBBox() when svg is not attached to DOM.
|
||||
sandbox.append(svg);
|
||||
|
||||
// Set up <svg> with nonce.
|
||||
svgN = document.createElementNS(NS.SVG, 'svg');
|
||||
svgN.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE);
|
||||
svgN.setAttributeNS(NS.SE, 'se:nonce', NONCE);
|
||||
|
||||
const svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
currentDrawing_ = new draw.Drawing(svgcontent, idprefix);
|
||||
});
|
||||
|
||||
it('Test draw module', function () {
|
||||
assert.ok(draw);
|
||||
assert.equal(typeof draw, typeof {});
|
||||
|
||||
assert.ok(draw.Drawing);
|
||||
assert.equal(typeof draw.Drawing, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
it('Test document creation', function () {
|
||||
let doc;
|
||||
try {
|
||||
doc = new draw.Drawing();
|
||||
assert.ok(false, 'Created drawing without a valid <svg> element');
|
||||
} catch (e) {
|
||||
assert.ok(true);
|
||||
}
|
||||
|
||||
try {
|
||||
doc = new draw.Drawing(svg);
|
||||
assert.ok(doc);
|
||||
assert.equal(typeof doc, typeof {});
|
||||
} catch (e) {
|
||||
assert.ok(false, 'Could not create document from valid <svg> element: ' + e);
|
||||
}
|
||||
});
|
||||
|
||||
it('Test nonce', function () {
|
||||
let doc = new draw.Drawing(svg);
|
||||
assert.equal(doc.getNonce(), '');
|
||||
|
||||
doc = new draw.Drawing(svgN);
|
||||
assert.equal(doc.getNonce(), NONCE);
|
||||
assert.equal(doc.getSvgElem().getAttributeNS(NS.SE, 'nonce'), NONCE);
|
||||
|
||||
doc.clearNonce();
|
||||
assert.ok(!doc.getNonce());
|
||||
assert.ok(!doc.getSvgElem().getAttributeNS(NS.SE, 'se:nonce'));
|
||||
|
||||
doc.setNonce(NONCE);
|
||||
assert.equal(doc.getNonce(), NONCE);
|
||||
assert.equal(doc.getSvgElem().getAttributeNS(NS.SE, 'nonce'), NONCE);
|
||||
});
|
||||
|
||||
it('Test getId() and getNextId() without nonce', function () {
|
||||
const elem2 = document.createElementNS(NS.SVG, 'circle');
|
||||
elem2.id = 'svg_2';
|
||||
svg.append(elem2);
|
||||
|
||||
const doc = new draw.Drawing(svg);
|
||||
|
||||
assert.equal(doc.getId(), 'svg_0');
|
||||
|
||||
assert.equal(doc.getNextId(), 'svg_1');
|
||||
assert.equal(doc.getId(), 'svg_1');
|
||||
|
||||
assert.equal(doc.getNextId(), 'svg_3');
|
||||
assert.equal(doc.getId(), 'svg_3');
|
||||
|
||||
assert.equal(doc.getNextId(), 'svg_4');
|
||||
assert.equal(doc.getId(), 'svg_4');
|
||||
// clean out svg document
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test getId() and getNextId() with prefix without nonce', function () {
|
||||
const prefix = 'Bar-';
|
||||
const doc = new draw.Drawing(svg, prefix);
|
||||
|
||||
assert.equal(doc.getId(), prefix + '0');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '1');
|
||||
assert.equal(doc.getId(), prefix + '1');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '2');
|
||||
assert.equal(doc.getId(), prefix + '2');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '3');
|
||||
assert.equal(doc.getId(), prefix + '3');
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test getId() and getNextId() with nonce', function () {
|
||||
const prefix = 'svg_' + NONCE;
|
||||
|
||||
const elem2 = document.createElementNS(NS.SVG, 'circle');
|
||||
elem2.id = prefix + '_2';
|
||||
svgN.append(elem2);
|
||||
|
||||
const doc = new draw.Drawing(svgN);
|
||||
|
||||
assert.equal(doc.getId(), prefix + '_0');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '_1');
|
||||
assert.equal(doc.getId(), prefix + '_1');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '_3');
|
||||
assert.equal(doc.getId(), prefix + '_3');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '_4');
|
||||
assert.equal(doc.getId(), prefix + '_4');
|
||||
|
||||
cleanupSVG(svgN);
|
||||
});
|
||||
|
||||
it('Test getId() and getNextId() with prefix with nonce', function () {
|
||||
const PREFIX = 'Bar-';
|
||||
const doc = new draw.Drawing(svgN, PREFIX);
|
||||
|
||||
const prefix = PREFIX + NONCE + '_';
|
||||
assert.equal(doc.getId(), prefix + '0');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '1');
|
||||
assert.equal(doc.getId(), prefix + '1');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '2');
|
||||
assert.equal(doc.getId(), prefix + '2');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '3');
|
||||
assert.equal(doc.getId(), prefix + '3');
|
||||
|
||||
cleanupSVG(svgN);
|
||||
});
|
||||
|
||||
it('Test releaseId()', function () {
|
||||
const doc = new draw.Drawing(svg);
|
||||
|
||||
const firstId = doc.getNextId();
|
||||
/* const secondId = */ doc.getNextId();
|
||||
|
||||
const result = doc.releaseId(firstId);
|
||||
assert.ok(result);
|
||||
assert.equal(doc.getNextId(), firstId);
|
||||
assert.equal(doc.getNextId(), 'svg_3');
|
||||
|
||||
assert.ok(!doc.releaseId('bad-id'));
|
||||
assert.ok(doc.releaseId(firstId));
|
||||
assert.ok(!doc.releaseId(firstId));
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test getNumLayers', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
assert.equal(typeof drawing.getNumLayers, typeof function () { /* */ });
|
||||
assert.equal(drawing.getNumLayers(), 0);
|
||||
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 3);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test hasLayer', function () {
|
||||
setupSVGWith3Layers(svg);
|
||||
const drawing = new draw.Drawing(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(typeof drawing.hasLayer, typeof function () { /* */ });
|
||||
assert.ok(!drawing.hasLayer('invalid-layer'));
|
||||
|
||||
assert.ok(drawing.hasLayer(LAYER3));
|
||||
assert.ok(drawing.hasLayer(LAYER2));
|
||||
assert.ok(drawing.hasLayer(LAYER1));
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test identifyLayers() with empty document', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
assert.equal(drawing.getCurrentLayer(), null);
|
||||
// By default, an empty document gets an empty group created.
|
||||
drawing.identifyLayers();
|
||||
|
||||
// Check that <svg> element now has one child node
|
||||
assert.ok(drawing.getSvgElem().hasChildNodes());
|
||||
assert.equal(drawing.getSvgElem().childNodes.length, 1);
|
||||
|
||||
// Check that all_layers are correctly set up.
|
||||
assert.equal(drawing.getNumLayers(), 1);
|
||||
const emptyLayer = drawing.all_layers[0];
|
||||
assert.ok(emptyLayer);
|
||||
const layerGroup = emptyLayer.getGroup();
|
||||
assert.equal(layerGroup, drawing.getSvgElem().firstChild);
|
||||
assert.equal(layerGroup.tagName, 'g');
|
||||
assert.equal(layerGroup.getAttribute('class'), LAYER_CLASS);
|
||||
assert.ok(layerGroup.hasChildNodes());
|
||||
assert.equal(layerGroup.childNodes.length, 1);
|
||||
const firstChild = layerGroup.childNodes.item(0);
|
||||
assert.equal(firstChild.tagName, 'title');
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test identifyLayers() with some layers', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
|
||||
assert.equal(svg.childNodes.length, 3);
|
||||
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 3);
|
||||
assert.equal(drawing.all_layers[0].getGroup(), svg.childNodes.item(0));
|
||||
assert.equal(drawing.all_layers[1].getGroup(), svg.childNodes.item(1));
|
||||
assert.equal(drawing.all_layers[2].getGroup(), svg.childNodes.item(2));
|
||||
|
||||
assert.equal(drawing.all_layers[0].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[1].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[2].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test identifyLayers() with some layers and orphans', function () {
|
||||
setupSVGWith3Layers(svg);
|
||||
|
||||
const orphan1 = document.createElementNS(NS.SVG, 'rect');
|
||||
const orphan2 = document.createElementNS(NS.SVG, 'rect');
|
||||
svg.append(orphan1, orphan2);
|
||||
|
||||
assert.equal(svg.childNodes.length, 5);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 4);
|
||||
assert.equal(drawing.all_layers[0].getGroup(), svg.childNodes.item(0));
|
||||
assert.equal(drawing.all_layers[1].getGroup(), svg.childNodes.item(1));
|
||||
assert.equal(drawing.all_layers[2].getGroup(), svg.childNodes.item(2));
|
||||
assert.equal(drawing.all_layers[3].getGroup(), svg.childNodes.item(3));
|
||||
|
||||
assert.equal(drawing.all_layers[0].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[1].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[2].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[3].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
|
||||
const layer4 = drawing.all_layers[3].getGroup();
|
||||
assert.equal(layer4.tagName, 'g');
|
||||
assert.equal(layer4.childNodes.length, 3);
|
||||
assert.equal(layer4.childNodes.item(1), orphan1);
|
||||
assert.equal(layer4.childNodes.item(2), orphan2);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test getLayerName()', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 3);
|
||||
assert.equal(drawing.getLayerName(0), LAYER1);
|
||||
assert.equal(drawing.getLayerName(1), LAYER2);
|
||||
assert.equal(drawing.getLayerName(2), LAYER3);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test getCurrentLayer()', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.getCurrentLayer);
|
||||
assert.equal(typeof drawing.getCurrentLayer, typeof function () { /* */ });
|
||||
assert.ok(drawing.getCurrentLayer());
|
||||
assert.equal(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup());
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test setCurrentLayer() and getCurrentLayerName()', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.setCurrentLayer);
|
||||
assert.equal(typeof drawing.setCurrentLayer, typeof function () { /* */ });
|
||||
|
||||
drawing.setCurrentLayer(LAYER2);
|
||||
assert.equal(drawing.getCurrentLayerName(), LAYER2);
|
||||
assert.equal(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup());
|
||||
|
||||
drawing.setCurrentLayer(LAYER3);
|
||||
assert.equal(drawing.getCurrentLayerName(), LAYER3);
|
||||
assert.equal(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup());
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test setCurrentLayerName()', function () {
|
||||
const mockHrService = {
|
||||
changeElement () {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
addOwnSpies(mockHrService);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.setCurrentLayerName);
|
||||
assert.equal(typeof drawing.setCurrentLayerName, typeof function () { /* */ });
|
||||
|
||||
const oldName = drawing.getCurrentLayerName();
|
||||
const newName = 'New Name';
|
||||
assert.ok(drawing.layer_map[oldName]);
|
||||
assert.equal(drawing.layer_map[newName], undefined); // newName shouldn't exist.
|
||||
const result = drawing.setCurrentLayerName(newName, mockHrService);
|
||||
assert.equal(result, newName);
|
||||
assert.equal(drawing.getCurrentLayerName(), newName);
|
||||
// Was the map updated?
|
||||
assert.equal(drawing.layer_map[oldName], undefined);
|
||||
assert.equal(drawing.layer_map[newName], drawing.current_layer);
|
||||
// Was mockHrService called?
|
||||
assert.ok(mockHrService.changeElement.calledOnce);
|
||||
assert.equal(oldName, mockHrService.changeElement.getCall(0).args[1]['#text']);
|
||||
assert.equal(newName, mockHrService.changeElement.getCall(0).args[0].textContent);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test createLayer()', function () {
|
||||
const mockHrService = {
|
||||
startBatchCommand () { /**/ },
|
||||
endBatchCommand () { /**/ },
|
||||
insertElement () { /**/ }
|
||||
};
|
||||
addOwnSpies(mockHrService);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.createLayer);
|
||||
assert.equal(typeof drawing.createLayer, typeof function () { /* */ });
|
||||
|
||||
const NEW_LAYER_NAME = 'Layer A';
|
||||
const layerG = drawing.createLayer(NEW_LAYER_NAME, mockHrService);
|
||||
assert.equal(drawing.getNumLayers(), 4);
|
||||
assert.equal(layerG, drawing.getCurrentLayer());
|
||||
assert.equal(layerG.getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(NEW_LAYER_NAME, drawing.getCurrentLayerName());
|
||||
assert.equal(NEW_LAYER_NAME, drawing.getLayerName(3));
|
||||
|
||||
assert.equal(layerG, mockHrService.insertElement.getCall(0).args[0]);
|
||||
assert.ok(mockHrService.startBatchCommand.calledOnce);
|
||||
assert.ok(mockHrService.endBatchCommand.calledOnce);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test mergeLayer()', function () {
|
||||
const mockHrService = {
|
||||
startBatchCommand () { /**/ },
|
||||
endBatchCommand () { /**/ },
|
||||
moveElement () { /**/ },
|
||||
removeElement () { /**/ }
|
||||
};
|
||||
addOwnSpies(mockHrService);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
const layers = setupSVGWith3Layers(svg);
|
||||
const elementCount = createSomeElementsInGroup(layers[2]) + 1; // +1 for title element
|
||||
assert.equal(layers[1].childElementCount, 1);
|
||||
assert.equal(layers[2].childElementCount, elementCount);
|
||||
drawing.identifyLayers();
|
||||
assert.equal(drawing.getCurrentLayer(), layers[2]);
|
||||
|
||||
assert.ok(drawing.mergeLayer);
|
||||
assert.equal(typeof drawing.mergeLayer, typeof function () { /* */ });
|
||||
|
||||
drawing.mergeLayer(mockHrService);
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 2);
|
||||
assert.equal(svg.childElementCount, 2);
|
||||
assert.equal(drawing.getCurrentLayer(), layers[1]);
|
||||
assert.equal(layers[1].childElementCount, elementCount);
|
||||
|
||||
// check history record
|
||||
assert.ok(mockHrService.startBatchCommand.calledOnce);
|
||||
assert.ok(mockHrService.endBatchCommand.calledOnce);
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge Layer');
|
||||
assert.equal(mockHrService.moveElement.callCount, elementCount - 1); // -1 because the title was not moved.
|
||||
assert.equal(mockHrService.removeElement.callCount, 2); // remove group and title.
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test mergeLayer() when no previous layer to merge', function () {
|
||||
const mockHrService = {
|
||||
startBatchCommand () { /**/ },
|
||||
endBatchCommand () { /**/ },
|
||||
moveElement () { /**/ },
|
||||
removeElement () { /**/ }
|
||||
};
|
||||
addOwnSpies(mockHrService);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
const layers = setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
drawing.setCurrentLayer(LAYER1);
|
||||
assert.equal(drawing.getCurrentLayer(), layers[0]);
|
||||
|
||||
drawing.mergeLayer(mockHrService);
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 3);
|
||||
assert.equal(svg.childElementCount, 3);
|
||||
assert.equal(drawing.getCurrentLayer(), layers[0]);
|
||||
assert.equal(layers[0].childElementCount, 1);
|
||||
assert.equal(layers[1].childElementCount, 1);
|
||||
assert.equal(layers[2].childElementCount, 1);
|
||||
|
||||
// check history record
|
||||
assert.equal(mockHrService.startBatchCommand.callCount, 0);
|
||||
assert.equal(mockHrService.endBatchCommand.callCount, 0);
|
||||
assert.equal(mockHrService.moveElement.callCount, 0);
|
||||
assert.equal(mockHrService.removeElement.callCount, 0);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test mergeAllLayers()', function () {
|
||||
const mockHrService = {
|
||||
startBatchCommand () { /**/ },
|
||||
endBatchCommand () { /**/ },
|
||||
moveElement () { /**/ },
|
||||
removeElement () { /**/ }
|
||||
};
|
||||
addOwnSpies(mockHrService);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
const layers = setupSVGWith3Layers(svg);
|
||||
const elementCount = createSomeElementsInGroup(layers[0]) + 1; // +1 for title element
|
||||
createSomeElementsInGroup(layers[1]);
|
||||
createSomeElementsInGroup(layers[2]);
|
||||
assert.equal(layers[0].childElementCount, elementCount);
|
||||
assert.equal(layers[1].childElementCount, elementCount);
|
||||
assert.equal(layers[2].childElementCount, elementCount);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.mergeAllLayers);
|
||||
assert.equal(typeof drawing.mergeAllLayers, typeof function () { /* */ });
|
||||
|
||||
drawing.mergeAllLayers(mockHrService);
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 1);
|
||||
assert.equal(svg.childElementCount, 1);
|
||||
assert.equal(drawing.getCurrentLayer(), layers[0]);
|
||||
assert.equal(layers[0].childElementCount, elementCount * 3 - 2); // -2 because two titles were deleted.
|
||||
|
||||
// check history record
|
||||
assert.equal(mockHrService.startBatchCommand.callCount, 3); // mergeAllLayers + 2 * mergeLayer
|
||||
assert.equal(mockHrService.endBatchCommand.callCount, 3);
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge all Layers');
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(1).args[0], 'Merge Layer');
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(2).args[0], 'Merge Layer');
|
||||
// moveElement count is times 3 instead of 2, because one layer's elements were moved twice.
|
||||
// moveElement count is minus 3 because the three titles were not moved.
|
||||
assert.equal(mockHrService.moveElement.callCount, elementCount * 3 - 3);
|
||||
assert.equal(mockHrService.removeElement.callCount, 2 * 2); // remove group and title twice.
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test cloneLayer()', function () {
|
||||
const mockHrService = {
|
||||
startBatchCommand () { /**/ },
|
||||
endBatchCommand () { /**/ },
|
||||
insertElement () { /**/ }
|
||||
};
|
||||
addOwnSpies(mockHrService);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
const layers = setupSVGWith3Layers(svg);
|
||||
const layer3 = layers[2];
|
||||
const elementCount = createSomeElementsInGroup(layer3) + 1; // +1 for title element
|
||||
assert.equal(layer3.childElementCount, elementCount);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.cloneLayer);
|
||||
assert.equal(typeof drawing.cloneLayer, typeof function () { /* */ });
|
||||
|
||||
const clone = drawing.cloneLayer('clone', mockHrService);
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 4);
|
||||
assert.equal(svg.childElementCount, 4);
|
||||
assert.equal(drawing.getCurrentLayer(), clone);
|
||||
assert.equal(clone.childElementCount, elementCount);
|
||||
|
||||
// check history record
|
||||
assert.ok(mockHrService.startBatchCommand.calledOnce); // mergeAllLayers + 2 * mergeLayer
|
||||
assert.ok(mockHrService.endBatchCommand.calledOnce);
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Duplicate Layer');
|
||||
assert.equal(mockHrService.insertElement.callCount, 1);
|
||||
assert.equal(mockHrService.insertElement.getCall(0).args[0], clone);
|
||||
|
||||
// check that path is cloned properly
|
||||
assert.equal(clone.childNodes.length, elementCount);
|
||||
const path = clone.childNodes[1];
|
||||
assert.equal(path.id, 'svg_1');
|
||||
assert.equal(path.getAttribute('d'), PATH_ATTR.d);
|
||||
assert.equal(path.getAttribute('transform'), PATH_ATTR.transform);
|
||||
assert.equal(path.getAttribute('fill'), PATH_ATTR.fill);
|
||||
assert.equal(path.getAttribute('stroke'), PATH_ATTR.stroke);
|
||||
assert.equal(path.getAttribute('stroke-width'), PATH_ATTR['stroke-width']);
|
||||
|
||||
// check that g is cloned properly
|
||||
const g = clone.childNodes[4];
|
||||
assert.equal(g.childNodes.length, 1);
|
||||
assert.equal(g.id, 'svg_4');
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test getLayerVisibility()', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.getLayerVisibility);
|
||||
assert.equal(typeof drawing.getLayerVisibility, typeof function () { /* */ });
|
||||
assert.ok(drawing.getLayerVisibility(LAYER1));
|
||||
assert.ok(drawing.getLayerVisibility(LAYER2));
|
||||
assert.ok(drawing.getLayerVisibility(LAYER3));
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test setLayerVisibility()', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.setLayerVisibility);
|
||||
assert.equal(typeof drawing.setLayerVisibility, typeof function () { /* */ });
|
||||
|
||||
drawing.setLayerVisibility(LAYER3, false);
|
||||
drawing.setLayerVisibility(LAYER2, true);
|
||||
drawing.setLayerVisibility(LAYER1, false);
|
||||
|
||||
assert.ok(!drawing.getLayerVisibility(LAYER1));
|
||||
assert.ok(drawing.getLayerVisibility(LAYER2));
|
||||
assert.ok(!drawing.getLayerVisibility(LAYER3));
|
||||
|
||||
drawing.setLayerVisibility(LAYER3, 'test-string');
|
||||
assert.ok(!drawing.getLayerVisibility(LAYER3));
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test getLayerOpacity()', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.getLayerOpacity);
|
||||
assert.equal(typeof drawing.getLayerOpacity, typeof function () { /* */ });
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER1), 1.0);
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER2), 1.0);
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test setLayerOpacity()', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.setLayerOpacity);
|
||||
assert.equal(typeof drawing.setLayerOpacity, typeof function () { /* */ });
|
||||
|
||||
drawing.setLayerOpacity(LAYER1, 0.4);
|
||||
drawing.setLayerOpacity(LAYER2, 'invalid-string');
|
||||
drawing.setLayerOpacity(LAYER3, -1.4);
|
||||
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER1), 0.4);
|
||||
// console.log('layer2 opacity ' + drawing.getLayerOpacity(LAYER2));
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER2), 1.0);
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0);
|
||||
|
||||
drawing.setLayerOpacity(LAYER3, 100);
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
it('Test deleteCurrentLayer()', function () {
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
drawing.setCurrentLayer(LAYER2);
|
||||
|
||||
const curLayer = drawing.getCurrentLayer();
|
||||
assert.equal(curLayer, drawing.all_layers[1].getGroup());
|
||||
const deletedLayer = drawing.deleteCurrentLayer();
|
||||
|
||||
assert.equal(curLayer, deletedLayer);
|
||||
assert.equal(drawing.getNumLayers(), 2);
|
||||
assert.equal(LAYER1, drawing.all_layers[0].getName());
|
||||
assert.equal(LAYER3, drawing.all_layers[1].getName());
|
||||
assert.equal(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup());
|
||||
});
|
||||
|
||||
it('Test svgedit.draw.randomizeIds()', function () {
|
||||
// Confirm in LET_DOCUMENT_DECIDE mode that the document decides
|
||||
// if there is a nonce.
|
||||
let drawing = new draw.Drawing(svgN.cloneNode(true));
|
||||
assert.ok(drawing.getNonce());
|
||||
|
||||
drawing = new draw.Drawing(svg.cloneNode(true));
|
||||
assert.ok(!drawing.getNonce());
|
||||
|
||||
// Confirm that a nonce is set once we're in ALWAYS_RANDOMIZE mode.
|
||||
draw.randomizeIds(true, drawing);
|
||||
assert.ok(drawing.getNonce());
|
||||
|
||||
// Confirm new drawings in ALWAYS_RANDOMIZE mode have a nonce.
|
||||
drawing = new draw.Drawing(svg.cloneNode(true));
|
||||
assert.ok(drawing.getNonce());
|
||||
|
||||
drawing.clearNonce();
|
||||
assert.ok(!drawing.getNonce());
|
||||
|
||||
// Confirm new drawings in NEVER_RANDOMIZE mode do not have a nonce
|
||||
// but that their se:nonce attribute is left alone.
|
||||
draw.randomizeIds(false, drawing);
|
||||
assert.ok(!drawing.getNonce());
|
||||
assert.ok(drawing.getSvgElem().getAttributeNS(NS.SE, 'nonce'));
|
||||
|
||||
drawing = new draw.Drawing(svg.cloneNode(true));
|
||||
assert.ok(!drawing.getNonce());
|
||||
|
||||
drawing = new draw.Drawing(svgN.cloneNode(true));
|
||||
assert.ok(!drawing.getNonce());
|
||||
});
|
||||
});
|
||||
516
cypress/integration/history.js
Normal file
516
cypress/integration/history.js
Normal file
@@ -0,0 +1,516 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as transformlist from '../../instrumented/svgtransformlist.js';
|
||||
import * as utilities from '../../instrumented/utilities.js';
|
||||
import * as hstory from '../../instrumented/history.js';
|
||||
|
||||
describe('history', function () {
|
||||
// TODO(codedread): Write tests for handling history events.
|
||||
|
||||
// Mocked out methods.
|
||||
transformlist.changeRemoveElementFromListMap((elem) => { /* */ });
|
||||
|
||||
utilities.mock({
|
||||
getHref (elem) { return '#foo'; },
|
||||
setHref (elem, val) { /* */ },
|
||||
getRotationAngle (elem) { return 0; }
|
||||
});
|
||||
|
||||
// const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
let undoMgr = null;
|
||||
|
||||
class MockCommand {
|
||||
constructor (optText) { this.text_ = optText; }
|
||||
apply () { /* */ } // eslint-disable-line class-methods-use-this
|
||||
unapply () { /* */ } // eslint-disable-line class-methods-use-this
|
||||
getText () { return this.text_; }
|
||||
elements () { return []; } // eslint-disable-line class-methods-use-this
|
||||
}
|
||||
|
||||
/*
|
||||
class MockHistoryEventHandler {
|
||||
handleHistoryEvent (eventType, command) {}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up tests (with undo manager).
|
||||
* @returns {void}
|
||||
*/
|
||||
beforeEach(function () {
|
||||
undoMgr = new hstory.UndoManager();
|
||||
|
||||
document.body.textContent = '';
|
||||
this.divparent = document.createElement('div');
|
||||
this.divparent.id = 'divparent';
|
||||
this.divparent.style.visibility = 'hidden';
|
||||
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
const div = document.createElement('div');
|
||||
const id = `div${i}`;
|
||||
div.id = id;
|
||||
this[id] = div;
|
||||
}
|
||||
|
||||
this.divparent.append(this.div1, this.div2, this.div3);
|
||||
|
||||
this.div4.style.visibility = 'hidden';
|
||||
this.div4.append(this.div5);
|
||||
|
||||
document.body.append(this.divparent, this.div);
|
||||
});
|
||||
/**
|
||||
* Tear down tests, destroying undo manager.
|
||||
* @returns {void}
|
||||
*/
|
||||
afterEach(() => {
|
||||
undoMgr = null;
|
||||
});
|
||||
|
||||
it('Test svgedit.history package', function () {
|
||||
assert.ok(hstory);
|
||||
assert.ok(hstory.MoveElementCommand);
|
||||
assert.ok(hstory.InsertElementCommand);
|
||||
assert.ok(hstory.ChangeElementCommand);
|
||||
assert.ok(hstory.RemoveElementCommand);
|
||||
assert.ok(hstory.BatchCommand);
|
||||
assert.ok(hstory.UndoManager);
|
||||
assert.equal(typeof hstory.MoveElementCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.InsertElementCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.ChangeElementCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.RemoveElementCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.BatchCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.UndoManager, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
it('Test UndoManager methods', function () {
|
||||
assert.ok(undoMgr);
|
||||
assert.ok(undoMgr.addCommandToHistory);
|
||||
assert.ok(undoMgr.getUndoStackSize);
|
||||
assert.ok(undoMgr.getRedoStackSize);
|
||||
assert.ok(undoMgr.resetUndoStack);
|
||||
assert.ok(undoMgr.getNextUndoCommandText);
|
||||
assert.ok(undoMgr.getNextRedoCommandText);
|
||||
|
||||
assert.equal(typeof undoMgr, typeof {});
|
||||
assert.equal(typeof undoMgr.addCommandToHistory, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.getUndoStackSize, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.getRedoStackSize, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.resetUndoStack, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.getNextUndoCommandText, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.getNextRedoCommandText, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
it('Test UndoManager.addCommandToHistory() function', function () {
|
||||
assert.equal(undoMgr.getUndoStackSize(), 0);
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
assert.equal(undoMgr.getUndoStackSize(), 1);
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
assert.equal(undoMgr.getUndoStackSize(), 2);
|
||||
});
|
||||
|
||||
it('Test UndoManager.getUndoStackSize() and getRedoStackSize() functions', function () {
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
|
||||
assert.equal(undoMgr.getUndoStackSize(), 3);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 0);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 2);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 1);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 1);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 2);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 0);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 3);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 0);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 3);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 1);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 2);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 2);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 1);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 3);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 0);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 3);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 0);
|
||||
});
|
||||
|
||||
it('Test UndoManager.resetUndoStackSize() function', function () {
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.undo();
|
||||
|
||||
assert.equal(undoMgr.getUndoStackSize(), 2);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 1);
|
||||
|
||||
undoMgr.resetUndoStack();
|
||||
|
||||
assert.equal(undoMgr.getUndoStackSize(), 0);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 0);
|
||||
});
|
||||
|
||||
it('Test UndoManager.getNextUndoCommandText() function', function () {
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), '');
|
||||
|
||||
undoMgr.addCommandToHistory(new MockCommand('First'));
|
||||
undoMgr.addCommandToHistory(new MockCommand('Second'));
|
||||
undoMgr.addCommandToHistory(new MockCommand('Third'));
|
||||
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Third');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Second');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'First');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), '');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'First');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Second');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Third');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Third');
|
||||
});
|
||||
|
||||
it('Test UndoManager.getNextRedoCommandText() function', function () {
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), '');
|
||||
|
||||
undoMgr.addCommandToHistory(new MockCommand('First'));
|
||||
undoMgr.addCommandToHistory(new MockCommand('Second'));
|
||||
undoMgr.addCommandToHistory(new MockCommand('Third'));
|
||||
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), '');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'Third');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'Second');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'First');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'Second');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'Third');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), '');
|
||||
});
|
||||
|
||||
it('Test UndoManager.undo() and redo() functions', function () {
|
||||
let lastCalled = null;
|
||||
const cmd1 = new MockCommand();
|
||||
const cmd2 = new MockCommand();
|
||||
const cmd3 = new MockCommand();
|
||||
cmd1.apply = function () { lastCalled = 'cmd1.apply'; };
|
||||
cmd2.apply = function () { lastCalled = 'cmd2.apply'; };
|
||||
cmd3.apply = function () { lastCalled = 'cmd3.apply'; };
|
||||
cmd1.unapply = function () { lastCalled = 'cmd1.unapply'; };
|
||||
cmd2.unapply = function () { lastCalled = 'cmd2.unapply'; };
|
||||
cmd3.unapply = function () { lastCalled = 'cmd3.unapply'; };
|
||||
|
||||
undoMgr.addCommandToHistory(cmd1);
|
||||
undoMgr.addCommandToHistory(cmd2);
|
||||
undoMgr.addCommandToHistory(cmd3);
|
||||
|
||||
assert.ok(!lastCalled);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(lastCalled, 'cmd3.unapply');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(lastCalled, 'cmd3.apply');
|
||||
|
||||
undoMgr.undo();
|
||||
undoMgr.undo();
|
||||
assert.equal(lastCalled, 'cmd2.unapply');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(lastCalled, 'cmd1.unapply');
|
||||
lastCalled = null;
|
||||
|
||||
undoMgr.undo();
|
||||
assert.ok(!lastCalled);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(lastCalled, 'cmd1.apply');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(lastCalled, 'cmd2.apply');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(lastCalled, 'cmd3.apply');
|
||||
lastCalled = null;
|
||||
|
||||
undoMgr.redo();
|
||||
assert.ok(!lastCalled);
|
||||
});
|
||||
|
||||
it('Test MoveElementCommand', function () {
|
||||
let move = new hstory.MoveElementCommand(this.div3, this.div1, this.divparent);
|
||||
assert.ok(move.unapply);
|
||||
assert.ok(move.apply);
|
||||
assert.equal(typeof move.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof move.apply, typeof function () { /* */ });
|
||||
|
||||
move.unapply();
|
||||
assert.equal(this.divparent.firstElementChild, this.div3);
|
||||
assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div1);
|
||||
assert.equal(this.divparent.lastElementChild, this.div2);
|
||||
|
||||
move.apply();
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2);
|
||||
assert.equal(this.divparent.lastElementChild, this.div3);
|
||||
|
||||
move = new hstory.MoveElementCommand(this.div1, null, this.divparent);
|
||||
|
||||
move.unapply();
|
||||
assert.equal(this.divparent.firstElementChild, this.div2);
|
||||
assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div3);
|
||||
assert.equal(this.divparent.lastElementChild, this.div1);
|
||||
|
||||
move.apply();
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2);
|
||||
assert.equal(this.divparent.lastElementChild, this.div3);
|
||||
|
||||
move = new hstory.MoveElementCommand(this.div2, this.div5, this.div4);
|
||||
|
||||
move.unapply();
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div3);
|
||||
assert.equal(this.divparent.lastElementChild, this.div3);
|
||||
assert.equal(this.div4.firstElementChild, this.div2);
|
||||
assert.equal(this.div4.firstElementChild.nextElementSibling, this.div5);
|
||||
|
||||
move.apply();
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.divparent.firstElementChild.nextElementSibling, this.div2);
|
||||
assert.equal(this.divparent.lastElementChild, this.div3);
|
||||
assert.equal(this.div4.firstElementChild, this.div5);
|
||||
assert.equal(this.div4.lastElementChild, this.div5);
|
||||
});
|
||||
|
||||
it('Test InsertElementCommand', function () {
|
||||
let insert = new hstory.InsertElementCommand(this.div3);
|
||||
assert.ok(insert.unapply);
|
||||
assert.ok(insert.apply);
|
||||
assert.equal(typeof insert.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof insert.apply, typeof function () { /* */ });
|
||||
|
||||
insert.unapply();
|
||||
assert.equal(this.divparent.childElementCount, 2);
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.div1.nextElementSibling, this.div2);
|
||||
assert.equal(this.divparent.lastElementChild, this.div2);
|
||||
|
||||
insert.apply();
|
||||
assert.equal(this.divparent.childElementCount, 3);
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.div1.nextElementSibling, this.div2);
|
||||
assert.equal(this.div2.nextElementSibling, this.div3);
|
||||
|
||||
insert = new hstory.InsertElementCommand(this.div2);
|
||||
|
||||
insert.unapply();
|
||||
assert.equal(this.divparent.childElementCount, 2);
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.div1.nextElementSibling, this.div3);
|
||||
assert.equal(this.divparent.lastElementChild, this.div3);
|
||||
|
||||
insert.apply();
|
||||
assert.equal(this.divparent.childElementCount, 3);
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.div1.nextElementSibling, this.div2);
|
||||
assert.equal(this.div2.nextElementSibling, this.div3);
|
||||
});
|
||||
|
||||
it('Test RemoveElementCommand', function () {
|
||||
const div6 = document.createElement('div');
|
||||
div6.id = 'div6';
|
||||
|
||||
let remove = new hstory.RemoveElementCommand(div6, null, this.divparent);
|
||||
assert.ok(remove.unapply);
|
||||
assert.ok(remove.apply);
|
||||
assert.equal(typeof remove.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof remove.apply, typeof function () { /* */ });
|
||||
|
||||
remove.unapply();
|
||||
assert.equal(this.divparent.childElementCount, 4);
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.div1.nextElementSibling, this.div2);
|
||||
assert.equal(this.div2.nextElementSibling, this.div3);
|
||||
assert.equal(this.div3.nextElementSibling, div6);
|
||||
|
||||
remove.apply();
|
||||
assert.equal(this.divparent.childElementCount, 3);
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.div1.nextElementSibling, this.div2);
|
||||
assert.equal(this.div2.nextElementSibling, this.div3);
|
||||
|
||||
remove = new hstory.RemoveElementCommand(div6, this.div2, this.divparent);
|
||||
|
||||
remove.unapply();
|
||||
assert.equal(this.divparent.childElementCount, 4);
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.div1.nextElementSibling, div6);
|
||||
assert.equal(div6.nextElementSibling, this.div2);
|
||||
assert.equal(this.div2.nextElementSibling, this.div3);
|
||||
|
||||
remove.apply();
|
||||
assert.equal(this.divparent.childElementCount, 3);
|
||||
assert.equal(this.divparent.firstElementChild, this.div1);
|
||||
assert.equal(this.div1.nextElementSibling, this.div2);
|
||||
assert.equal(this.div2.nextElementSibling, this.div3);
|
||||
});
|
||||
|
||||
it('Test ChangeElementCommand', function () {
|
||||
this.div1.setAttribute('title', 'new title');
|
||||
let change = new hstory.ChangeElementCommand(this.div1,
|
||||
{title: 'old title', class: 'foo'});
|
||||
assert.ok(change.unapply);
|
||||
assert.ok(change.apply);
|
||||
assert.equal(typeof change.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof change.apply, typeof function () { /* */ });
|
||||
|
||||
change.unapply();
|
||||
assert.equal(this.div1.getAttribute('title'), 'old title');
|
||||
assert.equal(this.div1.getAttribute('class'), 'foo');
|
||||
|
||||
change.apply();
|
||||
assert.equal(this.div1.getAttribute('title'), 'new title');
|
||||
assert.ok(!this.div1.getAttribute('class'));
|
||||
|
||||
this.div1.textContent = 'inner text';
|
||||
change = new hstory.ChangeElementCommand(this.div1,
|
||||
{'#text': null});
|
||||
|
||||
change.unapply();
|
||||
assert.ok(!this.div1.textContent);
|
||||
|
||||
change.apply();
|
||||
assert.equal(this.div1.textContent, 'inner text');
|
||||
|
||||
this.div1.textContent = '';
|
||||
change = new hstory.ChangeElementCommand(this.div1,
|
||||
{'#text': 'old text'});
|
||||
|
||||
change.unapply();
|
||||
assert.equal(this.div1.textContent, 'old text');
|
||||
|
||||
change.apply();
|
||||
assert.ok(!this.div1.textContent);
|
||||
|
||||
// TODO(codedread): Refactor this #href stuff in history.js and svgcanvas.js
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
let justCalled = null;
|
||||
let gethrefvalue = null;
|
||||
let sethrefvalue = null;
|
||||
utilities.mock({
|
||||
getHref (elem) {
|
||||
assert.equal(elem, rect);
|
||||
justCalled = 'getHref';
|
||||
return gethrefvalue;
|
||||
},
|
||||
setHref (elem, val) {
|
||||
assert.equal(elem, rect);
|
||||
assert.equal(val, sethrefvalue);
|
||||
justCalled = 'setHref';
|
||||
},
|
||||
getRotationAngle (elem) { return 0; }
|
||||
});
|
||||
|
||||
gethrefvalue = '#newhref';
|
||||
change = new hstory.ChangeElementCommand(rect,
|
||||
{'#href': '#oldhref'});
|
||||
assert.equal(justCalled, 'getHref');
|
||||
|
||||
justCalled = null;
|
||||
sethrefvalue = '#oldhref';
|
||||
change.unapply();
|
||||
assert.equal(justCalled, 'setHref');
|
||||
|
||||
justCalled = null;
|
||||
sethrefvalue = '#newhref';
|
||||
change.apply();
|
||||
assert.equal(justCalled, 'setHref');
|
||||
|
||||
const line = document.createElementNS(NS.SVG, 'line');
|
||||
line.setAttribute('class', 'newClass');
|
||||
change = new hstory.ChangeElementCommand(line, {class: 'oldClass'});
|
||||
|
||||
assert.ok(change.unapply);
|
||||
assert.ok(change.apply);
|
||||
assert.equal(typeof change.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof change.apply, typeof function () { /* */ });
|
||||
|
||||
change.unapply();
|
||||
assert.equal(line.getAttribute('class'), 'oldClass');
|
||||
|
||||
change.apply();
|
||||
assert.equal(line.getAttribute('class'), 'newClass');
|
||||
});
|
||||
|
||||
it('Test BatchCommand', function () {
|
||||
let concatResult = '';
|
||||
MockCommand.prototype.apply = function () { concatResult += this.text_; };
|
||||
|
||||
const batch = new hstory.BatchCommand();
|
||||
assert.ok(batch.unapply);
|
||||
assert.ok(batch.apply);
|
||||
assert.ok(batch.addSubCommand);
|
||||
assert.ok(batch.isEmpty);
|
||||
assert.equal(typeof batch.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof batch.apply, typeof function () { /* */ });
|
||||
assert.equal(typeof batch.addSubCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof batch.isEmpty, typeof function () { /* */ });
|
||||
|
||||
assert.ok(batch.isEmpty());
|
||||
|
||||
batch.addSubCommand(new MockCommand('a'));
|
||||
assert.ok(!batch.isEmpty());
|
||||
batch.addSubCommand(new MockCommand('b'));
|
||||
batch.addSubCommand(new MockCommand('c'));
|
||||
|
||||
assert.ok(!concatResult);
|
||||
batch.apply();
|
||||
assert.equal(concatResult, 'abc');
|
||||
|
||||
MockCommand.prototype.apply = function () { /* */ };
|
||||
MockCommand.prototype.unapply = function () { concatResult += this.text_; };
|
||||
concatResult = '';
|
||||
batch.unapply();
|
||||
assert.equal(concatResult, 'cba');
|
||||
|
||||
MockCommand.prototype.unapply = function () { /* */ };
|
||||
});
|
||||
});
|
||||
108
cypress/integration/math.js
Normal file
108
cypress/integration/math.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as math from '../../instrumented/math.js';
|
||||
|
||||
describe('math', function () {
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
it('Test svgedit.math package', function () {
|
||||
assert.ok(math);
|
||||
assert.ok(math.transformPoint);
|
||||
assert.ok(math.isIdentity);
|
||||
assert.ok(math.matrixMultiply);
|
||||
assert.equal(typeof math.transformPoint, typeof function () { /* */ });
|
||||
assert.equal(typeof math.isIdentity, typeof function () { /* */ });
|
||||
assert.equal(typeof math.matrixMultiply, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
it('Test svgedit.math.transformPoint() function', function () {
|
||||
const {transformPoint} = math;
|
||||
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 0; m.f = 0;
|
||||
let pt = transformPoint(100, 200, m);
|
||||
assert.equal(pt.x, 100);
|
||||
assert.equal(pt.y, 200);
|
||||
|
||||
m.e = 300; m.f = 400;
|
||||
pt = transformPoint(100, 200, m);
|
||||
assert.equal(pt.x, 400);
|
||||
assert.equal(pt.y, 600);
|
||||
|
||||
m.a = 0.5; m.b = 0.75;
|
||||
m.c = 1.25; m.d = 2;
|
||||
pt = transformPoint(100, 200, m);
|
||||
assert.equal(pt.x, 100 * m.a + 200 * m.c + m.e);
|
||||
assert.equal(pt.y, 100 * m.b + 200 * m.d + m.f);
|
||||
});
|
||||
|
||||
it('Test svgedit.math.isIdentity() function', function () {
|
||||
assert.ok(math.isIdentity(svg.createSVGMatrix()));
|
||||
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 0; m.f = 0;
|
||||
assert.ok(math.isIdentity(m));
|
||||
});
|
||||
|
||||
it('Test svgedit.math.matrixMultiply() function', function () {
|
||||
const mult = math.matrixMultiply;
|
||||
const {isIdentity} = math;
|
||||
|
||||
// translate there and back
|
||||
const tr1 = svg.createSVGMatrix().translate(100, 50),
|
||||
tr2 = svg.createSVGMatrix().translate(-90, 0),
|
||||
tr3 = svg.createSVGMatrix().translate(-10, -50);
|
||||
let I = mult(tr1, tr2, tr3);
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when translating there and back');
|
||||
|
||||
// rotate there and back
|
||||
// TODO: currently Mozilla fails this when rotating back at -50 and then -40 degrees
|
||||
// (b and c are *almost* zero, but not zero)
|
||||
const rotThere = svg.createSVGMatrix().rotate(90),
|
||||
rotBack = svg.createSVGMatrix().rotate(-90), // TODO: set this to -50
|
||||
rotBackMore = svg.createSVGMatrix().rotate(0); // TODO: set this to -40
|
||||
I = mult(rotThere, rotBack, rotBackMore);
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when rotating there and back');
|
||||
|
||||
// scale up and down
|
||||
const scaleUp = svg.createSVGMatrix().scale(4),
|
||||
scaleDown = svg.createSVGMatrix().scaleNonUniform(0.25, 1),
|
||||
scaleDownMore = svg.createSVGMatrix().scaleNonUniform(1, 0.25);
|
||||
I = mult(scaleUp, scaleDown, scaleDownMore);
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when scaling up and down');
|
||||
|
||||
// test multiplication with its inverse
|
||||
I = mult(rotThere, rotThere.inverse());
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse');
|
||||
I = mult(rotThere.inverse(), rotThere);
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse');
|
||||
});
|
||||
|
||||
it('Test svgedit.math.transformBox() function', function () {
|
||||
const {transformBox} = math;
|
||||
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
const r = transformBox(10, 10, 200, 300, m);
|
||||
assert.equal(r.tl.x, 10);
|
||||
assert.equal(r.tl.y, 10);
|
||||
assert.equal(r.tr.x, 210);
|
||||
assert.equal(r.tr.y, 10);
|
||||
assert.equal(r.bl.x, 10);
|
||||
assert.equal(r.bl.y, 310);
|
||||
assert.equal(r.br.x, 210);
|
||||
assert.equal(r.br.y, 310);
|
||||
assert.equal(r.aabox.x, 10);
|
||||
assert.equal(r.aabox.y, 10);
|
||||
assert.equal(r.aabox.width, 200);
|
||||
assert.equal(r.aabox.height, 300);
|
||||
});
|
||||
});
|
||||
167
cypress/integration/path.js
Normal file
167
cypress/integration/path.js
Normal file
@@ -0,0 +1,167 @@
|
||||
/* globals SVGPathSeg */
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import '../../instrumented/svgpathseg.js';
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as utilities from '../../instrumented/utilities.js';
|
||||
import * as pathModule from '../../instrumented/path.js';
|
||||
|
||||
describe('path', function () {
|
||||
/**
|
||||
* @typedef {GenericArray} EditorContexts
|
||||
* @property {module:path.EditorContext} 0
|
||||
* @property {module:path.EditorContext} 1
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {SVGSVGElement} [svg]
|
||||
* @returns {EditorContexts}
|
||||
*/
|
||||
function getMockContexts (svg) {
|
||||
svg = svg || document.createElementNS(NS.SVG, 'svg');
|
||||
const selectorParentGroup = document.createElementNS(NS.SVG, 'g');
|
||||
selectorParentGroup.setAttribute('id', 'selectorParentGroup');
|
||||
svg.append(selectorParentGroup);
|
||||
return [
|
||||
/**
|
||||
* @implements {module:path.EditorContext}
|
||||
*/
|
||||
{
|
||||
getSVGRoot () { return svg; },
|
||||
getCurrentZoom () { return 1; }
|
||||
},
|
||||
/**
|
||||
* @implements {module:utilities.EditorContext}
|
||||
*/
|
||||
{
|
||||
getDOMDocument () { return svg; },
|
||||
getDOMContainer () { return svg; },
|
||||
getSVGRoot () { return svg; }
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
it('Test svgedit.path.replacePathSeg', function () {
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 L10,11 L20,21Z');
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts();
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
new pathModule.Path(path); // eslint-disable-line no-new
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 10);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 11);
|
||||
|
||||
pathModule.replacePathSeg(SVGPathSeg.PATHSEG_LINETO_REL, 1, [30, 31], path);
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'l');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 30);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 31);
|
||||
});
|
||||
|
||||
it('Test svgedit.path.Segment.setType simple', function () {
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 L10,11 L20,21Z');
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts();
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
new pathModule.Path(path); // eslint-disable-line no-new
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 10);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 11);
|
||||
|
||||
const segment = new pathModule.Segment(1, path.pathSegList.getItem(1));
|
||||
segment.setType(SVGPathSeg.PATHSEG_LINETO_REL, [30, 31]);
|
||||
assert.equal(segment.item.pathSegTypeAsLetter, 'l');
|
||||
assert.equal(segment.item.x, 30);
|
||||
assert.equal(segment.item.y, 31);
|
||||
|
||||
// Also verify that the actual path changed.
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'l');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 30);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 31);
|
||||
});
|
||||
|
||||
it('Test svgedit.path.Segment.setType with control points', function () {
|
||||
// Setup the dom for a mock control group.
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C11,12 13,14 15,16 Z');
|
||||
svg.append(path);
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts(svg);
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
const segment = new pathModule.Segment(1, path.pathSegList.getItem(1));
|
||||
segment.path = new pathModule.Path(path);
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C');
|
||||
assert.equal(path.pathSegList.getItem(1).x1, 11);
|
||||
assert.equal(path.pathSegList.getItem(1).y1, 12);
|
||||
assert.equal(path.pathSegList.getItem(1).x2, 13);
|
||||
assert.equal(path.pathSegList.getItem(1).y2, 14);
|
||||
assert.equal(path.pathSegList.getItem(1).x, 15);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 16);
|
||||
|
||||
segment.setType(SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, [30, 31, 32, 33, 34, 35]);
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'c');
|
||||
assert.equal(path.pathSegList.getItem(1).x1, 32);
|
||||
assert.equal(path.pathSegList.getItem(1).y1, 33);
|
||||
assert.equal(path.pathSegList.getItem(1).x2, 34);
|
||||
assert.equal(path.pathSegList.getItem(1).y2, 35);
|
||||
assert.equal(path.pathSegList.getItem(1).x, 30);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 31);
|
||||
});
|
||||
|
||||
it('Test svgedit.path.Segment.move', function () {
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 L10,11 L20,21Z');
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts();
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
new pathModule.Path(path); // eslint-disable-line no-new
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 10);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 11);
|
||||
|
||||
const segment = new pathModule.Segment(1, path.pathSegList.getItem(1));
|
||||
segment.move(-3, 4);
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 7);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 15);
|
||||
});
|
||||
|
||||
it('Test svgedit.path.Segment.moveCtrl', function () {
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C11,12 13,14 15,16 Z');
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts();
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
new pathModule.Path(path); // eslint-disable-line no-new
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C');
|
||||
assert.equal(path.pathSegList.getItem(1).x1, 11);
|
||||
assert.equal(path.pathSegList.getItem(1).y1, 12);
|
||||
assert.equal(path.pathSegList.getItem(1).x2, 13);
|
||||
assert.equal(path.pathSegList.getItem(1).y2, 14);
|
||||
assert.equal(path.pathSegList.getItem(1).x, 15);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 16);
|
||||
|
||||
const segment = new pathModule.Segment(1, path.pathSegList.getItem(1));
|
||||
segment.moveCtrl(1, 100, -200);
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C');
|
||||
assert.equal(path.pathSegList.getItem(1).x1, 111);
|
||||
assert.equal(path.pathSegList.getItem(1).y1, -188);
|
||||
assert.equal(path.pathSegList.getItem(1).x2, 13);
|
||||
assert.equal(path.pathSegList.getItem(1).y2, 14);
|
||||
assert.equal(path.pathSegList.getItem(1).x, 15);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 16);
|
||||
});
|
||||
});
|
||||
153
cypress/integration/recalculate.js
Normal file
153
cypress/integration/recalculate.js
Normal file
@@ -0,0 +1,153 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as utilities from '../../instrumented/utilities.js';
|
||||
import * as coords from '../../instrumented/coords.js';
|
||||
import * as recalculate from '../../instrumented/recalculate.js';
|
||||
|
||||
describe('recalculate', function () {
|
||||
// eslint-disable-next-line no-shadow
|
||||
const root = document.createElement('div');
|
||||
root.id = 'root';
|
||||
root.style.visibility = 'hidden';
|
||||
|
||||
const svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot.id = 'svgroot';
|
||||
root.append(svgroot);
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot.append(svg);
|
||||
|
||||
let elemId = 1;
|
||||
|
||||
/**
|
||||
* Initilize modules to set up the tests.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUp () {
|
||||
utilities.init(
|
||||
/**
|
||||
* @implements {module:utilities.EditorContext}
|
||||
*/
|
||||
{
|
||||
getSVGRoot () { return svg; },
|
||||
getDOMDocument () { return null; },
|
||||
getDOMContainer () { return null; }
|
||||
}
|
||||
);
|
||||
coords.init(
|
||||
/**
|
||||
* @implements {module:coords.EditorContext}
|
||||
*/
|
||||
{
|
||||
getGridSnapping () { return false; },
|
||||
getDrawing () {
|
||||
return {
|
||||
getNextId () { return String(elemId++); }
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
recalculate.init(
|
||||
/**
|
||||
* @implements {module:recalculate.EditorContext}
|
||||
*/
|
||||
{
|
||||
getSVGRoot () { return svg; },
|
||||
getStartTransform () { return ''; },
|
||||
setStartTransform () { /* */ }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let elem;
|
||||
|
||||
/**
|
||||
* Initialize for tests and set up `rect` element.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUpRect () {
|
||||
setUp();
|
||||
elem = document.createElementNS(NS.SVG, 'rect');
|
||||
elem.setAttribute('x', '200');
|
||||
elem.setAttribute('y', '150');
|
||||
elem.setAttribute('width', '250');
|
||||
elem.setAttribute('height', '120');
|
||||
svg.append(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize for tests and set up `text` element with `tspan` child.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUpTextWithTspan () {
|
||||
setUp();
|
||||
elem = document.createElementNS(NS.SVG, 'text');
|
||||
elem.setAttribute('x', '200');
|
||||
elem.setAttribute('y', '150');
|
||||
|
||||
const tspan = document.createElementNS(NS.SVG, 'tspan');
|
||||
tspan.setAttribute('x', '200');
|
||||
tspan.setAttribute('y', '150');
|
||||
|
||||
const theText = document.createTextNode('Foo bar');
|
||||
tspan.append(theText);
|
||||
elem.append(tspan);
|
||||
svg.append(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down the tests (empty the svg element).
|
||||
* @returns {void}
|
||||
*/
|
||||
afterEach(() => {
|
||||
while (svg.hasChildNodes()) {
|
||||
svg.firstChild.remove();
|
||||
}
|
||||
});
|
||||
|
||||
it('Test recalculateDimensions() on rect with identity matrix', function () {
|
||||
setUpRect();
|
||||
elem.setAttribute('transform', 'matrix(1,0,0,1,0,0)');
|
||||
|
||||
recalculate.recalculateDimensions(elem);
|
||||
|
||||
// Ensure that the identity matrix is swallowed and the element has no
|
||||
// transform on it.
|
||||
assert.equal(elem.hasAttribute('transform'), false);
|
||||
});
|
||||
|
||||
it('Test recalculateDimensions() on rect with simple translate', function () {
|
||||
setUpRect();
|
||||
elem.setAttribute('transform', 'translate(100,50)');
|
||||
|
||||
recalculate.recalculateDimensions(elem);
|
||||
|
||||
assert.equal(elem.hasAttribute('transform'), false);
|
||||
assert.equal(elem.getAttribute('x'), '300');
|
||||
assert.equal(elem.getAttribute('y'), '200');
|
||||
assert.equal(elem.getAttribute('width'), '250');
|
||||
assert.equal(elem.getAttribute('height'), '120');
|
||||
});
|
||||
|
||||
it('Test recalculateDimensions() on text w/tspan with simple translate', function () {
|
||||
setUpTextWithTspan();
|
||||
elem.setAttribute('transform', 'translate(100,50)');
|
||||
|
||||
recalculate.recalculateDimensions(elem);
|
||||
|
||||
// Ensure that the identity matrix is swallowed and the element has no
|
||||
// transform on it.
|
||||
assert.equal(elem.hasAttribute('transform'), false);
|
||||
assert.equal(elem.getAttribute('x'), '300');
|
||||
assert.equal(elem.getAttribute('y'), '200');
|
||||
|
||||
const tspan = elem.firstElementChild;
|
||||
assert.equal(tspan.getAttribute('x'), '300');
|
||||
assert.equal(tspan.getAttribute('y'), '200');
|
||||
});
|
||||
|
||||
// TODO: Since recalculateDimensions() and surrounding code is
|
||||
// probably the largest, most complicated and strange piece of
|
||||
// code in SVG-edit, we need to write a whole lot of unit tests
|
||||
// for it here.
|
||||
});
|
||||
19
cypress/integration/sanitize.js
Normal file
19
cypress/integration/sanitize.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as sanitize from '../../instrumented/sanitize.js';
|
||||
|
||||
describe('sanitize', function () {
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
it('Test sanitizeSvg() strips ws from style attr', function () {
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('style', 'stroke: blue ;\t\tstroke-width :\t\t40;');
|
||||
// sanitizeSvg() requires the node to have a parent and a document.
|
||||
svg.append(rect);
|
||||
sanitize.sanitizeSvg(rect);
|
||||
|
||||
assert.equal(rect.getAttribute('stroke'), 'blue');
|
||||
assert.equal(rect.getAttribute('stroke-width'), '40');
|
||||
});
|
||||
});
|
||||
130
cypress/integration/select.js
Normal file
130
cypress/integration/select.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import * as select from '../../instrumented/select.js';
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
|
||||
describe('select', function () {
|
||||
const sandbox = document.createElement('div');
|
||||
sandbox.id = 'sandbox';
|
||||
|
||||
let svgroot;
|
||||
let svgcontent;
|
||||
const mockConfig = {
|
||||
dimensions: [640, 480]
|
||||
};
|
||||
|
||||
/**
|
||||
* @implements {module:select.SVGFactory}
|
||||
*/
|
||||
const mockFactory = {
|
||||
createSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
},
|
||||
svgRoot () { return svgroot; },
|
||||
svgContent () { return svgcontent; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Potentially reusable test set-up.
|
||||
* @returns {void}
|
||||
*/
|
||||
beforeEach(() => {
|
||||
svgroot = mockFactory.createSVGElement({
|
||||
element: 'svg',
|
||||
attr: {id: 'svgroot'}
|
||||
});
|
||||
svgcontent = svgroot.appendChild(
|
||||
mockFactory.createSVGElement({
|
||||
element: 'svg',
|
||||
attr: {id: 'svgcontent'}
|
||||
})
|
||||
);
|
||||
/* const rect = */ svgcontent.appendChild(
|
||||
mockFactory.createSVGElement({
|
||||
element: 'rect',
|
||||
attr: {
|
||||
id: 'rect',
|
||||
x: '50',
|
||||
y: '75',
|
||||
width: '200',
|
||||
height: '100'
|
||||
}
|
||||
})
|
||||
);
|
||||
sandbox.append(svgroot);
|
||||
});
|
||||
|
||||
/*
|
||||
function setUpWithInit () {
|
||||
select.init(mockConfig, mockFactory);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tear down the test by emptying our sandbox area.
|
||||
* @returns {void}
|
||||
*/
|
||||
afterEach(() => {
|
||||
while (sandbox.hasChildNodes()) {
|
||||
sandbox.firstChild.remove();
|
||||
}
|
||||
});
|
||||
|
||||
it('Test svgedit.select package', function () {
|
||||
assert.ok(select);
|
||||
assert.ok(select.Selector);
|
||||
assert.ok(select.SelectorManager);
|
||||
assert.ok(select.init);
|
||||
assert.ok(select.getSelectorManager);
|
||||
assert.equal(typeof select, typeof {});
|
||||
assert.equal(typeof select.Selector, typeof function () { /* */ });
|
||||
assert.equal(typeof select.SelectorManager, typeof function () { /* */ });
|
||||
assert.equal(typeof select.init, typeof function () { /* */ });
|
||||
assert.equal(typeof select.getSelectorManager, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
it('Test Selector DOM structure', function () {
|
||||
assert.ok(svgroot);
|
||||
assert.ok(svgroot.hasChildNodes());
|
||||
|
||||
// Verify non-existence of Selector DOM nodes
|
||||
assert.equal(svgroot.childNodes.length, 1);
|
||||
assert.equal(svgroot.childNodes.item(0), svgcontent);
|
||||
assert.ok(!svgroot.querySelector('#selectorParentGroup'));
|
||||
|
||||
select.init(mockConfig, mockFactory);
|
||||
|
||||
assert.equal(svgroot.childNodes.length, 3);
|
||||
|
||||
// Verify existence of canvas background.
|
||||
const cb = svgroot.childNodes.item(0);
|
||||
assert.ok(cb);
|
||||
assert.equal(cb.id, 'canvasBackground');
|
||||
|
||||
assert.ok(svgroot.childNodes.item(1));
|
||||
assert.equal(svgroot.childNodes.item(1), svgcontent);
|
||||
|
||||
// Verify existence of selectorParentGroup.
|
||||
const spg = svgroot.childNodes.item(2);
|
||||
assert.ok(spg);
|
||||
assert.equal(svgroot.querySelector('#selectorParentGroup'), spg);
|
||||
assert.equal(spg.id, 'selectorParentGroup');
|
||||
assert.equal(spg.tagName, 'g');
|
||||
|
||||
// Verify existence of all grip elements.
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_nw'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_n'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_ne'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_e'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_se'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_s'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_sw'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_w'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_rotateconnector'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_rotate'));
|
||||
});
|
||||
});
|
||||
329
cypress/integration/svgtransformlist.js
Normal file
329
cypress/integration/svgtransformlist.js
Normal file
@@ -0,0 +1,329 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as transformlist from '../../instrumented/svgtransformlist.js';
|
||||
import {disableSupportsNativeTransformLists} from '../../instrumented/browser.js';
|
||||
|
||||
import almostEqualsPlugin from '../support/assert-almostEquals.js';
|
||||
import expectOutOfBoundsExceptionPlugin from '../support/assert-expectOutOfBoundsException.js';
|
||||
|
||||
chai.use(almostEqualsPlugin);
|
||||
chai.use(expectOutOfBoundsExceptionPlugin);
|
||||
|
||||
describe('svgtransformlist', function () {
|
||||
disableSupportsNativeTransformLists();
|
||||
|
||||
let svgroot, svgcontent, rect, circle;
|
||||
|
||||
/**
|
||||
* Set up tests, adding elements.
|
||||
* @returns {void}
|
||||
*/
|
||||
beforeEach(() => {
|
||||
document.body.textContent = '';
|
||||
svgroot = document.createElement('div');
|
||||
svgroot.id = 'svgroot';
|
||||
svgroot.style.visibility = 'hidden';
|
||||
document.body.append(svgroot);
|
||||
|
||||
svgcontent = svgroot.appendChild(document.createElementNS(NS.SVG, 'svg'));
|
||||
rect = svgcontent.appendChild(document.createElementNS(NS.SVG, 'rect'));
|
||||
rect.id = 'r';
|
||||
circle = svgcontent.appendChild(document.createElementNS(NS.SVG, 'circle'));
|
||||
circle.id = 'c';
|
||||
});
|
||||
|
||||
/**
|
||||
* Tear down tests, emptying SVG root, and resetting list map.
|
||||
* @returns {void}
|
||||
*/
|
||||
afterEach(() => {
|
||||
transformlist.resetListMap();
|
||||
while (svgroot.hasChildNodes()) {
|
||||
svgroot.firstChild.remove();
|
||||
}
|
||||
});
|
||||
|
||||
it('Test svgedit.transformlist package', function () {
|
||||
assert.ok(transformlist);
|
||||
assert.ok(transformlist.getTransformList);
|
||||
});
|
||||
|
||||
it('Test svgedit.transformlist.getTransformList() function', function () {
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
assert.ok(rxform);
|
||||
assert.ok(cxform);
|
||||
assert.equal(typeof rxform, typeof {});
|
||||
assert.equal(typeof cxform, typeof {});
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.numberOfItems property', function () {
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
|
||||
assert.equal(typeof rxform.numberOfItems, typeof 0);
|
||||
assert.equal(rxform.numberOfItems, 0);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.initialize()', function () {
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
const t = svgcontent.createSVGTransform();
|
||||
assert.ok(t);
|
||||
assert.ok(rxform.initialize);
|
||||
assert.equal(typeof rxform.initialize, typeof function () { /* */ });
|
||||
rxform.initialize(t);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
assert.equal(cxform.numberOfItems, 0);
|
||||
|
||||
// If a transform was already in a transform list, this should
|
||||
// remove it from its old list and add it to this list.
|
||||
cxform.initialize(t);
|
||||
// This also fails in Firefox native.
|
||||
// assert.equal(rxform.numberOfItems, 0, 'Did not remove transform from list before initializing another transformlist');
|
||||
assert.equal(cxform.numberOfItems, 1);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.appendItem() and getItem()', function () {
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
const t1 = svgcontent.createSVGTransform(),
|
||||
t2 = svgcontent.createSVGTransform(),
|
||||
t3 = svgcontent.createSVGTransform();
|
||||
|
||||
assert.ok(rxform.appendItem);
|
||||
assert.ok(rxform.getItem);
|
||||
assert.equal(typeof rxform.appendItem, typeof function () { /* */ });
|
||||
assert.equal(typeof rxform.getItem, typeof function () { /* */ });
|
||||
|
||||
rxform.appendItem(t1);
|
||||
rxform.appendItem(t2);
|
||||
rxform.appendItem(t3);
|
||||
|
||||
assert.equal(rxform.numberOfItems, 3);
|
||||
const rxf = rxform.getItem(0);
|
||||
assert.equal(rxf, t1);
|
||||
assert.equal(rxform.getItem(1), t2);
|
||||
assert.equal(rxform.getItem(2), t3);
|
||||
|
||||
assert.expectOutOfBoundsException(rxform, 'getItem', -1);
|
||||
assert.expectOutOfBoundsException(rxform, 'getItem', 3);
|
||||
cxform.appendItem(t1);
|
||||
// These also fail in Firefox native.
|
||||
// assert.equal(rxform.numberOfItems, 2, 'Did not remove a transform from a list before appending it to a new transformlist');
|
||||
// assert.equal(rxform.getItem(0), t2, 'Found the wrong transform in a transformlist');
|
||||
// assert.equal(rxform.getItem(1), t3, 'Found the wrong transform in a transformlist');
|
||||
|
||||
assert.equal(cxform.numberOfItems, 1);
|
||||
assert.equal(cxform.getItem(0), t1);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.removeItem()', function () {
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
|
||||
const t1 = svgcontent.createSVGTransform(),
|
||||
t2 = svgcontent.createSVGTransform();
|
||||
assert.ok(rxform.removeItem);
|
||||
assert.equal(typeof rxform.removeItem, typeof function () { /* */ });
|
||||
rxform.appendItem(t1);
|
||||
rxform.appendItem(t2);
|
||||
|
||||
const removedTransform = rxform.removeItem(0);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
assert.equal(removedTransform, t1);
|
||||
assert.equal(rxform.getItem(0), t2);
|
||||
|
||||
assert.expectOutOfBoundsException(rxform, 'removeItem', -1);
|
||||
assert.expectOutOfBoundsException(rxform, 'removeItem', 1);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.replaceItem()', function () {
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
assert.ok(rxform.replaceItem);
|
||||
assert.equal(typeof rxform.replaceItem, typeof function () { /* */ });
|
||||
|
||||
const t1 = svgcontent.createSVGTransform(),
|
||||
t2 = svgcontent.createSVGTransform(),
|
||||
t3 = svgcontent.createSVGTransform();
|
||||
|
||||
rxform.appendItem(t1);
|
||||
rxform.appendItem(t2);
|
||||
cxform.appendItem(t3);
|
||||
|
||||
const newItem = rxform.replaceItem(t3, 0);
|
||||
assert.equal(rxform.numberOfItems, 2);
|
||||
assert.equal(newItem, t3);
|
||||
assert.equal(rxform.getItem(0), t3);
|
||||
assert.equal(rxform.getItem(1), t2);
|
||||
// Fails in Firefox native
|
||||
// assert.equal(cxform.numberOfItems, 0);
|
||||
|
||||
// test replaceItem within a list
|
||||
rxform.appendItem(t1);
|
||||
rxform.replaceItem(t1, 0);
|
||||
// Fails in Firefox native
|
||||
// assert.equal(rxform.numberOfItems, 2);
|
||||
assert.equal(rxform.getItem(0), t1);
|
||||
assert.equal(rxform.getItem(1), t2);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.insertItemBefore()', function () {
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
assert.ok(rxform.insertItemBefore);
|
||||
assert.equal(typeof rxform.insertItemBefore, typeof function () { /* */ });
|
||||
|
||||
const t1 = svgcontent.createSVGTransform(),
|
||||
t2 = svgcontent.createSVGTransform(),
|
||||
t3 = svgcontent.createSVGTransform();
|
||||
|
||||
rxform.appendItem(t1);
|
||||
rxform.appendItem(t2);
|
||||
cxform.appendItem(t3);
|
||||
|
||||
const newItem = rxform.insertItemBefore(t3, 0);
|
||||
assert.equal(rxform.numberOfItems, 3);
|
||||
assert.equal(newItem, t3);
|
||||
assert.equal(rxform.getItem(0), t3);
|
||||
assert.equal(rxform.getItem(1), t1);
|
||||
assert.equal(rxform.getItem(2), t2);
|
||||
// Fails in Firefox native
|
||||
// assert.equal(cxform.numberOfItems, 0);
|
||||
|
||||
rxform.insertItemBefore(t2, 1);
|
||||
// Fails in Firefox native (they make copies of the transforms)
|
||||
// assert.equal(rxform.numberOfItems, 3);
|
||||
assert.equal(rxform.getItem(0), t3);
|
||||
assert.equal(rxform.getItem(1), t2);
|
||||
assert.equal(rxform.getItem(2), t1);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.init() for translate(200,100)', function () {
|
||||
rect.setAttribute('transform', 'translate(200,100)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const translate = rxform.getItem(0);
|
||||
assert.equal(translate.type, 2);
|
||||
|
||||
const m = translate.matrix;
|
||||
assert.equal(m.a, 1);
|
||||
assert.equal(m.b, 0);
|
||||
assert.equal(m.c, 0);
|
||||
assert.equal(m.d, 1);
|
||||
assert.equal(m.e, 200);
|
||||
assert.equal(m.f, 100);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.init() for scale(4)', function () {
|
||||
rect.setAttribute('transform', 'scale(4)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const scale = rxform.getItem(0);
|
||||
assert.equal(scale.type, 3);
|
||||
|
||||
const m = scale.matrix;
|
||||
assert.equal(m.a, 4);
|
||||
assert.equal(m.b, 0);
|
||||
assert.equal(m.c, 0);
|
||||
assert.equal(m.d, 4);
|
||||
assert.equal(m.e, 0);
|
||||
assert.equal(m.f, 0);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.init() for scale(4,3)', function () {
|
||||
rect.setAttribute('transform', 'scale(4,3)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const scale = rxform.getItem(0);
|
||||
assert.equal(scale.type, 3);
|
||||
|
||||
const m = scale.matrix;
|
||||
assert.equal(m.a, 4);
|
||||
assert.equal(m.b, 0);
|
||||
assert.equal(m.c, 0);
|
||||
assert.equal(m.d, 3);
|
||||
assert.equal(m.e, 0);
|
||||
assert.equal(m.f, 0);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.init() for rotate(45)', function () {
|
||||
rect.setAttribute('transform', 'rotate(45)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const rotate = rxform.getItem(0);
|
||||
assert.equal(rotate.type, 4);
|
||||
assert.equal(rotate.angle, 45);
|
||||
|
||||
const m = rotate.matrix;
|
||||
assert.almostEquals(1 / Math.sqrt(2), m.a);
|
||||
assert.almostEquals(1 / Math.sqrt(2), m.b);
|
||||
assert.almostEquals(-1 / Math.sqrt(2), m.c);
|
||||
assert.almostEquals(1 / Math.sqrt(2), m.d);
|
||||
assert.equal(m.e, 0);
|
||||
assert.equal(m.f, 0);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.init() for rotate(45, 100, 200)', function () {
|
||||
rect.setAttribute('transform', 'rotate(45, 100, 200)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const rotate = rxform.getItem(0);
|
||||
assert.equal(rotate.type, 4);
|
||||
assert.equal(rotate.angle, 45);
|
||||
|
||||
const m = rotate.matrix;
|
||||
assert.almostEquals(m.a, 1 / Math.sqrt(2));
|
||||
assert.almostEquals(m.b, 1 / Math.sqrt(2));
|
||||
assert.almostEquals(m.c, -1 / Math.sqrt(2));
|
||||
assert.almostEquals(m.d, 1 / Math.sqrt(2));
|
||||
|
||||
const r = svgcontent.createSVGMatrix();
|
||||
r.a = 1 / Math.sqrt(2); r.b = 1 / Math.sqrt(2);
|
||||
r.c = -1 / Math.sqrt(2); r.d = 1 / Math.sqrt(2);
|
||||
|
||||
const t = svgcontent.createSVGMatrix();
|
||||
t.e = -100; t.f = -200;
|
||||
|
||||
const t_ = svgcontent.createSVGMatrix();
|
||||
t_.e = 100; t_.f = 200;
|
||||
|
||||
const result = t_.multiply(r).multiply(t);
|
||||
|
||||
assert.almostEquals(m.e, result.e);
|
||||
assert.almostEquals(m.f, result.f);
|
||||
});
|
||||
|
||||
it('Test SVGTransformList.init() for matrix(1, 2, 3, 4, 5, 6)', function () {
|
||||
rect.setAttribute('transform', 'matrix(1,2,3,4,5,6)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const mt = rxform.getItem(0);
|
||||
assert.equal(mt.type, 1);
|
||||
|
||||
const m = mt.matrix;
|
||||
assert.equal(m.a, 1);
|
||||
assert.equal(m.b, 2);
|
||||
assert.equal(m.c, 3);
|
||||
assert.equal(m.d, 4);
|
||||
assert.equal(m.e, 5);
|
||||
assert.equal(m.f, 6);
|
||||
});
|
||||
});
|
||||
270
cypress/integration/test1.js
Normal file
270
cypress/integration/test1.js
Normal file
@@ -0,0 +1,270 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
import '../../instrumented/jquery-ui/jquery-ui-1.8.17.custom.min.js';
|
||||
|
||||
import '../../instrumented/svgpathseg.js';
|
||||
import SvgCanvas from '../../instrumented/svgcanvas.js';
|
||||
|
||||
describe('Basic Module', function () {
|
||||
// helper functions
|
||||
/*
|
||||
const isIdentity = function (m) {
|
||||
return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0);
|
||||
};
|
||||
const matrixString = function (m) {
|
||||
return [m.a, m.b, m.c, m.d, m.e, m.f].join(',');
|
||||
};
|
||||
*/
|
||||
|
||||
let svgCanvas;
|
||||
|
||||
const
|
||||
// svgroot = document.getElementById('svgroot'),
|
||||
// svgdoc = svgroot.documentElement,
|
||||
svgns = 'http://www.w3.org/2000/svg',
|
||||
xlinkns = 'http://www.w3.org/1999/xlink';
|
||||
|
||||
beforeEach(() => {
|
||||
document.body.textContent = '';
|
||||
const svgEditor = document.createElement('div');
|
||||
svgEditor.id = 'svg_editor';
|
||||
const svgcanvas = document.createElement('div');
|
||||
svgcanvas.style.visibility = 'hidden';
|
||||
svgcanvas.id = 'svgcanvas';
|
||||
const workarea = document.createElement('div');
|
||||
workarea.id = 'workarea';
|
||||
workarea.append(svgcanvas);
|
||||
const toolsLeft = document.createElement('div');
|
||||
toolsLeft.id = 'tools_left';
|
||||
const toolsFlyout = document.createElement('div');
|
||||
toolsFlyout.id = 'tools_flyout';
|
||||
|
||||
svgEditor.append(workarea, toolsLeft, toolsFlyout);
|
||||
document.body.append(svgEditor);
|
||||
|
||||
svgCanvas = new SvgCanvas(
|
||||
document.getElementById('svgcanvas'), {
|
||||
canvas_expansion: 3,
|
||||
dimensions: [640, 480],
|
||||
initFill: {
|
||||
color: 'FF0000', // solid red
|
||||
opacity: 1
|
||||
},
|
||||
initStroke: {
|
||||
width: 5,
|
||||
color: '000000', // solid black
|
||||
opacity: 1
|
||||
},
|
||||
initOpacity: 1,
|
||||
imgPath: '../editor/images/',
|
||||
langPath: 'locale/',
|
||||
extPath: 'extensions/',
|
||||
extensions: ['ext-arrows.js', 'ext-connector.js', 'ext-eyedropper.js'],
|
||||
initTool: 'select',
|
||||
wireframe: false
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Test existence of SvgCanvas object', function () {
|
||||
assert.equal(typeof {}, typeof svgCanvas);
|
||||
});
|
||||
|
||||
describe('Path Module', function () {
|
||||
it('Test path conversion from absolute to relative', function () {
|
||||
const convert = svgCanvas.pathActions.convertPath;
|
||||
|
||||
// TODO: Test these paths:
|
||||
// "m400.00491,625.01379a1.78688,1.78688 0 1 1-3.57373,0a1.78688,1.78688 0 1 13.57373,0z"
|
||||
// "m36.812,15.8566c-28.03099,0 -26.28099,12.15601 -26.28099,12.15601l0.03099,12.59399h26.75v3.781h-37.37399c0,0 -17.938,-2.034 -133.00001,26.25c115.06201,28.284 130.71801,27.281 130.71801,27.281h9.34399v-13.125c0,0 -0.504,-15.656 15.40601,-15.656h26.532c0,0 14.90599,0.241 14.90599,-14.406v-24.219c0,0 2.263,-14.65601 -27.032,-14.65601zm-14.75,8.4684c2.662,0 4.813,2.151 4.813,4.813c0,2.661 -2.151,4.812 -4.813,4.812c-2.661,0 -4.812,-2.151 -4.812,-4.812c0,-2.662 2.151,-4.813 4.812,-4.813z"
|
||||
// "m 0,0 l 200,0 l 0,100 L 0,100"
|
||||
|
||||
svgCanvas.setSvgString(
|
||||
"<svg xmlns='http://www.w3.org/2000/svg' width='400' x='300'>" +
|
||||
"<path id='p1' d='M100,100 L200,100 L100,100Z'/>" +
|
||||
"<path id='p2' d='m 0,0 l 200,0 l 0,100 L 0,100'/>" +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const p1 = document.getElementById('p1'),
|
||||
p2 = document.getElementById('p2'),
|
||||
dAbs = p1.getAttribute('d'),
|
||||
seglist = p1.pathSegList;
|
||||
|
||||
assert.equal(p1.nodeName, 'path', "Expected 'path', got");
|
||||
|
||||
assert.equal(seglist.numberOfItems, 4, 'Number of segments before conversion');
|
||||
|
||||
// verify segments before conversion
|
||||
let curseg = seglist.getItem(0);
|
||||
assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'M', 'Before conversion, segment #1 type');
|
||||
curseg = seglist.getItem(1);
|
||||
assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'L', 'Before conversion, segment #2 type');
|
||||
curseg = seglist.getItem(3);
|
||||
assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'Z', 'Before conversion, segment #3 type' + dAbs);
|
||||
|
||||
// convert and verify segments
|
||||
let d = convert(p1, true);
|
||||
assert.equal(d, 'm100,100l100,0l-100,0z', 'Converted path to relative string');
|
||||
|
||||
// TODO: see why this isn't working in SVG-edit
|
||||
d = convert(p2, true);
|
||||
console.log('Convert true', d);
|
||||
d = convert(p2, false);
|
||||
console.log('Convert false', d);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Import Module', function () {
|
||||
it('Test import use', function () {
|
||||
svgCanvas.setSvgString(
|
||||
"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='400' x='300'>" +
|
||||
"<rect id='the-rect' width='200' height='200'/>" +
|
||||
"<use id='the-use' xlink:href='#the-rect'/>" +
|
||||
"<use id='foreign-use' xlink:href='somefile.svg#the-rect'/>" +
|
||||
"<use id='no-use'/>" +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const u = document.getElementById('the-use'),
|
||||
fu = document.getElementById('foreign-use'),
|
||||
nfu = document.getElementById('no-use');
|
||||
|
||||
assert.equal((u && u.nodeName === 'use'), true, 'Did not import <use> element');
|
||||
assert.equal(fu, null, 'Removed <use> element that had a foreign href');
|
||||
assert.equal(nfu, null, 'Removed <use> element that had no href');
|
||||
});
|
||||
|
||||
// This test shows that an element with an invalid attribute is still parsed in properly
|
||||
// and only the attribute is not imported
|
||||
it('Test invalid attribute', function () {
|
||||
svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<text x="182.75" y="173.5" id="the-text" fill="#008000" font-size="150" font-family="serif" text-anchor="middle" d="M116,222 L110,108">words</text>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const t = document.getElementById('the-text');
|
||||
|
||||
assert.equal((t && t.nodeName === 'text'), true, 'Did not import <text> element');
|
||||
assert.equal(t.getAttribute('d'), null, 'Imported a <text> with a d attribute');
|
||||
});
|
||||
|
||||
// This test makes sure import/export properly handles namespaced attributes
|
||||
it('Test importing/exporting namespaced attributes', function () {
|
||||
/* const setStr = */ svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:se="http://svg-edit.googlecode.com" xmlns:foo="http://example.com">' +
|
||||
'<image xlink:href="../editor/images/logo.png"/>' +
|
||||
'<polyline id="se_test_elem" se:foo="bar" foo:bar="baz"/>' +
|
||||
'</svg>'
|
||||
);
|
||||
const attrVal = document.getElementById('se_test_elem').getAttributeNS('http://svg-edit.googlecode.com', 'foo');
|
||||
|
||||
assert.equal(attrVal === 'bar', true, 'Preserved namespaced attribute on import');
|
||||
|
||||
const output = svgCanvas.getSvgString();
|
||||
// } catch(e) {console.log(e)}
|
||||
// console.log('output',output);
|
||||
const hasXlink = output.includes('xmlns:xlink="http://www.w3.org/1999/xlink"');
|
||||
const hasSe = output.includes('xmlns:se=');
|
||||
const hasFoo = output.includes('xmlns:foo=');
|
||||
const hasAttr = output.includes('se:foo="bar"');
|
||||
|
||||
assert.equal(hasAttr, true, 'Preserved namespaced attribute on export');
|
||||
assert.equal(hasXlink, true, 'Included xlink: xmlns');
|
||||
assert.equal(hasSe, true, 'Included se: xmlns');
|
||||
assert.equal(hasFoo, false, 'Did not include foo: xmlns');
|
||||
});
|
||||
|
||||
it('Test import math elements inside a foreignObject', function () {
|
||||
/* const set = */ svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:se="http://svg-edit.googlecode.com" xmlns:xlink="http://www.w3.org/1999/xlink">' +
|
||||
'<foreignObject id="fo" width="24" height="26" font-size="24"><math id="m" display="inline" xmlns="http://www.w3.org/1998/Math/MathML">' +
|
||||
'<msub>' +
|
||||
'<mi>A</mi>' +
|
||||
'<mn>0</mn>' +
|
||||
'</msub>' +
|
||||
'</math>' +
|
||||
'</foreignObject>' +
|
||||
'</svg>'
|
||||
);
|
||||
const fo = document.getElementById('fo');
|
||||
// we cannot use getElementById('math') because not all browsers understand MathML and do not know to use the @id attribute
|
||||
// see Bug https://bugs.webkit.org/show_bug.cgi?id=35042
|
||||
const math = fo.firstChild;
|
||||
|
||||
assert.equal(Boolean(math), true, 'Math element exists');
|
||||
assert.equal(math.nodeName, 'math', 'Math element has the proper nodeName');
|
||||
assert.equal(math.getAttribute('id'), 'm', 'Math element has an id');
|
||||
assert.equal(math.namespaceURI, 'http://www.w3.org/1998/Math/MathML', 'Preserved MathML namespace');
|
||||
});
|
||||
|
||||
it('Test importing SVG into existing drawing', function () {
|
||||
/* const doc = */ svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<g><title>Layer 1</title>' +
|
||||
'<circle cx="200" cy="200" r="50" fill="blue"/>' +
|
||||
'<ellipse cx="300" cy="100" rx="40" ry="30" fill="green"/>' +
|
||||
'</g>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
svgCanvas.importSvgString(
|
||||
'<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<circle cx="50" cy="50" r="40" fill="yellow"/>' +
|
||||
'<rect width="20" height="20" fill="blue"/>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const svgcontent = document.getElementById('svgcontent'),
|
||||
circles = svgcontent.getElementsByTagNameNS(svgns, 'circle'),
|
||||
rects = svgcontent.getElementsByTagNameNS(svgns, 'rect'),
|
||||
ellipses = svgcontent.getElementsByTagNameNS(svgns, 'ellipse');
|
||||
assert.equal(circles.length, 2, 'Found two circles upon importing');
|
||||
assert.equal(rects.length, 1, 'Found one rectangle upon importing');
|
||||
assert.equal(ellipses.length, 1, 'Found one ellipse upon importing');
|
||||
});
|
||||
|
||||
it('Test importing SVG remaps IDs', function () {
|
||||
/* const doc = */ svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<g><title>Layer 1</title>' +
|
||||
'<ellipse id="svg_1" cx="200" cy="200" rx="50" ry="20" fill="blue"/>' +
|
||||
'<ellipse id="svg_2" cx="300" cy="100" rx="40" ry="30" fill="green"/>' +
|
||||
'<ellipse id="svg_3" cx="300" cy="100" rx="40" ry="30" fill="green"/>' +
|
||||
'</g>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
svgCanvas.importSvgString(
|
||||
'<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink">' +
|
||||
'<defs>' +
|
||||
'<linearGradient id="svg_2">' +
|
||||
'<stop stop-color="red" offset="0"/>' +
|
||||
'<stop stop-color="green" offset="1"/>' +
|
||||
'</linearGradient>' +
|
||||
'<rect id="svg_3" width="20" height="20" fill="blue" stroke="url(#svg_2)"/>' +
|
||||
'</defs>' +
|
||||
'<circle id="svg_1" cx="50" cy="50" r="40" fill="url(#svg_2)"/>' +
|
||||
'<use id="svg_4" width="30" height="30" xl:href="#svg_3"/>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const svgcontent = document.getElementById('svgcontent'),
|
||||
circles = svgcontent.getElementsByTagNameNS(svgns, 'circle'),
|
||||
rects = svgcontent.getElementsByTagNameNS(svgns, 'rect'),
|
||||
// ellipses = svgcontent.getElementsByTagNameNS(svgns, 'ellipse'),
|
||||
defs = svgcontent.getElementsByTagNameNS(svgns, 'defs'),
|
||||
// grads = svgcontent.getElementsByTagNameNS(svgns, 'linearGradient'),
|
||||
uses = svgcontent.getElementsByTagNameNS(svgns, 'use');
|
||||
assert.notEqual(circles.item(0).id, 'svg_1', 'Circle not re-identified');
|
||||
assert.notEqual(rects.item(0).id, 'svg_3', 'Rectangle not re-identified');
|
||||
// TODO: determine why this test fails in WebKit browsers
|
||||
// assert.equal(grads.length, 1, 'Linear gradient imported');
|
||||
const grad = defs.item(0).firstChild;
|
||||
assert.notEqual(grad.id, 'svg_2', 'Linear gradient not re-identified');
|
||||
assert.notEqual(circles.item(0).getAttribute('fill'), 'url(#svg_2)', 'Circle fill value not remapped');
|
||||
assert.notEqual(rects.item(0).getAttribute('stroke'), 'url(#svg_2)', 'Rectangle stroke value not remapped');
|
||||
assert.notEqual(uses.item(0).getAttributeNS(xlinkns, 'href'), '#svg_3');
|
||||
});
|
||||
});
|
||||
});
|
||||
93
cypress/integration/units.js
Normal file
93
cypress/integration/units.js
Normal file
@@ -0,0 +1,93 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import * as units from '../../instrumented/units.js';
|
||||
|
||||
describe('units', function () {
|
||||
/**
|
||||
* Set up tests, supplying mock data.
|
||||
* @returns {void}
|
||||
*/
|
||||
beforeEach(() => {
|
||||
document.body.textContent = '';
|
||||
const anchor = document.createElement('div');
|
||||
anchor.id = 'anchor';
|
||||
anchor.style.visibility = 'hidden';
|
||||
|
||||
const elementsContainer = document.createElement('div');
|
||||
elementsContainer.id = 'elementsContainer';
|
||||
|
||||
const uniqueId = document.createElement('div');
|
||||
uniqueId.id = 'uniqueId';
|
||||
uniqueId.style.visibility = 'hidden';
|
||||
|
||||
const nonUniqueId = document.createElement('div');
|
||||
nonUniqueId.id = 'nonUniqueId';
|
||||
nonUniqueId.style.visibility = 'hidden';
|
||||
|
||||
elementsContainer.append(uniqueId, nonUniqueId);
|
||||
|
||||
document.body.append(anchor, elementsContainer);
|
||||
|
||||
units.init(
|
||||
/**
|
||||
* @implements {module:units.ElementContainer}
|
||||
*/
|
||||
{
|
||||
getBaseUnit () { return 'cm'; },
|
||||
getHeight () { return 600; },
|
||||
getWidth () { return 800; },
|
||||
getRoundDigits () { return 4; },
|
||||
getElement (elementId) { return document.getElementById(elementId); }
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Test svgedit.units package', function () {
|
||||
assert.ok(units);
|
||||
assert.equal(typeof units, typeof {});
|
||||
});
|
||||
|
||||
it('Test svgedit.units.shortFloat()', function () {
|
||||
assert.ok(units.shortFloat);
|
||||
assert.equal(typeof units.shortFloat, typeof function () { /* */ });
|
||||
|
||||
const {shortFloat} = units;
|
||||
assert.equal(shortFloat(0.00000001), 0);
|
||||
assert.equal(shortFloat(1), 1);
|
||||
assert.equal(shortFloat(3.45678), 3.4568);
|
||||
assert.equal(shortFloat(1.23443), 1.2344);
|
||||
assert.equal(shortFloat(1.23455), 1.2346);
|
||||
});
|
||||
|
||||
it('Test svgedit.units.isValidUnit()', function () {
|
||||
assert.ok(units.isValidUnit);
|
||||
assert.equal(typeof units.isValidUnit, typeof function () { /* */ });
|
||||
|
||||
const {isValidUnit} = units;
|
||||
assert.ok(isValidUnit('0'));
|
||||
assert.ok(isValidUnit('1'));
|
||||
assert.ok(isValidUnit('1.1'));
|
||||
assert.ok(isValidUnit('-1.1'));
|
||||
assert.ok(isValidUnit('.6mm'));
|
||||
assert.ok(isValidUnit('-.6cm'));
|
||||
assert.ok(isValidUnit('6000in'));
|
||||
assert.ok(isValidUnit('6px'));
|
||||
assert.ok(isValidUnit('6.3pc'));
|
||||
assert.ok(isValidUnit('-0.4em'));
|
||||
assert.ok(isValidUnit('-0.ex'));
|
||||
assert.ok(isValidUnit('40.123%'));
|
||||
|
||||
assert.equal(isValidUnit('id', 'uniqueId', document.getElementById('uniqueId')), true);
|
||||
assert.equal(isValidUnit('id', 'newId', document.getElementById('uniqueId')), true);
|
||||
assert.equal(isValidUnit('id', 'uniqueId'), false);
|
||||
assert.equal(isValidUnit('id', 'uniqueId', document.getElementById('nonUniqueId')), false);
|
||||
});
|
||||
|
||||
it('Test svgedit.units.convertUnit()', function () {
|
||||
assert.ok(units.convertUnit);
|
||||
assert.equal(typeof units.convertUnit, typeof function () { /* */ });
|
||||
// cm in default setup
|
||||
assert.equal(units.convertUnit(42), 1.1113);
|
||||
assert.equal(units.convertUnit(42, 'px'), 42);
|
||||
});
|
||||
});
|
||||
509
cypress/integration/utilities-bbox.js
Normal file
509
cypress/integration/utilities-bbox.js
Normal file
@@ -0,0 +1,509 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import '../../instrumented/svgpathseg.js';
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as utilities from '../../instrumented/utilities.js';
|
||||
import * as transformlist from '../../instrumented/svgtransformlist.js';
|
||||
import * as math from '../../instrumented/math.js';
|
||||
import * as path from '../../instrumented/path.js';
|
||||
import setAssertionMethods from '../support/assert-close.js';
|
||||
|
||||
chai.use(setAssertionMethods);
|
||||
|
||||
describe('utilities bbox', function () {
|
||||
/**
|
||||
* Create an SVG element for a mock.
|
||||
* @param {module:utilities.SVGElementJSON} jsonMap
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockCreateSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
}
|
||||
let mockaddSVGElementFromJsonCallCount = 0;
|
||||
|
||||
/**
|
||||
* Mock of {@link module:utilities.EditorContext#addSVGElementFromJson}.
|
||||
* @param {module:utilities.SVGElementJSON} json
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockaddSVGElementFromJson (json) {
|
||||
const elem = mockCreateSVGElement(json);
|
||||
svgroot.append(elem);
|
||||
mockaddSVGElementFromJsonCallCount++;
|
||||
return elem;
|
||||
}
|
||||
const mockPathActions = {
|
||||
resetOrientation (pth) {
|
||||
if (utilities.isNullish(pth) || pth.nodeName !== 'path') { return false; }
|
||||
const tlist = transformlist.getTransformList(pth);
|
||||
const m = math.transformListToTransform(tlist).matrix;
|
||||
tlist.clear();
|
||||
pth.removeAttribute('transform');
|
||||
const segList = pth.pathSegList;
|
||||
|
||||
const len = segList.numberOfItems;
|
||||
// let lastX, lastY;
|
||||
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const seg = segList.getItem(i);
|
||||
const type = seg.pathSegType;
|
||||
if (type === 1) { continue; }
|
||||
const pts = [];
|
||||
['', 1, 2].forEach(function (n, j) {
|
||||
const x = seg['x' + n], y = seg['y' + n];
|
||||
if (x !== undefined && y !== undefined) {
|
||||
const pt = math.transformPoint(x, y, m);
|
||||
pts.splice(pts.length, 0, pt.x, pt.y);
|
||||
}
|
||||
});
|
||||
path.replacePathSeg(type, i, pts, pth);
|
||||
}
|
||||
// path.reorientGrads(pth, m);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const EPSILON = 0.001;
|
||||
|
||||
let svgroot;
|
||||
beforeEach(() => {
|
||||
document.body.textContent = '';
|
||||
|
||||
// const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
const sandbox = document.createElement('div');
|
||||
sandbox.id = 'sandbox';
|
||||
document.body.append(sandbox);
|
||||
|
||||
svgroot = mockCreateSVGElement({
|
||||
element: 'svg',
|
||||
attr: {id: 'svgroot'}
|
||||
});
|
||||
sandbox.append(svgroot);
|
||||
|
||||
// We're reusing ID's so we need to do this for transforms.
|
||||
transformlist.resetListMap();
|
||||
path.init(null);
|
||||
mockaddSVGElementFromJsonCallCount = 0;
|
||||
});
|
||||
|
||||
it('Test svgedit.utilities package', function () {
|
||||
assert.ok(utilities);
|
||||
assert.ok(utilities.getBBoxWithTransform);
|
||||
assert.ok(utilities.getStrokedBBox);
|
||||
assert.ok(utilities.getRotationAngleFromTransformList);
|
||||
assert.ok(utilities.getRotationAngle);
|
||||
});
|
||||
|
||||
it('Test getBBoxWithTransform and no transform', function () {
|
||||
const {getBBoxWithTransform} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 L2,3'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 2, height: 2});
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 5});
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
g.remove();
|
||||
});
|
||||
|
||||
it('Test getBBoxWithTransform and a rotation transform', function () {
|
||||
const {getBBoxWithTransform} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M10,10 L20,20', transform: 'rotate(45 10,10)'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, 10, EPSILON);
|
||||
assert.close(bbox.y, 10, EPSILON);
|
||||
assert.close(bbox.width, 0, EPSILON);
|
||||
assert.close(bbox.height, Math.sqrt(100 + 100), EPSILON);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '10', y: '10', width: '10', height: '20', transform: 'rotate(90 15,20)'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, 5, EPSILON);
|
||||
assert.close(bbox.y, 15, EPSILON);
|
||||
assert.close(bbox.width, 20, EPSILON);
|
||||
assert.close(bbox.height, 10, EPSILON);
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 1);
|
||||
elem.remove();
|
||||
|
||||
const rect = {x: 10, y: 10, width: 10, height: 20};
|
||||
const angle = 45;
|
||||
const origin = {x: 15, y: 20}; // eslint-disable-line no-shadow
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect2', x: rect.x, y: rect.y, width: rect.width, height: rect.height, transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ')'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
mockaddSVGElementFromJsonCallCount = 0;
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
const r2 = rotateRect(rect, angle, origin);
|
||||
assert.close(bbox.x, r2.x, EPSILON, 'rect2 x is ' + r2.x);
|
||||
assert.close(bbox.y, r2.y, EPSILON, 'rect2 y is ' + r2.y);
|
||||
assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width);
|
||||
assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height);
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
elem.remove();
|
||||
|
||||
// Same as previous but wrapped with g and the transform is with the g.
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect3', x: rect.x, y: rect.y, width: rect.width, height: rect.height}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ')'}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
mockaddSVGElementFromJsonCallCount = 0;
|
||||
bbox = getBBoxWithTransform(g, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, r2.x, EPSILON, 'rect2 x is ' + r2.x);
|
||||
assert.close(bbox.y, r2.y, EPSILON, 'rect2 y is ' + r2.y);
|
||||
assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width);
|
||||
assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height);
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
g.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'ellipse',
|
||||
attr: {id: 'ellipse1', cx: '100', cy: '100', rx: '50', ry: '50', transform: 'rotate(45 100,100)'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
mockaddSVGElementFromJsonCallCount = 0;
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
// TODO: the BBox algorithm is using the bezier control points to calculate the bounding box. Should be 50, 50, 100, 100.
|
||||
assert.ok(bbox.x > 45 && bbox.x <= 50);
|
||||
assert.ok(bbox.y > 45 && bbox.y <= 50);
|
||||
assert.ok(bbox.width >= 100 && bbox.width < 110);
|
||||
assert.ok(bbox.height >= 100 && bbox.height < 110);
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 1);
|
||||
elem.remove();
|
||||
});
|
||||
|
||||
it('Test getBBoxWithTransform with rotation and matrix transforms', function () {
|
||||
const {getBBoxWithTransform} = utilities;
|
||||
|
||||
let tx = 10; // tx right
|
||||
let ty = 10; // tx down
|
||||
let txInRotatedSpace = Math.sqrt(tx * tx + ty * ty); // translate in rotated 45 space.
|
||||
let tyInRotatedSpace = 0;
|
||||
let matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')';
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M10,10 L20,20', transform: 'rotate(45 10,10) ' + matrix}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, 10 + tx, EPSILON);
|
||||
assert.close(bbox.y, 10 + ty, EPSILON);
|
||||
assert.close(bbox.width, 0, EPSILON);
|
||||
assert.close(bbox.height, Math.sqrt(100 + 100), EPSILON);
|
||||
elem.remove();
|
||||
|
||||
txInRotatedSpace = tx; // translate in rotated 90 space.
|
||||
tyInRotatedSpace = -ty;
|
||||
matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')';
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '10', y: '10', width: '10', height: '20', transform: 'rotate(90 15,20) ' + matrix}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, 5 + tx, EPSILON);
|
||||
assert.close(bbox.y, 15 + ty, EPSILON);
|
||||
assert.close(bbox.width, 20, EPSILON);
|
||||
assert.close(bbox.height, 10, EPSILON);
|
||||
elem.remove();
|
||||
|
||||
const rect = {x: 10, y: 10, width: 10, height: 20};
|
||||
const angle = 45;
|
||||
const origin = {x: 15, y: 20}; // eslint-disable-line no-shadow
|
||||
tx = 10; // tx right
|
||||
ty = 10; // tx down
|
||||
txInRotatedSpace = Math.sqrt(tx * tx + ty * ty); // translate in rotated 45 space.
|
||||
tyInRotatedSpace = 0;
|
||||
matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')';
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect2', x: rect.x, y: rect.y, width: rect.width, height: rect.height, transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ') ' + matrix}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
const r2 = rotateRect(rect, angle, origin);
|
||||
assert.close(bbox.x, r2.x + tx, EPSILON, 'rect2 x is ' + r2.x);
|
||||
assert.close(bbox.y, r2.y + ty, EPSILON, 'rect2 y is ' + r2.y);
|
||||
assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width);
|
||||
assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height);
|
||||
elem.remove();
|
||||
|
||||
// Same as previous but wrapped with g and the transform is with the g.
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect3', x: rect.x, y: rect.y, width: rect.width, height: rect.height}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ') ' + matrix}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getBBoxWithTransform(g, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, r2.x + tx, EPSILON, 'rect2 x is ' + r2.x);
|
||||
assert.close(bbox.y, r2.y + ty, EPSILON, 'rect2 y is ' + r2.y);
|
||||
assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width);
|
||||
assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height);
|
||||
g.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'ellipse',
|
||||
attr: {id: 'ellipse1', cx: '100', cy: '100', rx: '50', ry: '50', transform: 'rotate(45 100,100) ' + matrix}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
// TODO: the BBox algorithm is using the bezier control points to calculate the bounding box. Should be 50, 50, 100, 100.
|
||||
assert.ok(bbox.x > 45 + tx && bbox.x <= 50 + tx);
|
||||
assert.ok(bbox.y > 45 + ty && bbox.y <= 50 + ty);
|
||||
assert.ok(bbox.width >= 100 && bbox.width < 110);
|
||||
assert.ok(bbox.height >= 100 && bbox.height < 110);
|
||||
elem.remove();
|
||||
});
|
||||
|
||||
it('Test getStrokedBBox with stroke-width 10', function () {
|
||||
const {getStrokedBBox} = utilities;
|
||||
|
||||
const strokeWidth = 10;
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 L2,3', 'stroke-width': strokeWidth}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 2 + strokeWidth, height: 2 + strokeWidth});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': strokeWidth}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 10 + strokeWidth});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6', 'stroke-width': strokeWidth}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 5 + strokeWidth});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': strokeWidth}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 10 + strokeWidth});
|
||||
g.remove();
|
||||
});
|
||||
|
||||
it("Test getStrokedBBox with stroke-width 'none'", function () {
|
||||
const {getStrokedBBox} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 L2,3', 'stroke-width': 'none'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 2, height: 2});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': 'none'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6', 'stroke-width': 'none'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 5});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': 'none'}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
g.remove();
|
||||
});
|
||||
|
||||
it('Test getStrokedBBox with no stroke-width attribute', function () {
|
||||
const {getStrokedBBox} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 L2,3'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 2, height: 2});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 5});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
g.remove();
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns radians for degrees.
|
||||
* @param {Float} degrees
|
||||
* @returns {Float}
|
||||
*/
|
||||
function radians (degrees) {
|
||||
return degrees * Math.PI / 180;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {module:utilities.BBoxObject} point
|
||||
* @param {Float} angle
|
||||
* @param {module:math.XYObject} origin
|
||||
* @returns {module:math.XYObject}
|
||||
*/
|
||||
function rotatePoint (point, angle, origin) { // eslint-disable-line no-shadow
|
||||
if (!origin) {
|
||||
origin = {x: 0, y: 0};
|
||||
}
|
||||
const x = point.x - origin.x;
|
||||
const y = point.y - origin.y;
|
||||
const theta = radians(angle);
|
||||
return {
|
||||
x: x * Math.cos(theta) + y * Math.sin(theta) + origin.x,
|
||||
y: x * Math.sin(theta) + y * Math.cos(theta) + origin.y
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {module:utilities.BBoxObject} rect
|
||||
* @param {Float} angle
|
||||
* @param {module:math.XYObject} origin
|
||||
* @returns {module:utilities.BBoxObject}
|
||||
*/
|
||||
function rotateRect (rect, angle, origin) { // eslint-disable-line no-shadow
|
||||
const tl = rotatePoint({x: rect.x, y: rect.y}, angle, origin);
|
||||
const tr = rotatePoint({x: rect.x + rect.width, y: rect.y}, angle, origin);
|
||||
const br = rotatePoint({x: rect.x + rect.width, y: rect.y + rect.height}, angle, origin);
|
||||
const bl = rotatePoint({x: rect.x, y: rect.y + rect.height}, angle, origin);
|
||||
|
||||
const minx = Math.min(tl.x, tr.x, bl.x, br.x);
|
||||
const maxx = Math.max(tl.x, tr.x, bl.x, br.x);
|
||||
const miny = Math.min(tl.y, tr.y, bl.y, br.y);
|
||||
const maxy = Math.max(tl.y, tr.y, bl.y, br.y);
|
||||
|
||||
return {
|
||||
x: minx,
|
||||
y: miny,
|
||||
width: (maxx - minx),
|
||||
height: (maxy - miny)
|
||||
};
|
||||
}
|
||||
});
|
||||
239
cypress/integration/utilities-performance.js
Normal file
239
cypress/integration/utilities-performance.js
Normal file
@@ -0,0 +1,239 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import '../../instrumented/svgpathseg.js';
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
import * as utilities from '../../instrumented/utilities.js';
|
||||
import * as transformlist from '../../instrumented/svgtransformlist.js';
|
||||
import * as math from '../../instrumented/math.js';
|
||||
|
||||
describe('utilities performance', function () {
|
||||
let currentLayer, groupWithMatrixTransform, textWithMatrixTransform;
|
||||
beforeEach(() => {
|
||||
document.body.textContent = '';
|
||||
const style = document.createElement('style');
|
||||
style.id = 'styleoverrides';
|
||||
style.media = 'screen';
|
||||
style.textContent = `
|
||||
#svgcanvas svg * {
|
||||
cursor: move;
|
||||
pointer-events: all
|
||||
}
|
||||
#svgcanvas svg {
|
||||
cursor: default
|
||||
}`;
|
||||
|
||||
document.head.append(style);
|
||||
|
||||
const editor = new DOMParser().parseFromString(`<div id="svg_editor">
|
||||
<div id="workarea" style="cursor: auto; overflow: scroll; line-height: 12px; right: 100px;">
|
||||
|
||||
<!-- Must include this thumbnail view to see some of the performance issues -->
|
||||
<svg id="overviewMiniView" width="150" height="112.5" x="0" y="0" viewBox="100 100 1000 1000" style="float: right;"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<use x="0" y="0" xlink:href="#svgroot"></use>
|
||||
</svg>
|
||||
|
||||
|
||||
<div id="svgcanvas" style="position: relative; width: 1000px; height: 1000px;">
|
||||
<svg id="svgroot" xmlns="http://www.w3.org/2000/svg" xlinkns="http://www.w3.org/1999/xlink" width="1000" height="1000" x="640" y="480" overflow="visible">
|
||||
<defs><filter id="canvashadow" filterUnits="objectBoundingBox"><feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"></feGaussianBlur><feOffset in="blur" dx="5" dy="5" result="offsetBlur"></feOffset><feMerge><feMergeNode in="offsetBlur"></feMergeNode><feMergeNode in="SourceGraphic"></feMergeNode></feMerge></filter><pattern id="gridpattern" patternUnits="userSpaceOnUse" x="0" y="0" width="100" height="100"><image x="0" y="0" width="100" height="100"></image></pattern></defs>
|
||||
<svg id="canvasBackground" width="1000" height="200" x="10" y="10" overflow="none" style="pointer-events:none"><rect width="100%" height="100%" x="0" y="0" stroke="#000" fill="#000" style="pointer-events:none"></rect><svg id="canvasGrid" width="100%" height="100%" x="0" y="0" overflow="visible" display="none" style="display: inline;"><rect width="100%" height="100%" x="0" y="0" stroke-width="0" stroke="none" fill="url(#gridpattern)" style="pointer-events: none; display:visible;"></rect></svg></svg>
|
||||
<animate attributeName="opacity" begin="indefinite" dur="1" fill="freeze"></animate>
|
||||
|
||||
<svg id="svgcontent" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 480" overflow="visible" width="1000" height="200" x="100" y="20">
|
||||
|
||||
<g id="layer1">
|
||||
<title>Layer 1</title>
|
||||
|
||||
<g id="svg_group_with_matrix_transform" transform="matrix(0.5, 0, 0, 0.5, 10, 10)">
|
||||
<svg id="svg_2" x="100" y="0" class="symbol" preserveAspectRatio="xMaxYMax">
|
||||
<g id="svg_3">
|
||||
<rect id="svg_4" x="0" y="0" width="20" height="20" fill="#00FF00"></rect>
|
||||
</g>
|
||||
<g id="svg_5" display="none">
|
||||
<rect id="svg_6" x="0" y="0" width="20" height="20" fill="#A40000"></rect>
|
||||
</g>
|
||||
</svg>
|
||||
</g>
|
||||
<text id="svg_text_with_matrix_transform" transform="matrix(0.433735, 0, 0, 0.433735, 2, 4)" xml:space="preserve" text-anchor="middle" font-family="serif" font-size="24" y="0" x="61" stroke="#999999" fill="#999999">Some text</text>
|
||||
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 2</title>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
</svg>
|
||||
</div>
|
||||
</div></div>`, 'application/xml');
|
||||
const newNode = document.body.ownerDocument.importNode(editor.documentElement, true);
|
||||
document.body.append(newNode);
|
||||
|
||||
currentLayer = document.getElementById('layer1');
|
||||
groupWithMatrixTransform = document.getElementById('svg_group_with_matrix_transform');
|
||||
textWithMatrixTransform = document.getElementById('svg_text_with_matrix_transform');
|
||||
});
|
||||
|
||||
/**
|
||||
* Create an SVG element for a mock.
|
||||
* @param {module:utilities.SVGElementJSON} jsonMap
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockCreateSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock of {@link module:utilities.EditorContext#addSVGElementFromJson}.
|
||||
* @param {module:utilities.SVGElementJSON} json
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockaddSVGElementFromJson (json) {
|
||||
const elem = mockCreateSVGElement(json);
|
||||
currentLayer.append(elem);
|
||||
return elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toward performance testing, fill document with clones of element.
|
||||
* @param {SVGElement} elem
|
||||
* @param {Integer} count
|
||||
* @returns {void}
|
||||
*/
|
||||
function fillDocumentByCloningElement (elem, count) {
|
||||
const elemId = elem.getAttribute('id') + '-';
|
||||
for (let index = 0; index < count; index++) {
|
||||
const clone = elem.cloneNode(true); // t: deep clone
|
||||
// Make sure you set a unique ID like a real document.
|
||||
clone.setAttribute('id', elemId + index);
|
||||
const {parentNode} = elem;
|
||||
parentNode.append(clone);
|
||||
}
|
||||
}
|
||||
|
||||
const mockPathActions = {
|
||||
resetOrientation (path) {
|
||||
if (utilities.isNullish(path) || path.nodeName !== 'path') { return false; }
|
||||
const tlist = transformlist.getTransformList(path);
|
||||
const m = math.transformListToTransform(tlist).matrix;
|
||||
tlist.clear();
|
||||
path.removeAttribute('transform');
|
||||
const segList = path.pathSegList;
|
||||
|
||||
const len = segList.numberOfItems;
|
||||
// let lastX, lastY;
|
||||
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const seg = segList.getItem(i);
|
||||
const type = seg.pathSegType;
|
||||
if (type === 1) {
|
||||
continue;
|
||||
}
|
||||
const pts = [];
|
||||
['', 1, 2].forEach(function (n, j) {
|
||||
const x = seg['x' + n],
|
||||
y = seg['y' + n];
|
||||
if (x !== undefined && y !== undefined) {
|
||||
const pt = math.transformPoint(x, y, m);
|
||||
pts.splice(pts.length, 0, pt.x, pt.y);
|
||||
}
|
||||
});
|
||||
// path.replacePathSeg(type, i, pts, path);
|
||||
}
|
||||
|
||||
// utilities.reorientGrads(path, m);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// //////////////////////////////////////////////////////////
|
||||
// Performance times with various browsers on Macbook 2011 8MB RAM OS X El Capitan 10.11.4
|
||||
//
|
||||
// To see 'Before Optimization' performance, making the following two edits.
|
||||
// 1. utilities.getStrokedBBox - change if( elems.length === 1) to if( false && elems.length === 1)
|
||||
// 2. utilities.getBBoxWithTransform - uncomment 'Old technique that was very slow'
|
||||
|
||||
// Chrome
|
||||
// Before Optimization
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 4,218, ave ms 41.0, min/max 37 51
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 4,458, ave ms 43.3, min/max 32 63
|
||||
// Optimized Code
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 1,112, ave ms 10.8, min/max 9 20
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 34, ave ms 0.3, min/max 0 20
|
||||
|
||||
// Firefox
|
||||
// Before Optimization
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 3,794, ave ms 36.8, min/max 33 48
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 4,049, ave ms 39.3, min/max 28 53
|
||||
// Optimized Code
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 104, ave ms 1.0, min/max 0 23
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 71, ave ms 0.7, min/max 0 23
|
||||
|
||||
// Safari
|
||||
// Before Optimization
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 4,840, ave ms 47.0, min/max 45 62
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 4,849, ave ms 47.1, min/max 34 62
|
||||
// Optimized Code
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 42, ave ms 0.4, min/max 0 23
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 17, ave ms 0.2, min/max 0 23
|
||||
|
||||
it('Test svgCanvas.getStrokedBBox() performance with matrix transforms', function () {
|
||||
const {getStrokedBBox} = utilities;
|
||||
const {children} = currentLayer;
|
||||
|
||||
let lastTime, now,
|
||||
min = Number.MAX_VALUE,
|
||||
max = 0,
|
||||
total = 0;
|
||||
|
||||
fillDocumentByCloningElement(groupWithMatrixTransform, 50);
|
||||
fillDocumentByCloningElement(textWithMatrixTransform, 50);
|
||||
|
||||
// The first pass through all elements is slower.
|
||||
const count = children.length;
|
||||
const start = lastTime = now = Date.now();
|
||||
// Skip the first child which is the title.
|
||||
for (let index = 1; index < count; index++) {
|
||||
const child = children[index];
|
||||
/* const obj = */ getStrokedBBox([child], mockaddSVGElementFromJson, mockPathActions);
|
||||
now = Date.now(); const delta = now - lastTime; lastTime = now;
|
||||
total += delta;
|
||||
min = Math.min(min, delta);
|
||||
max = Math.max(max, delta);
|
||||
}
|
||||
total = lastTime - start;
|
||||
const ave = total / count;
|
||||
assert.ok(ave < 20, 'svgedit.utilities.getStrokedBBox average execution time is less than 20 ms');
|
||||
console.log('Pass1 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + ave.toFixed(1) + ',\t min/max ' + min + ' ' + max);
|
||||
|
||||
// eslint-disable-next-line promise/avoid-new
|
||||
return new Promise((resolve) => {
|
||||
// The second pass is two to ten times faster.
|
||||
setTimeout(function () {
|
||||
const ct = children.length;
|
||||
|
||||
const strt = lastTime = now = Date.now();
|
||||
// Skip the first child which is the title.
|
||||
for (let index = 1; index < ct; index++) {
|
||||
const child = children[index];
|
||||
/* const obj = */ getStrokedBBox([child], mockaddSVGElementFromJson, mockPathActions);
|
||||
now = Date.now(); const delta = now - lastTime; lastTime = now;
|
||||
total += delta;
|
||||
min = Math.min(min, delta);
|
||||
max = Math.max(max, delta);
|
||||
}
|
||||
|
||||
total = lastTime - strt;
|
||||
const avg = total / ct;
|
||||
assert.ok(avg < 2, 'svgedit.utilities.getStrokedBBox average execution time is less than 1 ms');
|
||||
console.log('Pass2 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + avg.toFixed(1) + ',\t min/max ' + min + ' ' + max);
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
361
cypress/integration/utilities.js
Normal file
361
cypress/integration/utilities.js
Normal file
@@ -0,0 +1,361 @@
|
||||
import '../../instrumented/jquery.min.js';
|
||||
|
||||
import * as browser from '../../instrumented/browser.js';
|
||||
import * as utilities from '../../instrumented/utilities.js';
|
||||
import {NS} from '../../instrumented/namespaces.js';
|
||||
|
||||
describe('utilities', function () {
|
||||
/**
|
||||
* Create an element for test.
|
||||
* @param {module:utilities.SVGElementJSON} jsonMap
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockCreateSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
}
|
||||
/**
|
||||
* Adds SVG Element per parameters and appends to root.
|
||||
* @param {module:utilities.SVGElementJSON} json
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockaddSVGElementFromJson (json) {
|
||||
const elem = mockCreateSVGElement(json);
|
||||
svgroot.append(elem);
|
||||
return elem;
|
||||
}
|
||||
const mockPathActions = {resetOrientation () { /* */ }};
|
||||
let mockHistorySubCommands = [];
|
||||
const mockHistory = {
|
||||
BatchCommand: class {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
addSubCommand (cmd) {
|
||||
mockHistorySubCommands.push(cmd);
|
||||
}
|
||||
},
|
||||
RemoveElementCommand: class {
|
||||
// Longhand needed since used as a constructor
|
||||
constructor (elem, nextSibling, parent) {
|
||||
this.elem = elem;
|
||||
this.nextSibling = nextSibling;
|
||||
this.parent = parent;
|
||||
}
|
||||
},
|
||||
InsertElementCommand: class {
|
||||
constructor (path) { // Longhand needed since used as a constructor
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
};
|
||||
const mockCount = {
|
||||
clearSelection: 0,
|
||||
addToSelection: 0,
|
||||
addCommandToHistory: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Increments clear seleciton count for mock test.
|
||||
* @returns {void}
|
||||
*/
|
||||
function mockClearSelection () {
|
||||
mockCount.clearSelection++;
|
||||
}
|
||||
/**
|
||||
* Increments add selection count for mock test.
|
||||
* @returns {void}
|
||||
*/
|
||||
function mockAddToSelection () {
|
||||
mockCount.addToSelection++;
|
||||
}
|
||||
/**
|
||||
* Increments add command to history count for mock test.
|
||||
* @returns {void}
|
||||
*/
|
||||
function mockAddCommandToHistory () {
|
||||
mockCount.addCommandToHistory++;
|
||||
}
|
||||
|
||||
let svg, svgroot;
|
||||
beforeEach(() => {
|
||||
document.body.textContent = '';
|
||||
|
||||
mockHistorySubCommands = [];
|
||||
mockCount.clearSelection = 0;
|
||||
mockCount.addToSelection = 0;
|
||||
mockCount.addCommandToHistory = 0;
|
||||
|
||||
const sandbox = document.createElement('div');
|
||||
svg = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot = mockCreateSVGElement({
|
||||
element: 'svg',
|
||||
attr: {id: 'svgroot'}
|
||||
});
|
||||
sandbox.append(svgroot);
|
||||
document.body.append(sandbox);
|
||||
});
|
||||
|
||||
it('Test svgedit.utilities package', function () {
|
||||
assert.ok(utilities);
|
||||
assert.ok(utilities.toXml);
|
||||
assert.equal(typeof utilities.toXml, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
it('Test svgedit.utilities.toXml() function', function () {
|
||||
const {toXml} = utilities;
|
||||
|
||||
assert.equal(toXml('a'), 'a');
|
||||
assert.equal(toXml('ABC_'), 'ABC_');
|
||||
assert.equal(toXml('PB&J'), 'PB&J');
|
||||
assert.equal(toXml('2 < 5'), '2 < 5');
|
||||
assert.equal(toXml('5 > 2'), '5 > 2');
|
||||
assert.equal(toXml('\'<&>"'), ''<&>"');
|
||||
});
|
||||
|
||||
it('Test svgedit.utilities.fromXml() function', function () {
|
||||
const {fromXml} = utilities;
|
||||
|
||||
assert.equal(fromXml('a'), 'a');
|
||||
assert.equal(fromXml('ABC_'), 'ABC_');
|
||||
assert.equal(fromXml('PB&J'), 'PB&J');
|
||||
assert.equal(fromXml('2 < 5'), '2 < 5');
|
||||
assert.equal(fromXml('5 > 2'), '5 > 2');
|
||||
assert.equal(fromXml('<&>'), '<&>');
|
||||
});
|
||||
|
||||
it('Test svgedit.utilities.encode64() function', function () {
|
||||
const {encode64} = utilities;
|
||||
|
||||
assert.equal(encode64('abcdef'), 'YWJjZGVm');
|
||||
assert.equal(encode64('12345'), 'MTIzNDU=');
|
||||
assert.equal(encode64(' '), 'IA==');
|
||||
assert.equal(encode64('`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?'), 'YH4hQCMkJV4mKigpLV89K1t7XX1cfDs6JyIsPC4+Lz8=');
|
||||
});
|
||||
|
||||
it('Test svgedit.utilities.decode64() function', function () {
|
||||
const {decode64} = utilities;
|
||||
|
||||
assert.equal(decode64('YWJjZGVm'), 'abcdef');
|
||||
assert.equal(decode64('MTIzNDU='), '12345');
|
||||
assert.equal(decode64('IA=='), ' ');
|
||||
assert.equal(decode64('YH4hQCMkJV4mKigpLV89K1t7XX1cfDs6JyIsPC4+Lz8='), '`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?');
|
||||
});
|
||||
|
||||
it('Test svgedit.utilities.convertToXMLReferences() function', function () {
|
||||
const convert = utilities.convertToXMLReferences;
|
||||
assert.equal(convert('ABC'), 'ABC');
|
||||
// assert.equal(convert('<27>BC'), 'ÀBC');
|
||||
});
|
||||
|
||||
it('Test svgedit.utilities.bboxToObj() function', function () {
|
||||
const {bboxToObj} = utilities;
|
||||
|
||||
const rect = svg.createSVGRect();
|
||||
rect.x = 1;
|
||||
rect.y = 2;
|
||||
rect.width = 3;
|
||||
rect.height = 4;
|
||||
|
||||
const obj = bboxToObj(rect);
|
||||
assert.equal(typeof obj, typeof {});
|
||||
assert.equal(obj.x, 1);
|
||||
assert.equal(obj.y, 2);
|
||||
assert.equal(obj.width, 3);
|
||||
assert.equal(obj.height, 4);
|
||||
});
|
||||
|
||||
it('Test getUrlFromAttr', function () {
|
||||
assert.equal(utilities.getUrlFromAttr('url(#foo)'), '#foo');
|
||||
assert.equal(utilities.getUrlFromAttr('url(somefile.svg#foo)'), 'somefile.svg#foo');
|
||||
assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo');
|
||||
assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo');
|
||||
});
|
||||
|
||||
it('Test getPathBBox', function () {
|
||||
if (browser.supportsPathBBox()) {
|
||||
return;
|
||||
}
|
||||
const doc = utilities.text2xml('<svg></svg>');
|
||||
const path = doc.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'm0,0l5,0l0,5l-5,0l0,-5z');
|
||||
const bb = utilities.getPathBBox(path);
|
||||
assert.equal(typeof bb, 'object', 'BBox returned object');
|
||||
assert.ok(bb.x && !isNaN(bb.x));
|
||||
assert.ok(bb.y && !isNaN(bb.y));
|
||||
});
|
||||
|
||||
it('Test getPathDFromSegments', function () {
|
||||
const {getPathDFromSegments} = utilities;
|
||||
|
||||
const doc = utilities.text2xml('<svg></svg>');
|
||||
const path = doc.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'm0,0l5,0l0,5l-5,0l0,-5z');
|
||||
let d = getPathDFromSegments([
|
||||
['M', [1, 2]],
|
||||
['Z', []]
|
||||
]);
|
||||
assert.equal(d, 'M1,2 Z');
|
||||
|
||||
d = getPathDFromSegments([
|
||||
['M', [1, 2]],
|
||||
['M', [3, 4]],
|
||||
['Z', []]
|
||||
]);
|
||||
assert.equal(d, 'M1,2 M3,4 Z');
|
||||
|
||||
d = getPathDFromSegments([
|
||||
['M', [1, 2]],
|
||||
['C', [3, 4, 5, 6]],
|
||||
['Z', []]
|
||||
]);
|
||||
assert.equal(d, 'M1,2 C3,4 5,6 Z');
|
||||
});
|
||||
|
||||
it('Test getPathDFromElement', function () {
|
||||
const {getPathDFromElement} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 Z'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M0,1 Z');
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M0,1 L5,1 L5,11 L0,11 L0,1 Z');
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'roundrect', x: '0', y: '1', rx: '2', ry: '3', width: '10', height: '11'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
const closeEnough = /M0,4 C0,2.3\d* 0.9\d*,1 2,1 L8,1 C9.0\d*,1 10,2.3\d* 10,4 L10,9 C10,10.6\d* 9.08675799086758,12 8,12 L2,12 C0.9\d*,12 0,10.6\d* 0,9 L0,4 Z/;
|
||||
assert.equal(closeEnough.test(getPathDFromElement(elem)), true);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M0,1L5,6');
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'circle',
|
||||
attr: {id: 'circle', cx: '10', cy: '11', rx: '5', ry: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M10,11 C10,11 10,11 10,11 C10,11 10,11 10,11 C10,11 10,11 10,11 C10,11 10,11 10,11 Z');
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'polyline',
|
||||
attr: {id: 'polyline', points: '0,1 5,1 5,11 0,11'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M0,1 5,1 5,11 0,11');
|
||||
elem.remove();
|
||||
|
||||
assert.equal(getPathDFromElement({tagName: 'something unknown'}), undefined);
|
||||
});
|
||||
|
||||
it('Test getBBoxOfElementAsPath', function () {
|
||||
/**
|
||||
* Wrap `utilities.getBBoxOfElementAsPath` to convert bbox to object for testing.
|
||||
* @type {module:utilities.getBBoxOfElementAsPath}
|
||||
*/
|
||||
function getBBoxOfElementAsPath (elem, addSVGElementFromJson, pathActions) {
|
||||
const bbox = utilities.getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions);
|
||||
return utilities.bboxToObj(bbox); // need this for assert.equal() to work.
|
||||
}
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 Z'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 0, height: 0});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 5});
|
||||
elem.remove();
|
||||
|
||||
// TODO: test element with transform. Need resetOrientation above to be working or mock it.
|
||||
});
|
||||
|
||||
it('Test convertToPath rect', function () {
|
||||
const {convertToPath} = utilities;
|
||||
const attrs = {
|
||||
fill: 'red',
|
||||
stroke: 'white',
|
||||
'stroke-width': '1',
|
||||
visibility: 'hidden'
|
||||
};
|
||||
|
||||
const elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
const path = convertToPath(elem, attrs, mockaddSVGElementFromJson, mockPathActions, mockClearSelection, mockAddToSelection, mockHistory, mockAddCommandToHistory);
|
||||
assert.equal(path.getAttribute('d'), 'M0,1 L5,1 L5,11 L0,11 L0,1 Z');
|
||||
assert.equal(path.getAttribute('visibilituy'), null);
|
||||
assert.equal(path.id, 'rect');
|
||||
assert.equal(path.parentNode, svgroot);
|
||||
assert.equal(elem.parentNode, null);
|
||||
assert.equal(mockHistorySubCommands.length, 2);
|
||||
assert.equal(mockCount.clearSelection, 1);
|
||||
assert.equal(mockCount.addToSelection, 1);
|
||||
assert.equal(mockCount.addCommandToHistory, 1);
|
||||
path.remove();
|
||||
});
|
||||
|
||||
it('Test convertToPath unknown element', function () {
|
||||
const {convertToPath} = utilities;
|
||||
const attrs = {
|
||||
fill: 'red',
|
||||
stroke: 'white',
|
||||
'stroke-width': '1',
|
||||
visibility: 'hidden'
|
||||
};
|
||||
|
||||
const elem = {
|
||||
tagName: 'something unknown',
|
||||
id: 'something-unknown',
|
||||
getAttribute (attr) { return ''; },
|
||||
parentNode: svgroot
|
||||
};
|
||||
const path = convertToPath(elem, attrs, mockaddSVGElementFromJson, mockPathActions, mockClearSelection, mockAddToSelection, mockHistory, mockAddCommandToHistory);
|
||||
assert.equal(path, null);
|
||||
assert.equal(elem.parentNode, svgroot);
|
||||
assert.equal(mockHistorySubCommands.length, 0);
|
||||
assert.equal(mockCount.clearSelection, 0);
|
||||
assert.equal(mockCount.addToSelection, 0);
|
||||
assert.equal(mockCount.addCommandToHistory, 0);
|
||||
});
|
||||
});
|
||||
29
cypress/support/assert-almostEquals.js
Normal file
29
cypress/support/assert-almostEquals.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import assertionWrapper from './assertion-wrapper.js';
|
||||
|
||||
const NEAR_ZERO = 5e-6; // 0.000005, Firefox fails at higher levels of precision.
|
||||
|
||||
/**
|
||||
* Checks that the supplied values are equal with a high though not absolute degree of precision.
|
||||
* @param {Float} actual
|
||||
* @param {Float} expected
|
||||
* @param {string} message
|
||||
* @returns {void}
|
||||
*/
|
||||
function almostEquals (actual, expected, message) {
|
||||
message = message || (actual + ' did not equal ' + expected);
|
||||
const result = Math.abs(actual - expected) < NEAR_ZERO;
|
||||
return {result, message, actual, expected};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {external:chai} _chai
|
||||
* @param {external:chai_utils} utils
|
||||
* @returns {void}
|
||||
*/
|
||||
function setAssertionMethods (_chai, utils) {
|
||||
const wrap = assertionWrapper(_chai, utils);
|
||||
|
||||
assert.almostEquals = wrap(almostEquals);
|
||||
}
|
||||
|
||||
export default setAssertionMethods;
|
||||
@@ -1,3 +1,13 @@
|
||||
import assertionWrapper from './assertion-wrapper.js';
|
||||
|
||||
/**
|
||||
* @typedef {PlainObject} InfoObject
|
||||
* @property {boolean} result
|
||||
* @property {string} message
|
||||
* @property {Float} actual
|
||||
* @property {Float} expected
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks that the first two arguments are equal, or are numbers close enough to be considered equal
|
||||
* based on a specified maximum allowable difference.
|
||||
@@ -8,26 +18,26 @@
|
||||
* @param {Float} expected
|
||||
* @param {Float} maxDifference (the maximum inclusive difference allowed between the actual and expected numbers)
|
||||
* @param {string} [message] Defaults to structured message
|
||||
* @returns {void}
|
||||
* @returns {InfoObject}
|
||||
*/
|
||||
function close (actual, expected, maxDifference, message) {
|
||||
const actualDiff = (actual === expected) ? 0 : Math.abs(actual - expected),
|
||||
result = actualDiff <= maxDifference;
|
||||
message = message || (actual + ' should be within ' + maxDifference + ' (inclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff));
|
||||
this.pushResult({result, actual, expected, message});
|
||||
return {result, message, actual, expected};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the first two arguments are equal, or are numbers close enough to be considered equal
|
||||
* based on a specified maximum allowable difference percentage.
|
||||
*
|
||||
* @example assert.close.percent(155, 150, 3.4); // Difference is ~3.33%
|
||||
* @example assert.closePercent(155, 150, 3.4); // Difference is ~3.33%
|
||||
*
|
||||
* @param {Float} actual
|
||||
* @param {Float} expected
|
||||
* @param {Float} maxPercentDifference (the maximum inclusive difference percentage allowed between the actual and expected numbers)
|
||||
* @param {string} [message] Defaults to a structured message
|
||||
* @returns {void}
|
||||
* @returns {InfoObject}
|
||||
*/
|
||||
function closePercent (actual, expected, maxPercentDifference, message) {
|
||||
let actualDiff, result;
|
||||
@@ -44,7 +54,7 @@ function closePercent (actual, expected, maxPercentDifference, message) {
|
||||
}
|
||||
message = message || (actual + ' should be within ' + maxPercentDifference + '% (inclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff + '%'));
|
||||
|
||||
this.pushResult(result, actual, expected, message);
|
||||
return {result, message, actual, expected};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,26 +67,26 @@ function closePercent (actual, expected, maxPercentDifference, message) {
|
||||
* @param {Float} expected
|
||||
* @param {Float} minDifference (the minimum exclusive difference allowed between the actual and expected numbers)
|
||||
* @param {string} [message] Defaults to structured message
|
||||
* @returns {void}
|
||||
* @returns {InfoObject}
|
||||
*/
|
||||
function notClose (actual, expected, minDifference, message) {
|
||||
const actualDiff = Math.abs(actual - expected),
|
||||
result = actualDiff > minDifference;
|
||||
message = message || (actual + ' should not be within ' + minDifference + ' (exclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff));
|
||||
this.pushResult(result, actual, expected, message);
|
||||
return {result, message, actual, expected};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the first two arguments are numbers with differences greater than the specified
|
||||
* minimum difference percentage.
|
||||
*
|
||||
* @example assert.notClose.percent(156, 150, 3.5); // Difference is 4.0%
|
||||
* @example assert.notClosePercent(156, 150, 3.5); // Difference is 4.0%
|
||||
*
|
||||
* @param {Float} actual
|
||||
* @param {Float} expected
|
||||
* @param {Float} minPercentDifference (the minimum exclusive difference percentage allowed between the actual and expected numbers)
|
||||
* @param {string} [message] Defaults to a structured message
|
||||
* @returns {void}
|
||||
* @returns {InfoObject}
|
||||
*/
|
||||
function notClosePercent (actual, expected, minPercentDifference, message) {
|
||||
let actualDiff, result;
|
||||
@@ -93,19 +103,21 @@ function notClosePercent (actual, expected, minPercentDifference, message) {
|
||||
}
|
||||
message = message || (actual + ' should not be within ' + minPercentDifference + '% (exclusive) of ' + expected + (result ? '' : '. Actual: ' + actualDiff + '%'));
|
||||
|
||||
this.pushResult({result, actual, expected, message});
|
||||
return {result, message, actual, expected};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {external:qunit} QUnit
|
||||
* @returns {external:qunit} The same instance passed in after extending
|
||||
* @param {external:chai} _chai
|
||||
* @param {external:chai_utils} utils
|
||||
* @returns {void}
|
||||
*/
|
||||
export default function extend (QUnit) {
|
||||
QUnit.extend(QUnit.assert, {
|
||||
close,
|
||||
closePercent,
|
||||
notClose,
|
||||
notClosePercent
|
||||
});
|
||||
return QUnit;
|
||||
function setAssertionMethods (_chai, utils) {
|
||||
const wrap = assertionWrapper(_chai, utils);
|
||||
|
||||
assert.close = wrap(close);
|
||||
assert.closePercent = wrap(closePercent);
|
||||
assert.notClose = wrap(notClose);
|
||||
assert.notClosePercent = wrap(notClosePercent);
|
||||
}
|
||||
|
||||
export default setAssertionMethods;
|
||||
@@ -1,3 +1,5 @@
|
||||
import assertionWrapper from './assertion-wrapper.js';
|
||||
|
||||
/**
|
||||
* Expects an out of bounds `INDEX_SIZE_ERR` exception.
|
||||
* @param {GenericObject} obj
|
||||
@@ -17,16 +19,18 @@ function expectOutOfBoundsException (obj, fn, arg1) {
|
||||
}
|
||||
}
|
||||
const actual = result;
|
||||
this.pushResult({result, actual, expected, message});
|
||||
return {result, message, actual, expected};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {external:qunit} QUnit
|
||||
* @returns {external:qunit} The same instance passed in after extending
|
||||
* @param {external:chai} _chai
|
||||
* @param {external:chai_utils} utils
|
||||
* @returns {void}
|
||||
*/
|
||||
export default function extend (QUnit) {
|
||||
QUnit.extend(QUnit.assert, {
|
||||
expectOutOfBoundsException
|
||||
});
|
||||
return QUnit;
|
||||
function setAssertionMethods (_chai, utils) {
|
||||
const wrap = assertionWrapper(_chai, utils);
|
||||
|
||||
assert.expectOutOfBoundsException = wrap(expectOutOfBoundsException);
|
||||
}
|
||||
|
||||
export default setAssertionMethods;
|
||||
15
cypress/support/assertion-wrapper.js
Normal file
15
cypress/support/assertion-wrapper.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @param {external:chai} _chai
|
||||
* @param {external:chai_utils} utils
|
||||
* @returns {void}
|
||||
*/
|
||||
function setAssertionMethods (_chai, utils) {
|
||||
return (method) => {
|
||||
return (...args) => {
|
||||
const {result, message, actual, expected} = method(...args);
|
||||
const assertion = new _chai.Assertion();
|
||||
assertion.assert(result, `Expected ${actual} to be ${expected}`, message);
|
||||
};
|
||||
};
|
||||
}
|
||||
export default setAssertionMethods;
|
||||
@@ -10,6 +10,5 @@ copyfiles([
|
||||
], {
|
||||
up: 1
|
||||
}, () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Done');
|
||||
});
|
||||
|
||||
165
package-lock.json
generated
165
package-lock.json
generated
@@ -1664,42 +1664,6 @@
|
||||
"integrity": "sha512-7XHoRB61hxsz8lBQrjC1tq/3OEIgpvGWg6DKAdwi7WRzruwkmsdwmOoUXbU4Dtd4RSOMDwed0SkP3y8UlMt1Bg==",
|
||||
"dev": true
|
||||
},
|
||||
"@sinonjs/commons": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz",
|
||||
"integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-detect": "4.0.8"
|
||||
}
|
||||
},
|
||||
"@sinonjs/formatio": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz",
|
||||
"integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@sinonjs/commons": "^1",
|
||||
"@sinonjs/samsam": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"@sinonjs/samsam": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz",
|
||||
"integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@sinonjs/commons": "^1.3.0",
|
||||
"array-from": "^2.1.1",
|
||||
"lodash": "^4.17.15"
|
||||
}
|
||||
},
|
||||
"@sinonjs/text-encoding": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz",
|
||||
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@textlint/ast-node-types": {
|
||||
"version": "4.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-4.2.5.tgz",
|
||||
@@ -2042,12 +2006,6 @@
|
||||
"integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
|
||||
"dev": true
|
||||
},
|
||||
"array-from": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz",
|
||||
"integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=",
|
||||
"dev": true
|
||||
},
|
||||
"array-includes": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
|
||||
@@ -4406,12 +4364,6 @@
|
||||
"minimist": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
||||
"dev": true
|
||||
},
|
||||
"diffie-hellman": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
||||
@@ -5106,12 +5058,6 @@
|
||||
"integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-plugin-qunit": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-qunit/-/eslint-plugin-qunit-4.0.0.tgz",
|
||||
"integrity": "sha512-+0i2xcYryUoLawi47Lp0iJKzkP931G5GXwIOq1KBKQc2pknV1VPjfE6b4mI2mR2RnL7WRoS30YjwC9SjQgJDXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-plugin-sonarjs": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.5.0.tgz",
|
||||
@@ -7045,12 +6991,6 @@
|
||||
"integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
|
||||
"dev": true
|
||||
},
|
||||
"js-reporters": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.1.tgz",
|
||||
"integrity": "sha1-+IxgjjJKM3OpW8xFrTBeXJecRZs=",
|
||||
"dev": true
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -7259,12 +7199,6 @@
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"just-extend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz",
|
||||
"integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==",
|
||||
"dev": true
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||
@@ -7798,12 +7732,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"lolex": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz",
|
||||
"integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==",
|
||||
"dev": true
|
||||
},
|
||||
"longest-streak": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.3.tgz",
|
||||
@@ -8357,19 +8285,6 @@
|
||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"nise": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz",
|
||||
"integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@sinonjs/formatio": "^3.2.1",
|
||||
"@sinonjs/text-encoding": "^0.7.1",
|
||||
"just-extend": "^4.0.2",
|
||||
"lolex": "^4.1.0",
|
||||
"path-to-regexp": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"node-environment-flags": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
|
||||
@@ -8406,12 +8321,6 @@
|
||||
"optimist": ">=0.3.4"
|
||||
}
|
||||
},
|
||||
"node-watch": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.6.1.tgz",
|
||||
"integrity": "sha512-gwQiR7weFRV8mAtT0x0kXkZ18dfRLB45xH7q0hCOVQMLfLb2f1ZaSvR57q4/b/Vj6B0RwMNJYbvb69e1yM7qEA==",
|
||||
"dev": true
|
||||
},
|
||||
"noms": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz",
|
||||
@@ -9096,23 +9005,6 @@
|
||||
"integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=",
|
||||
"dev": true
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
|
||||
"integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isarray": "0.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"path-type": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
|
||||
@@ -9345,36 +9237,6 @@
|
||||
"integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
|
||||
"dev": true
|
||||
},
|
||||
"qunit": {
|
||||
"version": "2.9.3",
|
||||
"resolved": "https://registry.npmjs.org/qunit/-/qunit-2.9.3.tgz",
|
||||
"integrity": "sha512-RH4VYSaVsNRDthMFFboTJAJ8q4kJM5LvOqWponKUYPEAeOcmc/YFV1QsZ7ikknA3TjqliWFJYEV63vvVXaALmQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "2.12.2",
|
||||
"js-reporters": "1.2.1",
|
||||
"minimatch": "3.0.4",
|
||||
"node-watch": "0.6.1",
|
||||
"resolve": "1.9.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
|
||||
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz",
|
||||
"integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.24.1",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz",
|
||||
@@ -10292,27 +10154,6 @@
|
||||
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=",
|
||||
"dev": true
|
||||
},
|
||||
"sinon": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz",
|
||||
"integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@sinonjs/commons": "^1.4.0",
|
||||
"@sinonjs/formatio": "^3.2.1",
|
||||
"@sinonjs/samsam": "^3.3.3",
|
||||
"diff": "^3.5.0",
|
||||
"lolex": "^4.2.0",
|
||||
"nise": "^1.5.2",
|
||||
"supports-color": "^5.5.0"
|
||||
}
|
||||
},
|
||||
"sinon-test": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/sinon-test/-/sinon-test-2.4.0.tgz",
|
||||
"integrity": "sha512-oQnO02I7JDbtrSKN8Qs3upobCQRythJCBn3DzPmv4m/SoPvhZJDVqHDFkRZ1lZhN2GkBqOR3m7WT79190z9kEg==",
|
||||
"dev": true
|
||||
},
|
||||
"slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
@@ -11347,12 +11188,6 @@
|
||||
"prelude-ls": "~1.1.2"
|
||||
}
|
||||
},
|
||||
"type-detect": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
|
||||
"dev": true
|
||||
},
|
||||
"type-fest": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||
|
||||
@@ -137,7 +137,6 @@
|
||||
"eslint-plugin-no-use-extend-native": "^0.4.1",
|
||||
"eslint-plugin-node": "10.0.0",
|
||||
"eslint-plugin-promise": "4.2.1",
|
||||
"eslint-plugin-qunit": "^4.0.0",
|
||||
"eslint-plugin-sonarjs": "^0.5.0",
|
||||
"eslint-plugin-standard": "4.0.1",
|
||||
"eslint-plugin-unicorn": "^13.0.0",
|
||||
@@ -153,7 +152,6 @@
|
||||
"promise-fs": "^2.1.1",
|
||||
"qr-manipulation": "https://github.com/brettz9/qr-manipulation",
|
||||
"query-result": "https://github.com/WebReflection/query-result",
|
||||
"qunit": "^2.9.3",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"remark-cli": "^7.0.1",
|
||||
"remark-lint-ordered-list-marker-value": "^1.0.3",
|
||||
@@ -161,8 +159,6 @@
|
||||
"rollup-plugin-babel": "^4.3.3",
|
||||
"rollup-plugin-re": "^1.0.7",
|
||||
"rollup-plugin-terser": "^5.1.2",
|
||||
"sinon": "^7.5.0",
|
||||
"sinon-test": "^2.4.0",
|
||||
"stackblur-canvas": "^2.2.0",
|
||||
"typescript": "^3.7.2"
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<title>All SVG-edit Tests</title>
|
||||
<style>
|
||||
iframe {width: 100%; height: 70px;}
|
||||
</style>
|
||||
<script defer="defer" src="all_tests.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>All SVG-edit Tests</h1>
|
||||
<p>This file frames all SVG-edit test pages. This should only include
|
||||
tests known to work. These tests are known to pass 100% in the
|
||||
following:
|
||||
Firefox 3.6, Chrome 7, IE9 Preview 6 (1.9.8006.6000), Opera 10.63.
|
||||
If a test is broken in this page, it is possible that <em>YOU</em>
|
||||
broke it. Please do not submit code that breaks any of these tests.</p>
|
||||
<!--
|
||||
<iframe src="jQuery.attr_test.html" scrolling="no"></iframe>
|
||||
-->
|
||||
<iframe src="svgtransformlist_test.html" scrolling="no"></iframe>
|
||||
<iframe src="contextmenu_test.html" scrolling="no"></iframe>
|
||||
<iframe src="math_test.html" scrolling="no"></iframe>
|
||||
<iframe src="utilities_test.html" scrolling="no"></iframe>
|
||||
<iframe src="utilities_bbox_test.html" scrolling="no"></iframe>
|
||||
<iframe src="history_test.html" scrolling="no"></iframe>
|
||||
<iframe src="select_test.html" scrolling="no"></iframe>
|
||||
<iframe src="draw_test.html" scrolling="no"></iframe>
|
||||
<iframe src="units_test.html" scrolling="no"></iframe>
|
||||
<iframe src="path_test.html" scrolling="no"></iframe>
|
||||
<iframe src="sanitize_test.html" scrolling="no"></iframe>
|
||||
<iframe src="coords_test.html" scrolling="no"></iframe>
|
||||
<iframe src="recalculate_test.html" scrolling="no"></iframe>
|
||||
|
||||
<iframe src="test1.html" scrolling="no"></iframe>
|
||||
<iframe src="utilities_performance_test.html" scrolling="no"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,8 +0,0 @@
|
||||
const iframes = document.querySelectorAll('iframe');
|
||||
[...iframes].forEach((f) => {
|
||||
f.addEventListener('load', () => {
|
||||
f.contentWindow.QUnit.done(() => {
|
||||
f.style.height = (f.contentDocument.body.scrollHeight + 20) + 'px';
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,21 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>removeItem and setAttribute test</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
var elem = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
elem.setAttribute('transform', 'matrix(1,0,0,1,0,0)');
|
||||
elem.transform.baseVal.removeItem(0);
|
||||
elem.removeAttribute('transform');
|
||||
console.log(elem.hasAttribute('transform'));
|
||||
</script>
|
||||
Issue:
|
||||
<a href="https://bugs.chromium.org/p/chromium/issues/detail?id=843901">
|
||||
Chromium 843901
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for contextmenu.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script>
|
||||
window.svgEditor = {
|
||||
ready () {
|
||||
// Mock for browser.js
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="contextmenu_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for contextmenu.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="svgroot" style="visibility: hidden;"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,73 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import * as contextmenu from '../editor/contextmenu.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Tear down tests, resetting custom menus.
|
||||
* @returns {void}
|
||||
*/
|
||||
function tearDown () {
|
||||
contextmenu.resetCustomMenus();
|
||||
}
|
||||
|
||||
QUnit.module('svgedit.contextmenu');
|
||||
|
||||
QUnit.test('Test svgedit.contextmenu package', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
assert.ok(contextmenu, 'contextmenu registered correctly');
|
||||
assert.ok(contextmenu.add, 'add registered correctly');
|
||||
assert.ok(contextmenu.hasCustomHandler, 'contextmenu hasCustomHandler registered correctly');
|
||||
assert.ok(contextmenu.getCustomHandler, 'contextmenu getCustomHandler registered correctly');
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.contextmenu does not add invalid menu item', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
assert.throws(
|
||||
() => contextmenu.add({id: 'justanid'}),
|
||||
'menu item with just an id is invalid'
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => contextmenu.add({id: 'idandlabel', label: 'anicelabel'}),
|
||||
'menu item with just an id and label is invalid'
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => contextmenu.add({id: 'idandlabel', label: 'anicelabel', action: 'notafunction'}),
|
||||
'menu item with action that is not a function is invalid'
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.contextmenu adds valid menu item', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const validItem = {id: 'valid', label: 'anicelabel', action () { console.log('testing'); }};
|
||||
contextmenu.add(validItem);
|
||||
|
||||
assert.ok(contextmenu.hasCustomHandler('valid'), 'Valid menu item is added.');
|
||||
assert.equal(contextmenu.getCustomHandler('valid'), validItem.action, 'Valid menu action is added.');
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.contextmenu rejects valid duplicate menu item id', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const validItem1 = {id: 'valid', label: 'anicelabel', action () { console.log('testing'); }};
|
||||
const validItem2 = {id: 'valid', label: 'anicelabel', action () { console.log('testingtwice'); }};
|
||||
contextmenu.add(validItem1);
|
||||
|
||||
assert.throws(
|
||||
() => contextmenu.add(validItem2),
|
||||
'duplicate menu item is rejected.'
|
||||
);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for coords.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="coords_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for coords</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="root" style="visibility: hidden;"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,355 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as utilities from '../editor/utilities.js';
|
||||
import * as coords from '../editor/coords.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
const root = document.getElementById('root');
|
||||
const svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot.id = 'svgroot';
|
||||
root.append(svgroot);
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot.append(svg);
|
||||
|
||||
let elemId = 1;
|
||||
|
||||
/**
|
||||
* Set up tests with mock data.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUp () {
|
||||
// Mock out editor context.
|
||||
utilities.init(
|
||||
/**
|
||||
* @implements {module:utilities.EditorContext}
|
||||
*/
|
||||
{
|
||||
getSVGRoot () { return svg; },
|
||||
getDOMDocument () { return null; },
|
||||
getDOMContainer () { return null; }
|
||||
}
|
||||
);
|
||||
coords.init(
|
||||
/**
|
||||
* @implements {module:coords.EditorContext}
|
||||
*/
|
||||
{
|
||||
getGridSnapping () { return false; },
|
||||
getDrawing () {
|
||||
return {
|
||||
getNextId () { return String(elemId++); }
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down tests, removing elements.
|
||||
* @returns {void}
|
||||
*/
|
||||
function tearDown () {
|
||||
while (svg.hasChildNodes()) {
|
||||
svg.firstChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
QUnit.test('Test remapElement(translate) for rect', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
setUp();
|
||||
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('x', '200');
|
||||
rect.setAttribute('y', '150');
|
||||
rect.setAttribute('width', '250');
|
||||
rect.setAttribute('height', '120');
|
||||
svg.append(rect);
|
||||
|
||||
const attrs = {
|
||||
x: '200',
|
||||
y: '150',
|
||||
width: '125',
|
||||
height: '75'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(rect, attrs, m);
|
||||
|
||||
assert.equal(rect.getAttribute('x'), '300');
|
||||
assert.equal(rect.getAttribute('y'), '100');
|
||||
assert.equal(rect.getAttribute('width'), '125');
|
||||
assert.equal(rect.getAttribute('height'), '75');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test remapElement(scale) for rect', function (assert) {
|
||||
assert.expect(4);
|
||||
setUp();
|
||||
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('width', '250');
|
||||
rect.setAttribute('height', '120');
|
||||
svg.append(rect);
|
||||
|
||||
const attrs = {
|
||||
x: '0',
|
||||
y: '0',
|
||||
width: '250',
|
||||
height: '120'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 2; m.b = 0;
|
||||
m.c = 0; m.d = 0.5;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
coords.remapElement(rect, attrs, m);
|
||||
|
||||
assert.equal(rect.getAttribute('x'), '0');
|
||||
assert.equal(rect.getAttribute('y'), '0');
|
||||
assert.equal(rect.getAttribute('width'), '500');
|
||||
assert.equal(rect.getAttribute('height'), '60');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test remapElement(translate) for circle', function (assert) {
|
||||
assert.expect(3);
|
||||
setUp();
|
||||
|
||||
const circle = document.createElementNS(NS.SVG, 'circle');
|
||||
circle.setAttribute('cx', '200');
|
||||
circle.setAttribute('cy', '150');
|
||||
circle.setAttribute('r', '125');
|
||||
svg.append(circle);
|
||||
|
||||
const attrs = {
|
||||
cx: '200',
|
||||
cy: '150',
|
||||
r: '125'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(circle, attrs, m);
|
||||
|
||||
assert.equal(circle.getAttribute('cx'), '300');
|
||||
assert.equal(circle.getAttribute('cy'), '100');
|
||||
assert.equal(circle.getAttribute('r'), '125');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test remapElement(scale) for circle', function (assert) {
|
||||
assert.expect(3);
|
||||
setUp();
|
||||
|
||||
const circle = document.createElementNS(NS.SVG, 'circle');
|
||||
circle.setAttribute('cx', '200');
|
||||
circle.setAttribute('cy', '150');
|
||||
circle.setAttribute('r', '250');
|
||||
svg.append(circle);
|
||||
|
||||
const attrs = {
|
||||
cx: '200',
|
||||
cy: '150',
|
||||
r: '250'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 2; m.b = 0;
|
||||
m.c = 0; m.d = 0.5;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
coords.remapElement(circle, attrs, m);
|
||||
|
||||
assert.equal(circle.getAttribute('cx'), '400');
|
||||
assert.equal(circle.getAttribute('cy'), '75');
|
||||
// Radius is the minimum that fits in the new bounding box.
|
||||
assert.equal(circle.getAttribute('r'), '125');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test remapElement(translate) for ellipse', function (assert) {
|
||||
assert.expect(4);
|
||||
setUp();
|
||||
|
||||
const ellipse = document.createElementNS(NS.SVG, 'ellipse');
|
||||
ellipse.setAttribute('cx', '200');
|
||||
ellipse.setAttribute('cy', '150');
|
||||
ellipse.setAttribute('rx', '125');
|
||||
ellipse.setAttribute('ry', '75');
|
||||
svg.append(ellipse);
|
||||
|
||||
const attrs = {
|
||||
cx: '200',
|
||||
cy: '150',
|
||||
rx: '125',
|
||||
ry: '75'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(ellipse, attrs, m);
|
||||
|
||||
assert.equal(ellipse.getAttribute('cx'), '300');
|
||||
assert.equal(ellipse.getAttribute('cy'), '100');
|
||||
assert.equal(ellipse.getAttribute('rx'), '125');
|
||||
assert.equal(ellipse.getAttribute('ry'), '75');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test remapElement(scale) for ellipse', function (assert) {
|
||||
assert.expect(4);
|
||||
setUp();
|
||||
|
||||
const ellipse = document.createElementNS(NS.SVG, 'ellipse');
|
||||
ellipse.setAttribute('cx', '200');
|
||||
ellipse.setAttribute('cy', '150');
|
||||
ellipse.setAttribute('rx', '250');
|
||||
ellipse.setAttribute('ry', '120');
|
||||
svg.append(ellipse);
|
||||
|
||||
const attrs = {
|
||||
cx: '200',
|
||||
cy: '150',
|
||||
rx: '250',
|
||||
ry: '120'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 2; m.b = 0;
|
||||
m.c = 0; m.d = 0.5;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
coords.remapElement(ellipse, attrs, m);
|
||||
|
||||
assert.equal(ellipse.getAttribute('cx'), '400');
|
||||
assert.equal(ellipse.getAttribute('cy'), '75');
|
||||
assert.equal(ellipse.getAttribute('rx'), '500');
|
||||
assert.equal(ellipse.getAttribute('ry'), '60');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test remapElement(translate) for line', function (assert) {
|
||||
assert.expect(4);
|
||||
setUp();
|
||||
|
||||
const line = document.createElementNS(NS.SVG, 'line');
|
||||
line.setAttribute('x1', '50');
|
||||
line.setAttribute('y1', '100');
|
||||
line.setAttribute('x2', '120');
|
||||
line.setAttribute('y2', '200');
|
||||
svg.append(line);
|
||||
|
||||
const attrs = {
|
||||
x1: '50',
|
||||
y1: '100',
|
||||
x2: '120',
|
||||
y2: '200'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(line, attrs, m);
|
||||
|
||||
assert.equal(line.getAttribute('x1'), '150');
|
||||
assert.equal(line.getAttribute('y1'), '50');
|
||||
assert.equal(line.getAttribute('x2'), '220');
|
||||
assert.equal(line.getAttribute('y2'), '150');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test remapElement(scale) for line', function (assert) {
|
||||
assert.expect(4);
|
||||
setUp();
|
||||
|
||||
const line = document.createElementNS(NS.SVG, 'line');
|
||||
line.setAttribute('x1', '50');
|
||||
line.setAttribute('y1', '100');
|
||||
line.setAttribute('x2', '120');
|
||||
line.setAttribute('y2', '200');
|
||||
svg.append(line);
|
||||
|
||||
const attrs = {
|
||||
x1: '50',
|
||||
y1: '100',
|
||||
x2: '120',
|
||||
y2: '200'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 2; m.b = 0;
|
||||
m.c = 0; m.d = 0.5;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
coords.remapElement(line, attrs, m);
|
||||
|
||||
assert.equal(line.getAttribute('x1'), '100');
|
||||
assert.equal(line.getAttribute('y1'), '50');
|
||||
assert.equal(line.getAttribute('x2'), '240');
|
||||
assert.equal(line.getAttribute('y2'), '100');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test remapElement(translate) for text', function (assert) {
|
||||
assert.expect(2);
|
||||
setUp();
|
||||
|
||||
const text = document.createElementNS(NS.SVG, 'text');
|
||||
text.setAttribute('x', '50');
|
||||
text.setAttribute('y', '100');
|
||||
svg.append(text);
|
||||
|
||||
const attrs = {
|
||||
x: '50',
|
||||
y: '100'
|
||||
};
|
||||
|
||||
// Create a translate.
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 100; m.f = -50;
|
||||
|
||||
coords.remapElement(text, attrs, m);
|
||||
|
||||
assert.equal(text.getAttribute('x'), '150');
|
||||
assert.equal(text.getAttribute('y'), '50');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for draw.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="draw_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for draw.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="sandbox" style="visibility: hidden;"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,830 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as draw from '../editor/draw.js';
|
||||
import * as units from '../editor/units.js';
|
||||
|
||||
import sinon from '../node_modules/sinon/pkg/sinon-esm.js';
|
||||
import sinonTest from '../node_modules/sinon-test/dist/sinon-test-es.js';
|
||||
import sinonQunit from './sinon/sinon-qunit.js';
|
||||
|
||||
sinon.test = sinonTest(sinon, {
|
||||
injectIntoThis: true,
|
||||
injectInto: null,
|
||||
properties: ['spy', 'stub', 'mock', 'clock', 'sandbox'],
|
||||
useFakeTimers: false,
|
||||
useFakeServer: false
|
||||
});
|
||||
sinonQunit({sinon, QUnit});
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
const LAYER_CLASS = draw.Layer.CLASS_NAME;
|
||||
const NONCE = 'foo';
|
||||
const LAYER1 = 'Layer 1';
|
||||
const LAYER2 = 'Layer 2';
|
||||
const LAYER3 = 'Layer 3';
|
||||
const PATH_ATTR = {
|
||||
// clone will convert relative to absolute, so the test for equality fails.
|
||||
// d: 'm7.38867,57.38867c0,-27.62431 22.37569,-50 50,-50c27.62431,0 50,22.37569 50,50c0,27.62431 -22.37569,50 -50,50c-27.62431,0 -50,-22.37569 -50,-50z',
|
||||
d: 'M7.389,57.389C7.389,29.764 29.764,7.389 57.389,7.389C85.013,7.389 107.389,29.764 107.389,57.389C107.389,85.013 85.013,107.389 57.389,107.389C29.764,107.389 7.389,85.013 7.389,57.389z',
|
||||
transform: 'rotate(45 57.388671875000036,57.388671874999986) ',
|
||||
'stroke-width': '5',
|
||||
stroke: '#660000',
|
||||
fill: '#ff0000'
|
||||
};
|
||||
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
const sandbox = document.getElementById('sandbox');
|
||||
// Firefox throws exception in getBBox() when svg is not attached to DOM.
|
||||
sandbox.append(svg);
|
||||
|
||||
// Set up <svg> with nonce.
|
||||
const svgN = document.createElementNS(NS.SVG, 'svg');
|
||||
svgN.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE);
|
||||
svgN.setAttributeNS(NS.SE, 'se:nonce', NONCE);
|
||||
|
||||
units.init(
|
||||
/**
|
||||
* @implements {module:units.ElementContainer}
|
||||
*/
|
||||
{
|
||||
// used by units.shortFloat - call path: cloneLayer -> copyElem -> convertPath -> pathDSegment -> shortFloat
|
||||
getRoundDigits () { return 3; }
|
||||
}
|
||||
);
|
||||
|
||||
// Simplifying from svgcanvas.js usage
|
||||
const idprefix = 'svg_';
|
||||
const svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
const currentDrawing_ = new draw.Drawing(svgcontent, idprefix);
|
||||
const getCurrentDrawing = function () {
|
||||
return currentDrawing_;
|
||||
};
|
||||
const setCurrentGroup = (cg) => { /* */ };
|
||||
draw.init(
|
||||
/**
|
||||
* @implements {module:draw.DrawCanvasInit}
|
||||
*/
|
||||
{
|
||||
getCurrentDrawing,
|
||||
setCurrentGroup
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @param {module:utilities.SVGElementJSON} jsonMap
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function createSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
}
|
||||
|
||||
const setupSVGWith3Layers = function (svgElem) {
|
||||
const layer1 = document.createElementNS(NS.SVG, 'g');
|
||||
const layer1Title = document.createElementNS(NS.SVG, 'title');
|
||||
layer1Title.append(document.createTextNode(LAYER1));
|
||||
layer1.append(layer1Title);
|
||||
svgElem.append(layer1);
|
||||
|
||||
const layer2 = document.createElementNS(NS.SVG, 'g');
|
||||
const layer2Title = document.createElementNS(NS.SVG, 'title');
|
||||
layer2Title.append(document.createTextNode(LAYER2));
|
||||
layer2.append(layer2Title);
|
||||
svgElem.append(layer2);
|
||||
|
||||
const layer3 = document.createElementNS(NS.SVG, 'g');
|
||||
const layer3Title = document.createElementNS(NS.SVG, 'title');
|
||||
layer3Title.append(document.createTextNode(LAYER3));
|
||||
layer3.append(layer3Title);
|
||||
svgElem.append(layer3);
|
||||
|
||||
return [layer1, layer2, layer3];
|
||||
};
|
||||
|
||||
const createSomeElementsInGroup = function (group) {
|
||||
group.append(
|
||||
createSVGElement({
|
||||
element: 'path',
|
||||
attr: PATH_ATTR
|
||||
}),
|
||||
// createSVGElement({
|
||||
// element: 'path',
|
||||
// attr: {d: 'M0,1L2,3'}
|
||||
// }),
|
||||
createSVGElement({
|
||||
element: 'rect',
|
||||
attr: {x: '0', y: '1', width: '5', height: '10'}
|
||||
}),
|
||||
createSVGElement({
|
||||
element: 'line',
|
||||
attr: {x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
})
|
||||
);
|
||||
|
||||
const g = createSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(createSVGElement({
|
||||
element: 'rect',
|
||||
attr: {x: '0', y: '1', width: '5', height: '10'}
|
||||
}));
|
||||
group.append(g);
|
||||
return 4;
|
||||
};
|
||||
|
||||
const cleanupSVG = function (svgElem) {
|
||||
while (svgElem.firstChild) { svgElem.firstChild.remove(); }
|
||||
};
|
||||
|
||||
QUnit.module('svgedit.draw.Drawing');
|
||||
|
||||
QUnit.test('Test draw module', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
assert.ok(draw);
|
||||
assert.equal(typeof draw, typeof {});
|
||||
|
||||
assert.ok(draw.Drawing);
|
||||
assert.equal(typeof draw.Drawing, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
QUnit.test('Test document creation', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
let doc;
|
||||
try {
|
||||
doc = new draw.Drawing();
|
||||
assert.ok(false, 'Created drawing without a valid <svg> element');
|
||||
} catch (e) {
|
||||
assert.ok(true);
|
||||
}
|
||||
|
||||
try {
|
||||
doc = new draw.Drawing(svg);
|
||||
assert.ok(doc);
|
||||
assert.equal(typeof doc, typeof {});
|
||||
} catch (e) {
|
||||
assert.ok(false, 'Could not create document from valid <svg> element: ' + e);
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('Test nonce', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
let doc = new draw.Drawing(svg);
|
||||
assert.equal(doc.getNonce(), '');
|
||||
|
||||
doc = new draw.Drawing(svgN);
|
||||
assert.equal(doc.getNonce(), NONCE);
|
||||
assert.equal(doc.getSvgElem().getAttributeNS(NS.SE, 'nonce'), NONCE);
|
||||
|
||||
doc.clearNonce();
|
||||
assert.ok(!doc.getNonce());
|
||||
assert.ok(!doc.getSvgElem().getAttributeNS(NS.SE, 'se:nonce'));
|
||||
|
||||
doc.setNonce(NONCE);
|
||||
assert.equal(doc.getNonce(), NONCE);
|
||||
assert.equal(doc.getSvgElem().getAttributeNS(NS.SE, 'nonce'), NONCE);
|
||||
});
|
||||
|
||||
QUnit.test('Test getId() and getNextId() without nonce', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const elem2 = document.createElementNS(NS.SVG, 'circle');
|
||||
elem2.id = 'svg_2';
|
||||
svg.append(elem2);
|
||||
|
||||
const doc = new draw.Drawing(svg);
|
||||
|
||||
assert.equal(doc.getId(), 'svg_0');
|
||||
|
||||
assert.equal(doc.getNextId(), 'svg_1');
|
||||
assert.equal(doc.getId(), 'svg_1');
|
||||
|
||||
assert.equal(doc.getNextId(), 'svg_3');
|
||||
assert.equal(doc.getId(), 'svg_3');
|
||||
|
||||
assert.equal(doc.getNextId(), 'svg_4');
|
||||
assert.equal(doc.getId(), 'svg_4');
|
||||
// clean out svg document
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test getId() and getNextId() with prefix without nonce', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const prefix = 'Bar-';
|
||||
const doc = new draw.Drawing(svg, prefix);
|
||||
|
||||
assert.equal(doc.getId(), prefix + '0');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '1');
|
||||
assert.equal(doc.getId(), prefix + '1');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '2');
|
||||
assert.equal(doc.getId(), prefix + '2');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '3');
|
||||
assert.equal(doc.getId(), prefix + '3');
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test getId() and getNextId() with nonce', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const prefix = 'svg_' + NONCE;
|
||||
|
||||
const elem2 = document.createElementNS(NS.SVG, 'circle');
|
||||
elem2.id = prefix + '_2';
|
||||
svgN.append(elem2);
|
||||
|
||||
const doc = new draw.Drawing(svgN);
|
||||
|
||||
assert.equal(doc.getId(), prefix + '_0');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '_1');
|
||||
assert.equal(doc.getId(), prefix + '_1');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '_3');
|
||||
assert.equal(doc.getId(), prefix + '_3');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '_4');
|
||||
assert.equal(doc.getId(), prefix + '_4');
|
||||
|
||||
cleanupSVG(svgN);
|
||||
});
|
||||
|
||||
QUnit.test('Test getId() and getNextId() with prefix with nonce', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const PREFIX = 'Bar-';
|
||||
const doc = new draw.Drawing(svgN, PREFIX);
|
||||
|
||||
const prefix = PREFIX + NONCE + '_';
|
||||
assert.equal(doc.getId(), prefix + '0');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '1');
|
||||
assert.equal(doc.getId(), prefix + '1');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '2');
|
||||
assert.equal(doc.getId(), prefix + '2');
|
||||
|
||||
assert.equal(doc.getNextId(), prefix + '3');
|
||||
assert.equal(doc.getId(), prefix + '3');
|
||||
|
||||
cleanupSVG(svgN);
|
||||
});
|
||||
|
||||
QUnit.test('Test releaseId()', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const doc = new draw.Drawing(svg);
|
||||
|
||||
const firstId = doc.getNextId();
|
||||
/* const secondId = */ doc.getNextId();
|
||||
|
||||
const result = doc.releaseId(firstId);
|
||||
assert.ok(result);
|
||||
assert.equal(doc.getNextId(), firstId);
|
||||
assert.equal(doc.getNextId(), 'svg_3');
|
||||
|
||||
assert.ok(!doc.releaseId('bad-id'));
|
||||
assert.ok(doc.releaseId(firstId));
|
||||
assert.ok(!doc.releaseId(firstId));
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test getNumLayers', function (assert) {
|
||||
assert.expect(3);
|
||||
const drawing = new draw.Drawing(svg);
|
||||
assert.equal(typeof drawing.getNumLayers, typeof function () { /* */ });
|
||||
assert.equal(drawing.getNumLayers(), 0);
|
||||
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 3);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test hasLayer', function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
setupSVGWith3Layers(svg);
|
||||
const drawing = new draw.Drawing(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(typeof drawing.hasLayer, typeof function () { /* */ });
|
||||
assert.ok(!drawing.hasLayer('invalid-layer'));
|
||||
|
||||
assert.ok(drawing.hasLayer(LAYER3));
|
||||
assert.ok(drawing.hasLayer(LAYER2));
|
||||
assert.ok(drawing.hasLayer(LAYER1));
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test identifyLayers() with empty document', function (assert) {
|
||||
assert.expect(11);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
assert.equal(drawing.getCurrentLayer(), null);
|
||||
// By default, an empty document gets an empty group created.
|
||||
drawing.identifyLayers();
|
||||
|
||||
// Check that <svg> element now has one child node
|
||||
assert.ok(drawing.getSvgElem().hasChildNodes());
|
||||
assert.equal(drawing.getSvgElem().childNodes.length, 1);
|
||||
|
||||
// Check that all_layers are correctly set up.
|
||||
assert.equal(drawing.getNumLayers(), 1);
|
||||
const emptyLayer = drawing.all_layers[0];
|
||||
assert.ok(emptyLayer);
|
||||
const layerGroup = emptyLayer.getGroup();
|
||||
assert.equal(layerGroup, drawing.getSvgElem().firstChild);
|
||||
assert.equal(layerGroup.tagName, 'g');
|
||||
assert.equal(layerGroup.getAttribute('class'), LAYER_CLASS);
|
||||
assert.ok(layerGroup.hasChildNodes());
|
||||
assert.equal(layerGroup.childNodes.length, 1);
|
||||
const firstChild = layerGroup.childNodes.item(0);
|
||||
assert.equal(firstChild.tagName, 'title');
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test identifyLayers() with some layers', function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
|
||||
assert.equal(svg.childNodes.length, 3);
|
||||
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 3);
|
||||
assert.equal(drawing.all_layers[0].getGroup(), svg.childNodes.item(0));
|
||||
assert.equal(drawing.all_layers[1].getGroup(), svg.childNodes.item(1));
|
||||
assert.equal(drawing.all_layers[2].getGroup(), svg.childNodes.item(2));
|
||||
|
||||
assert.equal(drawing.all_layers[0].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[1].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[2].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test identifyLayers() with some layers and orphans', function (assert) {
|
||||
assert.expect(14);
|
||||
|
||||
setupSVGWith3Layers(svg);
|
||||
|
||||
const orphan1 = document.createElementNS(NS.SVG, 'rect');
|
||||
const orphan2 = document.createElementNS(NS.SVG, 'rect');
|
||||
svg.append(orphan1, orphan2);
|
||||
|
||||
assert.equal(svg.childNodes.length, 5);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 4);
|
||||
assert.equal(drawing.all_layers[0].getGroup(), svg.childNodes.item(0));
|
||||
assert.equal(drawing.all_layers[1].getGroup(), svg.childNodes.item(1));
|
||||
assert.equal(drawing.all_layers[2].getGroup(), svg.childNodes.item(2));
|
||||
assert.equal(drawing.all_layers[3].getGroup(), svg.childNodes.item(3));
|
||||
|
||||
assert.equal(drawing.all_layers[0].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[1].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[2].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(drawing.all_layers[3].getGroup().getAttribute('class'), LAYER_CLASS);
|
||||
|
||||
const layer4 = drawing.all_layers[3].getGroup();
|
||||
assert.equal(layer4.tagName, 'g');
|
||||
assert.equal(layer4.childNodes.length, 3);
|
||||
assert.equal(layer4.childNodes.item(1), orphan1);
|
||||
assert.equal(layer4.childNodes.item(2), orphan2);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test getLayerName()', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 3);
|
||||
assert.equal(drawing.getLayerName(0), LAYER1);
|
||||
assert.equal(drawing.getLayerName(1), LAYER2);
|
||||
assert.equal(drawing.getLayerName(2), LAYER3);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test getCurrentLayer()', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.getCurrentLayer);
|
||||
assert.equal(typeof drawing.getCurrentLayer, typeof function () { /* */ });
|
||||
assert.ok(drawing.getCurrentLayer());
|
||||
assert.equal(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup());
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test setCurrentLayer() and getCurrentLayerName()', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.setCurrentLayer);
|
||||
assert.equal(typeof drawing.setCurrentLayer, typeof function () { /* */ });
|
||||
|
||||
drawing.setCurrentLayer(LAYER2);
|
||||
assert.equal(drawing.getCurrentLayerName(), LAYER2);
|
||||
assert.equal(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup());
|
||||
|
||||
drawing.setCurrentLayer(LAYER3);
|
||||
assert.equal(drawing.getCurrentLayerName(), LAYER3);
|
||||
assert.equal(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup());
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test setCurrentLayerName()', function (assert) {
|
||||
const mockHrService = {
|
||||
changeElement: this.spy()
|
||||
};
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.setCurrentLayerName);
|
||||
assert.equal(typeof drawing.setCurrentLayerName, typeof function () { /* */ });
|
||||
|
||||
const oldName = drawing.getCurrentLayerName();
|
||||
const newName = 'New Name';
|
||||
assert.ok(drawing.layer_map[oldName]);
|
||||
assert.equal(drawing.layer_map[newName], undefined); // newName shouldn't exist.
|
||||
const result = drawing.setCurrentLayerName(newName, mockHrService);
|
||||
assert.equal(result, newName);
|
||||
assert.equal(drawing.getCurrentLayerName(), newName);
|
||||
// Was the map updated?
|
||||
assert.equal(drawing.layer_map[oldName], undefined);
|
||||
assert.equal(drawing.layer_map[newName], drawing.current_layer);
|
||||
// Was mockHrService called?
|
||||
assert.ok(mockHrService.changeElement.calledOnce);
|
||||
assert.equal(oldName, mockHrService.changeElement.getCall(0).args[1]['#text']);
|
||||
assert.equal(newName, mockHrService.changeElement.getCall(0).args[0].textContent);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test createLayer()', function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
const mockHrService = {
|
||||
startBatchCommand: this.spy(),
|
||||
endBatchCommand: this.spy(),
|
||||
insertElement: this.spy()
|
||||
};
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.createLayer);
|
||||
assert.equal(typeof drawing.createLayer, typeof function () { /* */ });
|
||||
|
||||
const NEW_LAYER_NAME = 'Layer A';
|
||||
const layerG = drawing.createLayer(NEW_LAYER_NAME, mockHrService);
|
||||
assert.equal(drawing.getNumLayers(), 4);
|
||||
assert.equal(layerG, drawing.getCurrentLayer());
|
||||
assert.equal(layerG.getAttribute('class'), LAYER_CLASS);
|
||||
assert.equal(NEW_LAYER_NAME, drawing.getCurrentLayerName());
|
||||
assert.equal(NEW_LAYER_NAME, drawing.getLayerName(3));
|
||||
|
||||
assert.equal(layerG, mockHrService.insertElement.getCall(0).args[0]);
|
||||
assert.ok(mockHrService.startBatchCommand.calledOnce);
|
||||
assert.ok(mockHrService.endBatchCommand.calledOnce);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test mergeLayer()', function (assert) {
|
||||
const mockHrService = {
|
||||
startBatchCommand: this.spy(),
|
||||
endBatchCommand: this.spy(),
|
||||
moveElement: this.spy(),
|
||||
removeElement: this.spy()
|
||||
};
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
const layers = setupSVGWith3Layers(svg);
|
||||
const elementCount = createSomeElementsInGroup(layers[2]) + 1; // +1 for title element
|
||||
assert.equal(layers[1].childElementCount, 1);
|
||||
assert.equal(layers[2].childElementCount, elementCount);
|
||||
drawing.identifyLayers();
|
||||
assert.equal(drawing.getCurrentLayer(), layers[2]);
|
||||
|
||||
assert.ok(drawing.mergeLayer);
|
||||
assert.equal(typeof drawing.mergeLayer, typeof function () { /* */ });
|
||||
|
||||
drawing.mergeLayer(mockHrService);
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 2);
|
||||
assert.equal(svg.childElementCount, 2);
|
||||
assert.equal(drawing.getCurrentLayer(), layers[1]);
|
||||
assert.equal(layers[1].childElementCount, elementCount);
|
||||
|
||||
// check history record
|
||||
assert.ok(mockHrService.startBatchCommand.calledOnce);
|
||||
assert.ok(mockHrService.endBatchCommand.calledOnce);
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge Layer');
|
||||
assert.equal(mockHrService.moveElement.callCount, elementCount - 1); // -1 because the title was not moved.
|
||||
assert.equal(mockHrService.removeElement.callCount, 2); // remove group and title.
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test mergeLayer() when no previous layer to merge', function (assert) {
|
||||
const mockHrService = {
|
||||
startBatchCommand: this.spy(),
|
||||
endBatchCommand: this.spy(),
|
||||
moveElement: this.spy(),
|
||||
removeElement: this.spy()
|
||||
};
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
const layers = setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
drawing.setCurrentLayer(LAYER1);
|
||||
assert.equal(drawing.getCurrentLayer(), layers[0]);
|
||||
|
||||
drawing.mergeLayer(mockHrService);
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 3);
|
||||
assert.equal(svg.childElementCount, 3);
|
||||
assert.equal(drawing.getCurrentLayer(), layers[0]);
|
||||
assert.equal(layers[0].childElementCount, 1);
|
||||
assert.equal(layers[1].childElementCount, 1);
|
||||
assert.equal(layers[2].childElementCount, 1);
|
||||
|
||||
// check history record
|
||||
assert.equal(mockHrService.startBatchCommand.callCount, 0);
|
||||
assert.equal(mockHrService.endBatchCommand.callCount, 0);
|
||||
assert.equal(mockHrService.moveElement.callCount, 0);
|
||||
assert.equal(mockHrService.removeElement.callCount, 0);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test mergeAllLayers()', function (assert) {
|
||||
const mockHrService = {
|
||||
startBatchCommand: this.spy(),
|
||||
endBatchCommand: this.spy(),
|
||||
moveElement: this.spy(),
|
||||
removeElement: this.spy()
|
||||
};
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
const layers = setupSVGWith3Layers(svg);
|
||||
const elementCount = createSomeElementsInGroup(layers[0]) + 1; // +1 for title element
|
||||
createSomeElementsInGroup(layers[1]);
|
||||
createSomeElementsInGroup(layers[2]);
|
||||
assert.equal(layers[0].childElementCount, elementCount);
|
||||
assert.equal(layers[1].childElementCount, elementCount);
|
||||
assert.equal(layers[2].childElementCount, elementCount);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.mergeAllLayers);
|
||||
assert.equal(typeof drawing.mergeAllLayers, typeof function () { /* */ });
|
||||
|
||||
drawing.mergeAllLayers(mockHrService);
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 1);
|
||||
assert.equal(svg.childElementCount, 1);
|
||||
assert.equal(drawing.getCurrentLayer(), layers[0]);
|
||||
assert.equal(layers[0].childElementCount, elementCount * 3 - 2); // -2 because two titles were deleted.
|
||||
|
||||
// check history record
|
||||
assert.equal(mockHrService.startBatchCommand.callCount, 3); // mergeAllLayers + 2 * mergeLayer
|
||||
assert.equal(mockHrService.endBatchCommand.callCount, 3);
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge all Layers');
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(1).args[0], 'Merge Layer');
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(2).args[0], 'Merge Layer');
|
||||
// moveElement count is times 3 instead of 2, because one layer's elements were moved twice.
|
||||
// moveElement count is minus 3 because the three titles were not moved.
|
||||
assert.equal(mockHrService.moveElement.callCount, elementCount * 3 - 3);
|
||||
assert.equal(mockHrService.removeElement.callCount, 2 * 2); // remove group and title twice.
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test cloneLayer()', function (assert) {
|
||||
const mockHrService = {
|
||||
startBatchCommand: this.spy(),
|
||||
endBatchCommand: this.spy(),
|
||||
insertElement: this.spy()
|
||||
};
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
const layers = setupSVGWith3Layers(svg);
|
||||
const layer3 = layers[2];
|
||||
const elementCount = createSomeElementsInGroup(layer3) + 1; // +1 for title element
|
||||
assert.equal(layer3.childElementCount, elementCount);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.cloneLayer);
|
||||
assert.equal(typeof drawing.cloneLayer, typeof function () { /* */ });
|
||||
|
||||
const clone = drawing.cloneLayer('clone', mockHrService);
|
||||
|
||||
assert.equal(drawing.getNumLayers(), 4);
|
||||
assert.equal(svg.childElementCount, 4);
|
||||
assert.equal(drawing.getCurrentLayer(), clone);
|
||||
assert.equal(clone.childElementCount, elementCount);
|
||||
|
||||
// check history record
|
||||
assert.ok(mockHrService.startBatchCommand.calledOnce); // mergeAllLayers + 2 * mergeLayer
|
||||
assert.ok(mockHrService.endBatchCommand.calledOnce);
|
||||
assert.equal(mockHrService.startBatchCommand.getCall(0).args[0], 'Duplicate Layer');
|
||||
assert.equal(mockHrService.insertElement.callCount, 1);
|
||||
assert.equal(mockHrService.insertElement.getCall(0).args[0], clone);
|
||||
|
||||
// check that path is cloned properly
|
||||
assert.equal(clone.childNodes.length, elementCount);
|
||||
const path = clone.childNodes[1];
|
||||
assert.equal(path.id, 'svg_1');
|
||||
assert.equal(path.getAttribute('d'), PATH_ATTR.d);
|
||||
assert.equal(path.getAttribute('transform'), PATH_ATTR.transform);
|
||||
assert.equal(path.getAttribute('fill'), PATH_ATTR.fill);
|
||||
assert.equal(path.getAttribute('stroke'), PATH_ATTR.stroke);
|
||||
assert.equal(path.getAttribute('stroke-width'), PATH_ATTR['stroke-width']);
|
||||
|
||||
// check that g is cloned properly
|
||||
const g = clone.childNodes[4];
|
||||
assert.equal(g.childNodes.length, 1);
|
||||
assert.equal(g.id, 'svg_4');
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test getLayerVisibility()', function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.getLayerVisibility);
|
||||
assert.equal(typeof drawing.getLayerVisibility, typeof function () { /* */ });
|
||||
assert.ok(drawing.getLayerVisibility(LAYER1));
|
||||
assert.ok(drawing.getLayerVisibility(LAYER2));
|
||||
assert.ok(drawing.getLayerVisibility(LAYER3));
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test setLayerVisibility()', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.setLayerVisibility);
|
||||
assert.equal(typeof drawing.setLayerVisibility, typeof function () { /* */ });
|
||||
|
||||
drawing.setLayerVisibility(LAYER3, false);
|
||||
drawing.setLayerVisibility(LAYER2, true);
|
||||
drawing.setLayerVisibility(LAYER1, false);
|
||||
|
||||
assert.ok(!drawing.getLayerVisibility(LAYER1));
|
||||
assert.ok(drawing.getLayerVisibility(LAYER2));
|
||||
assert.ok(!drawing.getLayerVisibility(LAYER3));
|
||||
|
||||
drawing.setLayerVisibility(LAYER3, 'test-string');
|
||||
assert.ok(!drawing.getLayerVisibility(LAYER3));
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test getLayerOpacity()', function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.getLayerOpacity);
|
||||
assert.equal(typeof drawing.getLayerOpacity, typeof function () { /* */ });
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER1), 1.0);
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER2), 1.0);
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test setLayerOpacity()', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
assert.ok(drawing.setLayerOpacity);
|
||||
assert.equal(typeof drawing.setLayerOpacity, typeof function () { /* */ });
|
||||
|
||||
drawing.setLayerOpacity(LAYER1, 0.4);
|
||||
drawing.setLayerOpacity(LAYER2, 'invalid-string');
|
||||
drawing.setLayerOpacity(LAYER3, -1.4);
|
||||
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER1), 0.4);
|
||||
console.log('layer2 opacity ' + drawing.getLayerOpacity(LAYER2));
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER2), 1.0);
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0);
|
||||
|
||||
drawing.setLayerOpacity(LAYER3, 100);
|
||||
assert.strictEqual(drawing.getLayerOpacity(LAYER3), 1.0);
|
||||
|
||||
cleanupSVG(svg);
|
||||
});
|
||||
|
||||
QUnit.test('Test deleteCurrentLayer()', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const drawing = new draw.Drawing(svg);
|
||||
setupSVGWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
drawing.setCurrentLayer(LAYER2);
|
||||
|
||||
const curLayer = drawing.getCurrentLayer();
|
||||
assert.equal(curLayer, drawing.all_layers[1].getGroup());
|
||||
const deletedLayer = drawing.deleteCurrentLayer();
|
||||
|
||||
assert.equal(curLayer, deletedLayer);
|
||||
assert.equal(drawing.getNumLayers(), 2);
|
||||
assert.equal(LAYER1, drawing.all_layers[0].getName());
|
||||
assert.equal(LAYER3, drawing.all_layers[1].getName());
|
||||
assert.equal(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup());
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.draw.randomizeIds()', function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
// Confirm in LET_DOCUMENT_DECIDE mode that the document decides
|
||||
// if there is a nonce.
|
||||
let drawing = new draw.Drawing(svgN.cloneNode(true));
|
||||
assert.ok(drawing.getNonce());
|
||||
|
||||
drawing = new draw.Drawing(svg.cloneNode(true));
|
||||
assert.ok(!drawing.getNonce());
|
||||
|
||||
// Confirm that a nonce is set once we're in ALWAYS_RANDOMIZE mode.
|
||||
draw.randomizeIds(true, drawing);
|
||||
assert.ok(drawing.getNonce());
|
||||
|
||||
// Confirm new drawings in ALWAYS_RANDOMIZE mode have a nonce.
|
||||
drawing = new draw.Drawing(svg.cloneNode(true));
|
||||
assert.ok(drawing.getNonce());
|
||||
|
||||
drawing.clearNonce();
|
||||
assert.ok(!drawing.getNonce());
|
||||
|
||||
// Confirm new drawings in NEVER_RANDOMIZE mode do not have a nonce
|
||||
// but that their se:nonce attribute is left alone.
|
||||
draw.randomizeIds(false, drawing);
|
||||
assert.ok(!drawing.getNonce());
|
||||
assert.ok(drawing.getSvgElem().getAttributeNS(NS.SE, 'nonce'));
|
||||
|
||||
drawing = new draw.Drawing(svg.cloneNode(true));
|
||||
assert.ok(!drawing.getNonce());
|
||||
|
||||
drawing = new draw.Drawing(svgN.cloneNode(true));
|
||||
assert.ok(!drawing.getNonce());
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for history.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="history_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for history.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="divparent" style="visibility: hidden;">
|
||||
<div id="div1"></div>
|
||||
<div id="div2"></div>
|
||||
<div id="div3"></div>
|
||||
</div>
|
||||
<div id="div4" style="visibility: hidden;">
|
||||
<div id="div5"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,583 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as transformlist from '../editor/svgtransformlist.js';
|
||||
import * as utilities from '../editor/utilities.js';
|
||||
import * as hstory from '../editor/history.js';
|
||||
|
||||
// TODO(codedread): Write tests for handling history events.
|
||||
|
||||
// Mocked out methods.
|
||||
transformlist.changeRemoveElementFromListMap((elem) => { /* */ });
|
||||
|
||||
utilities.mock({
|
||||
getHref (elem) { return '#foo'; },
|
||||
setHref (elem, val) { /* */ },
|
||||
getRotationAngle (elem) { return 0; }
|
||||
});
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
// const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
let undoMgr = null;
|
||||
const divparent = document.getElementById('divparent');
|
||||
const div1 = document.getElementById('div1');
|
||||
const div2 = document.getElementById('div2');
|
||||
const div3 = document.getElementById('div3');
|
||||
const div4 = document.getElementById('div4');
|
||||
const div5 = document.getElementById('div5');
|
||||
|
||||
QUnit.module('svgedit.history');
|
||||
|
||||
class MockCommand {
|
||||
constructor (optText) { this.text_ = optText; }
|
||||
apply () { /* */ } // eslint-disable-line class-methods-use-this
|
||||
unapply () { /* */ } // eslint-disable-line class-methods-use-this
|
||||
getText () { return this.text_; }
|
||||
elements () { return []; } // eslint-disable-line class-methods-use-this
|
||||
}
|
||||
|
||||
/*
|
||||
class MockHistoryEventHandler {
|
||||
handleHistoryEvent (eventType, command) {}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set up tests (with undo manager).
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUp () {
|
||||
undoMgr = new hstory.UndoManager();
|
||||
}
|
||||
/**
|
||||
* Tear down tests, destroying undo manager.
|
||||
* @returns {void}
|
||||
*/
|
||||
function tearDown () {
|
||||
undoMgr = null;
|
||||
}
|
||||
|
||||
QUnit.test('Test svgedit.history package', function (assert) {
|
||||
assert.expect(13);
|
||||
|
||||
assert.ok(hstory);
|
||||
assert.ok(hstory.MoveElementCommand);
|
||||
assert.ok(hstory.InsertElementCommand);
|
||||
assert.ok(hstory.ChangeElementCommand);
|
||||
assert.ok(hstory.RemoveElementCommand);
|
||||
assert.ok(hstory.BatchCommand);
|
||||
assert.ok(hstory.UndoManager);
|
||||
assert.equal(typeof hstory.MoveElementCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.InsertElementCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.ChangeElementCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.RemoveElementCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.BatchCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof hstory.UndoManager, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
QUnit.test('Test UndoManager methods', function (assert) {
|
||||
assert.expect(14);
|
||||
setUp();
|
||||
|
||||
assert.ok(undoMgr);
|
||||
assert.ok(undoMgr.addCommandToHistory);
|
||||
assert.ok(undoMgr.getUndoStackSize);
|
||||
assert.ok(undoMgr.getRedoStackSize);
|
||||
assert.ok(undoMgr.resetUndoStack);
|
||||
assert.ok(undoMgr.getNextUndoCommandText);
|
||||
assert.ok(undoMgr.getNextRedoCommandText);
|
||||
|
||||
assert.equal(typeof undoMgr, typeof {});
|
||||
assert.equal(typeof undoMgr.addCommandToHistory, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.getUndoStackSize, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.getRedoStackSize, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.resetUndoStack, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.getNextUndoCommandText, typeof function () { /* */ });
|
||||
assert.equal(typeof undoMgr.getNextRedoCommandText, typeof function () { /* */ });
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test UndoManager.addCommandToHistory() function', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
setUp();
|
||||
|
||||
assert.equal(undoMgr.getUndoStackSize(), 0);
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
assert.equal(undoMgr.getUndoStackSize(), 1);
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
assert.equal(undoMgr.getUndoStackSize(), 2);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test UndoManager.getUndoStackSize() and getRedoStackSize() functions', function (assert) {
|
||||
assert.expect(18);
|
||||
|
||||
setUp();
|
||||
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
|
||||
assert.equal(undoMgr.getUndoStackSize(), 3);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 0);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 2);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 1);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 1);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 2);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 0);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 3);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 0);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 3);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 1);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 2);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 2);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 1);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 3);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 0);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getUndoStackSize(), 3);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 0);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test UndoManager.resetUndoStackSize() function', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
setUp();
|
||||
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.addCommandToHistory(new MockCommand());
|
||||
undoMgr.undo();
|
||||
|
||||
assert.equal(undoMgr.getUndoStackSize(), 2);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 1);
|
||||
|
||||
undoMgr.resetUndoStack();
|
||||
|
||||
assert.equal(undoMgr.getUndoStackSize(), 0);
|
||||
assert.equal(undoMgr.getRedoStackSize(), 0);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test UndoManager.getNextUndoCommandText() function', function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
setUp();
|
||||
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), '');
|
||||
|
||||
undoMgr.addCommandToHistory(new MockCommand('First'));
|
||||
undoMgr.addCommandToHistory(new MockCommand('Second'));
|
||||
undoMgr.addCommandToHistory(new MockCommand('Third'));
|
||||
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Third');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Second');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'First');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), '');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'First');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Second');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Third');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextUndoCommandText(), 'Third');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test UndoManager.getNextRedoCommandText() function', function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
setUp();
|
||||
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), '');
|
||||
|
||||
undoMgr.addCommandToHistory(new MockCommand('First'));
|
||||
undoMgr.addCommandToHistory(new MockCommand('Second'));
|
||||
undoMgr.addCommandToHistory(new MockCommand('Third'));
|
||||
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), '');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'Third');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'Second');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'First');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'Second');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), 'Third');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(undoMgr.getNextRedoCommandText(), '');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test UndoManager.undo() and redo() functions', function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
setUp();
|
||||
|
||||
let lastCalled = null;
|
||||
const cmd1 = new MockCommand();
|
||||
const cmd2 = new MockCommand();
|
||||
const cmd3 = new MockCommand();
|
||||
cmd1.apply = function () { lastCalled = 'cmd1.apply'; };
|
||||
cmd2.apply = function () { lastCalled = 'cmd2.apply'; };
|
||||
cmd3.apply = function () { lastCalled = 'cmd3.apply'; };
|
||||
cmd1.unapply = function () { lastCalled = 'cmd1.unapply'; };
|
||||
cmd2.unapply = function () { lastCalled = 'cmd2.unapply'; };
|
||||
cmd3.unapply = function () { lastCalled = 'cmd3.unapply'; };
|
||||
|
||||
undoMgr.addCommandToHistory(cmd1);
|
||||
undoMgr.addCommandToHistory(cmd2);
|
||||
undoMgr.addCommandToHistory(cmd3);
|
||||
|
||||
assert.ok(!lastCalled);
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(lastCalled, 'cmd3.unapply');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(lastCalled, 'cmd3.apply');
|
||||
|
||||
undoMgr.undo();
|
||||
undoMgr.undo();
|
||||
assert.equal(lastCalled, 'cmd2.unapply');
|
||||
|
||||
undoMgr.undo();
|
||||
assert.equal(lastCalled, 'cmd1.unapply');
|
||||
lastCalled = null;
|
||||
|
||||
undoMgr.undo();
|
||||
assert.ok(!lastCalled);
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(lastCalled, 'cmd1.apply');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(lastCalled, 'cmd2.apply');
|
||||
|
||||
undoMgr.redo();
|
||||
assert.equal(lastCalled, 'cmd3.apply');
|
||||
lastCalled = null;
|
||||
|
||||
undoMgr.redo();
|
||||
assert.ok(!lastCalled);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test MoveElementCommand', function (assert) {
|
||||
assert.expect(26);
|
||||
|
||||
setUp();
|
||||
|
||||
let move = new hstory.MoveElementCommand(div3, div1, divparent);
|
||||
assert.ok(move.unapply);
|
||||
assert.ok(move.apply);
|
||||
assert.equal(typeof move.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof move.apply, typeof function () { /* */ });
|
||||
|
||||
move.unapply();
|
||||
assert.equal(divparent.firstElementChild, div3);
|
||||
assert.equal(divparent.firstElementChild.nextElementSibling, div1);
|
||||
assert.equal(divparent.lastElementChild, div2);
|
||||
|
||||
move.apply();
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(divparent.firstElementChild.nextElementSibling, div2);
|
||||
assert.equal(divparent.lastElementChild, div3);
|
||||
|
||||
move = new hstory.MoveElementCommand(div1, null, divparent);
|
||||
|
||||
move.unapply();
|
||||
assert.equal(divparent.firstElementChild, div2);
|
||||
assert.equal(divparent.firstElementChild.nextElementSibling, div3);
|
||||
assert.equal(divparent.lastElementChild, div1);
|
||||
|
||||
move.apply();
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(divparent.firstElementChild.nextElementSibling, div2);
|
||||
assert.equal(divparent.lastElementChild, div3);
|
||||
|
||||
move = new hstory.MoveElementCommand(div2, div5, div4);
|
||||
|
||||
move.unapply();
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(divparent.firstElementChild.nextElementSibling, div3);
|
||||
assert.equal(divparent.lastElementChild, div3);
|
||||
assert.equal(div4.firstElementChild, div2);
|
||||
assert.equal(div4.firstElementChild.nextElementSibling, div5);
|
||||
|
||||
move.apply();
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(divparent.firstElementChild.nextElementSibling, div2);
|
||||
assert.equal(divparent.lastElementChild, div3);
|
||||
assert.equal(div4.firstElementChild, div5);
|
||||
assert.equal(div4.lastElementChild, div5);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test InsertElementCommand', function (assert) {
|
||||
assert.expect(20);
|
||||
|
||||
setUp();
|
||||
|
||||
let insert = new hstory.InsertElementCommand(div3);
|
||||
assert.ok(insert.unapply);
|
||||
assert.ok(insert.apply);
|
||||
assert.equal(typeof insert.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof insert.apply, typeof function () { /* */ });
|
||||
|
||||
insert.unapply();
|
||||
assert.equal(divparent.childElementCount, 2);
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(div1.nextElementSibling, div2);
|
||||
assert.equal(divparent.lastElementChild, div2);
|
||||
|
||||
insert.apply();
|
||||
assert.equal(divparent.childElementCount, 3);
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(div1.nextElementSibling, div2);
|
||||
assert.equal(div2.nextElementSibling, div3);
|
||||
|
||||
insert = new hstory.InsertElementCommand(div2);
|
||||
|
||||
insert.unapply();
|
||||
assert.equal(divparent.childElementCount, 2);
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(div1.nextElementSibling, div3);
|
||||
assert.equal(divparent.lastElementChild, div3);
|
||||
|
||||
insert.apply();
|
||||
assert.equal(divparent.childElementCount, 3);
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(div1.nextElementSibling, div2);
|
||||
assert.equal(div2.nextElementSibling, div3);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test RemoveElementCommand', function (assert) {
|
||||
assert.expect(22);
|
||||
|
||||
setUp();
|
||||
|
||||
const div6 = document.createElement('div');
|
||||
div6.id = 'div6';
|
||||
|
||||
let remove = new hstory.RemoveElementCommand(div6, null, divparent);
|
||||
assert.ok(remove.unapply);
|
||||
assert.ok(remove.apply);
|
||||
assert.equal(typeof remove.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof remove.apply, typeof function () { /* */ });
|
||||
|
||||
remove.unapply();
|
||||
assert.equal(divparent.childElementCount, 4);
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(div1.nextElementSibling, div2);
|
||||
assert.equal(div2.nextElementSibling, div3);
|
||||
assert.equal(div3.nextElementSibling, div6);
|
||||
|
||||
remove.apply();
|
||||
assert.equal(divparent.childElementCount, 3);
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(div1.nextElementSibling, div2);
|
||||
assert.equal(div2.nextElementSibling, div3);
|
||||
|
||||
remove = new hstory.RemoveElementCommand(div6, div2, divparent);
|
||||
|
||||
remove.unapply();
|
||||
assert.equal(divparent.childElementCount, 4);
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(div1.nextElementSibling, div6);
|
||||
assert.equal(div6.nextElementSibling, div2);
|
||||
assert.equal(div2.nextElementSibling, div3);
|
||||
|
||||
remove.apply();
|
||||
assert.equal(divparent.childElementCount, 3);
|
||||
assert.equal(divparent.firstElementChild, div1);
|
||||
assert.equal(div1.nextElementSibling, div2);
|
||||
assert.equal(div2.nextElementSibling, div3);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test ChangeElementCommand', function (assert) {
|
||||
assert.expect(26);
|
||||
|
||||
setUp();
|
||||
|
||||
div1.setAttribute('title', 'new title');
|
||||
let change = new hstory.ChangeElementCommand(div1,
|
||||
{title: 'old title', class: 'foo'});
|
||||
assert.ok(change.unapply);
|
||||
assert.ok(change.apply);
|
||||
assert.equal(typeof change.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof change.apply, typeof function () { /* */ });
|
||||
|
||||
change.unapply();
|
||||
assert.equal(div1.getAttribute('title'), 'old title');
|
||||
assert.equal(div1.getAttribute('class'), 'foo');
|
||||
|
||||
change.apply();
|
||||
assert.equal(div1.getAttribute('title'), 'new title');
|
||||
assert.ok(!div1.getAttribute('class'));
|
||||
|
||||
div1.textContent = 'inner text';
|
||||
change = new hstory.ChangeElementCommand(div1,
|
||||
{'#text': null});
|
||||
|
||||
change.unapply();
|
||||
assert.ok(!div1.textContent);
|
||||
|
||||
change.apply();
|
||||
assert.equal(div1.textContent, 'inner text');
|
||||
|
||||
div1.textContent = '';
|
||||
change = new hstory.ChangeElementCommand(div1,
|
||||
{'#text': 'old text'});
|
||||
|
||||
change.unapply();
|
||||
assert.equal(div1.textContent, 'old text');
|
||||
|
||||
change.apply();
|
||||
assert.ok(!div1.textContent);
|
||||
|
||||
// TODO(codedread): Refactor this #href stuff in history.js and svgcanvas.js
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
let justCalled = null;
|
||||
let gethrefvalue = null;
|
||||
let sethrefvalue = null;
|
||||
utilities.mock({
|
||||
getHref (elem) {
|
||||
assert.equal(elem, rect);
|
||||
justCalled = 'getHref';
|
||||
return gethrefvalue;
|
||||
},
|
||||
setHref (elem, val) {
|
||||
assert.equal(elem, rect);
|
||||
assert.equal(val, sethrefvalue);
|
||||
justCalled = 'setHref';
|
||||
},
|
||||
getRotationAngle (elem) { return 0; }
|
||||
});
|
||||
|
||||
gethrefvalue = '#newhref';
|
||||
change = new hstory.ChangeElementCommand(rect,
|
||||
{'#href': '#oldhref'});
|
||||
assert.equal(justCalled, 'getHref');
|
||||
|
||||
justCalled = null;
|
||||
sethrefvalue = '#oldhref';
|
||||
change.unapply();
|
||||
assert.equal(justCalled, 'setHref');
|
||||
|
||||
justCalled = null;
|
||||
sethrefvalue = '#newhref';
|
||||
change.apply();
|
||||
assert.equal(justCalled, 'setHref');
|
||||
|
||||
const line = document.createElementNS(NS.SVG, 'line');
|
||||
line.setAttribute('class', 'newClass');
|
||||
change = new hstory.ChangeElementCommand(line, {class: 'oldClass'});
|
||||
|
||||
assert.ok(change.unapply);
|
||||
assert.ok(change.apply);
|
||||
assert.equal(typeof change.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof change.apply, typeof function () { /* */ });
|
||||
|
||||
change.unapply();
|
||||
assert.equal(line.getAttribute('class'), 'oldClass');
|
||||
|
||||
change.apply();
|
||||
assert.equal(line.getAttribute('class'), 'newClass');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test BatchCommand', function (assert) {
|
||||
assert.expect(13);
|
||||
|
||||
setUp();
|
||||
|
||||
let concatResult = '';
|
||||
MockCommand.prototype.apply = function () { concatResult += this.text_; };
|
||||
|
||||
const batch = new hstory.BatchCommand();
|
||||
assert.ok(batch.unapply);
|
||||
assert.ok(batch.apply);
|
||||
assert.ok(batch.addSubCommand);
|
||||
assert.ok(batch.isEmpty);
|
||||
assert.equal(typeof batch.unapply, typeof function () { /* */ });
|
||||
assert.equal(typeof batch.apply, typeof function () { /* */ });
|
||||
assert.equal(typeof batch.addSubCommand, typeof function () { /* */ });
|
||||
assert.equal(typeof batch.isEmpty, typeof function () { /* */ });
|
||||
|
||||
assert.ok(batch.isEmpty());
|
||||
|
||||
batch.addSubCommand(new MockCommand('a'));
|
||||
assert.ok(!batch.isEmpty());
|
||||
batch.addSubCommand(new MockCommand('b'));
|
||||
batch.addSubCommand(new MockCommand('c'));
|
||||
|
||||
assert.ok(!concatResult);
|
||||
batch.apply();
|
||||
assert.equal(concatResult, 'abc');
|
||||
|
||||
MockCommand.prototype.apply = function () { /* */ };
|
||||
MockCommand.prototype.unapply = function () { concatResult += this.text_; };
|
||||
concatResult = '';
|
||||
batch.unapply();
|
||||
assert.equal(concatResult, 'cba');
|
||||
|
||||
MockCommand.prototype.unapply = function () { /* */ };
|
||||
|
||||
tearDown();
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for jQuery.attr.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="jQuery.attr_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for jQuery.attr</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="root" style=""></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,12 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
|
||||
/* eslint-disable import/unambiguous */
|
||||
|
||||
// Todo: Incomplete!
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for math.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="math_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for math.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,121 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as math from '../editor/math.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
QUnit.module('svgedit.math');
|
||||
|
||||
QUnit.test('Test svgedit.math package', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
assert.ok(math);
|
||||
assert.ok(math.transformPoint);
|
||||
assert.ok(math.isIdentity);
|
||||
assert.ok(math.matrixMultiply);
|
||||
assert.equal(typeof math.transformPoint, typeof function () { /* */ });
|
||||
assert.equal(typeof math.isIdentity, typeof function () { /* */ });
|
||||
assert.equal(typeof math.matrixMultiply, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.math.transformPoint() function', function (assert) {
|
||||
assert.expect(6);
|
||||
const {transformPoint} = math;
|
||||
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 0; m.f = 0;
|
||||
let pt = transformPoint(100, 200, m);
|
||||
assert.equal(pt.x, 100);
|
||||
assert.equal(pt.y, 200);
|
||||
|
||||
m.e = 300; m.f = 400;
|
||||
pt = transformPoint(100, 200, m);
|
||||
assert.equal(pt.x, 400);
|
||||
assert.equal(pt.y, 600);
|
||||
|
||||
m.a = 0.5; m.b = 0.75;
|
||||
m.c = 1.25; m.d = 2;
|
||||
pt = transformPoint(100, 200, m);
|
||||
assert.equal(pt.x, 100 * m.a + 200 * m.c + m.e);
|
||||
assert.equal(pt.y, 100 * m.b + 200 * m.d + m.f);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.math.isIdentity() function', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
assert.ok(math.isIdentity(svg.createSVGMatrix()));
|
||||
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 0; m.f = 0;
|
||||
assert.ok(math.isIdentity(m));
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.math.matrixMultiply() function', function (assert) {
|
||||
assert.expect(5);
|
||||
const mult = math.matrixMultiply;
|
||||
const {isIdentity} = math;
|
||||
|
||||
// translate there and back
|
||||
const tr1 = svg.createSVGMatrix().translate(100, 50),
|
||||
tr2 = svg.createSVGMatrix().translate(-90, 0),
|
||||
tr3 = svg.createSVGMatrix().translate(-10, -50);
|
||||
let I = mult(tr1, tr2, tr3);
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when translating there and back');
|
||||
|
||||
// rotate there and back
|
||||
// TODO: currently Mozilla fails this when rotating back at -50 and then -40 degrees
|
||||
// (b and c are *almost* zero, but not zero)
|
||||
const rotThere = svg.createSVGMatrix().rotate(90),
|
||||
rotBack = svg.createSVGMatrix().rotate(-90), // TODO: set this to -50
|
||||
rotBackMore = svg.createSVGMatrix().rotate(0); // TODO: set this to -40
|
||||
I = mult(rotThere, rotBack, rotBackMore);
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when rotating there and back');
|
||||
|
||||
// scale up and down
|
||||
const scaleUp = svg.createSVGMatrix().scale(4),
|
||||
scaleDown = svg.createSVGMatrix().scaleNonUniform(0.25, 1),
|
||||
scaleDownMore = svg.createSVGMatrix().scaleNonUniform(1, 0.25);
|
||||
I = mult(scaleUp, scaleDown, scaleDownMore);
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when scaling up and down');
|
||||
|
||||
// test multiplication with its inverse
|
||||
I = mult(rotThere, rotThere.inverse());
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse');
|
||||
I = mult(rotThere.inverse(), rotThere);
|
||||
assert.ok(isIdentity(I), 'Expected identity matrix when multiplying a matrix by its inverse');
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.math.transformBox() function', function (assert) {
|
||||
assert.expect(12);
|
||||
const {transformBox} = math;
|
||||
|
||||
const m = svg.createSVGMatrix();
|
||||
m.a = 1; m.b = 0;
|
||||
m.c = 0; m.d = 1;
|
||||
m.e = 0; m.f = 0;
|
||||
|
||||
const r = transformBox(10, 10, 200, 300, m);
|
||||
assert.equal(r.tl.x, 10);
|
||||
assert.equal(r.tl.y, 10);
|
||||
assert.equal(r.tr.x, 210);
|
||||
assert.equal(r.tr.y, 10);
|
||||
assert.equal(r.bl.x, 10);
|
||||
assert.equal(r.bl.y, 310);
|
||||
assert.equal(r.br.x, 210);
|
||||
assert.equal(r.br.y, 310);
|
||||
assert.equal(r.aabox.x, 10);
|
||||
assert.equal(r.aabox.y, 10);
|
||||
assert.equal(r.aabox.width, 200);
|
||||
assert.equal(r.aabox.height, 300);
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for path.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="path_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for path.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="anchor" style="visibility: hidden;"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,181 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
/* globals SVGPathSeg */
|
||||
import '../editor/svgpathseg.js';
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as utilities from '../editor/utilities.js';
|
||||
import * as pathModule from '../editor/path.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @typedef {GenericArray} EditorContexts
|
||||
* @property {module:path.EditorContext} 0
|
||||
* @property {module:path.EditorContext} 1
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {SVGSVGElement} [svg]
|
||||
* @returns {EditorContexts}
|
||||
*/
|
||||
function getMockContexts (svg) {
|
||||
svg = svg || document.createElementNS(NS.SVG, 'svg');
|
||||
const selectorParentGroup = document.createElementNS(NS.SVG, 'g');
|
||||
selectorParentGroup.setAttribute('id', 'selectorParentGroup');
|
||||
svg.append(selectorParentGroup);
|
||||
return [
|
||||
/**
|
||||
* @implements {module:path.EditorContext}
|
||||
*/
|
||||
{
|
||||
getSVGRoot () { return svg; },
|
||||
getCurrentZoom () { return 1; }
|
||||
},
|
||||
/**
|
||||
* @implements {module:utilities.EditorContext}
|
||||
*/
|
||||
{
|
||||
getDOMDocument () { return svg; },
|
||||
getDOMContainer () { return svg; },
|
||||
getSVGRoot () { return svg; }
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
QUnit.test('Test svgedit.path.replacePathSeg', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 L10,11 L20,21Z');
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts();
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
new pathModule.Path(path); // eslint-disable-line no-new
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 10);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 11);
|
||||
|
||||
pathModule.replacePathSeg(SVGPathSeg.PATHSEG_LINETO_REL, 1, [30, 31], path);
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'l');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 30);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 31);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.path.Segment.setType simple', function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 L10,11 L20,21Z');
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts();
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
new pathModule.Path(path); // eslint-disable-line no-new
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 10);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 11);
|
||||
|
||||
const segment = new pathModule.Segment(1, path.pathSegList.getItem(1));
|
||||
segment.setType(SVGPathSeg.PATHSEG_LINETO_REL, [30, 31]);
|
||||
assert.equal(segment.item.pathSegTypeAsLetter, 'l');
|
||||
assert.equal(segment.item.x, 30);
|
||||
assert.equal(segment.item.y, 31);
|
||||
|
||||
// Also verify that the actual path changed.
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'l');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 30);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 31);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.path.Segment.setType with control points', function (assert) {
|
||||
assert.expect(14);
|
||||
|
||||
// Setup the dom for a mock control group.
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C11,12 13,14 15,16 Z');
|
||||
svg.append(path);
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts(svg);
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
const segment = new pathModule.Segment(1, path.pathSegList.getItem(1));
|
||||
segment.path = new pathModule.Path(path);
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C');
|
||||
assert.equal(path.pathSegList.getItem(1).x1, 11);
|
||||
assert.equal(path.pathSegList.getItem(1).y1, 12);
|
||||
assert.equal(path.pathSegList.getItem(1).x2, 13);
|
||||
assert.equal(path.pathSegList.getItem(1).y2, 14);
|
||||
assert.equal(path.pathSegList.getItem(1).x, 15);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 16);
|
||||
|
||||
segment.setType(SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, [30, 31, 32, 33, 34, 35]);
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'c');
|
||||
assert.equal(path.pathSegList.getItem(1).x1, 32);
|
||||
assert.equal(path.pathSegList.getItem(1).y1, 33);
|
||||
assert.equal(path.pathSegList.getItem(1).x2, 34);
|
||||
assert.equal(path.pathSegList.getItem(1).y2, 35);
|
||||
assert.equal(path.pathSegList.getItem(1).x, 30);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 31);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.path.Segment.move', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 L10,11 L20,21Z');
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts();
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
new pathModule.Path(path); // eslint-disable-line no-new
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 10);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 11);
|
||||
|
||||
const segment = new pathModule.Segment(1, path.pathSegList.getItem(1));
|
||||
segment.move(-3, 4);
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'L');
|
||||
assert.equal(path.pathSegList.getItem(1).x, 7);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 15);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.path.Segment.moveCtrl', function (assert) {
|
||||
assert.expect(14);
|
||||
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C11,12 13,14 15,16 Z');
|
||||
|
||||
const [mockPathContext, mockUtilitiesContext] = getMockContexts();
|
||||
pathModule.init(mockPathContext);
|
||||
utilities.init(mockUtilitiesContext);
|
||||
new pathModule.Path(path); // eslint-disable-line no-new
|
||||
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C');
|
||||
assert.equal(path.pathSegList.getItem(1).x1, 11);
|
||||
assert.equal(path.pathSegList.getItem(1).y1, 12);
|
||||
assert.equal(path.pathSegList.getItem(1).x2, 13);
|
||||
assert.equal(path.pathSegList.getItem(1).y2, 14);
|
||||
assert.equal(path.pathSegList.getItem(1).x, 15);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 16);
|
||||
|
||||
const segment = new pathModule.Segment(1, path.pathSegList.getItem(1));
|
||||
segment.moveCtrl(1, 100, -200);
|
||||
assert.equal(path.pathSegList.getItem(1).pathSegTypeAsLetter, 'C');
|
||||
assert.equal(path.pathSegList.getItem(1).x1, 111);
|
||||
assert.equal(path.pathSegList.getItem(1).y1, -188);
|
||||
assert.equal(path.pathSegList.getItem(1).x2, 13);
|
||||
assert.equal(path.pathSegList.getItem(1).y2, 14);
|
||||
assert.equal(path.pathSegList.getItem(1).x, 15);
|
||||
assert.equal(path.pathSegList.getItem(1).y, 16);
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
const NEAR_ZERO = 5e-6; // 0.000005, Firefox fails at higher levels of precision.
|
||||
|
||||
/**
|
||||
* Checks that the supplied values are equal with a high though not absolute degree of precision.
|
||||
* @param {Float} actual
|
||||
* @param {Float} expected
|
||||
* @param {string} message
|
||||
* @returns {void}
|
||||
*/
|
||||
function almostEquals (actual, expected, message) {
|
||||
message = message || (actual + ' did not equal ' + expected);
|
||||
this.pushResult({
|
||||
result: Math.abs(actual - expected) < NEAR_ZERO,
|
||||
actual,
|
||||
expected,
|
||||
message
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {external:qunit} QUnit
|
||||
* @returns {external:qunit} The same instance passed in after extending
|
||||
*/
|
||||
export default function extend (QUnit) {
|
||||
QUnit.extend(QUnit.assert, {
|
||||
almostEquals
|
||||
});
|
||||
return QUnit;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for recalculate.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="recalculate_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for recalculate</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="root" style="visibility: hidden;"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,165 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as utilities from '../editor/utilities.js';
|
||||
import * as coords from '../editor/coords.js';
|
||||
import * as recalculate from '../editor/recalculate.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
const root = document.getElementById('root');
|
||||
const svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot.id = 'svgroot';
|
||||
root.append(svgroot);
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
svgroot.append(svg);
|
||||
|
||||
let elemId = 1;
|
||||
|
||||
/**
|
||||
* Initilize modules to set up the tests.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUp () {
|
||||
utilities.init(
|
||||
/**
|
||||
* @implements {module:utilities.EditorContext}
|
||||
*/
|
||||
{
|
||||
getSVGRoot () { return svg; },
|
||||
getDOMDocument () { return null; },
|
||||
getDOMContainer () { return null; }
|
||||
}
|
||||
);
|
||||
coords.init(
|
||||
/**
|
||||
* @implements {module:coords.EditorContext}
|
||||
*/
|
||||
{
|
||||
getGridSnapping () { return false; },
|
||||
getDrawing () {
|
||||
return {
|
||||
getNextId () { return String(elemId++); }
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
recalculate.init(
|
||||
/**
|
||||
* @implements {module:recalculate.EditorContext}
|
||||
*/
|
||||
{
|
||||
getSVGRoot () { return svg; },
|
||||
getStartTransform () { return ''; },
|
||||
setStartTransform () { /* */ }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let elem;
|
||||
|
||||
/**
|
||||
* Initialize for tests and set up `rect` element.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUpRect () {
|
||||
setUp();
|
||||
elem = document.createElementNS(NS.SVG, 'rect');
|
||||
elem.setAttribute('x', '200');
|
||||
elem.setAttribute('y', '150');
|
||||
elem.setAttribute('width', '250');
|
||||
elem.setAttribute('height', '120');
|
||||
svg.append(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize for tests and set up `text` element with `tspan` child.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUpTextWithTspan () {
|
||||
setUp();
|
||||
elem = document.createElementNS(NS.SVG, 'text');
|
||||
elem.setAttribute('x', '200');
|
||||
elem.setAttribute('y', '150');
|
||||
|
||||
const tspan = document.createElementNS(NS.SVG, 'tspan');
|
||||
tspan.setAttribute('x', '200');
|
||||
tspan.setAttribute('y', '150');
|
||||
|
||||
const theText = document.createTextNode('Foo bar');
|
||||
tspan.append(theText);
|
||||
elem.append(tspan);
|
||||
svg.append(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down the tests (empty the svg element).
|
||||
* @returns {void}
|
||||
*/
|
||||
function tearDown () {
|
||||
while (svg.hasChildNodes()) {
|
||||
svg.firstChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
QUnit.test('Test recalculateDimensions() on rect with identity matrix', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
setUpRect();
|
||||
elem.setAttribute('transform', 'matrix(1,0,0,1,0,0)');
|
||||
|
||||
recalculate.recalculateDimensions(elem);
|
||||
|
||||
// Ensure that the identity matrix is swallowed and the element has no
|
||||
// transform on it.
|
||||
assert.equal(elem.hasAttribute('transform'), false);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test recalculateDimensions() on rect with simple translate', function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
setUpRect();
|
||||
elem.setAttribute('transform', 'translate(100,50)');
|
||||
|
||||
recalculate.recalculateDimensions(elem);
|
||||
|
||||
assert.equal(elem.hasAttribute('transform'), false);
|
||||
assert.equal(elem.getAttribute('x'), '300');
|
||||
assert.equal(elem.getAttribute('y'), '200');
|
||||
assert.equal(elem.getAttribute('width'), '250');
|
||||
assert.equal(elem.getAttribute('height'), '120');
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test recalculateDimensions() on text w/tspan with simple translate', function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
setUpTextWithTspan();
|
||||
elem.setAttribute('transform', 'translate(100,50)');
|
||||
|
||||
recalculate.recalculateDimensions(elem);
|
||||
|
||||
// Ensure that the identity matrix is swallowed and the element has no
|
||||
// transform on it.
|
||||
assert.equal(elem.hasAttribute('transform'), false);
|
||||
assert.equal(elem.getAttribute('x'), '300');
|
||||
assert.equal(elem.getAttribute('y'), '200');
|
||||
|
||||
const tspan = elem.firstElementChild;
|
||||
assert.equal(tspan.getAttribute('x'), '300');
|
||||
assert.equal(tspan.getAttribute('y'), '200');
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
// TODO: Since recalculateDimensions() and surrounding code is
|
||||
// probably the largest, most complicated and strange piece of
|
||||
// code in SVG-edit, we need to write a whole lot of unit tests
|
||||
// for it here.
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for sanitize.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="sanitize_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for sanitize.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="anchor" style="visibility: hidden;"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,25 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as sanitize from '../editor/sanitize.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
QUnit.test('Test sanitizeSvg() strips ws from style attr', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('style', 'stroke: blue ;\t\tstroke-width :\t\t40;');
|
||||
// sanitizeSvg() requires the node to have a parent and a document.
|
||||
svg.append(rect);
|
||||
sanitize.sanitizeSvg(rect);
|
||||
|
||||
assert.equal(rect.getAttribute('stroke'), 'blue');
|
||||
assert.equal(rect.getAttribute('stroke-width'), '40');
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for select.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="select_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for select.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="sandbox"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,143 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import * as select from '../editor/select.js';
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.module('svgedit.select');
|
||||
|
||||
const sandbox = document.getElementById('sandbox');
|
||||
let svgroot;
|
||||
let svgcontent;
|
||||
const mockConfig = {
|
||||
dimensions: [640, 480]
|
||||
};
|
||||
|
||||
/**
|
||||
* @implements {module:select.SVGFactory}
|
||||
*/
|
||||
const mockFactory = {
|
||||
createSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
},
|
||||
svgRoot () { return svgroot; },
|
||||
svgContent () { return svgcontent; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Potentially reusable test set-up.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUp () {
|
||||
svgroot = mockFactory.createSVGElement({
|
||||
element: 'svg',
|
||||
attr: {id: 'svgroot'}
|
||||
});
|
||||
svgcontent = svgroot.appendChild(
|
||||
mockFactory.createSVGElement({
|
||||
element: 'svg',
|
||||
attr: {id: 'svgcontent'}
|
||||
})
|
||||
);
|
||||
/* const rect = */ svgcontent.appendChild(
|
||||
mockFactory.createSVGElement({
|
||||
element: 'rect',
|
||||
attr: {
|
||||
id: 'rect',
|
||||
x: '50',
|
||||
y: '75',
|
||||
width: '200',
|
||||
height: '100'
|
||||
}
|
||||
})
|
||||
);
|
||||
sandbox.append(svgroot);
|
||||
}
|
||||
|
||||
/*
|
||||
function setUpWithInit () {
|
||||
setUp();
|
||||
select.init(mockConfig, mockFactory);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tear down the test by emptying our sandbox area.
|
||||
* @returns {void}
|
||||
*/
|
||||
function tearDown () {
|
||||
while (sandbox.hasChildNodes()) {
|
||||
sandbox.firstChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
QUnit.test('Test svgedit.select package', function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
assert.ok(select);
|
||||
assert.ok(select.Selector);
|
||||
assert.ok(select.SelectorManager);
|
||||
assert.ok(select.init);
|
||||
assert.ok(select.getSelectorManager);
|
||||
assert.equal(typeof select, typeof {});
|
||||
assert.equal(typeof select.Selector, typeof function () { /* */ });
|
||||
assert.equal(typeof select.SelectorManager, typeof function () { /* */ });
|
||||
assert.equal(typeof select.init, typeof function () { /* */ });
|
||||
assert.equal(typeof select.getSelectorManager, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
QUnit.test('Test Selector DOM structure', function (assert) {
|
||||
assert.expect(24);
|
||||
|
||||
setUp();
|
||||
|
||||
assert.ok(svgroot);
|
||||
assert.ok(svgroot.hasChildNodes());
|
||||
|
||||
// Verify non-existence of Selector DOM nodes
|
||||
assert.equal(svgroot.childNodes.length, 1);
|
||||
assert.equal(svgroot.childNodes.item(0), svgcontent);
|
||||
assert.ok(!svgroot.querySelector('#selectorParentGroup'));
|
||||
|
||||
select.init(mockConfig, mockFactory);
|
||||
|
||||
assert.equal(svgroot.childNodes.length, 3);
|
||||
|
||||
// Verify existence of canvas background.
|
||||
const cb = svgroot.childNodes.item(0);
|
||||
assert.ok(cb);
|
||||
assert.equal(cb.id, 'canvasBackground');
|
||||
|
||||
assert.ok(svgroot.childNodes.item(1));
|
||||
assert.equal(svgroot.childNodes.item(1), svgcontent);
|
||||
|
||||
// Verify existence of selectorParentGroup.
|
||||
const spg = svgroot.childNodes.item(2);
|
||||
assert.ok(spg);
|
||||
assert.equal(svgroot.querySelector('#selectorParentGroup'), spg);
|
||||
assert.equal(spg.id, 'selectorParentGroup');
|
||||
assert.equal(spg.tagName, 'g');
|
||||
|
||||
// Verify existence of all grip elements.
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_nw'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_n'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_ne'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_e'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_se'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_s'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_sw'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_resize_w'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_rotateconnector'));
|
||||
assert.ok(spg.querySelector('#selectorGrip_rotate'));
|
||||
|
||||
tearDown();
|
||||
});
|
||||
@@ -1,30 +0,0 @@
|
||||
// Adapted from https://www.npmjs.com/package/sinon-test
|
||||
|
||||
/**
|
||||
* @external QUnit
|
||||
*/
|
||||
/**
|
||||
* @external sinon
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds methods to Sinon using a QUnit implementation.
|
||||
* @param {PlainObject} implementations
|
||||
* @param {external:sinon} implementations.sinon
|
||||
* @param {external:QUnit} implementations.QUnit
|
||||
* @returns {void}
|
||||
*/
|
||||
export default function sinonQunit ({sinon, QUnit}) {
|
||||
sinon.assert.fail = function (msg) {
|
||||
QUnit.ok(false, msg);
|
||||
};
|
||||
|
||||
sinon.assert.pass = function (assertion) {
|
||||
QUnit.ok(true, assertion);
|
||||
};
|
||||
|
||||
const qTest = QUnit.test;
|
||||
QUnit.test = function (testName, callback) { // eslint-disable-line promise/prefer-await-to-callbacks
|
||||
return qTest(testName, sinon.test(callback));
|
||||
};
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for svgtransformlist.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="svgtransformlist_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for svgtransformlist.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="svgroot" style="visibility: hidden;"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,389 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as transformlist from '../editor/svgtransformlist.js';
|
||||
import {disableSupportsNativeTransformLists} from '../editor/browser.js';
|
||||
import almostEqualsPlugin from './qunit/qunit-assert-almostEquals.js';
|
||||
import expectOutOfBoundsExceptionPlugin from './qunit/qunit-assert-expectOutOfBoundsException.js';
|
||||
|
||||
almostEqualsPlugin(QUnit);
|
||||
expectOutOfBoundsExceptionPlugin(QUnit);
|
||||
|
||||
disableSupportsNativeTransformLists();
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
const svgroot = document.querySelector('#svgroot');
|
||||
let svgcontent, rect, circle;
|
||||
|
||||
/**
|
||||
* Set up tests, adding elements.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUp () {
|
||||
svgcontent = svgroot.appendChild(document.createElementNS(NS.SVG, 'svg'));
|
||||
rect = svgcontent.appendChild(document.createElementNS(NS.SVG, 'rect'));
|
||||
rect.id = 'r';
|
||||
circle = svgcontent.appendChild(document.createElementNS(NS.SVG, 'circle'));
|
||||
circle.id = 'c';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down tests, emptying SVG root, and resetting list map.
|
||||
* @returns {void}
|
||||
*/
|
||||
function tearDown () {
|
||||
transformlist.resetListMap();
|
||||
while (svgroot.hasChildNodes()) {
|
||||
svgroot.firstChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
QUnit.module('svgedit.svgtransformlist');
|
||||
|
||||
QUnit.test('Test svgedit.transformlist package', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
assert.ok(transformlist);
|
||||
assert.ok(transformlist.getTransformList);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.transformlist.getTransformList() function', function (assert) {
|
||||
assert.expect(4);
|
||||
setUp();
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
assert.ok(rxform);
|
||||
assert.ok(cxform);
|
||||
assert.equal(typeof rxform, typeof {});
|
||||
assert.equal(typeof cxform, typeof {});
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.numberOfItems property', function (assert) {
|
||||
assert.expect(2);
|
||||
setUp();
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
|
||||
assert.equal(typeof rxform.numberOfItems, typeof 0);
|
||||
assert.equal(rxform.numberOfItems, 0);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.initialize()', function (assert) {
|
||||
assert.expect(6);
|
||||
setUp();
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
const t = svgcontent.createSVGTransform();
|
||||
assert.ok(t);
|
||||
assert.ok(rxform.initialize);
|
||||
assert.equal(typeof rxform.initialize, typeof function () { /* */ });
|
||||
rxform.initialize(t);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
assert.equal(cxform.numberOfItems, 0);
|
||||
|
||||
// If a transform was already in a transform list, this should
|
||||
// remove it from its old list and add it to this list.
|
||||
cxform.initialize(t);
|
||||
// This also fails in Firefox native.
|
||||
// assert.equal(rxform.numberOfItems, 0, 'Did not remove transform from list before initializing another transformlist');
|
||||
assert.equal(cxform.numberOfItems, 1);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.appendItem() and getItem()', function (assert) {
|
||||
assert.expect(12);
|
||||
setUp();
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
const t1 = svgcontent.createSVGTransform(),
|
||||
t2 = svgcontent.createSVGTransform(),
|
||||
t3 = svgcontent.createSVGTransform();
|
||||
|
||||
assert.ok(rxform.appendItem);
|
||||
assert.ok(rxform.getItem);
|
||||
assert.equal(typeof rxform.appendItem, typeof function () { /* */ });
|
||||
assert.equal(typeof rxform.getItem, typeof function () { /* */ });
|
||||
|
||||
rxform.appendItem(t1);
|
||||
rxform.appendItem(t2);
|
||||
rxform.appendItem(t3);
|
||||
|
||||
assert.equal(rxform.numberOfItems, 3);
|
||||
const rxf = rxform.getItem(0);
|
||||
assert.equal(rxf, t1);
|
||||
assert.equal(rxform.getItem(1), t2);
|
||||
assert.equal(rxform.getItem(2), t3);
|
||||
|
||||
assert.expectOutOfBoundsException(rxform, 'getItem', -1);
|
||||
assert.expectOutOfBoundsException(rxform, 'getItem', 3);
|
||||
cxform.appendItem(t1);
|
||||
// These also fail in Firefox native.
|
||||
// assert.equal(rxform.numberOfItems, 2, 'Did not remove a transform from a list before appending it to a new transformlist');
|
||||
// assert.equal(rxform.getItem(0), t2, 'Found the wrong transform in a transformlist');
|
||||
// assert.equal(rxform.getItem(1), t3, 'Found the wrong transform in a transformlist');
|
||||
|
||||
assert.equal(cxform.numberOfItems, 1);
|
||||
assert.equal(cxform.getItem(0), t1);
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.removeItem()', function (assert) {
|
||||
assert.expect(7);
|
||||
setUp();
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
|
||||
const t1 = svgcontent.createSVGTransform(),
|
||||
t2 = svgcontent.createSVGTransform();
|
||||
assert.ok(rxform.removeItem);
|
||||
assert.equal(typeof rxform.removeItem, typeof function () { /* */ });
|
||||
rxform.appendItem(t1);
|
||||
rxform.appendItem(t2);
|
||||
|
||||
const removedTransform = rxform.removeItem(0);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
assert.equal(removedTransform, t1);
|
||||
assert.equal(rxform.getItem(0), t2);
|
||||
|
||||
assert.expectOutOfBoundsException(rxform, 'removeItem', -1);
|
||||
assert.expectOutOfBoundsException(rxform, 'removeItem', 1);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.replaceItem()', function (assert) {
|
||||
assert.expect(8);
|
||||
setUp();
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
assert.ok(rxform.replaceItem);
|
||||
assert.equal(typeof rxform.replaceItem, typeof function () { /* */ });
|
||||
|
||||
const t1 = svgcontent.createSVGTransform(),
|
||||
t2 = svgcontent.createSVGTransform(),
|
||||
t3 = svgcontent.createSVGTransform();
|
||||
|
||||
rxform.appendItem(t1);
|
||||
rxform.appendItem(t2);
|
||||
cxform.appendItem(t3);
|
||||
|
||||
const newItem = rxform.replaceItem(t3, 0);
|
||||
assert.equal(rxform.numberOfItems, 2);
|
||||
assert.equal(newItem, t3);
|
||||
assert.equal(rxform.getItem(0), t3);
|
||||
assert.equal(rxform.getItem(1), t2);
|
||||
// Fails in Firefox native
|
||||
// assert.equal(cxform.numberOfItems, 0);
|
||||
|
||||
// test replaceItem within a list
|
||||
rxform.appendItem(t1);
|
||||
rxform.replaceItem(t1, 0);
|
||||
// Fails in Firefox native
|
||||
// assert.equal(rxform.numberOfItems, 2);
|
||||
assert.equal(rxform.getItem(0), t1);
|
||||
assert.equal(rxform.getItem(1), t2);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.insertItemBefore()', function (assert) {
|
||||
assert.expect(10);
|
||||
setUp();
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
const cxform = transformlist.getTransformList(circle);
|
||||
|
||||
assert.ok(rxform.insertItemBefore);
|
||||
assert.equal(typeof rxform.insertItemBefore, typeof function () { /* */ });
|
||||
|
||||
const t1 = svgcontent.createSVGTransform(),
|
||||
t2 = svgcontent.createSVGTransform(),
|
||||
t3 = svgcontent.createSVGTransform();
|
||||
|
||||
rxform.appendItem(t1);
|
||||
rxform.appendItem(t2);
|
||||
cxform.appendItem(t3);
|
||||
|
||||
const newItem = rxform.insertItemBefore(t3, 0);
|
||||
assert.equal(rxform.numberOfItems, 3);
|
||||
assert.equal(newItem, t3);
|
||||
assert.equal(rxform.getItem(0), t3);
|
||||
assert.equal(rxform.getItem(1), t1);
|
||||
assert.equal(rxform.getItem(2), t2);
|
||||
// Fails in Firefox native
|
||||
// assert.equal(cxform.numberOfItems, 0);
|
||||
|
||||
rxform.insertItemBefore(t2, 1);
|
||||
// Fails in Firefox native (they make copies of the transforms)
|
||||
// assert.equal(rxform.numberOfItems, 3);
|
||||
assert.equal(rxform.getItem(0), t3);
|
||||
assert.equal(rxform.getItem(1), t2);
|
||||
assert.equal(rxform.getItem(2), t1);
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.init() for translate(200,100)', function (assert) {
|
||||
assert.expect(8);
|
||||
setUp();
|
||||
rect.setAttribute('transform', 'translate(200,100)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const translate = rxform.getItem(0);
|
||||
assert.equal(translate.type, 2);
|
||||
|
||||
const m = translate.matrix;
|
||||
assert.equal(m.a, 1);
|
||||
assert.equal(m.b, 0);
|
||||
assert.equal(m.c, 0);
|
||||
assert.equal(m.d, 1);
|
||||
assert.equal(m.e, 200);
|
||||
assert.equal(m.f, 100);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.init() for scale(4)', function (assert) {
|
||||
assert.expect(8);
|
||||
setUp();
|
||||
rect.setAttribute('transform', 'scale(4)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const scale = rxform.getItem(0);
|
||||
assert.equal(scale.type, 3);
|
||||
|
||||
const m = scale.matrix;
|
||||
assert.equal(m.a, 4);
|
||||
assert.equal(m.b, 0);
|
||||
assert.equal(m.c, 0);
|
||||
assert.equal(m.d, 4);
|
||||
assert.equal(m.e, 0);
|
||||
assert.equal(m.f, 0);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.init() for scale(4,3)', function (assert) {
|
||||
assert.expect(8);
|
||||
setUp();
|
||||
rect.setAttribute('transform', 'scale(4,3)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const scale = rxform.getItem(0);
|
||||
assert.equal(scale.type, 3);
|
||||
|
||||
const m = scale.matrix;
|
||||
assert.equal(m.a, 4);
|
||||
assert.equal(m.b, 0);
|
||||
assert.equal(m.c, 0);
|
||||
assert.equal(m.d, 3);
|
||||
assert.equal(m.e, 0);
|
||||
assert.equal(m.f, 0);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.init() for rotate(45)', function (assert) {
|
||||
assert.expect(9);
|
||||
setUp();
|
||||
rect.setAttribute('transform', 'rotate(45)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const rotate = rxform.getItem(0);
|
||||
assert.equal(rotate.type, 4);
|
||||
assert.equal(rotate.angle, 45);
|
||||
|
||||
const m = rotate.matrix;
|
||||
assert.almostEquals(1 / Math.sqrt(2), m.a);
|
||||
assert.almostEquals(1 / Math.sqrt(2), m.b);
|
||||
assert.almostEquals(-1 / Math.sqrt(2), m.c);
|
||||
assert.almostEquals(1 / Math.sqrt(2), m.d);
|
||||
assert.equal(m.e, 0);
|
||||
assert.equal(m.f, 0);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.init() for rotate(45, 100, 200)', function (assert) {
|
||||
assert.expect(9);
|
||||
setUp();
|
||||
rect.setAttribute('transform', 'rotate(45, 100, 200)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const rotate = rxform.getItem(0);
|
||||
assert.equal(rotate.type, 4);
|
||||
assert.equal(rotate.angle, 45);
|
||||
|
||||
const m = rotate.matrix;
|
||||
assert.almostEquals(m.a, 1 / Math.sqrt(2));
|
||||
assert.almostEquals(m.b, 1 / Math.sqrt(2));
|
||||
assert.almostEquals(m.c, -1 / Math.sqrt(2));
|
||||
assert.almostEquals(m.d, 1 / Math.sqrt(2));
|
||||
|
||||
const r = svgcontent.createSVGMatrix();
|
||||
r.a = 1 / Math.sqrt(2); r.b = 1 / Math.sqrt(2);
|
||||
r.c = -1 / Math.sqrt(2); r.d = 1 / Math.sqrt(2);
|
||||
|
||||
const t = svgcontent.createSVGMatrix();
|
||||
t.e = -100; t.f = -200;
|
||||
|
||||
const t_ = svgcontent.createSVGMatrix();
|
||||
t_.e = 100; t_.f = 200;
|
||||
|
||||
const result = t_.multiply(r).multiply(t);
|
||||
|
||||
assert.almostEquals(m.e, result.e);
|
||||
assert.almostEquals(m.f, result.f);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
|
||||
QUnit.test('Test SVGTransformList.init() for matrix(1, 2, 3, 4, 5, 6)', function (assert) {
|
||||
assert.expect(8);
|
||||
setUp();
|
||||
rect.setAttribute('transform', 'matrix(1,2,3,4,5,6)');
|
||||
|
||||
const rxform = transformlist.getTransformList(rect);
|
||||
assert.equal(rxform.numberOfItems, 1);
|
||||
|
||||
const mt = rxform.getItem(0);
|
||||
assert.equal(mt.type, 1);
|
||||
|
||||
const m = mt.matrix;
|
||||
assert.equal(m.a, 1);
|
||||
assert.equal(m.b, 2);
|
||||
assert.equal(m.c, 3);
|
||||
assert.equal(m.d, 4);
|
||||
assert.equal(m.e, 5);
|
||||
assert.equal(m.f, 6);
|
||||
|
||||
tearDown();
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for SvgCanvas</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../editor/jquery-ui/jquery-ui-1.8.custom.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="test1.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for SvgCanvas</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="svg_editor">
|
||||
<div id="workarea">
|
||||
<div id="svgcanvas" style="visibility: hidden;"></div>
|
||||
</div>
|
||||
<div id="tools_left"></div>
|
||||
<div class="tools_flyout"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
269
test/test1.js
269
test/test1.js
@@ -1,269 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
|
||||
import '../editor/svgpathseg.js';
|
||||
import SvgCanvas from '../editor/svgcanvas.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
// helper functions
|
||||
/*
|
||||
const isIdentity = function (m) {
|
||||
return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0);
|
||||
};
|
||||
const matrixString = function (m) {
|
||||
return [m.a, m.b, m.c, m.d, m.e, m.f].join(',');
|
||||
};
|
||||
*/
|
||||
|
||||
const svgCanvas = new SvgCanvas(
|
||||
document.getElementById('svgcanvas'), {
|
||||
canvas_expansion: 3,
|
||||
dimensions: [640, 480],
|
||||
initFill: {
|
||||
color: 'FF0000', // solid red
|
||||
opacity: 1
|
||||
},
|
||||
initStroke: {
|
||||
width: 5,
|
||||
color: '000000', // solid black
|
||||
opacity: 1
|
||||
},
|
||||
initOpacity: 1,
|
||||
imgPath: '../editor/images/',
|
||||
langPath: 'locale/',
|
||||
extPath: 'extensions/',
|
||||
extensions: ['ext-arrows.js', 'ext-connector.js', 'ext-eyedropper.js'],
|
||||
initTool: 'select',
|
||||
wireframe: false
|
||||
}
|
||||
);
|
||||
|
||||
const
|
||||
// svgroot = document.getElementById('svgroot'),
|
||||
// svgdoc = svgroot.documentElement,
|
||||
svgns = 'http://www.w3.org/2000/svg',
|
||||
xlinkns = 'http://www.w3.org/1999/xlink';
|
||||
|
||||
QUnit.module('Basic Module');
|
||||
|
||||
QUnit.test('Test existence of SvgCanvas object', function (assert) {
|
||||
assert.expect(1);
|
||||
assert.equal(typeof {}, typeof svgCanvas);
|
||||
});
|
||||
|
||||
QUnit.module('Path Module');
|
||||
|
||||
QUnit.test('Test path conversion from absolute to relative', function (assert) {
|
||||
assert.expect(6);
|
||||
const convert = svgCanvas.pathActions.convertPath;
|
||||
|
||||
// TODO: Test these paths:
|
||||
// "m400.00491,625.01379a1.78688,1.78688 0 1 1-3.57373,0a1.78688,1.78688 0 1 13.57373,0z"
|
||||
// "m36.812,15.8566c-28.03099,0 -26.28099,12.15601 -26.28099,12.15601l0.03099,12.59399h26.75v3.781h-37.37399c0,0 -17.938,-2.034 -133.00001,26.25c115.06201,28.284 130.71801,27.281 130.71801,27.281h9.34399v-13.125c0,0 -0.504,-15.656 15.40601,-15.656h26.532c0,0 14.90599,0.241 14.90599,-14.406v-24.219c0,0 2.263,-14.65601 -27.032,-14.65601zm-14.75,8.4684c2.662,0 4.813,2.151 4.813,4.813c0,2.661 -2.151,4.812 -4.813,4.812c-2.661,0 -4.812,-2.151 -4.812,-4.812c0,-2.662 2.151,-4.813 4.812,-4.813z"
|
||||
// "m 0,0 l 200,0 l 0,100 L 0,100"
|
||||
|
||||
svgCanvas.setSvgString(
|
||||
"<svg xmlns='http://www.w3.org/2000/svg' width='400' x='300'>" +
|
||||
"<path id='p1' d='M100,100 L200,100 L100,100Z'/>" +
|
||||
"<path id='p2' d='m 0,0 l 200,0 l 0,100 L 0,100'/>" +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const p1 = document.getElementById('p1'),
|
||||
p2 = document.getElementById('p2'),
|
||||
dAbs = p1.getAttribute('d'),
|
||||
seglist = p1.pathSegList;
|
||||
|
||||
assert.equal(p1.nodeName, 'path', "Expected 'path', got");
|
||||
|
||||
assert.equal(seglist.numberOfItems, 4, 'Number of segments before conversion');
|
||||
|
||||
// verify segments before conversion
|
||||
let curseg = seglist.getItem(0);
|
||||
assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'M', 'Before conversion, segment #1 type');
|
||||
curseg = seglist.getItem(1);
|
||||
assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'L', 'Before conversion, segment #2 type');
|
||||
curseg = seglist.getItem(3);
|
||||
assert.equal(curseg.pathSegTypeAsLetter.toUpperCase(), 'Z', 'Before conversion, segment #3 type' + dAbs);
|
||||
|
||||
// convert and verify segments
|
||||
let d = convert(p1, true);
|
||||
assert.equal(d, 'm100,100l100,0l-100,0z', 'Converted path to relative string');
|
||||
|
||||
// TODO: see why this isn't working in SVG-edit
|
||||
d = convert(p2, true);
|
||||
console.log('Convert true', d);
|
||||
d = convert(p2, false);
|
||||
console.log('Convert false', d);
|
||||
});
|
||||
|
||||
QUnit.module('Import Module');
|
||||
|
||||
QUnit.test('Test import use', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
svgCanvas.setSvgString(
|
||||
"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='400' x='300'>" +
|
||||
"<rect id='the-rect' width='200' height='200'/>" +
|
||||
"<use id='the-use' xlink:href='#the-rect'/>" +
|
||||
"<use id='foreign-use' xlink:href='somefile.svg#the-rect'/>" +
|
||||
"<use id='no-use'/>" +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const u = document.getElementById('the-use'),
|
||||
fu = document.getElementById('foreign-use'),
|
||||
nfu = document.getElementById('no-use');
|
||||
|
||||
assert.equal((u && u.nodeName === 'use'), true, 'Did not import <use> element');
|
||||
assert.equal(fu, null, 'Removed <use> element that had a foreign href');
|
||||
assert.equal(nfu, null, 'Removed <use> element that had no href');
|
||||
});
|
||||
|
||||
// This test shows that an element with an invalid attribute is still parsed in properly
|
||||
// and only the attribute is not imported
|
||||
QUnit.test('Test invalid attribute', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<text x="182.75" y="173.5" id="the-text" fill="#008000" font-size="150" font-family="serif" text-anchor="middle" d="M116,222 L110,108">words</text>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const t = document.getElementById('the-text');
|
||||
|
||||
assert.equal((t && t.nodeName === 'text'), true, 'Did not import <text> element');
|
||||
assert.equal(t.getAttribute('d'), null, 'Imported a <text> with a d attribute');
|
||||
});
|
||||
|
||||
// This test makes sure import/export properly handles namespaced attributes
|
||||
QUnit.test('Test importing/exporting namespaced attributes', function (assert) {
|
||||
assert.expect(5);
|
||||
/* const setStr = */ svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:se="http://svg-edit.googlecode.com" xmlns:foo="http://example.com">' +
|
||||
'<image xlink:href="../editor/images/logo.png"/>' +
|
||||
'<polyline id="se_test_elem" se:foo="bar" foo:bar="baz"/>' +
|
||||
'</svg>'
|
||||
);
|
||||
const attrVal = document.getElementById('se_test_elem').getAttributeNS('http://svg-edit.googlecode.com', 'foo');
|
||||
|
||||
assert.equal(attrVal === 'bar', true, 'Preserved namespaced attribute on import');
|
||||
//
|
||||
// console.log('getSvgString' in svgCanvas)
|
||||
|
||||
const output = svgCanvas.getSvgString();
|
||||
// } catch(e) {console.log(e)}
|
||||
// console.log('output',output);
|
||||
const hasXlink = output.includes('xmlns:xlink="http://www.w3.org/1999/xlink"');
|
||||
const hasSe = output.includes('xmlns:se=');
|
||||
const hasFoo = output.includes('xmlns:foo=');
|
||||
const hasAttr = output.includes('se:foo="bar"');
|
||||
|
||||
assert.equal(hasAttr, true, 'Preserved namespaced attribute on export');
|
||||
assert.equal(hasXlink, true, 'Included xlink: xmlns');
|
||||
assert.equal(hasSe, true, 'Included se: xmlns');
|
||||
assert.equal(hasFoo, false, 'Did not include foo: xmlns');
|
||||
});
|
||||
|
||||
QUnit.test('Test import math elements inside a foreignObject', function (assert) {
|
||||
assert.expect(4);
|
||||
/* const set = */ svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:se="http://svg-edit.googlecode.com" xmlns:xlink="http://www.w3.org/1999/xlink">' +
|
||||
'<foreignObject id="fo" width="24" height="26" font-size="24"><math id="m" display="inline" xmlns="http://www.w3.org/1998/Math/MathML">' +
|
||||
'<msub>' +
|
||||
'<mi>A</mi>' +
|
||||
'<mn>0</mn>' +
|
||||
'</msub>' +
|
||||
'</math>' +
|
||||
'</foreignObject>' +
|
||||
'</svg>'
|
||||
);
|
||||
const fo = document.getElementById('fo');
|
||||
// we cannot use getElementById('math') because not all browsers understand MathML and do not know to use the @id attribute
|
||||
// see Bug https://bugs.webkit.org/show_bug.cgi?id=35042
|
||||
const math = fo.firstChild;
|
||||
|
||||
assert.equal(Boolean(math), true, 'Math element exists');
|
||||
assert.equal(math.nodeName, 'math', 'Math element has the proper nodeName');
|
||||
assert.equal(math.getAttribute('id'), 'm', 'Math element has an id');
|
||||
assert.equal(math.namespaceURI, 'http://www.w3.org/1998/Math/MathML', 'Preserved MathML namespace');
|
||||
});
|
||||
|
||||
QUnit.test('Test importing SVG into existing drawing', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
/* const doc = */ svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<g><title>Layer 1</title>' +
|
||||
'<circle cx="200" cy="200" r="50" fill="blue"/>' +
|
||||
'<ellipse cx="300" cy="100" rx="40" ry="30" fill="green"/>' +
|
||||
'</g>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
svgCanvas.importSvgString(
|
||||
'<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<circle cx="50" cy="50" r="40" fill="yellow"/>' +
|
||||
'<rect width="20" height="20" fill="blue"/>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const svgcontent = document.getElementById('svgcontent'),
|
||||
circles = svgcontent.getElementsByTagNameNS(svgns, 'circle'),
|
||||
rects = svgcontent.getElementsByTagNameNS(svgns, 'rect'),
|
||||
ellipses = svgcontent.getElementsByTagNameNS(svgns, 'ellipse');
|
||||
assert.equal(circles.length, 2, 'Found two circles upon importing');
|
||||
assert.equal(rects.length, 1, 'Found one rectangle upon importing');
|
||||
assert.equal(ellipses.length, 1, 'Found one ellipse upon importing');
|
||||
});
|
||||
|
||||
QUnit.test('Test importing SVG remaps IDs', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
/* const doc = */ svgCanvas.setSvgString(
|
||||
'<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<g><title>Layer 1</title>' +
|
||||
'<ellipse id="svg_1" cx="200" cy="200" rx="50" ry="20" fill="blue"/>' +
|
||||
'<ellipse id="svg_2" cx="300" cy="100" rx="40" ry="30" fill="green"/>' +
|
||||
'<ellipse id="svg_3" cx="300" cy="100" rx="40" ry="30" fill="green"/>' +
|
||||
'</g>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
svgCanvas.importSvgString(
|
||||
'<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink">' +
|
||||
'<defs>' +
|
||||
'<linearGradient id="svg_2">' +
|
||||
'<stop stop-color="red" offset="0"/>' +
|
||||
'<stop stop-color="green" offset="1"/>' +
|
||||
'</linearGradient>' +
|
||||
'<rect id="svg_3" width="20" height="20" fill="blue" stroke="url(#svg_2)"/>' +
|
||||
'</defs>' +
|
||||
'<circle id="svg_1" cx="50" cy="50" r="40" fill="url(#svg_2)"/>' +
|
||||
'<use id="svg_4" width="30" height="30" xl:href="#svg_3"/>' +
|
||||
'</svg>'
|
||||
);
|
||||
|
||||
const svgcontent = document.getElementById('svgcontent'),
|
||||
circles = svgcontent.getElementsByTagNameNS(svgns, 'circle'),
|
||||
rects = svgcontent.getElementsByTagNameNS(svgns, 'rect'),
|
||||
// ellipses = svgcontent.getElementsByTagNameNS(svgns, 'ellipse'),
|
||||
defs = svgcontent.getElementsByTagNameNS(svgns, 'defs'),
|
||||
// grads = svgcontent.getElementsByTagNameNS(svgns, 'linearGradient'),
|
||||
uses = svgcontent.getElementsByTagNameNS(svgns, 'use');
|
||||
assert.notEqual(circles.item(0).id, 'svg_1', 'Circle not re-identified');
|
||||
assert.notEqual(rects.item(0).id, 'svg_3', 'Rectangle not re-identified');
|
||||
// TODO: determine why this test fails in WebKit browsers
|
||||
// assert.equal(grads.length, 1, 'Linear gradient imported');
|
||||
const grad = defs.item(0).firstChild;
|
||||
assert.notEqual(grad.id, 'svg_2', 'Linear gradient not re-identified');
|
||||
assert.notEqual(circles.item(0).getAttribute('fill'), 'url(#svg_2)', 'Circle fill value not remapped');
|
||||
assert.notEqual(rects.item(0).getAttribute('stroke'), 'url(#svg_2)', 'Rectangle stroke value not remapped');
|
||||
assert.notEqual(uses.item(0).getAttributeNS(xlinkns, 'href'), '#svg_3');
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for units.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="units_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for units.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="anchor" style="visibility: hidden;"></div>
|
||||
<div id="elementsContainer">
|
||||
<div id="uniqueId" style="visibility: hidden;"></div>
|
||||
<div id="nonUniqueId" style="visibility: hidden;"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,90 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import * as units from '../editor/units.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Set up tests, supplying mock data.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setUp () {
|
||||
units.init(
|
||||
/**
|
||||
* @implements {module:units.ElementContainer}
|
||||
*/
|
||||
{
|
||||
getBaseUnit () { return 'cm'; },
|
||||
getHeight () { return 600; },
|
||||
getWidth () { return 800; },
|
||||
getRoundDigits () { return 4; },
|
||||
getElement (elementId) { return document.getElementById(elementId); }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
QUnit.test('Test svgedit.units package', function (assert) {
|
||||
assert.expect(2);
|
||||
assert.ok(units);
|
||||
assert.equal(typeof units, typeof {});
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.units.shortFloat()', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
setUp();
|
||||
|
||||
assert.ok(units.shortFloat);
|
||||
assert.equal(typeof units.shortFloat, typeof function () { /* */ });
|
||||
|
||||
const {shortFloat} = units;
|
||||
assert.equal(shortFloat(0.00000001), 0);
|
||||
assert.equal(shortFloat(1), 1);
|
||||
assert.equal(shortFloat(3.45678), 3.4568);
|
||||
assert.equal(shortFloat(1.23443), 1.2344);
|
||||
assert.equal(shortFloat(1.23455), 1.2346);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.units.isValidUnit()', function (assert) {
|
||||
assert.expect(18);
|
||||
|
||||
setUp();
|
||||
|
||||
assert.ok(units.isValidUnit);
|
||||
assert.equal(typeof units.isValidUnit, typeof function () { /* */ });
|
||||
|
||||
const {isValidUnit} = units;
|
||||
assert.ok(isValidUnit('0'));
|
||||
assert.ok(isValidUnit('1'));
|
||||
assert.ok(isValidUnit('1.1'));
|
||||
assert.ok(isValidUnit('-1.1'));
|
||||
assert.ok(isValidUnit('.6mm'));
|
||||
assert.ok(isValidUnit('-.6cm'));
|
||||
assert.ok(isValidUnit('6000in'));
|
||||
assert.ok(isValidUnit('6px'));
|
||||
assert.ok(isValidUnit('6.3pc'));
|
||||
assert.ok(isValidUnit('-0.4em'));
|
||||
assert.ok(isValidUnit('-0.ex'));
|
||||
assert.ok(isValidUnit('40.123%'));
|
||||
|
||||
assert.equal(isValidUnit('id', 'uniqueId', document.getElementById('uniqueId')), true);
|
||||
assert.equal(isValidUnit('id', 'newId', document.getElementById('uniqueId')), true);
|
||||
assert.equal(isValidUnit('id', 'uniqueId'), false);
|
||||
assert.equal(isValidUnit('id', 'uniqueId', document.getElementById('nonUniqueId')), false);
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.units.convertUnit()', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
setUp();
|
||||
|
||||
assert.ok(units.convertUnit);
|
||||
assert.equal(typeof units.convertUnit, typeof function () { /* */ });
|
||||
// cm in default setup
|
||||
assert.equal(units.convertUnit(42), 1.1113);
|
||||
assert.equal(units.convertUnit(42, 'px'), 42);
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for utilities.js BBox functions</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="utilities_bbox_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for utilities.js BBox functions</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="sandbox"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,508 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import '../editor/svgpathseg.js';
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as utilities from '../editor/utilities.js';
|
||||
import * as transformlist from '../editor/svgtransformlist.js';
|
||||
import * as math from '../editor/math.js';
|
||||
import * as path from '../editor/path.js';
|
||||
import closePlugin from './qunit/qunit-assert-close.js';
|
||||
|
||||
closePlugin(QUnit);
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Create an SVG element for a mock.
|
||||
* @param {module:utilities.SVGElementJSON} jsonMap
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockCreateSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
}
|
||||
let mockaddSVGElementFromJsonCallCount = 0;
|
||||
|
||||
/**
|
||||
* Mock of {@link module:utilities.EditorContext#addSVGElementFromJson}.
|
||||
* @param {module:utilities.SVGElementJSON} json
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockaddSVGElementFromJson (json) {
|
||||
const elem = mockCreateSVGElement(json);
|
||||
svgroot.append(elem);
|
||||
mockaddSVGElementFromJsonCallCount++;
|
||||
return elem;
|
||||
}
|
||||
const mockPathActions = {
|
||||
resetOrientation (pth) {
|
||||
if (utilities.isNullish(pth) || pth.nodeName !== 'path') { return false; }
|
||||
const tlist = transformlist.getTransformList(pth);
|
||||
const m = math.transformListToTransform(tlist).matrix;
|
||||
tlist.clear();
|
||||
pth.removeAttribute('transform');
|
||||
const segList = pth.pathSegList;
|
||||
|
||||
const len = segList.numberOfItems;
|
||||
// let lastX, lastY;
|
||||
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const seg = segList.getItem(i);
|
||||
const type = seg.pathSegType;
|
||||
if (type === 1) { continue; }
|
||||
const pts = [];
|
||||
['', 1, 2].forEach(function (n, j) {
|
||||
const x = seg['x' + n], y = seg['y' + n];
|
||||
if (x !== undefined && y !== undefined) {
|
||||
const pt = math.transformPoint(x, y, m);
|
||||
pts.splice(pts.length, 0, pt.x, pt.y);
|
||||
}
|
||||
});
|
||||
path.replacePathSeg(type, i, pts, pth);
|
||||
}
|
||||
// path.reorientGrads(pth, m);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const EPSILON = 0.001;
|
||||
// const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
const sandbox = document.getElementById('sandbox');
|
||||
const svgroot = mockCreateSVGElement({
|
||||
element: 'svg',
|
||||
attr: {id: 'svgroot'}
|
||||
});
|
||||
sandbox.append(svgroot);
|
||||
|
||||
QUnit.module('svgedit.utilities_bbox', {
|
||||
beforeEach () {
|
||||
// We're reusing ID's so we need to do this for transforms.
|
||||
transformlist.resetListMap();
|
||||
path.init(null);
|
||||
mockaddSVGElementFromJsonCallCount = 0;
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.utilities package', function (assert) {
|
||||
assert.ok(utilities);
|
||||
assert.ok(utilities.getBBoxWithTransform);
|
||||
assert.ok(utilities.getStrokedBBox);
|
||||
assert.ok(utilities.getRotationAngleFromTransformList);
|
||||
assert.ok(utilities.getRotationAngle);
|
||||
});
|
||||
|
||||
QUnit.test('Test getBBoxWithTransform and no transform', function (assert) {
|
||||
const {getBBoxWithTransform} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 L2,3'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 2, height: 2});
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 5});
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
g.remove();
|
||||
});
|
||||
|
||||
QUnit.test('Test getBBoxWithTransform and a rotation transform', function (assert) {
|
||||
const {getBBoxWithTransform} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M10,10 L20,20', transform: 'rotate(45 10,10)'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, 10, EPSILON);
|
||||
assert.close(bbox.y, 10, EPSILON);
|
||||
assert.close(bbox.width, 0, EPSILON);
|
||||
assert.close(bbox.height, Math.sqrt(100 + 100), EPSILON);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '10', y: '10', width: '10', height: '20', transform: 'rotate(90 15,20)'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, 5, EPSILON);
|
||||
assert.close(bbox.y, 15, EPSILON);
|
||||
assert.close(bbox.width, 20, EPSILON);
|
||||
assert.close(bbox.height, 10, EPSILON);
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 1);
|
||||
elem.remove();
|
||||
|
||||
const rect = {x: 10, y: 10, width: 10, height: 20};
|
||||
const angle = 45;
|
||||
const origin = {x: 15, y: 20}; // eslint-disable-line no-shadow
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect2', x: rect.x, y: rect.y, width: rect.width, height: rect.height, transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ')'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
mockaddSVGElementFromJsonCallCount = 0;
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
const r2 = rotateRect(rect, angle, origin);
|
||||
assert.close(bbox.x, r2.x, EPSILON, 'rect2 x is ' + r2.x);
|
||||
assert.close(bbox.y, r2.y, EPSILON, 'rect2 y is ' + r2.y);
|
||||
assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width);
|
||||
assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height);
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
elem.remove();
|
||||
|
||||
// Same as previous but wrapped with g and the transform is with the g.
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect3', x: rect.x, y: rect.y, width: rect.width, height: rect.height}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ')'}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
mockaddSVGElementFromJsonCallCount = 0;
|
||||
bbox = getBBoxWithTransform(g, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, r2.x, EPSILON, 'rect2 x is ' + r2.x);
|
||||
assert.close(bbox.y, r2.y, EPSILON, 'rect2 y is ' + r2.y);
|
||||
assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width);
|
||||
assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height);
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 0);
|
||||
g.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'ellipse',
|
||||
attr: {id: 'ellipse1', cx: '100', cy: '100', rx: '50', ry: '50', transform: 'rotate(45 100,100)'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
mockaddSVGElementFromJsonCallCount = 0;
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
// TODO: the BBox algorithm is using the bezier control points to calculate the bounding box. Should be 50, 50, 100, 100.
|
||||
assert.ok(bbox.x > 45 && bbox.x <= 50);
|
||||
assert.ok(bbox.y > 45 && bbox.y <= 50);
|
||||
assert.ok(bbox.width >= 100 && bbox.width < 110);
|
||||
assert.ok(bbox.height >= 100 && bbox.height < 110);
|
||||
assert.equal(mockaddSVGElementFromJsonCallCount, 1);
|
||||
elem.remove();
|
||||
});
|
||||
|
||||
QUnit.test('Test getBBoxWithTransform with rotation and matrix transforms', function (assert) {
|
||||
const {getBBoxWithTransform} = utilities;
|
||||
|
||||
let tx = 10; // tx right
|
||||
let ty = 10; // tx down
|
||||
let txInRotatedSpace = Math.sqrt(tx * tx + ty * ty); // translate in rotated 45 space.
|
||||
let tyInRotatedSpace = 0;
|
||||
let matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')';
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M10,10 L20,20', transform: 'rotate(45 10,10) ' + matrix}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, 10 + tx, EPSILON);
|
||||
assert.close(bbox.y, 10 + ty, EPSILON);
|
||||
assert.close(bbox.width, 0, EPSILON);
|
||||
assert.close(bbox.height, Math.sqrt(100 + 100), EPSILON);
|
||||
elem.remove();
|
||||
|
||||
txInRotatedSpace = tx; // translate in rotated 90 space.
|
||||
tyInRotatedSpace = -ty;
|
||||
matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')';
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '10', y: '10', width: '10', height: '20', transform: 'rotate(90 15,20) ' + matrix}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, 5 + tx, EPSILON);
|
||||
assert.close(bbox.y, 15 + ty, EPSILON);
|
||||
assert.close(bbox.width, 20, EPSILON);
|
||||
assert.close(bbox.height, 10, EPSILON);
|
||||
elem.remove();
|
||||
|
||||
const rect = {x: 10, y: 10, width: 10, height: 20};
|
||||
const angle = 45;
|
||||
const origin = {x: 15, y: 20}; // eslint-disable-line no-shadow
|
||||
tx = 10; // tx right
|
||||
ty = 10; // tx down
|
||||
txInRotatedSpace = Math.sqrt(tx * tx + ty * ty); // translate in rotated 45 space.
|
||||
tyInRotatedSpace = 0;
|
||||
matrix = 'matrix(1,0,0,1,' + txInRotatedSpace + ',' + tyInRotatedSpace + ')';
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect2', x: rect.x, y: rect.y, width: rect.width, height: rect.height, transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ') ' + matrix}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
const r2 = rotateRect(rect, angle, origin);
|
||||
assert.close(bbox.x, r2.x + tx, EPSILON, 'rect2 x is ' + r2.x);
|
||||
assert.close(bbox.y, r2.y + ty, EPSILON, 'rect2 y is ' + r2.y);
|
||||
assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width);
|
||||
assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height);
|
||||
elem.remove();
|
||||
|
||||
// Same as previous but wrapped with g and the transform is with the g.
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect3', x: rect.x, y: rect.y, width: rect.width, height: rect.height}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {transform: 'rotate(' + angle + ' ' + origin.x + ',' + origin.y + ') ' + matrix}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getBBoxWithTransform(g, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.close(bbox.x, r2.x + tx, EPSILON, 'rect2 x is ' + r2.x);
|
||||
assert.close(bbox.y, r2.y + ty, EPSILON, 'rect2 y is ' + r2.y);
|
||||
assert.close(bbox.width, r2.width, EPSILON, 'rect2 width is' + r2.width);
|
||||
assert.close(bbox.height, r2.height, EPSILON, 'rect2 height is ' + r2.height);
|
||||
g.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'ellipse',
|
||||
attr: {id: 'ellipse1', cx: '100', cy: '100', rx: '50', ry: '50', transform: 'rotate(45 100,100) ' + matrix}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxWithTransform(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
// TODO: the BBox algorithm is using the bezier control points to calculate the bounding box. Should be 50, 50, 100, 100.
|
||||
assert.ok(bbox.x > 45 + tx && bbox.x <= 50 + tx);
|
||||
assert.ok(bbox.y > 45 + ty && bbox.y <= 50 + ty);
|
||||
assert.ok(bbox.width >= 100 && bbox.width < 110);
|
||||
assert.ok(bbox.height >= 100 && bbox.height < 110);
|
||||
elem.remove();
|
||||
});
|
||||
|
||||
QUnit.test('Test getStrokedBBox with stroke-width 10', function (assert) {
|
||||
const {getStrokedBBox} = utilities;
|
||||
|
||||
const strokeWidth = 10;
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 L2,3', 'stroke-width': strokeWidth}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 2 + strokeWidth, height: 2 + strokeWidth});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': strokeWidth}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 10 + strokeWidth});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6', 'stroke-width': strokeWidth}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 5 + strokeWidth});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': strokeWidth}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0 - strokeWidth / 2, y: 1 - strokeWidth / 2, width: 5 + strokeWidth, height: 10 + strokeWidth});
|
||||
g.remove();
|
||||
});
|
||||
|
||||
QUnit.test("Test getStrokedBBox with stroke-width 'none'", function (assert) {
|
||||
const {getStrokedBBox} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 L2,3', 'stroke-width': 'none'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 2, height: 2});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': 'none'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6', 'stroke-width': 'none'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 5});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10', 'stroke-width': 'none'}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
g.remove();
|
||||
});
|
||||
|
||||
QUnit.test('Test getStrokedBBox with no stroke-width attribute', function (assert) {
|
||||
const {getStrokedBBox} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 L2,3'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 2, height: 2});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 5});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
const g = mockCreateSVGElement({
|
||||
element: 'g',
|
||||
attr: {}
|
||||
});
|
||||
g.append(elem);
|
||||
svgroot.append(g);
|
||||
bbox = getStrokedBBox([elem], mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
g.remove();
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns radians for degrees.
|
||||
* @param {Float} degrees
|
||||
* @returns {Float}
|
||||
*/
|
||||
function radians (degrees) {
|
||||
return degrees * Math.PI / 180;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {module:utilities.BBoxObject} point
|
||||
* @param {Float} angle
|
||||
* @param {module:math.XYObject} origin
|
||||
* @returns {module:math.XYObject}
|
||||
*/
|
||||
function rotatePoint (point, angle, origin) { // eslint-disable-line no-shadow
|
||||
if (!origin) {
|
||||
origin = {x: 0, y: 0};
|
||||
}
|
||||
const x = point.x - origin.x;
|
||||
const y = point.y - origin.y;
|
||||
const theta = radians(angle);
|
||||
return {
|
||||
x: x * Math.cos(theta) + y * Math.sin(theta) + origin.x,
|
||||
y: x * Math.sin(theta) + y * Math.cos(theta) + origin.y
|
||||
};
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {module:utilities.BBoxObject} rect
|
||||
* @param {Float} angle
|
||||
* @param {module:math.XYObject} origin
|
||||
* @returns {module:utilities.BBoxObject}
|
||||
*/
|
||||
function rotateRect (rect, angle, origin) { // eslint-disable-line no-shadow
|
||||
const tl = rotatePoint({x: rect.x, y: rect.y}, angle, origin);
|
||||
const tr = rotatePoint({x: rect.x + rect.width, y: rect.y}, angle, origin);
|
||||
const br = rotatePoint({x: rect.x + rect.width, y: rect.y + rect.height}, angle, origin);
|
||||
const bl = rotatePoint({x: rect.x, y: rect.y + rect.height}, angle, origin);
|
||||
|
||||
const minx = Math.min(tl.x, tr.x, bl.x, br.x);
|
||||
const maxx = Math.max(tl.x, tr.x, bl.x, br.x);
|
||||
const miny = Math.min(tl.y, tr.y, bl.y, br.y);
|
||||
const maxy = Math.max(tl.y, tr.y, bl.y, br.y);
|
||||
|
||||
return {
|
||||
x: minx,
|
||||
y: miny,
|
||||
width: (maxx - minx),
|
||||
height: (maxy - miny)
|
||||
};
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge, chrome=1"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
|
||||
<title>Performance Unit Tests for utilities.js</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<style id="styleoverrides" media="screen">
|
||||
#svgcanvas svg * {
|
||||
cursor: move;
|
||||
pointer-events: all
|
||||
}
|
||||
#svgcanvas svg {
|
||||
cursor: default
|
||||
}
|
||||
</style>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="utilities_performance_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Performance Unit Tests for utilities.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
|
||||
<div id="svg_editor">
|
||||
<div id="workarea" style="cursor: auto; overflow: scroll; line-height: 12px; right: 100px;">
|
||||
|
||||
<!-- Must include this thumbnail view to see some of the performance issues -->
|
||||
<svg id="overviewMiniView" width="150" height="112.5" x="0" y="0" viewBox="100 100 1000 1000" style="float: right;"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<use x="0" y="0" xlink:href="#svgroot"></use>
|
||||
</svg>
|
||||
|
||||
|
||||
<div id="svgcanvas" style="position: relative; width: 1000px; height: 1000px;">
|
||||
<svg id="svgroot" xmlns="http://www.w3.org/2000/svg" xlinkns="http://www.w3.org/1999/xlink" width="1000" height="1000" x="640" y="480" overflow="visible">
|
||||
<defs><filter id="canvashadow" filterUnits="objectBoundingBox"><feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"></feGaussianBlur><feOffset in="blur" dx="5" dy="5" result="offsetBlur"></feOffset><feMerge><feMergeNode in="offsetBlur"></feMergeNode><feMergeNode in="SourceGraphic"></feMergeNode></feMerge></filter><pattern id="gridpattern" patternUnits="userSpaceOnUse" x="0" y="0" width="100" height="100"><image x="0" y="0" width="100" height="100"></image></pattern></defs>
|
||||
<svg id="canvasBackground" width="1000" height="200" x="10" y="10" overflow="none" style="pointer-events:none"><rect width="100%" height="100%" x="0" y="0" stroke="#000" fill="#000" style="pointer-events:none"></rect><svg id="canvasGrid" width="100%" height="100%" x="0" y="0" overflow="visible" display="none" style="display: inline;"><rect width="100%" height="100%" x="0" y="0" stroke-width="0" stroke="none" fill="url(#gridpattern)" style="pointer-events: none; display:visible;"></rect></svg></svg>
|
||||
<animate attributeName="opacity" begin="indefinite" dur="1" fill="freeze"></animate>
|
||||
|
||||
<svg id="svgcontent" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1000 480" overflow="visible" width="1000" height="200" x="100" y="20">
|
||||
|
||||
<g id="layer1">
|
||||
<title>Layer 1</title>
|
||||
|
||||
<g id="svg_group_with_matrix_transform" transform="matrix(0.5, 0, 0, 0.5, 10, 10)">
|
||||
<svg id="svg_2" x="100" y="0" class="symbol" preserveAspectRatio="xMaxYMax">
|
||||
<g id="svg_3">
|
||||
<rect id="svg_4" x="0" y="0" width="20" height="20" fill="#00FF00"></rect>
|
||||
</g>
|
||||
<g id="svg_5" display="none">
|
||||
<rect id="svg_6" x="0" y="0" width="20" height="20" fill="#A40000"></rect>
|
||||
</g>
|
||||
</svg>
|
||||
</g>
|
||||
<text id="svg_text_with_matrix_transform" transform="matrix(0.433735, 0, 0, 0.433735, 2, 4)" xml:space="preserve" text-anchor="middle" font-family="serif" font-size="24" y="0" x="61" stroke="#999999" fill="#999999">Some text</text>
|
||||
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 2</title>
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,183 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
import '../editor/svgpathseg.js';
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
import * as utilities from '../editor/utilities.js';
|
||||
import * as transformlist from '../editor/svgtransformlist.js';
|
||||
import * as math from '../editor/math.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
const currentLayer = document.getElementById('layer1');
|
||||
|
||||
/**
|
||||
* Create an SVG element for a mock.
|
||||
* @param {module:utilities.SVGElementJSON} jsonMap
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockCreateSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock of {@link module:utilities.EditorContext#addSVGElementFromJson}.
|
||||
* @param {module:utilities.SVGElementJSON} json
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockaddSVGElementFromJson (json) {
|
||||
const elem = mockCreateSVGElement(json);
|
||||
currentLayer.append(elem);
|
||||
return elem;
|
||||
}
|
||||
|
||||
// const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
const groupWithMatrixTransform = document.getElementById('svg_group_with_matrix_transform');
|
||||
const textWithMatrixTransform = document.getElementById('svg_text_with_matrix_transform');
|
||||
|
||||
/**
|
||||
* Toward performance testing, fill document with clones of element.
|
||||
* @param {SVGElement} elem
|
||||
* @param {Integer} count
|
||||
* @returns {void}
|
||||
*/
|
||||
function fillDocumentByCloningElement (elem, count) {
|
||||
const elemId = elem.getAttribute('id') + '-';
|
||||
for (let index = 0; index < count; index++) {
|
||||
const clone = elem.cloneNode(true); // t: deep clone
|
||||
// Make sure you set a unique ID like a real document.
|
||||
clone.setAttribute('id', elemId + index);
|
||||
const {parentNode} = elem;
|
||||
parentNode.append(clone);
|
||||
}
|
||||
}
|
||||
|
||||
QUnit.module('svgedit.utilities_performance');
|
||||
|
||||
const mockPathActions = {
|
||||
resetOrientation (path) {
|
||||
if (utilities.isNullish(path) || path.nodeName !== 'path') { return false; }
|
||||
const tlist = transformlist.getTransformList(path);
|
||||
const m = math.transformListToTransform(tlist).matrix;
|
||||
tlist.clear();
|
||||
path.removeAttribute('transform');
|
||||
const segList = path.pathSegList;
|
||||
|
||||
const len = segList.numberOfItems;
|
||||
// let lastX, lastY;
|
||||
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const seg = segList.getItem(i);
|
||||
const type = seg.pathSegType;
|
||||
if (type === 1) {
|
||||
continue;
|
||||
}
|
||||
const pts = [];
|
||||
['', 1, 2].forEach(function (n, j) {
|
||||
const x = seg['x' + n],
|
||||
y = seg['y' + n];
|
||||
if (x !== undefined && y !== undefined) {
|
||||
const pt = math.transformPoint(x, y, m);
|
||||
pts.splice(pts.length, 0, pt.x, pt.y);
|
||||
}
|
||||
});
|
||||
// path.replacePathSeg(type, i, pts, path);
|
||||
}
|
||||
|
||||
// utilities.reorientGrads(path, m);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// //////////////////////////////////////////////////////////
|
||||
// Performance times with various browsers on Macbook 2011 8MB RAM OS X El Capitan 10.11.4
|
||||
//
|
||||
// To see 'Before Optimization' performance, making the following two edits.
|
||||
// 1. utilities.getStrokedBBox - change if( elems.length === 1) to if( false && elems.length === 1)
|
||||
// 2. utilities.getBBoxWithTransform - uncomment 'Old technique that was very slow'
|
||||
|
||||
// Chrome
|
||||
// Before Optimization
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 4,218, ave ms 41.0, min/max 37 51
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 4,458, ave ms 43.3, min/max 32 63
|
||||
// Optimized Code
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 1,112, ave ms 10.8, min/max 9 20
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 34, ave ms 0.3, min/max 0 20
|
||||
|
||||
// Firefox
|
||||
// Before Optimization
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 3,794, ave ms 36.8, min/max 33 48
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 4,049, ave ms 39.3, min/max 28 53
|
||||
// Optimized Code
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 104, ave ms 1.0, min/max 0 23
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 71, ave ms 0.7, min/max 0 23
|
||||
|
||||
// Safari
|
||||
// Before Optimization
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 4,840, ave ms 47.0, min/max 45 62
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 4,849, ave ms 47.1, min/max 34 62
|
||||
// Optimized Code
|
||||
// Pass1 svgCanvas.getStrokedBBox total ms 42, ave ms 0.4, min/max 0 23
|
||||
// Pass2 svgCanvas.getStrokedBBox total ms 17, ave ms 0.2, min/max 0 23
|
||||
|
||||
QUnit.test('Test svgCanvas.getStrokedBBox() performance with matrix transforms', function (assert) {
|
||||
const done = assert.async();
|
||||
assert.expect(2);
|
||||
const {getStrokedBBox} = utilities;
|
||||
const {children} = currentLayer;
|
||||
|
||||
let lastTime, now,
|
||||
min = Number.MAX_VALUE,
|
||||
max = 0,
|
||||
total = 0;
|
||||
|
||||
fillDocumentByCloningElement(groupWithMatrixTransform, 50);
|
||||
fillDocumentByCloningElement(textWithMatrixTransform, 50);
|
||||
|
||||
// The first pass through all elements is slower.
|
||||
const count = children.length;
|
||||
const start = lastTime = now = Date.now();
|
||||
// Skip the first child which is the title.
|
||||
for (let index = 1; index < count; index++) {
|
||||
const child = children[index];
|
||||
/* const obj = */ getStrokedBBox([child], mockaddSVGElementFromJson, mockPathActions);
|
||||
now = Date.now(); const delta = now - lastTime; lastTime = now;
|
||||
total += delta;
|
||||
min = Math.min(min, delta);
|
||||
max = Math.max(max, delta);
|
||||
}
|
||||
total = lastTime - start;
|
||||
const ave = total / count;
|
||||
assert.ok(ave < 20, 'svgedit.utilities.getStrokedBBox average execution time is less than 20 ms');
|
||||
console.log('Pass1 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + ave.toFixed(1) + ',\t min/max ' + min + ' ' + max);
|
||||
|
||||
// The second pass is two to ten times faster.
|
||||
setTimeout(function () {
|
||||
const ct = children.length;
|
||||
|
||||
const strt = lastTime = now = Date.now();
|
||||
// Skip the first child which is the title.
|
||||
for (let index = 1; index < ct; index++) {
|
||||
const child = children[index];
|
||||
/* const obj = */ getStrokedBBox([child], mockaddSVGElementFromJson, mockPathActions);
|
||||
now = Date.now(); const delta = now - lastTime; lastTime = now;
|
||||
total += delta;
|
||||
min = Math.min(min, delta);
|
||||
max = Math.max(max, delta);
|
||||
}
|
||||
|
||||
total = lastTime - strt;
|
||||
const avg = total / ct;
|
||||
assert.ok(avg < 2, 'svgedit.utilities.getStrokedBBox average execution time is less than 1 ms');
|
||||
console.log('Pass2 svgCanvas.getStrokedBBox total ms ' + total + ', ave ms ' + avg.toFixed(1) + ',\t min/max ' + min + ' ' + max);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Unit Tests for utilities.js</title>
|
||||
<link rel="icon" type="image/png" href="../editor/images/logo.png"/>
|
||||
<link rel="stylesheet" href="../node_modules/qunit/qunit/qunit.css"/>
|
||||
<script src="../editor/jquery.min.js"></script>
|
||||
<script src="../node_modules/qunit/qunit/qunit.js"></script>
|
||||
<script type="module" src="utilities_test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Unit Tests for utilities.js</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div id="sandbox"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,378 +0,0 @@
|
||||
/* eslint-env qunit */
|
||||
|
||||
import * as browser from '../editor/browser.js';
|
||||
import * as utilities from '../editor/utilities.js';
|
||||
import {NS} from '../editor/namespaces.js';
|
||||
|
||||
// log function
|
||||
QUnit.log((details) => {
|
||||
if (window.console && window.console.log) {
|
||||
window.console.log(details.result + ' :: ' + details.message);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Create an element for test.
|
||||
* @param {module:utilities.SVGElementJSON} jsonMap
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockCreateSVGElement (jsonMap) {
|
||||
const elem = document.createElementNS(NS.SVG, jsonMap.element);
|
||||
Object.entries(jsonMap.attr).forEach(([attr, value]) => {
|
||||
elem.setAttribute(attr, value);
|
||||
});
|
||||
return elem;
|
||||
}
|
||||
/**
|
||||
* Adds SVG Element per parameters and appends to root.
|
||||
* @param {module:utilities.SVGElementJSON} json
|
||||
* @returns {SVGElement}
|
||||
*/
|
||||
function mockaddSVGElementFromJson (json) {
|
||||
const elem = mockCreateSVGElement(json);
|
||||
svgroot.append(elem);
|
||||
return elem;
|
||||
}
|
||||
const mockPathActions = {resetOrientation () { /* */ }};
|
||||
let mockHistorySubCommands = [];
|
||||
const mockHistory = {
|
||||
BatchCommand: class {
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
addSubCommand (cmd) {
|
||||
mockHistorySubCommands.push(cmd);
|
||||
}
|
||||
},
|
||||
RemoveElementCommand: class {
|
||||
// Longhand needed since used as a constructor
|
||||
constructor (elem, nextSibling, parent) {
|
||||
this.elem = elem;
|
||||
this.nextSibling = nextSibling;
|
||||
this.parent = parent;
|
||||
}
|
||||
},
|
||||
InsertElementCommand: class {
|
||||
constructor (path) { // Longhand needed since used as a constructor
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
};
|
||||
const mockCount = {
|
||||
clearSelection: 0,
|
||||
addToSelection: 0,
|
||||
addCommandToHistory: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Increments clear seleciton count for mock test.
|
||||
* @returns {void}
|
||||
*/
|
||||
function mockClearSelection () {
|
||||
mockCount.clearSelection++;
|
||||
}
|
||||
/**
|
||||
* Increments add selection count for mock test.
|
||||
* @returns {void}
|
||||
*/
|
||||
function mockAddToSelection () {
|
||||
mockCount.addToSelection++;
|
||||
}
|
||||
/**
|
||||
* Increments add command to history count for mock test.
|
||||
* @returns {void}
|
||||
*/
|
||||
function mockAddCommandToHistory () {
|
||||
mockCount.addCommandToHistory++;
|
||||
}
|
||||
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
const sandbox = document.getElementById('sandbox');
|
||||
const svgroot = mockCreateSVGElement({
|
||||
element: 'svg',
|
||||
attr: {id: 'svgroot'}
|
||||
});
|
||||
sandbox.append(svgroot);
|
||||
|
||||
QUnit.module('svgedit.utilities', {
|
||||
beforeEach () {
|
||||
mockHistorySubCommands = [];
|
||||
mockCount.clearSelection = 0;
|
||||
mockCount.addToSelection = 0;
|
||||
mockCount.addCommandToHistory = 0;
|
||||
},
|
||||
afterEach () { /* */ }
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.utilities package', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
assert.ok(utilities);
|
||||
assert.ok(utilities.toXml);
|
||||
assert.equal(typeof utilities.toXml, typeof function () { /* */ });
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.utilities.toXml() function', function (assert) {
|
||||
assert.expect(6);
|
||||
const {toXml} = utilities;
|
||||
|
||||
assert.equal(toXml('a'), 'a');
|
||||
assert.equal(toXml('ABC_'), 'ABC_');
|
||||
assert.equal(toXml('PB&J'), 'PB&J');
|
||||
assert.equal(toXml('2 < 5'), '2 < 5');
|
||||
assert.equal(toXml('5 > 2'), '5 > 2');
|
||||
assert.equal(toXml('\'<&>"'), ''<&>"');
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.utilities.fromXml() function', function (assert) {
|
||||
assert.expect(6);
|
||||
const {fromXml} = utilities;
|
||||
|
||||
assert.equal(fromXml('a'), 'a');
|
||||
assert.equal(fromXml('ABC_'), 'ABC_');
|
||||
assert.equal(fromXml('PB&J'), 'PB&J');
|
||||
assert.equal(fromXml('2 < 5'), '2 < 5');
|
||||
assert.equal(fromXml('5 > 2'), '5 > 2');
|
||||
assert.equal(fromXml('<&>'), '<&>');
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.utilities.encode64() function', function (assert) {
|
||||
assert.expect(4);
|
||||
const {encode64} = utilities;
|
||||
|
||||
assert.equal(encode64('abcdef'), 'YWJjZGVm');
|
||||
assert.equal(encode64('12345'), 'MTIzNDU=');
|
||||
assert.equal(encode64(' '), 'IA==');
|
||||
assert.equal(encode64('`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?'), 'YH4hQCMkJV4mKigpLV89K1t7XX1cfDs6JyIsPC4+Lz8=');
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.utilities.decode64() function', function (assert) {
|
||||
assert.expect(4);
|
||||
const {decode64} = utilities;
|
||||
|
||||
assert.equal(decode64('YWJjZGVm'), 'abcdef');
|
||||
assert.equal(decode64('MTIzNDU='), '12345');
|
||||
assert.equal(decode64('IA=='), ' ');
|
||||
assert.equal(decode64('YH4hQCMkJV4mKigpLV89K1t7XX1cfDs6JyIsPC4+Lz8='), '`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?');
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.utilities.convertToXMLReferences() function', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const convert = utilities.convertToXMLReferences;
|
||||
assert.equal(convert('ABC'), 'ABC');
|
||||
// assert.equal(convert('<27>BC'), 'ÀBC');
|
||||
});
|
||||
|
||||
QUnit.test('Test svgedit.utilities.bboxToObj() function', function (assert) {
|
||||
assert.expect(5);
|
||||
const {bboxToObj} = utilities;
|
||||
|
||||
const rect = svg.createSVGRect();
|
||||
rect.x = 1;
|
||||
rect.y = 2;
|
||||
rect.width = 3;
|
||||
rect.height = 4;
|
||||
|
||||
const obj = bboxToObj(rect);
|
||||
assert.equal(typeof obj, typeof {});
|
||||
assert.equal(obj.x, 1);
|
||||
assert.equal(obj.y, 2);
|
||||
assert.equal(obj.width, 3);
|
||||
assert.equal(obj.height, 4);
|
||||
});
|
||||
|
||||
QUnit.test('Test getUrlFromAttr', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
assert.equal(utilities.getUrlFromAttr('url(#foo)'), '#foo');
|
||||
assert.equal(utilities.getUrlFromAttr('url(somefile.svg#foo)'), 'somefile.svg#foo');
|
||||
assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo');
|
||||
assert.equal(utilities.getUrlFromAttr('url("#foo")'), '#foo');
|
||||
});
|
||||
|
||||
QUnit.test('Test getPathBBox', function (assert) {
|
||||
if (browser.supportsPathBBox()) {
|
||||
assert.expect(0);
|
||||
return;
|
||||
}
|
||||
assert.expect(3);
|
||||
const doc = utilities.text2xml('<svg></svg>');
|
||||
const path = doc.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'm0,0l5,0l0,5l-5,0l0,-5z');
|
||||
const bb = utilities.getPathBBox(path);
|
||||
assert.equal(typeof bb, 'object', 'BBox returned object');
|
||||
assert.ok(bb.x && !isNaN(bb.x));
|
||||
assert.ok(bb.y && !isNaN(bb.y));
|
||||
});
|
||||
|
||||
QUnit.test('Test getPathDFromSegments', function (assert) {
|
||||
const {getPathDFromSegments} = utilities;
|
||||
|
||||
const doc = utilities.text2xml('<svg></svg>');
|
||||
const path = doc.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'm0,0l5,0l0,5l-5,0l0,-5z');
|
||||
let d = getPathDFromSegments([
|
||||
['M', [1, 2]],
|
||||
['Z', []]
|
||||
]);
|
||||
assert.equal(d, 'M1,2 Z');
|
||||
|
||||
d = getPathDFromSegments([
|
||||
['M', [1, 2]],
|
||||
['M', [3, 4]],
|
||||
['Z', []]
|
||||
]);
|
||||
assert.equal(d, 'M1,2 M3,4 Z');
|
||||
|
||||
d = getPathDFromSegments([
|
||||
['M', [1, 2]],
|
||||
['C', [3, 4, 5, 6]],
|
||||
['Z', []]
|
||||
]);
|
||||
assert.equal(d, 'M1,2 C3,4 5,6 Z');
|
||||
});
|
||||
|
||||
QUnit.test('Test getPathDFromElement', function (assert) {
|
||||
const {getPathDFromElement} = utilities;
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 Z'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M0,1 Z');
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M0,1 L5,1 L5,11 L0,11 L0,1 Z');
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'roundrect', x: '0', y: '1', rx: '2', ry: '3', width: '10', height: '11'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
const closeEnough = /M0,4 C0,2.3\d* 0.9\d*,1 2,1 L8,1 C9.0\d*,1 10,2.3\d* 10,4 L10,9 C10,10.6\d* 9.08675799086758,12 8,12 L2,12 C0.9\d*,12 0,10.6\d* 0,9 L0,4 Z/;
|
||||
assert.equal(closeEnough.test(getPathDFromElement(elem)), true);
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M0,1L5,6');
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'circle',
|
||||
attr: {id: 'circle', cx: '10', cy: '11', rx: '5', ry: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M10,11 C10,11 10,11 10,11 C10,11 10,11 10,11 C10,11 10,11 10,11 C10,11 10,11 10,11 Z');
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'polyline',
|
||||
attr: {id: 'polyline', points: '0,1 5,1 5,11 0,11'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
assert.equal(getPathDFromElement(elem), 'M0,1 5,1 5,11 0,11');
|
||||
elem.remove();
|
||||
|
||||
assert.equal(getPathDFromElement({tagName: 'something unknown'}), undefined);
|
||||
});
|
||||
|
||||
QUnit.test('Test getBBoxOfElementAsPath', function (assert) {
|
||||
/**
|
||||
* Wrap `utilities.getBBoxOfElementAsPath` to convert bbox to object for testing.
|
||||
* @type {module:utilities.getBBoxOfElementAsPath}
|
||||
*/
|
||||
function getBBoxOfElementAsPath (elem, addSVGElementFromJson, pathActions) {
|
||||
const bbox = utilities.getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions);
|
||||
return utilities.bboxToObj(bbox); // need this for assert.equal() to work.
|
||||
}
|
||||
|
||||
let elem = mockCreateSVGElement({
|
||||
element: 'path',
|
||||
attr: {id: 'path', d: 'M0,1 Z'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
let bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 0, height: 0});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 10});
|
||||
elem.remove();
|
||||
|
||||
elem = mockCreateSVGElement({
|
||||
element: 'line',
|
||||
attr: {id: 'line', x1: '0', y1: '1', x2: '5', y2: '6'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
bbox = getBBoxOfElementAsPath(elem, mockaddSVGElementFromJson, mockPathActions);
|
||||
assert.deepEqual(bbox, {x: 0, y: 1, width: 5, height: 5});
|
||||
elem.remove();
|
||||
|
||||
// TODO: test element with transform. Need resetOrientation above to be working or mock it.
|
||||
});
|
||||
|
||||
QUnit.test('Test convertToPath rect', function (assert) {
|
||||
const {convertToPath} = utilities;
|
||||
const attrs = {
|
||||
fill: 'red',
|
||||
stroke: 'white',
|
||||
'stroke-width': '1',
|
||||
visibility: 'hidden'
|
||||
};
|
||||
|
||||
const elem = mockCreateSVGElement({
|
||||
element: 'rect',
|
||||
attr: {id: 'rect', x: '0', y: '1', width: '5', height: '10'}
|
||||
});
|
||||
svgroot.append(elem);
|
||||
const path = convertToPath(elem, attrs, mockaddSVGElementFromJson, mockPathActions, mockClearSelection, mockAddToSelection, mockHistory, mockAddCommandToHistory);
|
||||
assert.equal(path.getAttribute('d'), 'M0,1 L5,1 L5,11 L0,11 L0,1 Z');
|
||||
assert.equal(path.getAttribute('visibilituy'), null);
|
||||
assert.equal(path.id, 'rect');
|
||||
assert.equal(path.parentNode, svgroot);
|
||||
assert.equal(elem.parentNode, null);
|
||||
assert.equal(mockHistorySubCommands.length, 2);
|
||||
assert.equal(mockCount.clearSelection, 1);
|
||||
assert.equal(mockCount.addToSelection, 1);
|
||||
assert.equal(mockCount.addCommandToHistory, 1);
|
||||
path.remove();
|
||||
});
|
||||
|
||||
QUnit.test('Test convertToPath unknown element', function (assert) {
|
||||
const {convertToPath} = utilities;
|
||||
const attrs = {
|
||||
fill: 'red',
|
||||
stroke: 'white',
|
||||
'stroke-width': '1',
|
||||
visibility: 'hidden'
|
||||
};
|
||||
|
||||
const elem = {
|
||||
tagName: 'something unknown',
|
||||
id: 'something-unknown',
|
||||
getAttribute (attr) { return ''; },
|
||||
parentNode: svgroot
|
||||
};
|
||||
const path = convertToPath(elem, attrs, mockaddSVGElementFromJson, mockPathActions, mockClearSelection, mockAddToSelection, mockHistory, mockAddCommandToHistory);
|
||||
assert.equal(path, null);
|
||||
assert.equal(elem.parentNode, svgroot);
|
||||
assert.equal(mockHistorySubCommands.length, 0);
|
||||
assert.equal(mockCount.clearSelection, 0);
|
||||
assert.equal(mockCount.addToSelection, 0);
|
||||
assert.equal(mockCount.addCommandToHistory, 0);
|
||||
});
|
||||
Reference in New Issue
Block a user