Fix collapsed blocks not updating when modified (#3806)

* Stop recursive render calls

* Fix visibility bugs.

* Make toString ignore collapsed input.

* Add automatic collapse rendering handling

* Fix insertion markers with collapsed

* Add tests

* Fix build?

* PR comments

* Add missing jsdoc
This commit is contained in:
Beka Westberg
2020-04-16 13:02:05 -07:00
committed by GitHub
parent 0230a4c192
commit 9e98df9949
7 changed files with 560 additions and 104 deletions

View File

@@ -229,6 +229,17 @@ Blockly.Block = function(workspace, prototypeName, opt_id) {
*/
Blockly.Block.CommentModel;
/**
* The language-neutral id given to the collapsed input.
* @const {string}
*/
Blockly.Block.COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT';
/**
* The language-neutral id given to the collapsed field.
* @const {string}
*/
Blockly.Block.COLLAPSED_FIELD_NAME = '_TEMP_COLLAPSED_FIELD';
/**
* Optional text data that round-trips between blocks and XML.
* Has no effect. May be used by 3rd parties for meta information.
@@ -1295,20 +1306,19 @@ Blockly.Block.prototype.setCollapsed = function(collapsed) {
Blockly.Block.prototype.toString = function(opt_maxLength, opt_emptyToken) {
var text = [];
var emptyFieldPlaceholder = opt_emptyToken || '?';
if (this.collapsed_) {
text.push(this.getInput('_TEMP_COLLAPSED_INPUT').fieldRow[0].getText());
} else {
for (var i = 0, input; (input = this.inputList[i]); i++) {
for (var j = 0, field; (field = input.fieldRow[j]); j++) {
text.push(field.getText());
}
if (input.connection) {
var child = input.connection.targetBlock();
if (child) {
text.push(child.toString(undefined, opt_emptyToken));
} else {
text.push(emptyFieldPlaceholder);
}
for (var i = 0, input; (input = this.inputList[i]); i++) {
if (input.name == Blockly.Block.COLLAPSED_INPUT_NAME) {
continue;
}
for (var j = 0, field; (field = input.fieldRow[j]); j++) {
text.push(field.getText());
}
if (input.connection) {
var child = input.connection.targetBlock();
if (child) {
text.push(child.toString(undefined, opt_emptyToken));
} else {
text.push(emptyFieldPlaceholder);
}
}
}

View File

@@ -69,6 +69,14 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) {
/** @type {boolean} */
this.rendered = false;
/**
* Is this block currently rendering? Used to stop recursive render calls
* from actually triggering a re-render.
* @type {boolean}
* @private
*/
this.renderIsInProgress_ = false;
/** @type {!Blockly.WorkspaceSvg} */
this.workspace = workspace;
@@ -602,60 +610,51 @@ Blockly.BlockSvg.prototype.setCollapsed = function(collapsed) {
if (this.collapsed_ == collapsed) {
return;
}
var renderList = [];
// Show/hide the inputs.
for (var i = 0, input; (input = this.inputList[i]); i++) {
renderList.push.apply(renderList, input.setVisible(!collapsed));
}
var COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT';
if (collapsed) {
var icons = this.getIcons();
for (var i = 0; i < icons.length; i++) {
icons[i].setVisible(false);
}
var text = this.toString(Blockly.COLLAPSE_CHARS);
this.appendDummyInput(COLLAPSED_INPUT_NAME).appendField(text).init();
// Add any warnings on enclosed blocks to this block.
var descendants = this.getDescendants(true);
var nextBlock = this.getNextBlock();
if (nextBlock) {
var index = descendants.indexOf(nextBlock);
descendants.splice(index, descendants.length - index);
}
for (var i = 1, block; (block = descendants[i]); i++) {
if (block.warning) {
this.setWarningText(Blockly.Msg['COLLAPSED_WARNINGS_WARNING'],
Blockly.BlockSvg.COLLAPSED_WARNING_ID);
break;
}
}
} else {
this.removeInput(COLLAPSED_INPUT_NAME);
// Clear any warnings inherited from enclosed blocks.
if (this.warning) {
this.warning.setText('', Blockly.BlockSvg.COLLAPSED_WARNING_ID);
if (!Object.keys(this.warning.text_).length) {
this.setWarningText(null);
}
}
}
Blockly.BlockSvg.superClass_.setCollapsed.call(this, collapsed);
if (!collapsed) {
this.updateCollapsed_();
} else if (this.rendered) {
this.render();
// Don't bump neighbours. Users like to store collapsed functions together
// and bumping makes them go out of alignment.
}
};
if (!renderList.length) {
// No child blocks, just render this block.
renderList[0] = this;
}
if (this.rendered) {
for (var i = 0, block; (block = renderList[i]); i++) {
block.render();
/**
* Makes sure that when the block is collapsed, it is rendered correctly
* for that state.
* @private
*/
Blockly.BlockSvg.prototype.updateCollapsed_ = function() {
var collapsed = this.isCollapsed();
var collapsedInputName = Blockly.Block.COLLAPSED_INPUT_NAME;
var collapsedFieldName = Blockly.Block.COLLAPSED_FIELD_NAME;
for (var i = 0, input; (input = this.inputList[i]); i++) {
if (input.name != collapsedInputName) {
input.setVisible(!collapsed);
}
// Don't bump neighbours.
// Although bumping neighbours would make sense, users often collapse
// all their functions and store them next to each other. Expanding and
// bumping causes all their definitions to go out of alignment.
}
if (!collapsed) {
this.removeInput(collapsedInputName);
return;
}
var icons = this.getIcons();
for (var i = 0, icon; (icon = icons[i]); i++) {
icon.setVisible(false);
}
var text = this.toString(Blockly.COLLAPSE_CHARS);
var field = this.getField(collapsedFieldName);
if (field) {
field.setValue(text);
return;
}
var input = this.getInput(collapsedInputName) ||
this.appendDummyInput(collapsedInputName);
input.appendField(new Blockly.FieldLabel(text), collapsedFieldName);
};
/**
@@ -1647,31 +1646,40 @@ Blockly.BlockSvg.prototype.getRootBlock = function() {
};
/**
* Render the block.
* Lays out and reflows a block based on its contents and settings.
* @param {boolean=} opt_bubble If false, just render this block.
* If true, also render block's parent, grandparent, etc. Defaults to true.
*/
Blockly.BlockSvg.prototype.render = function(opt_bubble) {
Blockly.utils.dom.startTextWidthCache();
this.rendered = true;
(/** @type {!Blockly.WorkspaceSvg} */ (this.workspace))
.getRenderer().render(this);
// No matter how we rendered, connection locations should now be correct.
this.updateConnectionLocations_();
if (opt_bubble !== false) {
// Render all blocks above this one (propagate a reflow).
var parentBlock = this.getParent();
if (parentBlock) {
parentBlock.render(true);
} else {
// Top-most block. Fire an event to allow scrollbars to resize.
this.workspace.resizeContents();
}
if (this.renderIsInProgress_) {
return; // Don't allow recursive renders.
}
Blockly.utils.dom.stopTextWidthCache();
this.renderIsInProgress_ = true;
try {
this.rendered = true;
Blockly.utils.dom.startTextWidthCache();
this.updateMarkers_();
if (this.isCollapsed()) {
this.updateCollapsed_();
}
this.workspace.getRenderer().render(this);
this.updateConnectionLocations_();
if (opt_bubble !== false) {
var parentBlock = this.getParent();
if (parentBlock) {
parentBlock.render(true);
} else {
// Top-most block. Fire an event to allow scrollbars to resize.
this.workspace.resizeContents();
}
}
Blockly.utils.dom.stopTextWidthCache();
this.updateMarkers_();
} finally {
this.renderIsInProgress_ = false;
}
};
/**

View File

@@ -91,21 +91,23 @@ Blockly.Input.prototype.insertFieldAt = function(index, field, opt_name) {
if (index < 0 || index > this.fieldRow.length) {
throw Error('index ' + index + ' out of bounds.');
}
// Falsy field values don't generate a field, unless the field is an empty
// string and named.
if (!field && !(field == '' && opt_name)) {
return index;
}
// Generate a FieldLabel when given a plain text field.
if (typeof field == 'string') {
field = new Blockly.FieldLabel(/** @type {string} */ (field));
}
field.setSourceBlock(this.sourceBlock_);
if (this.sourceBlock_.rendered) {
field.init();
}
field.name = opt_name;
field.setVisible(this.isVisible());
if (field.prefixField) {
// Add any prefix.
@@ -173,7 +175,6 @@ Blockly.Input.prototype.setVisible = function(visible) {
}
this.visible_ = visible;
var display = visible ? 'block' : 'none';
for (var y = 0, field; (field = this.fieldRow[y]); y++) {
field.setVisible(visible);
}
@@ -186,10 +187,7 @@ Blockly.Input.prototype.setVisible = function(visible) {
}
var child = this.connection.targetBlock();
if (child) {
child.getSvgRoot().style.display = display;
if (!visible) {
child.rendered = false;
}
child.getSvgRoot().style.display = visible ? 'block' : 'none';
}
}
return renderList;

View File

@@ -253,23 +253,25 @@ Blockly.InsertionMarkerManager.prototype.createMarkerBlock_ = function(sourceBlo
result.domToMutation(oldMutationDom);
}
}
result.setCollapsed(sourceBlock.isCollapsed());
result.setInputsInline(sourceBlock.getInputsInline());
// Copy visible field values from the other block. These values may impact
// the rendered size of the insertion marker. Note that we do not care
// about child blocks here.
// Copy field values from the other block. These values may impact the
// rendered size of the insertion marker. Note that we do not care about
// child blocks here.
for (var i = 0; i < sourceBlock.inputList.length; i++) {
var sourceInput = sourceBlock.inputList[i];
if (sourceInput.isVisible()) {
var resultInput = result.inputList[i];
for (var j = 0; j < sourceInput.fieldRow.length; j++) {
var sourceField = sourceInput.fieldRow[j];
var resultField = resultInput.fieldRow[j];
resultField.setValue(sourceField.getValue());
}
if (sourceInput.name == Blockly.Block.COLLAPSED_INPUT_NAME) {
continue; // Ignore the collapsed input.
}
var resultInput = result.inputList[i];
for (var j = 0; j < sourceInput.fieldRow.length; j++) {
var sourceField = sourceInput.fieldRow[j];
var resultField = resultInput.fieldRow[j];
resultField.setValue(sourceField.getValue());
}
}
result.setCollapsed(sourceBlock.isCollapsed());
result.setInputsInline(sourceBlock.getInputsInline());
result.initSvg();
result.getSvgRoot().setAttribute('visibility', 'hidden');
} finally {

View File

@@ -454,6 +454,8 @@ Blockly.RenderedConnection.prototype.disconnectInternal_ = function(parentBlock,
if (childBlock.rendered) {
childBlock.updateDisabled();
childBlock.render();
// Reset visibility, since the child is now a top block.
childBlock.getSvgRoot().style.display = 'block';
}
};
@@ -504,14 +506,16 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) {
var parentConnection = this;
var parentBlock = parentConnection.getSourceBlock();
var childBlock = childConnection.getSourceBlock();
var parentRendered = parentBlock.rendered;
var childRendered = childBlock.rendered;
if (parentBlock.rendered) {
if (parentRendered) {
parentBlock.updateDisabled();
}
if (childBlock.rendered) {
if (childRendered) {
childBlock.updateDisabled();
}
if (parentBlock.rendered && childBlock.rendered) {
if (parentRendered && childRendered) {
if (parentConnection.type == Blockly.NEXT_STATEMENT ||
parentConnection.type == Blockly.PREVIOUS_STATEMENT) {
// Child block may need to square off its corners if it is in a stack.
@@ -523,6 +527,13 @@ Blockly.RenderedConnection.prototype.connect_ = function(childConnection) {
parentBlock.render();
}
}
// The input the child block is connected to (if any).
var parentInput = parentBlock.getInputWithBlock(childBlock);
if (parentInput) {
var visible = parentInput.isVisible();
childBlock.getSvgRoot().style.display = visible ? 'block' : 'none';
}
};
/**

View File

@@ -1209,7 +1209,434 @@ suite('Blocks', function() {
});
});
});
suite('Collapsing and Expanding', function() {
function assertCollapsed(block, opt_string) {
chai.assert.isTrue(block.isCollapsed());
for (var i = 0, input; (input = block.inputList[i]); i++) {
if (input.name == Blockly.Block.COLLAPSED_INPUT_NAME) {
continue;
}
chai.assert.isFalse(input.isVisible());
for (var j = 0, field; (field = input.fieldRow[j]); j++) {
chai.assert.isFalse(field.isVisible());
}
}
var icons = block.getIcons();
for (var i = 0, icon; (icon = icons[i]); i++) {
chai.assert.isFalse(icon.isVisible());
}
var input = block.getInput(Blockly.Block.COLLAPSED_INPUT_NAME);
chai.assert.isNotNull(input);
chai.assert.isTrue(input.isVisible());
var field = block.getField(Blockly.Block.COLLAPSED_FIELD_NAME);
chai.assert.isNotNull(field);
chai.assert.isTrue(field.isVisible());
if (opt_string) {
chai.assert.equal(field.getText(), opt_string);
}
}
function assertNotCollapsed(block) {
chai.assert.isFalse(block.isCollapsed());
for (var i = 0, input; (input = block.inputList[i]); i++) {
chai.assert.isTrue(input.isVisible());
for (var j = 0, field; (field = input.fieldRow[j]); j++) {
chai.assert.isTrue(field.isVisible());
}
}
var input = block.getInput(Blockly.Block.COLLAPSED_INPUT_NAME);
chai.assert.isNull(input);
var field = block.getField(Blockly.Block.COLLAPSED_FIELD_NAME);
chai.assert.isNull(field);
}
function isBlockHidden(block) {
var node = block.getSvgRoot();
do {
var visible = node.style.display != 'none';
if (!visible) {
return true;
}
node = node.parentNode;
} while (node != document);
return false;
}
setup(function() {
Blockly.Events.disable();
// We need a visible workspace.
this.workspace = Blockly.inject('blocklyDiv', {});
Blockly.defineBlocksWithJsonArray([
{
"type": "variable_block",
"message0": "%1",
"args0": [
{
"type": "field_variable",
"name": "NAME",
"variable": "x"
}
],
}
]);
this.createBlock = function(type) {
var block = this.workspace.newBlock(type);
block.initSvg();
block.render();
return block;
};
});
teardown(function() {
Blockly.Events.enable();
delete Blockly.Blocks['variable_block'];
});
suite('Connecting and Disconnecting', function() {
test('Connect Block to Next', function() {
var blockA = this.createBlock('stack_block');
var blockB = this.createBlock('stack_block');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.nextConnection.connect(blockB.previousConnection);
assertNotCollapsed(blockB);
});
test('Connect Block to Value Input', function() {
var blockA = this.createBlock('row_block');
var blockB = this.createBlock('row_block');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.getInput('INPUT').connection.connect(blockB.outputConnection);
chai.assert.isTrue(isBlockHidden(blockB));
blockA.setCollapsed(false);
assertNotCollapsed(blockA);
chai.assert.isFalse(isBlockHidden(blockB));
});
test('Connect Block to Statement Input', function() {
var blockA = this.createBlock('statement_block');
var blockB = this.createBlock('stack_block');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.getInput('STATEMENT').connection
.connect(blockB.previousConnection);
chai.assert.isTrue(isBlockHidden(blockB));
blockA.setCollapsed(false);
assertNotCollapsed(blockA);
chai.assert.isFalse(isBlockHidden(blockB));
});
test('Connect Block to Child of Collapsed - Input', function() {
var blockA = this.createBlock('row_block');
var blockB = this.createBlock('row_block');
var blockC = this.createBlock('row_block');
blockA.getInput('INPUT').connection.connect(blockB.outputConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
blockB.getInput('INPUT').connection.connect(blockC.outputConnection);
chai.assert.isTrue(isBlockHidden(blockC));
blockA.setCollapsed(false);
assertNotCollapsed(blockA);
chai.assert.isFalse(isBlockHidden(blockB));
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Connect Block to Child of Collapsed - Next', function() {
var blockA = this.createBlock('statement_block');
var blockB = this.createBlock('stack_block');
var blockC = this.createBlock('stack_block');
blockA.getInput('STATEMENT').connection
.connect(blockB.previousConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
blockB.nextConnection.connect(blockC.previousConnection);
chai.assert.isTrue(isBlockHidden(blockC));
blockA.setCollapsed(false);
assertNotCollapsed(blockA);
chai.assert.isFalse(isBlockHidden(blockB));
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Connect Block to Value Input Already Taken', function() {
var blockA = this.createBlock('row_block');
var blockB = this.createBlock('row_block');
var blockC = this.createBlock('row_block');
blockA.getInput('INPUT').connection.connect(blockB.outputConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
blockA.getInput('INPUT').connection.connect(blockC.outputConnection);
chai.assert.isTrue(isBlockHidden(blockC));
// Still hidden after C is inserted between.
chai.assert.isTrue(isBlockHidden(blockB));
blockA.setCollapsed(false);
assertNotCollapsed(blockA);
chai.assert.isFalse(isBlockHidden(blockB));
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Connect Block to Statement Input Already Taken', function() {
var blockA = this.createBlock('statement_block');
var blockB = this.createBlock('stack_block');
var blockC = this.createBlock('stack_block');
blockA.getInput('STATEMENT').connection
.connect(blockB.previousConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
blockA.getInput('STATEMENT').connection
.connect(blockC.previousConnection);
chai.assert.isTrue(isBlockHidden(blockC));
// Still hidden after C is inserted between.
chai.assert.isTrue(isBlockHidden(blockB));
blockA.setCollapsed(false);
assertNotCollapsed(blockA);
chai.assert.isFalse(isBlockHidden(blockB));
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Connect Block with Child - Input', function() {
var blockA = this.createBlock('row_block');
var blockB = this.createBlock('row_block');
var blockC = this.createBlock('row_block');
blockB.getInput('INPUT').connection.connect(blockC.outputConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.getInput('INPUT').connection.connect(blockB.outputConnection);
chai.assert.isTrue(isBlockHidden(blockC));
chai.assert.isTrue(isBlockHidden(blockB));
blockA.setCollapsed(false);
assertNotCollapsed(blockA);
chai.assert.isFalse(isBlockHidden(blockB));
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Connect Block with Child - Statement', function() {
var blockA = this.createBlock('statement_block');
var blockB = this.createBlock('stack_block');
var blockC = this.createBlock('stack_block');
blockB.nextConnection.connect(blockC.previousConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.getInput('STATEMENT').connection
.connect(blockB.previousConnection);
chai.assert.isTrue(isBlockHidden(blockC));
chai.assert.isTrue(isBlockHidden(blockB));
blockA.setCollapsed(false);
assertNotCollapsed(blockA);
chai.assert.isFalse(isBlockHidden(blockB));
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Disconnect Block from Value Input', function() {
var blockA = this.createBlock('row_block');
var blockB = this.createBlock('row_block');
blockA.getInput('INPUT').connection.connect(blockB.outputConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
blockB.outputConnection.disconnect();
chai.assert.isFalse(isBlockHidden(blockB));
});
test('Disconnect Block from Statement Input', function() {
var blockA = this.createBlock('statement_block');
var blockB = this.createBlock('stack_block');
blockA.getInput('STATEMENT').connection
.connect(blockB.previousConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
blockB.previousConnection.disconnect();
chai.assert.isFalse(isBlockHidden(blockB));
});
test('Disconnect Block from Child of Collapsed - Input', function() {
var blockA = this.createBlock('row_block');
var blockB = this.createBlock('row_block');
var blockC = this.createBlock('row_block');
blockA.getInput('INPUT').connection.connect(blockB.outputConnection);
blockB.getInput('INPUT').connection.connect(blockC.outputConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
chai.assert.isTrue(isBlockHidden(blockC));
blockC.outputConnection.disconnect();
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Disconnect Block from Child of Collapsed - Next', function() {
var blockA = this.createBlock('statement_block');
var blockB = this.createBlock('stack_block');
var blockC = this.createBlock('stack_block');
blockA.getInput('STATEMENT').connection
.connect(blockB.previousConnection);
blockB.nextConnection.connect(blockC.previousConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
chai.assert.isTrue(isBlockHidden(blockC));
blockC.previousConnection.disconnect();
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Disconnect Block with Child - Input', function() {
var blockA = this.createBlock('row_block');
var blockB = this.createBlock('row_block');
var blockC = this.createBlock('row_block');
blockB.getInput('INPUT').connection.connect(blockC.outputConnection);
blockA.getInput('INPUT').connection.connect(blockB.outputConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockB));
chai.assert.isTrue(isBlockHidden(blockC));
blockB.outputConnection.disconnect();
chai.assert.isFalse(isBlockHidden(blockB));
chai.assert.isFalse(isBlockHidden(blockC));
});
test('Disconnect Block with Child - Statement', function() {
var blockA = this.createBlock('statement_block');
var blockB = this.createBlock('stack_block');
var blockC = this.createBlock('stack_block');
blockB.nextConnection.connect(blockC.previousConnection);
blockA.getInput('STATEMENT').connection
.connect(blockB.previousConnection);
blockA.setCollapsed(true);
assertCollapsed(blockA);
chai.assert.isTrue(isBlockHidden(blockC));
chai.assert.isTrue(isBlockHidden(blockB));
blockB.previousConnection.disconnect();
chai.assert.isFalse(isBlockHidden(blockB));
chai.assert.isFalse(isBlockHidden(blockC));
});
});
suite('Adding and Removing Block Parts', function() {
test('Add Previous Connection', function() {
var blockA = this.createBlock('empty_block');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.setPreviousStatement(true);
assertCollapsed(blockA);
chai.assert.isNotNull(blockA.previousConnection);
});
test('Add Next Connection', function() {
var blockA = this.createBlock('empty_block');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.setNextStatement(true);
assertCollapsed(blockA);
chai.assert.isNotNull(blockA.nextConnection);
});
test('Add Input', function() {
var blockA = this.createBlock('empty_block');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.appendDummyInput('NAME');
assertCollapsed(blockA);
chai.assert.isNotNull(blockA.getInput('NAME'));
});
test('Add Field', function() {
var blockA = this.createBlock('empty_block');
var input = blockA.appendDummyInput('NAME');
blockA.setCollapsed(true);
assertCollapsed(blockA);
input.appendField(new Blockly.FieldLabel('test'), 'FIELD');
assertCollapsed(blockA);
var field = blockA.getField('FIELD');
chai.assert.isNotNull(field);
chai.assert.equal('test', field.getText());
});
test('Add Icon', function() {
var blockA = this.createBlock('empty_block');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.setCommentText('test');
assertCollapsed(blockA);
});
test('Remove Previous Connection', function() {
var blockA = this.createBlock('empty_block');
blockA.setPreviousStatement(true);
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.setPreviousStatement(false);
assertCollapsed(blockA);
chai.assert.isNull(blockA.previousConnection);
});
test('Remove Next Connection', function() {
var blockA = this.createBlock('empty_block');
blockA.setNextStatement(true);
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.setNextStatement(false);
assertCollapsed(blockA);
chai.assert.isNull(blockA.nextConnection);
});
test('Remove Input', function() {
var blockA = this.createBlock('empty_block');
blockA.appendDummyInput('NAME');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.removeInput('NAME');
assertCollapsed(blockA);
chai.assert.isNull(blockA.getInput('NAME'));
});
test('Remove Field', function() {
var blockA = this.createBlock('empty_block');
var input = blockA.appendDummyInput('NAME');
input.appendField(new Blockly.FieldLabel('test'), 'FIELD');
blockA.setCollapsed(true);
assertCollapsed(blockA);
input.removeField('FIELD');
assertCollapsed(blockA);
var field = blockA.getField('FIELD');
chai.assert.isNull(field);
});
test('Remove Icon', function() {
var blockA = this.createBlock('empty_block');
blockA.setCommentText('test');
blockA.setCollapsed(true);
assertCollapsed(blockA);
blockA.setCommentText(null);
assertCollapsed(blockA);
});
});
suite('Renaming Vars', function() {
test('Simple Rename', function() {
var blockA = this.createBlock('variable_block');
blockA.setCollapsed(true);
assertCollapsed(blockA, 'x');
var variable = this.workspace.getVariable('x', '');
this.workspace.renameVariableById(variable.getId(), 'y');
assertCollapsed(blockA, 'y');
});
test('Coalesce, Different Case', function() {
var blockA = this.createBlock('variable_block');
blockA.setCollapsed(true);
assertCollapsed(blockA, 'x');
var variable = this.workspace.createVariable('y');
this.workspace.renameVariableById(variable.getId(), 'X');
assertCollapsed(blockA, 'X');
});
});
});
suite('Style', function() {
suite('Headless', function() {
setup(function() {

View File

@@ -40,7 +40,7 @@ async function runMochaTestsInBrowser() {
var elem = await browser.$('#failureCount');
var text = await elem.getAttribute('tests_failed');
return text != 'unset';
}, 7000);
}, 9000);
const elem = await browser.$('#failureCount');
const numOfFailure = await elem.getAttribute('tests_failed');