#931 Aligning code standard

This commit is contained in:
knsv
2019-09-12 12:54:59 -07:00
parent b3dac15d57
commit f2a6ba80b5
2 changed files with 272 additions and 225 deletions

View File

@@ -1,71 +1,87 @@
export const drawRect = function (elem, rectData) { export const drawRect = function(elem, rectData) {
const rectElem = elem.append('rect') const rectElem = elem.append('rect');
rectElem.attr('x', rectData.x) rectElem.attr('x', rectData.x);
rectElem.attr('y', rectData.y) rectElem.attr('y', rectData.y);
rectElem.attr('fill', rectData.fill) rectElem.attr('fill', rectData.fill);
rectElem.attr('stroke', rectData.stroke) rectElem.attr('stroke', rectData.stroke);
rectElem.attr('width', rectData.width) rectElem.attr('width', rectData.width);
rectElem.attr('height', rectData.height) rectElem.attr('height', rectData.height);
rectElem.attr('rx', rectData.rx) rectElem.attr('rx', rectData.rx);
rectElem.attr('ry', rectData.ry) rectElem.attr('ry', rectData.ry);
if (typeof rectData.class !== 'undefined') { if (typeof rectData.class !== 'undefined') {
rectElem.attr('class', rectData.class) rectElem.attr('class', rectData.class);
} }
return rectElem return rectElem;
} };
export const drawText = function (elem, textData, width) { export const drawText = function(elem, textData, width) {
// Remove and ignore br:s // Remove and ignore br:s
const nText = textData.text.replace(/<br\/?>/ig, ' ') const nText = textData.text.replace(/<br\/?>/gi, ' ');
const textElem = elem.append('text') const textElem = elem.append('text');
textElem.attr('x', textData.x) textElem.attr('x', textData.x);
textElem.attr('y', textData.y) textElem.attr('y', textData.y);
textElem.style('text-anchor', textData.anchor) textElem.style('text-anchor', textData.anchor);
textElem.attr('fill', textData.fill) textElem.attr('fill', textData.fill);
if (typeof textData.class !== 'undefined') { if (typeof textData.class !== 'undefined') {
textElem.attr('class', textData.class) textElem.attr('class', textData.class);
} }
const span = textElem.append('tspan') const span = textElem.append('tspan');
span.attr('x', textData.x + textData.textMargin * 2) span.attr('x', textData.x + textData.textMargin * 2);
span.attr('fill', textData.fill) span.attr('fill', textData.fill);
span.text(nText) span.text(nText);
return textElem return textElem;
} };
export const drawLabel = function (elem, txtObject) { export const drawLabel = function(elem, txtObject) {
function genPoints (x, y, width, height, cut) { function genPoints(x, y, width, height, cut) {
return x + ',' + y + ' ' + return (
(x + width) + ',' + y + ' ' + x +
(x + width) + ',' + (y + height - cut) + ' ' + ',' +
(x + width - cut * 1.2) + ',' + (y + height) + ' ' + y +
(x) + ',' + (y + height) ' ' +
(x + width) +
',' +
y +
' ' +
(x + width) +
',' +
(y + height - cut) +
' ' +
(x + width - cut * 1.2) +
',' +
(y + height) +
' ' +
x +
',' +
(y + height)
);
} }
const polygon = elem.append('polygon') const polygon = elem.append('polygon');
polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7)) polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7));
polygon.attr('class', 'labelBox') polygon.attr('class', 'labelBox');
txtObject.y = txtObject.y + txtObject.labelMargin txtObject.y = txtObject.y + txtObject.labelMargin;
txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin;
drawText(elem, txtObject) drawText(elem, txtObject);
} };
let actorCnt = -1 let actorCnt = -1;
/** /**
* Draws an actor in the diagram with the attaced line * Draws an actor in the diagram with the attaced line
* @param center - The center of the the actor * @param center - The center of the the actor
* @param pos The position if the actor in the liost of actors * @param pos The position if the actor in the liost of actors
* @param description The text in the box * @param description The text in the box
*/ */
export const drawActor = function (elem, left, verticalPos, description, conf) { export const drawActor = function(elem, left, verticalPos, description, conf) {
const center = left + (conf.width / 2) const center = left + conf.width / 2;
const g = elem.append('g') const g = elem.append('g');
if (verticalPos === 0) { if (verticalPos === 0) {
actorCnt++ actorCnt++;
g.append('line') g.append('line')
.attr('id', 'actor' + actorCnt) .attr('id', 'actor' + actorCnt)
.attr('x1', center) .attr('x1', center)
@@ -74,43 +90,51 @@ export const drawActor = function (elem, left, verticalPos, description, conf) {
.attr('y2', 2000) .attr('y2', 2000)
.attr('class', 'actor-line') .attr('class', 'actor-line')
.attr('stroke-width', '0.5px') .attr('stroke-width', '0.5px')
.attr('stroke', '#999') .attr('stroke', '#999');
} }
const rect = getNoteRect() const rect = getNoteRect();
rect.x = left rect.x = left;
rect.y = verticalPos rect.y = verticalPos;
rect.fill = '#eaeaea' rect.fill = '#eaeaea';
rect.width = conf.width rect.width = conf.width;
rect.height = conf.height rect.height = conf.height;
rect.class = 'actor' rect.class = 'actor';
rect.rx = 3 rect.rx = 3;
rect.ry = 3 rect.ry = 3;
drawRect(g, rect) drawRect(g, rect);
_drawTextCandidateFunc(conf)(description, g, _drawTextCandidateFunc(conf)(
rect.x, rect.y, rect.width, rect.height, { 'class': 'actor' }, conf) description,
} g,
rect.x,
rect.y,
rect.width,
rect.height,
{ class: 'actor' },
conf
);
};
export const anchorElement = function (elem) { export const anchorElement = function(elem) {
return elem.append('g') return elem.append('g');
} };
/** /**
* Draws an actor in the diagram with the attaced line * Draws an actor in the diagram with the attaced line
* @param elem - element to append activation rect * @param elem - element to append activation rect
* @param bounds - activation box bounds * @param bounds - activation box bounds
* @param verticalPos - precise y cooridnate of bottom activation box edge * @param verticalPos - precise y cooridnate of bottom activation box edge
*/ */
export const drawActivation = function (elem, bounds, verticalPos, conf, actorActivations) { export const drawActivation = function(elem, bounds, verticalPos, conf, actorActivations) {
const rect = getNoteRect() const rect = getNoteRect();
const g = bounds.anchored const g = bounds.anchored;
rect.x = bounds.startx rect.x = bounds.startx;
rect.y = bounds.starty rect.y = bounds.starty;
rect.class = 'activation' + (actorActivations % 3) // Will evaluate to 0, 1 or 2 rect.class = 'activation' + (actorActivations % 3); // Will evaluate to 0, 1 or 2
rect.width = bounds.stopx - bounds.startx rect.width = bounds.stopx - bounds.startx;
rect.height = verticalPos - bounds.starty rect.height = verticalPos - bounds.starty;
drawRect(g, rect) drawRect(g, rect);
} };
/** /**
* Draws an actor in the diagram with the attaced line * Draws an actor in the diagram with the attaced line
@@ -118,60 +142,61 @@ export const drawActivation = function (elem, bounds, verticalPos, conf, actorAc
* @param pos The position if the actor in the list of actors * @param pos The position if the actor in the list of actors
* @param description The text in the box * @param description The text in the box
*/ */
export const drawLoop = function (elem, bounds, labelText, conf) { export const drawLoop = function(elem, bounds, labelText, conf) {
const g = elem.append('g') const g = elem.append('g');
const drawLoopLine = function (startx, starty, stopx, stopy) { const drawLoopLine = function(startx, starty, stopx, stopy) {
return g.append('line') return g
.append('line')
.attr('x1', startx) .attr('x1', startx)
.attr('y1', starty) .attr('y1', starty)
.attr('x2', stopx) .attr('x2', stopx)
.attr('y2', stopy) .attr('y2', stopy)
.attr('class', 'loopLine') .attr('class', 'loopLine');
} };
drawLoopLine(bounds.startx, bounds.starty, bounds.stopx, bounds.starty) drawLoopLine(bounds.startx, bounds.starty, bounds.stopx, bounds.starty);
drawLoopLine(bounds.stopx, bounds.starty, bounds.stopx, bounds.stopy) drawLoopLine(bounds.stopx, bounds.starty, bounds.stopx, bounds.stopy);
drawLoopLine(bounds.startx, bounds.stopy, bounds.stopx, bounds.stopy) drawLoopLine(bounds.startx, bounds.stopy, bounds.stopx, bounds.stopy);
drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy) drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy);
if (typeof bounds.sections !== 'undefined') { if (typeof bounds.sections !== 'undefined') {
bounds.sections.forEach(function (item) { bounds.sections.forEach(function(item) {
drawLoopLine(bounds.startx, item, bounds.stopx, item).style('stroke-dasharray', '3, 3') drawLoopLine(bounds.startx, item, bounds.stopx, item).style('stroke-dasharray', '3, 3');
}) });
} }
let txt = getTextObj() let txt = getTextObj();
txt.text = labelText txt.text = labelText;
txt.x = bounds.startx txt.x = bounds.startx;
txt.y = bounds.starty txt.y = bounds.starty;
txt.labelMargin = 1.5 * 10 // This is the small box that says "loop" txt.labelMargin = 1.5 * 10; // This is the small box that says "loop"
txt.class = 'labelText' // Its size & position are fixed. txt.class = 'labelText'; // Its size & position are fixed.
drawLabel(g, txt) drawLabel(g, txt);
txt = getTextObj() txt = getTextObj();
txt.text = '[ ' + bounds.title + ' ]' txt.text = '[ ' + bounds.title + ' ]';
txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2 txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2;
txt.y = bounds.starty + 1.5 * conf.boxMargin txt.y = bounds.starty + 1.5 * conf.boxMargin;
txt.anchor = 'middle' txt.anchor = 'middle';
txt.class = 'loopText' txt.class = 'loopText';
drawText(g, txt) drawText(g, txt);
if (typeof bounds.sectionTitles !== 'undefined') { if (typeof bounds.sectionTitles !== 'undefined') {
bounds.sectionTitles.forEach(function (item, idx) { bounds.sectionTitles.forEach(function(item, idx) {
if (item !== '') { if (item !== '') {
txt.text = '[ ' + item + ' ]' txt.text = '[ ' + item + ' ]';
txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin;
drawText(g, txt) drawText(g, txt);
} }
}) });
} }
} };
/** /**
* Draws a background rectangle * Draws a background rectangle
* @param color - The fill color for the background * @param color - The fill color for the background
*/ */
export const drawBackgroundRect = function (elem, bounds) { export const drawBackgroundRect = function(elem, bounds) {
const rectElem = drawRect(elem, { const rectElem = drawRect(elem, {
x: bounds.startx, x: bounds.startx,
y: bounds.starty, y: bounds.starty,
@@ -179,14 +204,16 @@ export const drawBackgroundRect = function (elem, bounds) {
height: bounds.stopy - bounds.starty, height: bounds.stopy - bounds.starty,
fill: bounds.fill, fill: bounds.fill,
class: 'rect' class: 'rect'
}) });
rectElem.lower() rectElem.lower();
} };
/** /**
* Setup arrow head and define the marker. The result is appended to the svg. * Setup arrow head and define the marker. The result is appended to the svg.
*/ */
export const insertArrowHead = function (elem) { export const insertArrowHead = function(elem) {
elem.append('defs').append('marker') elem
.append('defs')
.append('marker')
.attr('id', 'arrowhead') .attr('id', 'arrowhead')
.attr('refX', 5) .attr('refX', 5)
.attr('refY', 2) .attr('refY', 2)
@@ -194,13 +221,15 @@ export const insertArrowHead = function (elem) {
.attr('markerHeight', 4) .attr('markerHeight', 4)
.attr('orient', 'auto') .attr('orient', 'auto')
.append('path') .append('path')
.attr('d', 'M 0,0 V 4 L6,2 Z') // this is actual shape for arrowhead .attr('d', 'M 0,0 V 4 L6,2 Z'); // this is actual shape for arrowhead
} };
/** /**
* Setup node number. The result is appended to the svg. * Setup node number. The result is appended to the svg.
*/ */
export const insertSequenceNumber = function (elem) { export const insertSequenceNumber = function(elem) {
elem.append('defs').append('marker') elem
.append('defs')
.append('marker')
.attr('id', 'sequencenumber') .attr('id', 'sequencenumber')
.attr('refX', 15) .attr('refX', 15)
.attr('refY', 15) .attr('refY', 15)
@@ -210,45 +239,48 @@ export const insertSequenceNumber = function (elem) {
.append('circle') .append('circle')
.attr('cx', 15) .attr('cx', 15)
.attr('cy', 15) .attr('cy', 15)
.attr('r', 6) .attr('r', 6);
// .style("fill", '#f00'); // .style("fill", '#f00');
} };
/** /**
* Setup arrow head and define the marker. The result is appended to the svg. * Setup arrow head and define the marker. The result is appended to the svg.
*/ */
export const insertArrowCrossHead = function (elem) { export const insertArrowCrossHead = function(elem) {
const defs = elem.append('defs') const defs = elem.append('defs');
const marker = defs.append('marker') const marker = defs
.append('marker')
.attr('id', 'crosshead') .attr('id', 'crosshead')
.attr('markerWidth', 15) .attr('markerWidth', 15)
.attr('markerHeight', 8) .attr('markerHeight', 8)
.attr('orient', 'auto') .attr('orient', 'auto')
.attr('refX', 16) .attr('refX', 16)
.attr('refY', 4) .attr('refY', 4);
// The arrow // The arrow
marker.append('path') marker
.append('path')
.attr('fill', 'black') .attr('fill', 'black')
.attr('stroke', '#000000') .attr('stroke', '#000000')
.style('stroke-dasharray', ('0, 0')) .style('stroke-dasharray', '0, 0')
.attr('stroke-width', '1px') .attr('stroke-width', '1px')
.attr('d', 'M 9,2 V 6 L16,4 Z') .attr('d', 'M 9,2 V 6 L16,4 Z');
// The cross // The cross
marker.append('path') marker
.append('path')
.attr('fill', 'none') .attr('fill', 'none')
.attr('stroke', '#000000') .attr('stroke', '#000000')
.style('stroke-dasharray', ('0, 0')) .style('stroke-dasharray', '0, 0')
.attr('stroke-width', '1px') .attr('stroke-width', '1px')
.attr('d', 'M 0,1 L 6,7 M 6,1 L 0,7') .attr('d', 'M 0,1 L 6,7 M 6,1 L 0,7');
// this is actual shape for arrowhead // this is actual shape for arrowhead
} };
export const getTextObj = function () { export const getTextObj = function() {
const txt = { const txt = {
x: 0, x: 0,
y: 0, y: 0,
'fill': undefined, fill: undefined,
'text-anchor': 'start', 'text-anchor': 'start',
style: '#666', style: '#666',
width: 100, width: 100,
@@ -256,11 +288,11 @@ export const getTextObj = function () {
textMargin: 0, textMargin: 0,
rx: 0, rx: 0,
ry: 0 ry: 0
} };
return txt return txt;
} };
export const getNoteRect = function () { export const getNoteRect = function() {
const rect = { const rect = {
x: 0, x: 0,
y: 0, y: 0,
@@ -271,72 +303,87 @@ export const getNoteRect = function () {
height: 100, height: 100,
rx: 0, rx: 0,
ry: 0 ry: 0
} };
return rect return rect;
} };
const _drawTextCandidateFunc = (function () { const _drawTextCandidateFunc = (function() {
function byText (content, g, x, y, width, height, textAttrs) { function byText(content, g, x, y, width, height, textAttrs) {
const text = g.append('text') const text = g
.attr('x', x + width / 2).attr('y', y + height / 2 + 5) .append('text')
.attr('x', x + width / 2)
.attr('y', y + height / 2 + 5)
.style('text-anchor', 'middle') .style('text-anchor', 'middle')
.text(content) .text(content);
_setTextAttrs(text, textAttrs) _setTextAttrs(text, textAttrs);
} }
function byTspan (content, g, x, y, width, height, textAttrs, conf) { function byTspan(content, g, x, y, width, height, textAttrs, conf) {
const { actorFontSize, actorFontFamily } = conf const { actorFontSize, actorFontFamily } = conf;
const lines = content.split(/<br\/?>/ig) const lines = content.split(/<br\/?>/gi);
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const dy = (i * actorFontSize) - (actorFontSize * (lines.length - 1) / 2) const dy = i * actorFontSize - (actorFontSize * (lines.length - 1)) / 2;
const text = g.append('text') const text = g
.attr('x', x + width / 2).attr('y', y) .append('text')
.attr('x', x + width / 2)
.attr('y', y)
.style('text-anchor', 'middle') .style('text-anchor', 'middle')
.style('font-size', actorFontSize) .style('font-size', actorFontSize)
.style('font-family', actorFontFamily) .style('font-family', actorFontFamily);
text.append('tspan') text
.attr('x', x + width / 2).attr('dy', dy) .append('tspan')
.text(lines[i]) .attr('x', x + width / 2)
.attr('dy', dy)
.text(lines[i]);
text.attr('y', y + height / 2.0) text
.attr('y', y + height / 2.0)
.attr('dominant-baseline', 'central') .attr('dominant-baseline', 'central')
.attr('alignment-baseline', 'central') .attr('alignment-baseline', 'central');
_setTextAttrs(text, textAttrs) _setTextAttrs(text, textAttrs);
} }
} }
function byFo (content, g, x, y, width, height, textAttrs, conf) { function byFo(content, g, x, y, width, height, textAttrs, conf) {
const s = g.append('switch') const s = g.append('switch');
const f = s.append('foreignObject') const f = s
.attr('x', x).attr('y', y) .append('foreignObject')
.attr('width', width).attr('height', height) .attr('x', x)
.attr('y', y)
.attr('width', width)
.attr('height', height);
const text = f.append('div').style('display', 'table') const text = f
.style('height', '100%').style('width', '100%') .append('div')
.style('display', 'table')
.style('height', '100%')
.style('width', '100%');
text.append('div').style('display', 'table-cell') text
.style('text-align', 'center').style('vertical-align', 'middle') .append('div')
.text(content) .style('display', 'table-cell')
.style('text-align', 'center')
.style('vertical-align', 'middle')
.text(content);
byTspan(content, s, x, y, width, height, textAttrs, conf) byTspan(content, s, x, y, width, height, textAttrs, conf);
_setTextAttrs(text, textAttrs) _setTextAttrs(text, textAttrs);
} }
function _setTextAttrs (toText, fromTextAttrsDict) { function _setTextAttrs(toText, fromTextAttrsDict) {
for (const key in fromTextAttrsDict) { for (const key in fromTextAttrsDict) {
if (fromTextAttrsDict.hasOwnProperty(key)) { if (fromTextAttrsDict.hasOwnProperty(key)) {
toText.attr(key, fromTextAttrsDict[key]) toText.attr(key, fromTextAttrsDict[key]);
} }
} }
} }
return function (conf) { return function(conf) {
return conf.textPlacement === 'fo' ? byFo : ( return conf.textPlacement === 'fo' ? byFo : conf.textPlacement === 'old' ? byText : byTspan;
conf.textPlacement === 'old' ? byText : byTspan) };
} })();
})()
export default { export default {
drawRect, drawRect,
@@ -352,4 +399,4 @@ export default {
insertArrowCrossHead, insertArrowCrossHead,
getTextObj, getTextObj,
getNoteRect getNoteRect
} };

View File

@@ -1,11 +1,11 @@
/* eslint-env jasmine */ /* eslint-env jasmine */
const svgDraw = require('./svgDraw') const svgDraw = require('./svgDraw');
const { MockD3 } = require('d3') const { MockD3 } = require('d3');
describe('svgDraw', function () { describe('svgDraw', function() {
describe('drawRect', function () { describe('drawRect', function() {
it('it should append a rectangle', function () { it('it should append a rectangle', function() {
const svg = MockD3('svg') const svg = MockD3('svg');
svgDraw.drawRect(svg, { svgDraw.drawRect(svg, {
x: 10, x: 10,
y: 10, y: 10,
@@ -16,22 +16,22 @@ describe('svgDraw', function () {
rx: '10', rx: '10',
ry: '10', ry: '10',
class: 'unitTestRectangleClass' class: 'unitTestRectangleClass'
}) });
expect(svg.__children.length).toBe(1) expect(svg.__children.length).toBe(1);
const rect = svg.__children[0] const rect = svg.__children[0];
expect(rect.__name).toBe('rect') expect(rect.__name).toBe('rect');
expect(rect.attr).toHaveBeenCalledWith('x', 10) expect(rect.attr).toHaveBeenCalledWith('x', 10);
expect(rect.attr).toHaveBeenCalledWith('y', 10) expect(rect.attr).toHaveBeenCalledWith('y', 10);
expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc') expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc');
expect(rect.attr).toHaveBeenCalledWith('stroke', 'red') expect(rect.attr).toHaveBeenCalledWith('stroke', 'red');
expect(rect.attr).toHaveBeenCalledWith('width', '20') expect(rect.attr).toHaveBeenCalledWith('width', '20');
expect(rect.attr).toHaveBeenCalledWith('height', '20') expect(rect.attr).toHaveBeenCalledWith('height', '20');
expect(rect.attr).toHaveBeenCalledWith('rx', '10') expect(rect.attr).toHaveBeenCalledWith('rx', '10');
expect(rect.attr).toHaveBeenCalledWith('ry', '10') expect(rect.attr).toHaveBeenCalledWith('ry', '10');
expect(rect.attr).toHaveBeenCalledWith('class', 'unitTestRectangleClass') expect(rect.attr).toHaveBeenCalledWith('class', 'unitTestRectangleClass');
}) });
it('it should not add the class attribute if a class isn`t provided', () => { it('it should not add the class attribute if a class isn`t provided', () => {
const svg = MockD3('svg') const svg = MockD3('svg');
svgDraw.drawRect(svg, { svgDraw.drawRect(svg, {
x: 10, x: 10,
y: 10, y: 10,
@@ -41,17 +41,17 @@ describe('svgDraw', function () {
height: '20', height: '20',
rx: '10', rx: '10',
ry: '10' ry: '10'
}) });
expect(svg.__children.length).toBe(1) expect(svg.__children.length).toBe(1);
const rect = svg.__children[0] const rect = svg.__children[0];
expect(rect.__name).toBe('rect') expect(rect.__name).toBe('rect');
expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc') expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc');
expect(rect.attr).not.toHaveBeenCalledWith('class', expect.anything()) expect(rect.attr).not.toHaveBeenCalledWith('class', expect.anything());
}) });
}) });
describe('drawBackgroundRect', function () { describe('drawBackgroundRect', function() {
it('it should append a rect before the previous element within a given bound', function () { it('it should append a rect before the previous element within a given bound', function() {
const svg = MockD3('svg') const svg = MockD3('svg');
const boundingRect = { const boundingRect = {
startx: 50, startx: 50,
starty: 200, starty: 200,
@@ -59,18 +59,18 @@ describe('svgDraw', function () {
stopy: 260, stopy: 260,
title: undefined, title: undefined,
fill: '#ccc' fill: '#ccc'
} };
svgDraw.drawBackgroundRect(svg, boundingRect) svgDraw.drawBackgroundRect(svg, boundingRect);
expect(svg.__children.length).toBe(1) expect(svg.__children.length).toBe(1);
const rect = svg.__children[0] const rect = svg.__children[0];
expect(rect.__name).toBe('rect') expect(rect.__name).toBe('rect');
expect(rect.attr).toHaveBeenCalledWith('x', 50) expect(rect.attr).toHaveBeenCalledWith('x', 50);
expect(rect.attr).toHaveBeenCalledWith('y', 200) expect(rect.attr).toHaveBeenCalledWith('y', 200);
expect(rect.attr).toHaveBeenCalledWith('width', 100) expect(rect.attr).toHaveBeenCalledWith('width', 100);
expect(rect.attr).toHaveBeenCalledWith('height', 60) expect(rect.attr).toHaveBeenCalledWith('height', 60);
expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc') expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc');
expect(rect.attr).toHaveBeenCalledWith('class', 'rect') expect(rect.attr).toHaveBeenCalledWith('class', 'rect');
expect(rect.lower).toHaveBeenCalled() expect(rect.lower).toHaveBeenCalled();
}) });
}) });
}) });