Shared events cleanup (#4092)

* Remove temp fix for event queue cleanup.

* Implementing shared setup and cleanup.

* Remove unecessary restore and add comment.

* Adds helper for workspace teardown

* Remove unecessary restore calls in event tests
This commit is contained in:
Monica Kozbial
2020-08-03 16:50:23 -07:00
committed by GitHub
parent 4a2b0b583c
commit b7305c1eed
10 changed files with 210 additions and 124 deletions

View File

@@ -17,14 +17,16 @@
"defineRowBlock": true,
"defineStackBlock": true,
"defineStatementBlock": true,
"createEventsFireStub": true,
"createFireChangeListenerSpy": true,
"createGenUidStubWithReturns": true,
"testAWorkspace": true,
"testHelpers" : true,
"getCategoryJSON": true,
"getSimpleJSON": true,
"getXmlArray": true,
"getCategoryJSON": true
"sharedTestSetup": true,
"sharedTestTeardown": true,
"testAWorkspace": true,
"testHelpers" : true,
"workspaceTeardown": true
},
"rules": {
"no-unused-vars": ["off"],

View File

@@ -6,6 +6,7 @@
suite('Blocks', function() {
setup(function() {
sharedTestSetup.call(this, {fireEventsNow: false});
this.workspace = new Blockly.Workspace();
Blockly.defineBlocksWithJsonArray([
{
@@ -43,7 +44,7 @@ suite('Blocks', function() {
}]);
});
teardown(function() {
this.workspace.dispose();
sharedTestTeardown.call(this);
delete Blockly.Blocks['empty_block'];
delete Blockly.Blocks['stack_block'];
delete Blockly.Blocks['row_block'];
@@ -392,8 +393,6 @@ suite('Blocks', function() {
});
suite('Connection Tracking', function() {
setup(function() {
this.workspace.dispose();
// The new rendered workspace will get disposed by the parent teardown.
this.workspace = Blockly.inject('blocklyDiv');
this.getInputs = function() {
@@ -419,12 +418,11 @@ suite('Blocks', function() {
chai.assert.isEmpty(this.getNext());
chai.assert.isEmpty(this.getPrevious());
};
this.clock = sinon.useFakeTimers();
});
teardown(function() {
this.clock.restore();
workspaceTeardown.call(this, this.workspace);
});
suite('Deserialization', function() {
test('Stack', function() {
Blockly.Xml.appendDomToWorkspace(Blockly.Xml.textToDom(
@@ -433,7 +431,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
@@ -452,7 +450,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 3);
});
@@ -463,7 +461,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
@@ -482,7 +480,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 3);
});
@@ -493,7 +491,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 1);
});
@@ -512,7 +510,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
});
@@ -523,7 +521,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 0);
});
@@ -542,7 +540,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 0);
});
@@ -561,7 +559,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 2);
chai.assert.equal(this.getInputs().length, 1);
});
@@ -572,7 +570,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 2);
});
@@ -591,7 +589,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
});
@@ -602,7 +600,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
@@ -621,7 +619,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
});
@@ -640,7 +638,7 @@ suite('Blocks', function() {
'</xml>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 2);
chai.assert.equal(this.getNext().length, 3);
});
@@ -679,7 +677,7 @@ suite('Blocks', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="stack_block"/>'
), this.workspace);
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 1);
@@ -704,7 +702,7 @@ suite('Blocks', function() {
'</block>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 3);
@@ -720,7 +718,7 @@ suite('Blocks', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="row_block"/>'
), this.workspace);
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 1);
chai.assert.equal(this.getInputs().length, 1);
@@ -744,7 +742,7 @@ suite('Blocks', function() {
' </value>' +
'</block>'
), this.workspace);
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
@@ -768,7 +766,7 @@ suite('Blocks', function() {
' </value>' +
'</block>'
), this.workspace);
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
@@ -795,7 +793,7 @@ suite('Blocks', function() {
' </value>' +
'</block>'
), this.workspace);
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getOutputs().length, 3);
chai.assert.equal(this.getInputs().length, 3);
@@ -820,7 +818,7 @@ suite('Blocks', function() {
var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
'<block type="statement_block"/>'
), this.workspace);
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 1);
chai.assert.equal(this.getNext().length, 2);
@@ -845,7 +843,7 @@ suite('Blocks', function() {
'</block>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
@@ -870,7 +868,7 @@ suite('Blocks', function() {
'</block>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
@@ -896,7 +894,7 @@ suite('Blocks', function() {
'</block>'
), this.workspace);
this.assertConnectionsEmpty();
this.clock.tick(1);
this.clock.runAll();
chai.assert.equal(this.getPrevious().length, 3);
chai.assert.equal(this.getNext().length, 6);
@@ -1019,12 +1017,6 @@ suite('Blocks', function() {
});
});
suite('Comments', function() {
setup(function() {
this.eventSpy = sinon.spy(Blockly.Events, 'fire');
});
teardown(function() {
this.eventSpy.restore();
});
suite('Set/Get Text', function() {
function assertCommentEvent(eventSpy, oldValue, newValue) {
var calls = eventSpy.getCalls();
@@ -1039,6 +1031,12 @@ suite('Blocks', function() {
var event = calls[calls.length - 1].args[0];
chai.assert.notEqual(event.type, Blockly.Events.BLOCK_CHANGE);
}
setup(function() {
this.eventsFireSpy = sinon.spy(Blockly.Events, 'fire');
});
teardown(function() {
this.eventsFireSpy.restore();
});
suite('Headless', function() {
setup(function() {
this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom(
@@ -1048,24 +1046,24 @@ suite('Blocks', function() {
test('Text', function() {
this.block.setCommentText('test text');
chai.assert.equal(this.block.getCommentText(), 'test text');
assertCommentEvent(this.eventSpy, null, 'test text');
assertCommentEvent(this.eventsFireSpy, null, 'test text');
});
test('Text Empty', function() {
this.block.setCommentText('');
chai.assert.equal(this.block.getCommentText(), '');
assertCommentEvent(this.eventSpy, null, '');
assertCommentEvent(this.eventsFireSpy, null, '');
});
test('Text Null', function() {
this.block.setCommentText(null);
chai.assert.isNull(this.block.getCommentText());
assertNoCommentEvent(this.eventSpy);
assertNoCommentEvent(this.eventsFireSpy);
});
test('Text -> Null', function() {
this.block.setCommentText('first text');
this.block.setCommentText(null);
chai.assert.isNull(this.block.getCommentText());
assertCommentEvent(this.eventSpy, 'first text', null);
assertCommentEvent(this.eventsFireSpy, 'first text', null);
});
});
suite('Rendered', function() {
@@ -1084,24 +1082,24 @@ suite('Blocks', function() {
test('Text', function() {
this.block.setCommentText('test text');
chai.assert.equal(this.block.getCommentText(), 'test text');
assertCommentEvent(this.eventSpy, null, 'test text');
assertCommentEvent(this.eventsFireSpy, null, 'test text');
});
test('Text Empty', function() {
this.block.setCommentText('');
chai.assert.equal(this.block.getCommentText(), '');
assertCommentEvent(this.eventSpy, null, '');
assertCommentEvent(this.eventsFireSpy, null, '');
});
test('Text Null', function() {
this.block.setCommentText(null);
chai.assert.isNull(this.block.getCommentText());
assertNoCommentEvent(this.eventSpy);
assertNoCommentEvent(this.eventsFireSpy);
});
test('Text -> Null', function() {
this.block.setCommentText('first text');
this.block.setCommentText(null);
chai.assert.isNull(this.block.getCommentText());
assertCommentEvent(this.eventSpy, 'first text', null);
assertCommentEvent(this.eventsFireSpy, 'first text', null);
});
test('Set While Visible - Editable', function() {
this.block.setCommentText('test1');
@@ -1110,22 +1108,21 @@ suite('Blocks', function() {
this.block.setCommentText('test2');
chai.assert.equal(this.block.getCommentText(), 'test2');
assertCommentEvent(this.eventSpy, 'test1', 'test2');
assertCommentEvent(this.eventsFireSpy, 'test1', 'test2');
chai.assert.equal(icon.textarea_.value, 'test2');
});
test('Set While Visible - NonEditable', function() {
this.block.setCommentText('test1');
var editableStub = sinon.stub(this.block, 'isEditable').returns(false);
// Restored up by call to sinon.restore() in sharedTestTeardown()
sinon.stub(this.block, 'isEditable').returns(false);
var icon = this.block.getCommentIcon();
icon.setVisible(true);
this.block.setCommentText('test2');
chai.assert.equal(this.block.getCommentText(), 'test2');
assertCommentEvent(this.eventSpy, 'test1', 'test2');
assertCommentEvent(this.eventsFireSpy, 'test1', 'test2');
chai.assert.equal(icon.paragraphElement_.firstChild.textContent,
'test2');
editableStub.restore();
});
test('Get Text While Editing', function() {
this.block.setCommentText('test1');

View File

@@ -6,6 +6,7 @@
suite('Comments', function() {
setup(function() {
sharedTestSetup.call(this);
Blockly.defineBlocksWithJsonArray([
{
"type": "empty_block",
@@ -25,16 +26,12 @@ suite('Comments', function() {
this.comment.computeIconLocation();
});
teardown(function() {
sharedTestTeardown.call(this);
delete Blockly.Blocks['empty_block'];
this.workspace.dispose();
});
suite('Visibility and Editability', function() {
setup(function() {
this.comment.setText('test text');
this.eventsStub = createEventsFireStub();
});
teardown(function() {
sinon.restore();
});
function assertEditable(comment) {
@@ -53,7 +50,7 @@ suite('Comments', function() {
chai.assert.isTrue(this.comment.isVisible());
assertEditable(this.comment);
assertLastCallEventArgEquals(
this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
this.eventsFireStub, Blockly.Events.UI, this.workspace.id, this.block.id,
{element: 'commentOpen', oldValue: false, newValue: true});
});
test('Not Editable', function() {
@@ -63,7 +60,7 @@ suite('Comments', function() {
chai.assert.isTrue(this.comment.isVisible());
assertNotEditable(this.comment);
assertLastCallEventArgEquals(
this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
this.eventsFireStub, Blockly.Events.UI, this.workspace.id, this.block.id,
{element: 'commentOpen', oldValue: false, newValue: true});
});
test('Editable -> Not Editable', function() {
@@ -73,10 +70,10 @@ suite('Comments', function() {
this.comment.updateEditable();
chai.assert.isTrue(this.comment.isVisible());
assertNotEditable(this.comment);assertLastCallEventArgEquals(
this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
this.eventsFireStub, 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,
this.eventsFireStub, Blockly.Events.UI, this.workspace.id, this.block.id,
{element: 'commentOpen', oldValue: false, newValue: true});
});
test('Not Editable -> Editable', function() {
@@ -88,7 +85,7 @@ suite('Comments', function() {
chai.assert.isTrue(this.comment.isVisible());
assertEditable(this.comment);
assertLastCallEventArgEquals(
this.eventsStub, Blockly.Events.UI, this.workspace.id, this.block.id,
this.eventsFireStub, Blockly.Events.UI, this.workspace.id, this.block.id,
{element: 'commentOpen', oldValue: false, newValue: true});
});
});

View File

@@ -6,6 +6,8 @@
suite('Events', function() {
setup(function() {
sharedTestSetup.call(this, {fireEventsNow: false});
this.eventsFireSpy = sinon.spy(Blockly.Events, 'fire');
this.workspace = new Blockly.Workspace();
Blockly.defineBlocksWithJsonArray([{
'type': 'field_variable_test_block',
@@ -25,13 +27,9 @@ suite('Events', function() {
});
teardown(function() {
sharedTestTeardown.call(this);
delete Blockly.Blocks['field_variable_test_block'];
delete Blockly.Blocks['simple_test_block'];
this.workspace.dispose();
// Clear Blockly.Event state.
Blockly.Events.setGroup(false);
Blockly.Events.disabled_ = 0;
});
function createSimpleTestBlock(workspace, opt_prototypeName) {
@@ -75,9 +73,6 @@ suite('Events', function() {
[this.TEST_BLOCK_ID, this.TEST_PARENT_ID]);
this.block = createSimpleTestBlock(this.workspace);
});
teardown(function() {
sinon.restore();
});
test('Block base', function() {
var event = new Blockly.Events.BlockBase(this.block);
@@ -232,9 +227,6 @@ suite('Events', function() {
this.block =
createSimpleTestBlock(this.workspace, 'field_variable_test_block');
});
teardown(function() {
sinon.restore();
});
test('Change', function() {
var event = new Blockly.Events.Change(
@@ -625,18 +617,17 @@ suite('Events', function() {
suite('Firing', function() {
setup(function() {
this.eventsStub = createEventsFireStub();
this.changeListenerSpy = createFireChangeListenerSpy(this.workspace);
});
teardown(function() {
sinon.restore();
});
test('Block dispose triggers Delete', function() {
try {
var toolbox = document.getElementById('toolbox-categories');
var workspaceSvg = Blockly.inject('blocklyDiv', {toolbox: toolbox});
var changeListenerSpy = createFireChangeListenerSpy(workspaceSvg);
var TEST_BLOCK_ID = 'test_block_id';
var genUidStub = createGenUidStubWithReturns(
[TEST_BLOCK_ID, 'test_group_id']);
var block = workspaceSvg.newBlock('');
block.initSvg();
@@ -646,9 +637,22 @@ suite('Events', function() {
block.dispose();
// Run all queued events.
this.clock.runAll();
// Expect two calls to genUid: one to set the block's ID, and one for
// the event group's ID for creating block.
sinon.assert.calledTwice(genUidStub);
assertLastCallEventArgEquals(
this.eventsStub, Blockly.Events.DELETE, workspaceSvg.id,
expectedId, {oldXml: expectedOldXml});
this.eventsFireSpy, Blockly.Events.DELETE, workspaceSvg.id,
expectedId, {oldXml: expectedOldXml, group: ''});
assertLastCallEventArgEquals(
changeListenerSpy, Blockly.Events.DELETE, workspaceSvg.id,
expectedId, {oldXml: expectedOldXml, group: ''});
// Expect the workspace to not have a variable with ID 'test_block_id'.
chai.assert.isNull(this.workspace.getVariableById(TEST_BLOCK_ID));
} finally {
workspaceSvg.dispose();
}
@@ -663,12 +667,15 @@ suite('Events', function() {
var _ = this.workspace.newBlock('field_variable_test_block');
var TEST_VAR_NAME = 'item'; // As defined in block's json.
// Run all queued events.
this.clock.runAll();
// 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.
// group's ID, and one for the variable's ID.
sinon.assert.calledThrice(genUidStub);
// Expect two events fired: varCreate and block create.
sinon.assert.calledTwice(this.eventsStub);
sinon.assert.calledTwice(this.eventsFireSpy);
// Expect both events to trigger change listener.
sinon.assert.calledTwice(this.changeListenerSpy);
// Both events should be on undo stack
@@ -701,6 +708,9 @@ suite('Events', function() {
var TEST_VAR_ID = 'test_var_id';
var TEST_VAR_NAME = 'name1';
// Run all queued events.
this.clock.runAll();
// Expect one call to genUid: for the event group's id
sinon.assert.calledOnce(genUidStub);
@@ -710,7 +720,7 @@ suite('Events', function() {
// 3. block create
// 4. move (no-op, is filtered out)
// 5. finished loading
sinon.assert.callCount(this.eventsStub, 5);
sinon.assert.callCount(this.eventsFireSpy, 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.

View File

@@ -9,6 +9,7 @@ goog.require('Blockly.Msg');
suite('Procedures', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.callForAllTypes = function(func, startName) {
@@ -37,7 +38,7 @@ suite('Procedures', function() {
};
});
teardown(function() {
this.workspace.dispose();
sharedTestTeardown.call(this);
});
suite('allProcedures', function() {
@@ -340,7 +341,6 @@ suite('Procedures', function() {
});
suite('Enable/Disable', function() {
setup(function() {
createEventsFireStub();
var toolbox = document.getElementById('toolbox-categories');
this.workspaceSvg = Blockly.inject('blocklyDiv', {toolbox: toolbox});
});

View File

@@ -39,10 +39,114 @@ function captureWarnings(innerFunc) {
return msgs;
}
/**
* Safely disposes of Blockly workspace, logging any errors.
* Assumes that sharedTestSetup has also been called. This should be called
* using workspaceTeardown.call(this).
* @param {!Blockly.Workspace} workspace The workspace to dispose.
*/
function workspaceTeardown(workspace) {
try {
this.clock.runAll(); // Run all queued setTimeout calls.
workspace.dispose();
this.clock.runAll(); // Run all remaining queued setTimeout calls.
} catch (e) {
console.error(this.currentTest.fullTitle() + '\n', e);
}
}
/**
* Creates stub for Blockly.Events.fire that advances the clock forward after
* the event fires so it is processed immediately instead of on a timeout.
* @param {!SinonClock} clock The sinon clock.
* @return {!SinonStub} The created stub.
* @private
*/
function createEventsFireStubFireImmediately_(clock) {
var stub = sinon.stub(Blockly.Events, 'fire');
stub.callsFake(function(event) {
// TODO(#4070) Replace the fake function content with the following code
// that uses wrappedMethod after cleanup is added to ALL tests.
// Calling the original method will not consistently work if other tests
// add things to the event queue because the setTimeout call will not be
// added to the stubbed clock (so runAll cannot be used to control).
// // Call original method.
// stub.wrappedMethod.call(this, ...arguments);
// // Advance clock forward to run any queued events.
// clock.runAll();
//
if (!Blockly.Events.isEnabled()) {
return;
}
Blockly.Events.FIRE_QUEUE_.push(event);
Blockly.Events.fireNow_();
});
return stub;
}
/**
* Shared setup method that sets up fake timer for clock so that pending
* setTimeout calls can be cleared in test teardown along with other common
* stubs. Should be called in setup of outermost suite using
* sharedTestSetup.call(this).
* @param {Object<string, boolean>} options Options to enable/disable setup
* of certain stubs.
*/
function sharedTestSetup(options = {}) {
this.sharedSetupCalled_ = true;
// Sandbox created for greater control when certain stubs are cleared.
this.sharedSetupSandbox_ = sinon.createSandbox();
this.clock = this.sharedSetupSandbox_.useFakeTimers();
if (options['fireEventsNow'] === undefined || options['fireEventsNow']) {
// Stubs event firing unless passed option "fireEventsNow: false"
this.eventsFireStub = createEventsFireStubFireImmediately_(this.clock);
}
}
/**
* Shared cleanup method that clears up pending setTimeout calls, disposes of
* workspace, and resets global variables. Should be called in setup of
* outermost suite using sharedTestTeardown.call(this).
*/
function sharedTestTeardown() {
if (!this.sharedSetupCalled_) {
console.error('"' + this.currentTest.fullTitle() +
'" did not call sharedTestSetup');
}
try {
if (this.workspace) {
workspaceTeardown.call(this, this.workspace);
this.workspace = null;
} else {
this.clock.runAll(); // Run all queued setTimeout calls.
}
} catch (e) {
console.error(this.currentTest.fullTitle() + '\n', e);
} finally {
// Clear Blockly.Event state.
Blockly.Events.setGroup(false);
Blockly.Events.disabled_ = 0;
if (Blockly.Events.FIRE_QUEUE_.length) {
// If this happens, it may mean that some previous test is missing cleanup
// (i.e. a previous test added an event to the queue on a timeout that
// did not use a stubbed clock).
Blockly.Events.FIRE_QUEUE_.length = 0;
console.warn(this.currentTest.fullTitle() +
'" needed cleanup of Blockly.Events.FIRE_QUEUE_. This may indicate ' +
'leakage from an earlier test');
}
// Restore all stubbed methods.
this.sharedSetupSandbox_.restore();
sinon.restore();
}
}
/**
* 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.
* Recommended to also assert that the stub is called the expected number of
* times.
* @param {string|!Array<string>} returnIds The return values to use for the
* created stub. If a single value is passed, then the stub always returns
* that value.
@@ -60,27 +164,6 @@ function createGenUidStubWithReturns(returnIds) {
return stub;
}
/**
* Creates stub for Blockly.Events.fire that fires events immediately instead of
* with timeout.
* @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()) {
return;
}
Blockly.Events.FIRE_QUEUE_.push(event);
Blockly.Events.fireNow_();
});
return stub;
}
/**
* Creates spy for workspace fireChangeListener
* @param {!Blockly.Workspace} workspace The workspace to spy fireChangeListener
@@ -124,7 +207,7 @@ function assertEventEquals(event, expectedType,
/**
* 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.
* 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.
@@ -142,7 +225,7 @@ function assertLastCallEventArgEquals(spy, expectedType,
/**
* 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.
* 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.

View File

@@ -26,7 +26,7 @@ suite("Trashcan", function() {
}
setup(function() {
this.eventsStub = createEventsFireStub();
sharedTestSetup.call(this);
var options = new Blockly.Options(
{'trashcan': true, 'maxTrashcanContents': Infinity});
this.workspace = new Blockly.WorkspaceSvg(options);
@@ -35,7 +35,7 @@ suite("Trashcan", function() {
this.trashcan.svgLid_ = sinon.createStubInstance(SVGElement);
});
teardown(function() {
sinon.restore();
sharedTestTeardown.call(this);
});
suite("Events", function() {
@@ -63,7 +63,7 @@ suite("Trashcan", function() {
});
test("Click without contents - fires no events", function() {
this.trashcan.click();
var lastFireCall = this.eventsStub.lastCall;
var lastFireCall = this.eventsFireStub.lastCall;
chai.assert.notExists(lastFireCall);
});
test("Click with contents - fires trashcanOpen", function() {
@@ -73,7 +73,7 @@ suite("Trashcan", function() {
var showFlyoutStub = sinon.stub(this.trashcan.flyout, "show");
this.trashcan.click();
assertLastCallEventArgEquals(
this.eventsStub, Blockly.Events.UI, this.workspace.id, undefined,
this.eventsFireStub, Blockly.Events.UI, this.workspace.id, undefined,
{element: 'trashcanOpen', oldValue: null, newValue: true});
sinon.assert.calledOnce(showFlyoutStub);
});

View File

@@ -8,11 +8,12 @@ goog.require('Blockly.WorkspaceComment');
suite('Workspace comment', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
});
teardown(function() {
this.workspace.dispose();
sharedTestTeardown.call(this);
});
suite('getTopComments(ordered=true)', function() {
@@ -163,7 +164,6 @@ suite('Workspace comment', function() {
suite('Content', function() {
setup(function() {
createEventsFireStub();
this.comment = new Blockly.WorkspaceComment(
this.workspace, 'comment text', 0, 0, 'comment id');

View File

@@ -6,6 +6,7 @@
suite('WorkspaceSvg', function() {
setup(function() {
sharedTestSetup.call(this);
var toolbox = document.getElementById('toolbox-categories');
this.workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox});
Blockly.defineBlocksWithJsonArray([{
@@ -26,10 +27,9 @@ suite('WorkspaceSvg', function() {
});
teardown(function() {
sharedTestTeardown.call(this);
delete Blockly.Blocks['simple_test_block'];
delete Blockly.Blocks['test_val_in'];
this.workspace.dispose();
sinon.restore();
});
test('appendDomToWorkspace alignment', function() {

View File

@@ -6,11 +6,12 @@
suite('Workspace', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
});
teardown(function() {
this.workspace.dispose();
sharedTestTeardown.call(this);
});
// eslint-disable-next-line no-use-before-define
@@ -663,10 +664,6 @@ function testAWorkspace() {
});
suite('Undo/Redo', function() {
setup(function() {
createEventsFireStub();
});
function createTwoVarsDifferentTypes(workspace) {
workspace.createVariable('name1', 'type1', 'id1');
workspace.createVariable('name2', 'type2', 'id2');