Yes, the whole point of using Canvas is to avoid the overhead of dealing with DOM elements.
I think you have the right idea. What I think you don’t know how to do is how to simulate mouse and keyboard events.
We implemented our own test system years ago. In our “Test” class we defined a number of handy methods for simulating mouse and keyboard input. Here’s our code:
NOTE: this is obsolete – use the Robot class defined in extensions/Robot.js
[code]
/**
- Simulate a mouse down event.
- @this {Test}
- @param {Point} pt a point in document coordinates.
-
@param {object=} eventprops an optional argument providing properties for the InputEvent.
*/
Test.prototype.mouseDown = function (pt, eventprops) {
var diagram = this.diagram;
var n = new go.InputEvent();
n.diagram = diagram;
n.documentPoint = pt;
n.viewPoint = diagram.transformDocToView(pt);
n.down = true;
if (eventprops) {
for (var p in eventprops) {
n[ p ] = eventprops[ p ];
}
}
diagram.lastInput = n;
diagram.firstInput = n.copy();
diagram.currentTool.doMouseDown();
};
/**
- Simulate a mouse move event.
- @this {Test}
- @param {Point} pt a point in document coordinates.
-
@param {object=} eventprops an optional argument providing properties for the InputEvent.
*/
Test.prototype.mouseMove = function (pt, eventprops) {
var diagram = this.diagram;
var n = new go.InputEvent();
n.diagram = diagram;
n.documentPoint = pt;
n.viewPoint = diagram.transformDocToView(pt);
if (eventprops) {
for (var p in eventprops) {
n[ p ] = eventprops[ p ];
}
}
diagram.lastInput = n;
diagram.currentTool.doMouseMove();
};
/**
- Simulate a mouse up event.
- @this {Test}
- @param {Point} pt a point in document coordinates.
-
@param {object=} eventprops an optional argument providing properties for the InputEvent.
*/
Test.prototype.mouseUp = function (pt, eventprops) {
var diagram = this.diagram;
var n = new go.InputEvent();
n.diagram = diagram;
n.documentPoint = pt;
n.viewPoint = diagram.transformDocToView(pt);
n.up = true;
if (diagram.firstInput.documentPoint.equals(pt)) n.clickCount = 1; // at least??
if (eventprops) {
for (var p in eventprops) {
n[ p ] = eventprops[ p ];
}
}
diagram.lastInput = n;
diagram.currentTool.doMouseUp();
};
/**
- Simulate a mouse wheel event.
- @this {Test}
- @param {number} delta non-zero turn
-
@param {object=} eventprops an optional argument providing properties for the InputEvent.
*/
Test.prototype.mouseWheel = function (delta, eventprops) {
var diagram = this.diagram;
var n = diagram.lastInput.copy();
n.diagram = diagram;
n.delta = delta;
if (eventprops) {
for (var p in eventprops) {
n[ p ] = eventprops[ p ];
}
}
diagram.lastInput = n;
diagram.currentTool.doMouseWheel();
};
/**
- Simulate a key down event.
- @this {Test}
- @param {string|number} keyorcode
-
@param {object=} eventprops an optional argument providing properties for the InputEvent.
*/
Test.prototype.keyDown = function (keyorcode, eventprops) {
var diagram = this.diagram;
var n = diagram.lastInput.copy();
n.diagram = diagram;
if (typeof(keyorcode) === ‘string’) {
n.key = keyorcode;
} else if (typeof(keyorcode) === ‘number’) {
n.key = String.fromCharCode(keyorcode);
}
n.down = true;
if (eventprops) {
for (var p in eventprops) {
n[ p ] = eventprops[ p ];
}
}
diagram.lastInput = n;
diagram.currentTool.doKeyDown();
};
/**
- Simulate a key up event.
- @this {Test}
- @param {string|number} keyorcode
-
@param {object=} eventprops an optional argument providing properties for the InputEvent.
*/
Test.prototype.keyUp = function (keyorcode, eventprops) {
var diagram = this.diagram;
var n = diagram.lastInput.copy();
n.diagram = diagram;
if (typeof(keyorcode) === ‘string’) {
n.key = keyorcode;
} else if (typeof(keyorcode) === ‘number’) {
n.key = String.fromCharCode(keyorcode);
}
n.up = true;
if (eventprops) {
for (var p in eventprops) {
n[ p ] = eventprops[ p ];
}
}
diagram.lastInput = n;
diagram.currentTool.doKeyUp();
};[/code]
This allows us to write tests that perform actions like:function(test) { // execute the test test.mouseDown(new go.Point(60, 10), { timestamp: 0 }); // below/right of Alpha location test.mouseMove(new go.Point(75, -25), { timestamp: 100 }); // between down and up points test.mouseUp(new go.Point(100, -50), { timestamp: 200 }); // mouse up point }
The test could then check:function(test) { // check the results test.assert(test.diagram.selection.count === 1, "should have selected one node"); var alpha = test.diagram.findNodeForKey("Alpha"); test.assert(test.diagram.selection.first() === alpha, "selected Node isn't Alpha"); test.assert(test.isApproxPoint(alpha.location, new go.Point(90, -60)), "didn't move Alpha to 90,-60"); }
So you could do similar things in your environment. The advantage of this is that everything is in document coordinates, so it is more resistant to irrelevant changes in the DOM.
HOWEVER:
However, in our tests we infrequently make use of mouse or keyboard events. Instead, most of our tests deal directly with the model and with Parts in the Diagram. This is what you are doing by calling Diagram.select, rather than pretending to click at a certain point in order to select a Node. You can still check that a Node is at a particular location (but remember not to compare floating point numbers with equality!). But be careful about checking for sizes, especially if the size is dependent on the measurement of TextBlocks, since those can be different on different platforms.