diff --git a/tests/mocha/.eslintrc.json b/tests/mocha/.eslintrc.json
index 70e611cad..838abc187 100644
--- a/tests/mocha/.eslintrc.json
+++ b/tests/mocha/.eslintrc.json
@@ -8,6 +8,9 @@
"chai": false,
"sinon": false,
"assertArrayEquals": true,
+ "assertEventEquals": true,
+ "assertLastCallEventArgEquals": true,
+ "assertNthCallEventArgEquals": true,
"assertVariableValues": true,
"captureWarnings": true,
"createTestBlock": true,
@@ -15,6 +18,8 @@
"defineStackBlock": true,
"defineStatementBlock": true,
"createEventsFireStub": true,
+ "createFireChangeListenerSpy": true,
+ "createGenUidStubWithReturns": true,
"testAWorkspace": true,
"testHelpers" : true,
"getSimpleJSON": true,
diff --git a/tests/mocha/comment_test.js b/tests/mocha/comment_test.js
index a24f68c95..ace22c603 100644
--- a/tests/mocha/comment_test.js
+++ b/tests/mocha/comment_test.js
@@ -31,19 +31,12 @@ suite('Comments', function() {
suite('Visibility and Editability', function() {
setup(function() {
this.comment.setText('test text');
- this.eventSpy = sinon.stub(Blockly.Events, 'fire');
+ this.eventsStub = createEventsFireStub();
});
teardown(function() {
- this.eventSpy.restore();
+ sinon.restore();
});
- function assertEvent(eventSpy, type, element, oldValue, newValue) {
- var calls = eventSpy.getCalls();
- var event = calls[calls.length - 1].args[0];
- chai.assert.equal(event.type, type);
- chai.assert.equal(event.element, element);
- chai.assert.equal(event.oldValue, oldValue);
- chai.assert.equal(event.newValue, newValue);
- }
+
function assertEditable(comment) {
chai.assert.isNotOk(comment.paragraphElement_);
chai.assert.isOk(comment.textarea_);
@@ -59,28 +52,32 @@ suite('Comments', function() {
this.comment.setVisible(true);
chai.assert.isTrue(this.comment.isVisible());
assertEditable(this.comment);
- assertEvent(this.eventSpy, Blockly.Events.UI, 'commentOpen', false, true);
+ assertLastCallEventArgEquals(
+ this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
+ {element: 'commentOpen', oldValue: false, newValue: true});
});
test('Not Editable', function() {
- var editableStub = sinon.stub(this.block, 'isEditable').returns(false);
+ sinon.stub(this.block, 'isEditable').returns(false);
this.comment.setVisible(true);
chai.assert.isTrue(this.comment.isVisible());
assertNotEditable(this.comment);
- assertEvent(this.eventSpy, Blockly.Events.UI, 'commentOpen', false, true);
-
- editableStub.restore();
+ assertLastCallEventArgEquals(
+ this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
+ {element: 'commentOpen', oldValue: false, newValue: true});
});
test('Editable -> Not Editable', function() {
this.comment.setVisible(true);
- var editableStub = sinon.stub(this.block, 'isEditable').returns(false);
+ sinon.stub(this.block, 'isEditable').returns(false);
this.comment.updateEditable();
chai.assert.isTrue(this.comment.isVisible());
- assertNotEditable(this.comment);
- assertEvent(this.eventSpy, Blockly.Events.UI, 'commentOpen', false, true);
-
- editableStub.restore();
+ assertNotEditable(this.comment);assertLastCallEventArgEquals(
+ this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
+ {element: 'commentOpen', oldValue: false, newValue: true});
+ assertLastCallEventArgEquals(
+ this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
+ {element: 'commentOpen', oldValue: false, newValue: true});
});
test('Not Editable -> Editable', function() {
var editableStub = sinon.stub(this.block, 'isEditable').returns(false);
@@ -90,12 +87,15 @@ suite('Comments', function() {
this.comment.updateEditable();
chai.assert.isTrue(this.comment.isVisible());
assertEditable(this.comment);
- assertEvent(this.eventSpy, Blockly.Events.UI, 'commentOpen', false, true);
-
- editableStub.restore();
+ assertLastCallEventArgEquals(
+ this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
+ {element: 'commentOpen', oldValue: false, newValue: true});
});
});
suite('Set/Get Bubble Size', function() {
+ teardown(function() {
+ sinon.restore();
+ });
function assertBubbleSize(comment, height, width) {
var size = comment.getBubbleSize();
chai.assert.equal(size.height, height);
@@ -111,12 +111,10 @@ suite('Comments', function() {
assertBubbleSizeDefault(this.comment);
this.comment.setBubbleSize(100, 100);
assertBubbleSize(this.comment, 100, 100);
- chai.assert(bubbleSizeSpy.calledOnce);
+ sinon.assert.calledOnce(bubbleSizeSpy);
this.comment.setVisible(false);
assertBubbleSize(this.comment, 100, 100);
-
- bubbleSizeSpy.restore();
});
test('Set Size While Invisible', function() {
assertBubbleSizeDefault(this.comment);
diff --git a/tests/mocha/event_test.js b/tests/mocha/event_test.js
index 6cf675875..c7d0bbcd5 100644
--- a/tests/mocha/event_test.js
+++ b/tests/mocha/event_test.js
@@ -34,30 +34,6 @@ suite('Events', function() {
Blockly.Events.disabled_ = 0;
});
- function checkExactEventValues(event, values) {
- var keys = Object.keys(values);
- for (var i = 0; i < keys.length; i++) {
- var field = keys[i];
- chai.assert.equal(values[field], event[field]);
- }
- }
-
- function checkCreateEventValues(event, block, ids, type) {
- var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block));
- var result_xml = Blockly.Xml.domToText(event.xml);
- chai.assert.equal(expected_xml, result_xml);
- chai.assert.deepEqual(ids, event.ids);
- chai.assert.equal(type, event.type);
- }
-
- function checkDeleteEventValues(event, block, ids, type) {
- var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block));
- var result_xml = Blockly.Xml.domToText(event.oldXml);
- chai.assert.equal(expected_xml, result_xml);
- chai.assert.deepEqual(ids, event.ids);
- chai.assert.equal(type, event.type);
- }
-
function createSimpleTestBlock(workspace, opt_prototypeName) {
// Disable events while constructing the block: this is a test of the
// Blockly.Event constructors, not the block constructor.s
@@ -71,84 +47,107 @@ suite('Events', function() {
suite('Constructors', function() {
test('Abstract', function() {
var event = new Blockly.Events.Abstract();
- chai.assert.isUndefined(event.blockId);
- chai.assert.isUndefined(event.workspaceId);
- chai.assert.isUndefined(event.varId);
- checkExactEventValues(event, {'group': '', 'recordUndo': true});
+ assertEventEquals(event, undefined, undefined, undefined, {
+ 'recordUndo': true,
+ 'group': ''
+ });
});
test('UI event without block', function() {
- Blockly.Events.setGroup('testGroup');
+ var TEST_GROUP_ID = 'testGroup';
+ Blockly.Events.setGroup(TEST_GROUP_ID);
var event = new Blockly.Events.Ui(null, 'foo', 'bar', 'baz');
- checkExactEventValues(event,
- {
- 'blockId': null,
- 'workspaceId': null,
- 'type': 'ui',
- 'oldValue': 'bar',
- 'newValue': 'baz',
- 'element': 'foo',
- 'recordUndo': false,
- 'group': 'testGroup'
- });
+ assertEventEquals(event, Blockly.Events.UI, null, null, {
+ 'element': 'foo',
+ 'oldValue': 'bar',
+ 'newValue': 'baz',
+ 'recordUndo': false,
+ 'group': TEST_GROUP_ID
+ });
});
suite('With simple blocks', function() {
setup(function() {
- this.FAKE_ID = 'hedgehog';
- sinon.stub(Blockly.utils, "genUid").returns(this.FAKE_ID);
+ this.TEST_BLOCK_ID = 'test_block_id';
+ this.TEST_PARENT_ID = 'parent';
+ // genUid is expected to be called either once or twice in this suite.
+ this.genUidStub = createGenUidStubWithReturns(
+ [this.TEST_BLOCK_ID, this.TEST_PARENT_ID]);
this.block = createSimpleTestBlock(this.workspace);
- sinon.restore();
});
-
teardown(function() {
+ sinon.restore();
});
test('Block base', function() {
var event = new Blockly.Events.BlockBase(this.block);
- chai.assert.isUndefined(event.varId);
- checkExactEventValues(event,
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, undefined,
+ this.workspace.id, this.TEST_BLOCK_ID,
{
- 'blockId': this.FAKE_ID,
- 'workspaceId': this.workspace.id,
+ 'varId': undefined,
+ 'recordUndo': true,
'group': '',
- 'recordUndo': true
});
});
test('Create', function() {
var event = new Blockly.Events.Create(this.block);
- checkCreateEventValues(event, this.block, [this.FAKE_ID], 'create');
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.CREATE,
+ this.workspace.id, this.TEST_BLOCK_ID,
+ {
+ 'recordUndo': true,
+ 'group': '',
+ });
});
test('Block create', function() {
var event = new Blockly.Events.BlockCreate(this.block);
- checkCreateEventValues(event, this.block, [this.FAKE_ID], 'create');
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.CREATE,
+ this.workspace.id, this.TEST_BLOCK_ID,
+ {
+ 'recordUndo': true,
+ 'group': '',
+ });
});
test('Delete', function() {
var event = new Blockly.Events.Delete(this.block);
- checkDeleteEventValues(event, this.block, [this.FAKE_ID], 'delete');
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.DELETE,
+ this.workspace.id, this.TEST_BLOCK_ID,
+ {
+ 'recordUndo': true,
+ 'group': '',
+ });
});
test('Block delete', function() {
var event = new Blockly.Events.BlockDelete(this.block);
- checkDeleteEventValues(event, this.block, [this.FAKE_ID], 'delete');
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.DELETE,
+ this.workspace.id, this.TEST_BLOCK_ID,
+ {
+ 'recordUndo': true,
+ 'group': '',
+ });
});
test('UI event with block', function() {
- Blockly.Events.setGroup('testGroup');
+ var TEST_GROUP_ID = 'testGroup';
+ Blockly.Events.setGroup(TEST_GROUP_ID);
var event = new Blockly.Events.Ui(this.block, 'foo', 'bar', 'baz');
- checkExactEventValues(event,
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.UI, this.workspace.id,
+ this.TEST_BLOCK_ID,
{
- 'blockId': this.FAKE_ID,
- 'workspaceId': this.workspace.id,
- 'type': 'ui',
+ 'element': 'foo',
'oldValue': 'bar',
'newValue': 'baz',
- 'element': 'foo',
'recordUndo': false,
- 'group': 'testGroup'
+ 'group': TEST_GROUP_ID
});
});
@@ -158,8 +157,15 @@ suite('Events', function() {
this.block.xy_ = coordinate;
var event = new Blockly.Events.Move(this.block);
- checkExactEventValues(event,
- {'oldCoordinate': coordinate, 'type': 'move'});
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
+ this.TEST_BLOCK_ID, {
+ 'oldParentId': undefined,
+ 'oldInputName': undefined,
+ 'oldCoordinate': coordinate,
+ 'recordUndo': true,
+ 'group': ''
+ });
});
test('Block move by coordinate', function() {
@@ -167,36 +173,54 @@ suite('Events', function() {
this.block.xy_ = coordinate;
var event = new Blockly.Events.BlockMove(this.block);
- checkExactEventValues(event,
- {'oldCoordinate': coordinate, 'type': 'move'});
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
+ this.TEST_BLOCK_ID, {
+ 'oldParentId': undefined,
+ 'oldInputName': undefined,
+ 'oldCoordinate': coordinate,
+ 'recordUndo': true,
+ 'group': ''
+ });
});
suite('Move by parent', function() {
setup(function() {
- sinon.stub(Blockly.utils, "genUid").returns("parent");
this.parentBlock = createSimpleTestBlock(this.workspace);
- sinon.restore();
this.block.parentBlock_ = this.parentBlock;
this.block.xy_ = new Blockly.utils.Coordinate(3, 4);
});
-
teardown(function() {
+ // This needs to be cleared, otherwise workspace.dispose will fail.
this.block.parentBlock_ = null;
});
test('Move by parent', function() {
- // Expect the oldParentId to be set but not the oldCoordinate to be set.
var event = new Blockly.Events.Move(this.block);
- checkExactEventValues(event, {'oldCoordinate': undefined,
- 'oldParentId': 'parent', 'type': 'move'});
+ sinon.assert.calledTwice(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
+ this.TEST_BLOCK_ID, {
+ 'oldParentId': this.TEST_PARENT_ID,
+ 'oldInputName': undefined,
+ 'oldCoordinate': undefined,
+ 'recordUndo': true,
+ 'group': ''
+ });
});
test('Block move by parent', function() {
- // Expect the oldParentId to be set but not the oldCoordinate to be set.
var event = new Blockly.Events.BlockMove(this.block);
- checkExactEventValues(event, {'oldCoordinate': undefined,
- 'oldParentId': 'parent', 'type': 'move'});
+ sinon.assert.calledTwice(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
+ this.TEST_BLOCK_ID,
+ {
+ 'oldParentId': this.TEST_PARENT_ID,
+ 'oldInputName': undefined,
+ 'oldCoordinate': undefined,
+ 'recordUndo': true,
+ 'group': ''
+ });
});
});
});
@@ -204,21 +228,44 @@ suite('Events', function() {
suite('With variable getter blocks', function() {
setup(function() {
- this.block = createSimpleTestBlock(this.workspace, 'field_variable_test_block');
+ this.genUidStub = createGenUidStubWithReturns(this.TEST_BLOCK_ID);
+ this.block =
+ createSimpleTestBlock(this.workspace, 'field_variable_test_block');
+ });
+ teardown(function() {
+ sinon.restore();
});
test('Change', function() {
- var event =
- new Blockly.Events.Change(this.block, 'field', 'VAR', 'id1', 'id2');
- checkExactEventValues(event, {'element': 'field', 'name': 'VAR',
- 'oldValue': 'id1', 'newValue': 'id2', 'type': 'change'});
+ var event = new Blockly.Events.Change(
+ this.block, 'field', 'VAR', 'id1', 'id2');
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.CHANGE, this.workspace.id,
+ this.TEST_BLOCK_ID,
+ {
+ 'element': 'field',
+ 'name': 'VAR',
+ 'oldValue': 'id1',
+ 'newValue': 'id2',
+ 'recordUndo': true,
+ 'group': ''
+ });
});
test('Block change', function() {
var event = new Blockly.Events.BlockChange(
this.block, 'field', 'VAR', 'id1', 'id2');
- checkExactEventValues(event, {'element': 'field', 'name': 'VAR',
- 'oldValue': 'id1', 'newValue': 'id2', 'type': 'change'});
+ sinon.assert.calledOnce(this.genUidStub);
+ assertEventEquals(event, Blockly.Events.CHANGE, this.workspace.id,
+ this.TEST_BLOCK_ID,
+ {
+ 'element': 'field',
+ 'name': 'VAR',
+ 'oldValue': 'id1',
+ 'newValue': 'id2',
+ 'recordUndo': true,
+ 'group': ''
+ });
});
});
});
@@ -247,27 +294,50 @@ suite('Events', function() {
suite('Constructors', function() {
test('Var base', function() {
var event = new Blockly.Events.VarBase(this.variable);
- chai.assert.isUndefined(event.blockId);
- checkExactEventValues(event, {'varId': 'id1',
- 'workspaceId': this.workspace.id, 'group': '', 'recordUndo': true});
+ assertEventEquals(event, undefined, this.workspace.id, undefined, {
+ 'varId': 'id1',
+ 'recordUndo': true,
+ 'group': ''
+ });
});
test('Var create', function() {
var event = new Blockly.Events.VarCreate(this.variable);
- checkExactEventValues(event, {'varName': 'name1', 'varType': 'type1',
- 'type': 'var_create'});
+ assertEventEquals(event, Blockly.Events.VAR_CREATE, this.workspace.id,
+ undefined,
+ {
+ 'varId': 'id1',
+ 'varType': 'type1',
+ 'varName': 'name1',
+ 'recordUndo': true,
+ 'group': ''
+ });
});
test('Var delete', function() {
var event = new Blockly.Events.VarDelete(this.variable);
- checkExactEventValues(event, {'varName': 'name1', 'varType': 'type1',
- 'varId':'id1', 'type': 'var_delete'});
+ assertEventEquals(event, Blockly.Events.VAR_DELETE, this.workspace.id,
+ undefined,
+ {
+ 'varId': 'id1',
+ 'varType': 'type1',
+ 'varName': 'name1',
+ 'recordUndo': true,
+ 'group': ''
+ });
});
test('Var rename', function() {
var event = new Blockly.Events.VarRename(this.variable, 'name2');
- checkExactEventValues(event, {'varId': 'id1', 'oldName': 'name1',
- 'newName': 'name2', 'type': 'var_rename'});
+ assertEventEquals(event, Blockly.Events.VAR_RENAME, this.workspace.id,
+ undefined,
+ {
+ 'varId': 'id1',
+ 'oldName': 'name1',
+ 'newName': 'name2',
+ 'recordUndo': true,
+ 'group': ''
+ });
});
});
@@ -378,7 +448,6 @@ suite('Events', function() {
});
suite('Filters', function() {
-
function addMoveEvent(events, block, newX, newY) {
events.push(new Blockly.Events.BlockMove(block));
block.xy_ = new Blockly.utils.Coordinate(newX, newY);
@@ -556,93 +625,113 @@ suite('Events', function() {
suite('Firing', function() {
setup(function() {
- createEventsFireStub();
+ this.eventsStub = createEventsFireStub();
+ this.changeListenerSpy = createFireChangeListenerSpy(this.workspace);
});
teardown(function() {
sinon.restore();
});
- test('Block dispose triggers BlockDelete', function() {
+ test('Block dispose triggers Delete', function() {
try {
var toolbox = document.getElementById('toolbox-categories');
var workspaceSvg = Blockly.inject('blocklyDiv', {toolbox: toolbox});
- Blockly.Events.fire.firedEvents_ = [];
var block = workspaceSvg.newBlock('');
block.initSvg();
block.setCommentText('test comment');
+ var expectedOldXml = Blockly.Xml.blockToDomWithXY(block);
+ var expectedId = block.id;
- var event = new Blockly.Events.BlockDelete(block);
-
- workspaceSvg.clearUndo();
block.dispose();
- var firedEvents = workspaceSvg.undoStack_;
- chai.assert.equal(
- Blockly.Xml.domToText(firedEvents[0].oldXml),
- Blockly.Xml.domToText(event.oldXml),
- 'Delete event created by dispose');
+ assertLastCallEventArgEquals(
+ this.eventsStub, Blockly.Events.DELETE, workspaceSvg.id,
+ expectedId, {oldXml: expectedOldXml});
} finally {
workspaceSvg.dispose();
}
});
test('New block new var', function() {
+ var TEST_BLOCK_ID = 'test_block_id';
+ var TEST_GROUP_ID = 'test_group_id';
+ var TEST_VAR_ID = 'test_var_id';
+ var genUidStub = createGenUidStubWithReturns(
+ [TEST_BLOCK_ID, TEST_GROUP_ID, TEST_VAR_ID]);
+ var _ = this.workspace.newBlock('field_variable_test_block');
+ var TEST_VAR_NAME = 'item'; // As defined in block's json.
+
// Expect three calls to genUid: one to set the block's ID, one for the event
// group's id, and one for the variable's ID.
- var stub = sinon.stub(Blockly.utils, "genUid");
- stub.onCall(0).returns('1');
- stub.onCall(1).returns('2');
- stub.onCall(2).returns('3');
- var _ = this.workspace.newBlock('field_variable_test_block');
+ sinon.assert.calledThrice(genUidStub);
- var firedEvents = this.workspace.undoStack_;
- // Expect two events: varCreate and block create.
- chai.assert.equal(2, firedEvents.length);
+ // Expect two events fired: varCreate and block create.
+ sinon.assert.calledTwice(this.eventsStub);
+ // Expect both events to trigger change listener.
+ sinon.assert.calledTwice(this.changeListenerSpy);
+ // Both events should be on undo stack
+ chai.assert.equal(this.workspace.undoStack_.length, 2,
+ 'Undo stack length');
- var event0 = firedEvents[0];
- var event1 = firedEvents[1];
- chai.assert.equal(event0.type, 'var_create');
- chai.assert.equal(event1.type, 'create');
+ assertNthCallEventArgEquals(
+ this.changeListenerSpy, 0, Blockly.Events.VAR_CREATE, this.workspace.id,
+ undefined, {group: TEST_GROUP_ID, varId: TEST_VAR_ID,
+ varName: TEST_VAR_NAME}, 'varCreate:');
+ assertNthCallEventArgEquals(
+ this.changeListenerSpy, 1, Blockly.Events.CREATE, this.workspace.id,
+ TEST_BLOCK_ID, {group: TEST_GROUP_ID}, 'block create:');
- // Expect the events to have the same group ID.
- chai.assert.equal(event0.group, event1.group);
-
- // Expect the group ID to be the result of the second call to genUid.
- chai.assert.equal(event0.group, '2');
-
- // Expect the workspace to have a variable with ID '3'.
- chai.assert.isNotNull(this.workspace.getVariableById('3'));
- chai.assert.equal(event0.varId, '3');
+ // Expect the workspace to have a variable with ID 'test_var_id'.
+ chai.assert.isNotNull(this.workspace.getVariableById(TEST_VAR_ID));
});
test('New block new var xml', function() {
- // The sequence of events should be the same whether the block was created from
- // XML or directly.
+ var TEST_GROUP_ID = 'test_group_id';
+ var genUidStub = createGenUidStubWithReturns(TEST_GROUP_ID);
var dom = Blockly.Xml.textToDom(
'' +
- ' ' +
- ' name1' +
+ ' ' +
+ ' name1' +
' ' +
'');
Blockly.Xml.domToWorkspace(dom, this.workspace);
+ var TEST_BLOCK_ID = 'test_block_id';
+ var TEST_VAR_ID = 'test_var_id';
+ var TEST_VAR_NAME = 'name1';
- var firedEvents = this.workspace.undoStack_;
- // Expect two events: varCreate and block create.
- chai.assert.equal(2, firedEvents.length);
+ // Expect one call to genUid: for the event group's id
+ sinon.assert.calledOnce(genUidStub);
- var event0 = firedEvents[0];
- var event1 = firedEvents[1];
- chai.assert.equal(event0.type, 'var_create');
- chai.assert.equal(event1.type, 'create');
+ // When block is created using domToWorkspace, 5 events are fired:
+ // 1. varCreate (events disabled)
+ // 2. varCreate
+ // 3. block create
+ // 4. move (no-op, is filtered out)
+ // 5. finished loading
+ sinon.assert.callCount(this.eventsStub, 5);
+ // The first varCreate and move event should have been ignored.
+ sinon.assert.callCount(this.changeListenerSpy, 3);
+ // Expect two events on undo stack: varCreate and block create.
+ chai.assert.equal(2, this.workspace.undoStack_.length,
+ 'Undo stack length');
- // Expect the events to have the same group ID.
- chai.assert.equal(event0.group, event1.group);
+ assertNthCallEventArgEquals(
+ this.changeListenerSpy, 0, Blockly.Events.VAR_CREATE, this.workspace.id,
+ undefined, {group: TEST_GROUP_ID, varId: TEST_VAR_ID,
+ varName: TEST_VAR_NAME}, 'varCreate:');
+ assertNthCallEventArgEquals(
+ this.changeListenerSpy, 1, Blockly.Events.CREATE, this.workspace.id,
+ TEST_BLOCK_ID, {group: TEST_GROUP_ID}, 'block create:');
- // Expect the workspace to have a variable with ID 'id1'.
- chai.assert.isNotNull(this.workspace.getVariableById('id1'));
- chai.assert.equal(event0.varId, 'id1');
+ // Finished loading event should not be part of event group.
+ assertNthCallEventArgEquals(
+ this.changeListenerSpy, 2, Blockly.Events.FINISHED_LOADING, this.workspace.id,
+ undefined, {group: ''}, 'finished loading:');
+
+ // Expect the workspace to have a variable with ID 'test_var_id'.
+ chai.assert.isNotNull(this.workspace.getVariableById(TEST_VAR_ID));
});
});
});
diff --git a/tests/mocha/field_variable_test.js b/tests/mocha/field_variable_test.js
index c1d3207a8..b4776187b 100644
--- a/tests/mocha/field_variable_test.js
+++ b/tests/mocha/field_variable_test.js
@@ -45,9 +45,7 @@ suite('Variable Fields', function() {
setup(function() {
this.workspace = new Blockly.Workspace();
-
- sinon.stub(Blockly.utils, 'genUid')
- .returns(FAKE_ID);
+ createGenUidStubWithReturns(FAKE_ID);
sinon.stub(Blockly.Variables, 'generateUniqueName')
.returns(FAKE_VARIABLE_NAME);
});
@@ -325,8 +323,6 @@ suite('Variable Fields', function() {
});
teardown(function() {
this.variableBlock.dispose();
- this.variableBlock = null;
- this.variableField = null;
delete Blockly.Blocks['field_variable_test_block'];
});
test('Rename & Keep Old ID', function() {
diff --git a/tests/mocha/gesture_test.js b/tests/mocha/gesture_test.js
index 4372151bc..4ba2b591c 100644
--- a/tests/mocha/gesture_test.js
+++ b/tests/mocha/gesture_test.js
@@ -18,7 +18,6 @@ suite('Gesture', function() {
});
teardown(function() {
- this.e = null;
this.workspace.dispose();
});
diff --git a/tests/mocha/test_helpers.js b/tests/mocha/test_helpers.js
index 636d52d7e..f65c70606 100644
--- a/tests/mocha/test_helpers.js
+++ b/tests/mocha/test_helpers.js
@@ -39,13 +39,37 @@ function captureWarnings(innerFunc) {
return msgs;
}
+/**
+ * Creates stub for Blockly.utils.genUid that returns the provided id or ids.
+ * Recommended to also assert that the stub is called the expected number of
+ * times.
+ * @param {string|!Array} returnIds The return values to use for the
+ * created stub. If a single value is passed, then the stub always returns
+ * that value.
+ * @return {!SinonStub} The created stub.
+ */
+function createGenUidStubWithReturns(returnIds) {
+ var stub = sinon.stub(Blockly.utils, "genUid");
+ if (Array.isArray(returnIds)) {
+ for (var i = 0; i < returnIds.length; i++) {
+ stub.onCall(i).returns(returnIds[i]);
+ }
+ } else {
+ stub.returns(returnIds);
+ }
+ return stub;
+}
/**
* Creates stub for Blockly.Events.fire that fires events immediately instead of
* with timeout.
- * @return {sinon.stub} The created stub.
+ * @return {!SinonStub} The created stub.
*/
function createEventsFireStub() {
+ // TODO(#4064): Remove clearing of event clear here in favor of adding cleanup
+ // to other tests that cause events to be added to the queue even after they
+ // end.
+ Blockly.Events.FIRE_QUEUE_.length = 0;
var stub = sinon.stub(Blockly.Events, 'fire');
stub.callsFake(function(event) {
if (!Blockly.Events.isEnabled()) {
@@ -54,10 +78,87 @@ function createEventsFireStub() {
Blockly.Events.FIRE_QUEUE_.push(event);
Blockly.Events.fireNow_();
});
- stub.firedEvents_ = [];
return stub;
}
+/**
+ * Creates spy for workspace fireChangeListener
+ * @param {!Blockly.Workspace} workspace The workspace to spy fireChangeListener
+ * calls on.
+ * @return {!SinonSpy} The created spy.
+ */
+function createFireChangeListenerSpy(workspace) {
+ return sinon.spy(workspace, 'fireChangeListener');
+}
+
+/**
+ * Asserts that the given event has the expected values.
+ * @param {!Blockly.Event.Abstract} event The event to check.
+ * @param {string} expectedType Expected type of event fired.
+ * @param {string} expectedWorkspaceId Expected workspace id of event fired.
+ * @param {string} expectedBlockId Expected block id of event fired.
+ * @param {!Object} expectedProperties Map of of additional expected
+ * properties to check on fired event.
+ * @param {string=} message Optional message to prepend assert messages.
+ * @private
+ */
+function assertEventEquals(event, expectedType,
+ expectedWorkspaceId, expectedBlockId, expectedProperties, message) {
+ var prependMessage = message ? message + ' ' : '';
+ chai.assert.equal(event.type, expectedType,
+ prependMessage + 'Event fired type');
+ chai.assert.equal(event.workspaceId, expectedWorkspaceId,
+ prependMessage + 'Event fired workspace id');
+ chai.assert.equal(event.blockId, expectedBlockId,
+ prependMessage + 'Event fired block id');
+ Object.keys(expectedProperties).map((key) => {
+ var value = event[key];
+ var expectedValue = expectedProperties[key];
+ if (key.endsWith('Xml')) {
+ value = Blockly.Xml.domToText(value);
+ expectedValue = Blockly.Xml.domToText(expectedValue);
+ }
+ chai.assert.equal(value, expectedValue, prependMessage + 'Event fired ' + key);
+ });
+}
+
+/**
+ * Asserts that the event passed to the last call of the given spy has the
+ * expected values. Assumes that the event is passed as the first argument.
+ * @param {!SinonSpy} spy The spy to use.
+ * @param {string} expectedType Expected type of event fired.
+ * @param {string} expectedWorkspaceId Expected workspace id of event fired.
+ * @param {string} expectedBlockId Expected block id of event fired.
+ * @param {!Object} expectedProperties Map of of expected properties
+ * to check on fired event.
+ * @param {string=} message Optional message to prepend assert messages.
+ */
+function assertLastCallEventArgEquals(spy, expectedType,
+ expectedWorkspaceId, expectedBlockId, expectedProperties, message) {
+ var event = spy.lastCall.firstArg;
+ assertEventEquals(event, expectedType, expectedWorkspaceId, expectedBlockId,
+ expectedProperties, message);
+}
+
+/**
+ * Asserts that the event passed to the nth call of the given spy has the
+ * expected values. Assumes that the event is passed as the first argument.
+ * @param {!SinonSpy} spy The spy to use.
+ * @param {number} n Which call to check.
+ * @param {string} expectedType Expected type of event fired.
+ * @param {string} expectedWorkspaceId Expected workspace id of event fired.
+ * @param {string} expectedBlockId Expected block id of event fired.
+ * @param {Object} expectedProperties Map of of expected properties
+ * to check on fired event.
+ * @param {string=} message Optional message to prepend assert messages.
+ */
+function assertNthCallEventArgEquals(spy, n, expectedType,
+ expectedWorkspaceId, expectedBlockId, expectedProperties, message) {
+ var event = spy.getCall(n).firstArg;
+ assertEventEquals(event, expectedType, expectedWorkspaceId, expectedBlockId,
+ expectedProperties, message);
+}
+
function defineStackBlock() {
Blockly.defineBlocksWithJsonArray([{
"type": "stack_block",
diff --git a/tests/mocha/trashcan_test.js b/tests/mocha/trashcan_test.js
index 388e33405..315ebc66e 100644
--- a/tests/mocha/trashcan_test.js
+++ b/tests/mocha/trashcan_test.js
@@ -5,52 +5,46 @@
*/
suite("Trashcan", function() {
- var workspace = {
- addChangeListener: function(func) {
- this.listener = func;
- },
- triggerListener: function(event) {
- this.listener(event);
- },
- options: {
- maxTrashcanContents: Infinity
- }
- };
- var themeManager = new Blockly.ThemeManager(workspace, Blockly.Themes.Classic);
- workspace.getThemeManager = function() {
- return themeManager;
- };
- function sendDeleteEvent(xmlString) {
+ function fireDeleteEvent(workspace, xmlString) {
var xml = Blockly.Xml.textToDom(
'' +
xmlString + '');
xml = xml.children[0];
- var event = {
- type: Blockly.Events.BLOCK_DELETE,
- oldXml: xml
- };
- workspace.triggerListener(event);
+ var event = new Blockly.Events.Delete(null);
+ event.oldXml = xml;
+ event.workspaceId = workspace.id;
+ Blockly.Events.fire(event);
+ }
+ function fireNonDeleteEvent(workspace, oldXml) {
+ var event = new Blockly.Events.Abstract();
+ event.type = 'dummy_type';
+ event.workspaceId = workspace.id;
+ if (oldXml) {
+ event.oldXml = oldXml;
+ }
+ Blockly.Events.fire(/** @type {Blockly.Events.Abstract} */ event);
}
setup(function() {
- this.trashcan = new Blockly.Trashcan(workspace);
- this.setLidStub = sinon.stub(this.trashcan, 'setLidAngle_');
+ this.eventsStub = createEventsFireStub();
+ var options = new Blockly.Options(
+ {'trashcan': true, 'maxTrashcanContents': Infinity});
+ this.workspace = new Blockly.WorkspaceSvg(options);
+ this.trashcan = new Blockly.Trashcan(this.workspace);
+ // Stub the trashcan dom.
+ this.trashcan.svgLid_ = sinon.createStubInstance(SVGElement);
});
teardown(function() {
- this.setLidStub.restore();
- this.trashcan = null;
+ sinon.restore();
});
suite("Events", function() {
test("Delete", function() {
- sendDeleteEvent('');
+ fireDeleteEvent(this.workspace, '');
chai.assert.equal(this.trashcan.contents_.length, 1);
});
test("Non-Delete", function() {
- var event = {
- type: 'dummy_type'
- };
- workspace.triggerListener(event);
+ fireNonDeleteEvent(this.workspace);
chai.assert.equal(this.trashcan.contents_.length, 0);
});
test("Non-Delete w/ oldXml", function() {
@@ -60,58 +54,70 @@ suite("Trashcan", function() {
''
);
xml = xml.children[0];
- var event = {
- type: 'dummy_type',
- oldXml: xml
- };
- workspace.triggerListener(event);
+ fireNonDeleteEvent(this.workspace, xml);
chai.assert.equal(this.trashcan.contents_.length, 0);
});
test("Shadow Delete", function() {
- sendDeleteEvent('');
+ fireDeleteEvent(this.workspace, '');
chai.assert.equal(this.trashcan.contents_.length, 0);
});
+ test("Click without contents - fires no events", function() {
+ this.trashcan.click();
+ var lastFireCall = this.eventsStub.lastCall;
+ chai.assert.notExists(lastFireCall);
+ });
+ test("Click with contents - fires trashcanOpen", function() {
+ fireDeleteEvent(this.workspace, '');
+ chai.assert.equal(this.trashcan.contents_.length, 1);
+ // Stub flyout interaction.
+ var showFlyoutStub = sinon.stub(this.trashcan.flyout, "show");
+ this.trashcan.click();
+ assertLastCallEventArgEquals(
+ this.eventsStub, Blockly.Events.UI, this.workspace.id, undefined,
+ {element: 'trashcanOpen', oldValue: null, newValue: true});
+ sinon.assert.calledOnce(showFlyoutStub);
+ });
});
suite("Unique Contents", function() {
test("Simple", function() {
- sendDeleteEvent('');
- sendDeleteEvent('');
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace, '');
chai.assert.equal(this.trashcan.contents_.length, 1);
});
test("Different Coords", function() {
- sendDeleteEvent('');
- sendDeleteEvent('');
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace, '');
chai.assert.equal(this.trashcan.contents_.length, 1);
});
test("Different IDs", function() {
- sendDeleteEvent('');
- sendDeleteEvent('');
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace, '');
chai.assert.equal(this.trashcan.contents_.length, 1);
});
test("No Disabled - Disabled True", function() {
- sendDeleteEvent('');
- sendDeleteEvent('');
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace, '');
// Disabled tags get removed because disabled blocks aren't allowed to
// be dragged from flyouts. See #2239 and #3243.
chai.assert.equal(this.trashcan.contents_.length, 1);
});
test("No Editable - Editable False", function() {
- sendDeleteEvent('');
- sendDeleteEvent('');
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace, '');
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("No Movable - Movable False", function() {
- sendDeleteEvent('');
- sendDeleteEvent('');
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace, '');
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("Different Field Values", function() {
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' dummy_value1' +
''
);
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' dummy_value2' +
''
@@ -119,8 +125,8 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("No Values - Values", function() {
- sendDeleteEvent('');
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
@@ -130,14 +136,14 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("Different Value Blocks", function() {
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
' ' +
''
);
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
@@ -147,8 +153,8 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("No Statements - Statements", function() {
- sendDeleteEvent('');
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
@@ -158,14 +164,14 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("Different Statement Blocks", function() {
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
' ' +
''
);
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
@@ -175,8 +181,8 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("No Next - Next", function() {
- sendDeleteEvent('');
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
@@ -186,14 +192,14 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("Different Next Blocks", function() {
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
' ' +
''
);
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' ' +
' ' +
@@ -203,8 +209,8 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("No Comment - Comment", function() {
- sendDeleteEvent('');
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace,
'' +
' comment_text' +
''
@@ -212,12 +218,12 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("Different Comment Text", function() {
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' comment_text1' +
''
);
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' comment_text2' +
''
@@ -225,12 +231,12 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("Different Comment Size", function() {
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' comment_text' +
''
);
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' comment_text' +
''
@@ -239,12 +245,12 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 1);
});
test("Different Comment Pinned", function() {
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' comment_text' +
''
);
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' comment_text' +
''
@@ -253,8 +259,8 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 1);
});
test("No Mutator - Mutator", function() {
- sendDeleteEvent('');
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace,
'' +
' ' +
''
@@ -262,12 +268,12 @@ suite("Trashcan", function() {
chai.assert.equal(this.trashcan.contents_.length, 2);
});
test("Different Mutator", function() {
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' ' +
''
);
- sendDeleteEvent(
+ fireDeleteEvent(this.workspace,
'' +
' ' +
''
@@ -277,24 +283,24 @@ suite("Trashcan", function() {
});
suite("Max Contents", function() {
test("Max 0", function() {
- workspace.options.maxTrashcanContents = 0;
- sendDeleteEvent(
+ this.workspace.options.maxTrashcanContents = 0;
+ fireDeleteEvent(this.workspace,
''
);
chai.assert.equal(this.trashcan.contents_.length, 0);
- workspace.options.maxTrashcanContents = Infinity;
+ this.workspace.options.maxTrashcanContents = Infinity;
});
test("Last In First Out", function() {
- workspace.options.maxTrashcanContents = 1;
- sendDeleteEvent('');
- sendDeleteEvent('');
+ this.workspace.options.maxTrashcanContents = 1;
+ fireDeleteEvent(this.workspace, '');
+ fireDeleteEvent(this.workspace, '');
chai.assert.equal(this.trashcan.contents_.length, 1);
chai.assert.equal(
Blockly.Xml.textToDom(this.trashcan.contents_[0])
.getAttribute('type'),
'dummy_type2'
);
- workspace.options.maxTrashcanContents = Infinity;
+ this.workspace.options.maxTrashcanContents = Infinity;
});
});
});
diff --git a/tests/mocha/variable_map_test.js b/tests/mocha/variable_map_test.js
index c68c96984..6c7fa7bf8 100644
--- a/tests/mocha/variable_map_test.js
+++ b/tests/mocha/variable_map_test.js
@@ -70,13 +70,13 @@ suite('Variable Map', function() {
});
test('Null id', function() {
- sinon.stub(Blockly.utils, "genUid").returns('1');
+ createGenUidStubWithReturns('1');
this.variableMap.createVariable('name1', 'type1', null);
assertVariableValues(this.variableMap, 'name1', 'type1', '1');
});
test('Undefined id', function() {
- sinon.stub(Blockly.utils, "genUid").returns('1');
+ createGenUidStubWithReturns('1');
this.variableMap.createVariable('name1', 'type1', undefined);
assertVariableValues(this.variableMap, 'name1', 'type1', '1');
});
diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js
index 0acab1b17..7d1b1841d 100644
--- a/tests/mocha/xml_test.js
+++ b/tests/mocha/xml_test.js
@@ -299,7 +299,7 @@ suite('XML', function() {
assertVariableDomField(resultFieldDom, 'VAR', 'string', 'id1', 'name1');
});
test('Variable Default Case', function() {
- sinon.stub(Blockly.utils, 'genUid').returns('1');
+ createGenUidStubWithReturns('1');
this.workspace.createVariable('name1');
Blockly.Events.disable();
@@ -409,7 +409,7 @@ suite('XML', function() {
this.workspace.dispose();
});
test('One Variable', function() {
- sinon.stub(Blockly.utils, 'genUid').returns('1');
+ createGenUidStubWithReturns('1');
this.workspace.createVariable('name1');
var resultDom =
Blockly.Xml.variablesToDom(this.workspace.getAllVariables());
@@ -685,7 +685,7 @@ suite('XML', function() {
this.workspace.dispose();
});
test('Backwards compatibility', function() {
- sinon.stub(Blockly.utils, 'genUid').returns('1');
+ createGenUidStubWithReturns('1');
var dom = Blockly.Xml.textToDom(
'' +
' ' +