From ee78b419875572f3a3182d3c8ba97c2f6526d069 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Thu, 12 Aug 2021 15:53:28 +0000 Subject: [PATCH] feat: upgrade block defs to have JSO serialization hooks (#5329) * Respect nulls from blocks.save * Upgrade list blocks to use JSO serialization * Upgrade logic blocks to use JSO serialization * Upgrade math blocks to use JSO serialization * Upgrade text blocks to use JSO serialization * Upgrade procedure blocks to use JSO serialization * Add more mutator tests * Fix firing enabled events * PR Comments --- blocks/lists.js | 44 ++++++++++++++- blocks/logic.js | 30 +++++++++++ blocks/math.js | 17 +++++- blocks/procedures.js | 92 +++++++++++++++++++++++++++++++- blocks/text.js | 44 ++++++++++++++- core/block.js | 5 +- core/serialization/workspaces.js | 3 +- tests/deps.js | 8 +-- tests/mocha/serializer_test.js | 63 +++++++++++++++++++++- 9 files changed, 293 insertions(+), 13 deletions(-) diff --git a/blocks/lists.js b/blocks/lists.js index 7d1cc9be2be..00dedd555c1 100644 --- a/blocks/lists.js +++ b/blocks/lists.js @@ -131,6 +131,7 @@ Blockly.Blocks['lists_create_with'] = { }, /** * Create XML to represent list inputs. + * Backwards compatible serialization implementation. * @return {!Element} XML storage element. * @this {Blockly.Block} */ @@ -141,6 +142,7 @@ Blockly.Blocks['lists_create_with'] = { }, /** * Parse XML to restore the list inputs. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ @@ -148,6 +150,23 @@ Blockly.Blocks['lists_create_with'] = { this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10); this.updateShape_(); }, + /** + * Returns the state of this block as a JSON serializable object. + * @return {{itemCount: number}} The state of this block, ie the item count. + */ + saveExtraState: function() { + return { + 'itemCount': this.itemCount_, + }; + }, + /** + * Applies the given state to this block. + * @param {*} state The state to apply to this block, ie the item count. + */ + loadExtraState: function(state) { + this.itemCount_ = state['itemCount']; + this.updateShape_(); + }, /** * Populate the mutator's dialog with this block's components. * @param {!Blockly.Workspace} workspace Mutator's workspace. @@ -424,6 +443,12 @@ Blockly.Blocks['lists_getIndex'] = { var isAt = (xmlElement.getAttribute('at') != 'false'); this.updateAt_(isAt); }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. + /** * Switch between a value block and a statement block. * @param {boolean} newStatement True if the block should be a statement. @@ -584,6 +609,12 @@ Blockly.Blocks['lists_setIndex'] = { var isAt = (xmlElement.getAttribute('at') != 'false'); this.updateAt_(isAt); }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. + /** * Create or delete an input for the numeric index. * @param {boolean} isAt True if the input should exist. @@ -684,6 +715,12 @@ Blockly.Blocks['lists_getSublist'] = { this.updateAt_(1, isAt1); this.updateAt_(2, isAt2); }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. + /** * Create or delete an input for a numeric index. * This block has two such inputs, independent of each other. @@ -857,5 +894,10 @@ Blockly.Blocks['lists_split'] = { */ domToMutation: function(xmlElement) { this.updateType_(xmlElement.getAttribute('mode')); - } + }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. }; diff --git a/blocks/logic.js b/blocks/logic.js index c7b6acf0cdc..6779ffa0b6b 100644 --- a/blocks/logic.js +++ b/blocks/logic.js @@ -303,6 +303,7 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = { /** * Create XML to represent the number of else-if and else inputs. + * Backwards compatible serialization implementation. * @return {Element} XML storage element. * @this {Blockly.Block} */ @@ -321,6 +322,7 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = { }, /** * Parse XML to restore the else-if and else inputs. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ @@ -329,6 +331,34 @@ Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = { this.elseCount_ = parseInt(xmlElement.getAttribute('else'), 10) || 0; this.rebuildShape_(); }, + /** + * Returns the state of this block as a JSON serializable object. + * @return {?{elseIfCount: (number|undefined), haseElse: (boolean|undefined)}} + * The state of this block, ie the else if count and else state. + */ + saveExtraState: function() { + if (!this.elseifCount_ && !this.elseCount_) { + return null; + } + var state = Object.create(null); + if (this.elseifCount_) { + state['elseIfCount'] = this.elseifCount_; + } + if (this.elseCount_) { + state['hasElse'] = true; + } + return state; + }, + /** + * Applies the given state to this block. + * @param {*} state The state to apply to this block, ie the else if count and + * else state. + */ + loadExtraState: function(state) { + this.elseifCount_ = state['elseIfCount'] || 0; + this.elseCount_ = state['hasElse'] ? 1 : 0; + this.updateShape_(); + }, /** * Populate the mutator's dialog with this block's components. * @param {!Blockly.Workspace} workspace Mutator's workspace. diff --git a/blocks/math.js b/blocks/math.js index b6827c5b121..d86da5d5d0c 100644 --- a/blocks/math.js +++ b/blocks/math.js @@ -446,6 +446,7 @@ Blockly.Extensions.register('math_op_tooltip', Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = { /** * Create XML to represent whether the 'divisorInput' should be present. + * Backwards compatible serialization implementation. * @return {!Element} XML storage element. * @this {Blockly.Block} */ @@ -457,6 +458,7 @@ Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = { }, /** * Parse XML to restore the 'divisorInput'. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ @@ -464,6 +466,12 @@ Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = { var divisorInput = (xmlElement.getAttribute('divisor_input') == 'true'); this.updateShape_(divisorInput); }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. + /** * Modify this block to have (or not have) an input for 'is divisible by'. * @param {boolean} divisorInput True if this block has a divisor input. @@ -531,6 +539,7 @@ Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN = { }, /** * Create XML to represent the output type. + * Backwards compatible serialization implementation. * @return {!Element} XML storage element. * @this {Blockly.Block} */ @@ -541,12 +550,18 @@ Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN = { }, /** * Parse XML to restore the output type. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ domToMutation: function(xmlElement) { this.updateType_(xmlElement.getAttribute('op')); - } + }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. }; /** diff --git a/blocks/procedures.js b/blocks/procedures.js index 644d7a7511d..4e3327d620f 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -95,6 +95,7 @@ Blockly.Blocks['procedures_defnoreturn'] = { }, /** * Create XML to represent the argument inputs. + * Backwards compatible serialization implementation. * @param {boolean=} opt_paramIds If true include the IDs of the parameter * quarks. Used by Blockly.Procedures.mutateCallers for reconnection. * @return {!Element} XML storage element. @@ -124,6 +125,7 @@ Blockly.Blocks['procedures_defnoreturn'] = { }, /** * Parse XML to restore the argument inputs. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ @@ -150,6 +152,54 @@ Blockly.Blocks['procedures_defnoreturn'] = { // Show or hide the statement input. this.setStatements_(xmlElement.getAttribute('statements') !== 'false'); }, + /** + * Returns the state of this block as a JSON serializable object. + * @return {?{params: (!Array<{name: string, id: string}>|undefined), + * hasStatements: (boolean|undefined)}} The state of this block, eg the + * parameters and statements. + */ + saveExtraState: function() { + if (!this.argumentVarModels_.length && this.hasStatements_) { + return null; + } + var state = Object.create(null); + if (this.argumentVarModels_.length) { + state['params'] = []; + for (var i = 0; i < this.argumentVarModels_.length; i++) { + state['params'].push({ + // We don't need to serialize the name, but just in case we decide + // to separate params from variables. + 'name': this.argumentVarModels_[i].name, + 'id': this.argumentVarModels_[i].getId() + }); + } + } + if (!this.hasStatements_) { + state['hasStatements'] = false; + } + return state; + }, + /** + * Applies the given state to this block. + * @param {*} state The state to apply to this block, eg the parameters and + * statements. + */ + loadExtraState: function(state) { + this.arguments_ = []; + this.argumentVarModels_ = []; + if (state['params']) { + for (var i = 0; i < state['params'].length; i++) { + var param = state['params'][i]; + var variable = Blockly.Variables.getOrCreateVariablePackage( + this.workspace, param['id'], param['name'], ''); + this.arguments_.push(variable.name); + this.argumentVarModels_.push(variable); + } + } + this.updateParams_(); + Blockly.Procedures.mutateCallers(this); + this.setStatements_(state['hasStatements'] === false ? false : true); + }, /** * Populate the mutator's dialog with this block's components. * @param {!Blockly.Workspace} workspace Mutator's workspace. @@ -436,6 +486,8 @@ Blockly.Blocks['procedures_defreturn'] = { updateParams_: Blockly.Blocks['procedures_defnoreturn'].updateParams_, mutationToDom: Blockly.Blocks['procedures_defnoreturn'].mutationToDom, domToMutation: Blockly.Blocks['procedures_defnoreturn'].domToMutation, + saveExtraState: Blockly.Blocks['procedures_defnoreturn'].saveExtraState, + loadExtraState: Blockly.Blocks['procedures_defnoreturn'].loadExtraState, decompose: Blockly.Blocks['procedures_defnoreturn'].decompose, compose: Blockly.Blocks['procedures_defnoreturn'].compose, /** @@ -776,6 +828,7 @@ Blockly.Blocks['procedures_callnoreturn'] = { }, /** * Create XML to represent the (non-editable) name and arguments. + * Backwards compatible serialization implementation. * @return {!Element} XML storage element. * @this {Blockly.Block} */ @@ -791,6 +844,7 @@ Blockly.Blocks['procedures_callnoreturn'] = { }, /** * Parse XML to restore the (non-editable) name and parameters. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ @@ -807,6 +861,34 @@ Blockly.Blocks['procedures_callnoreturn'] = { } this.setProcedureParameters_(args, paramIds); }, + /** + * Returns the state of this block as a JSON serializable object. + * @return {{name: string, params:(!Array|undefined)}} The state of + * this block, ie the params and procedure name. + */ + saveExtraState: function() { + var state = Object.create(null); + state['name'] = this.getProcedureCall(); + if (this.arguments_.length) { + state['params'] = this.arguments_; + } + return state; + }, + /** + * Applies the given state to this block. + * @param {*} state The state to apply to this block, ie the params and + * procedure name. + */ + loadExtraState: function(state) { + this.renameProcedure(this.getProcedureCall(), state['name']); + const params = state['params']; + if (params) { + const ids = []; + ids.length = params.length; + ids.fill(null); + this.setProcedureParameters_(params, ids); + } + }, /** * Return all variables referenced by this block. * @return {!Array} List of variable names. @@ -975,6 +1057,8 @@ Blockly.Blocks['procedures_callreturn'] = { updateShape_: Blockly.Blocks['procedures_callnoreturn'].updateShape_, mutationToDom: Blockly.Blocks['procedures_callnoreturn'].mutationToDom, domToMutation: Blockly.Blocks['procedures_callnoreturn'].domToMutation, + saveExtraState: Blockly.Blocks['procedures_callnoreturn'].saveExtraState, + loadExtraState: Blockly.Blocks['procedures_callnoreturn'].loadExtraState, getVars: Blockly.Blocks['procedures_callnoreturn'].getVars, getVarModels: Blockly.Blocks['procedures_callnoreturn'].getVarModels, onchange: Blockly.Blocks['procedures_callnoreturn'].onchange, @@ -1026,6 +1110,12 @@ Blockly.Blocks['procedures_ifreturn'] = { .appendField(Blockly.Msg['PROCEDURES_DEFRETURN_RETURN']); } }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this block is already encoded in the + // block's position in the workspace. + // XML hooks are kept for backwards compatibility. + /** * Called whenever anything on the workspace changes. * Add warning if this flow block is not nested inside a loop. @@ -1033,7 +1123,7 @@ Blockly.Blocks['procedures_ifreturn'] = { * @this {Blockly.Block} */ onchange: function(_e) { - if (!this.workspace.isDragging || this.workspace.isDragging()) { + if (this.workspace.isDragging && this.workspace.isDragging()) { return; // Don't change state at the start of a drag. } var legal = false; diff --git a/blocks/text.js b/blocks/text.js index 9e806be92f3..2738c047f61 100644 --- a/blocks/text.js +++ b/blocks/text.js @@ -261,6 +261,7 @@ Blockly.Blocks['text_getSubstring'] = { }, /** * Create XML to represent whether there are 'AT' inputs. + * Backwards compatible serialization implementation. * @return {!Element} XML storage element. * @this {Blockly.Block} */ @@ -274,6 +275,7 @@ Blockly.Blocks['text_getSubstring'] = { }, /** * Parse XML to restore the 'AT' inputs. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ @@ -283,6 +285,12 @@ Blockly.Blocks['text_getSubstring'] = { this.updateAt_(1, isAt1); this.updateAt_(2, isAt2); }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. + /** * Create or delete an input for a numeric index. * This block has two such inputs, independent of each other. @@ -441,6 +449,7 @@ Blockly.Blocks['text_prompt_ext'] = { }, /** * Create XML to represent the output type. + * Backwards compatible serialization implementation. * @return {!Element} XML storage element. * @this {Blockly.Block} */ @@ -451,12 +460,18 @@ Blockly.Blocks['text_prompt_ext'] = { }, /** * Parse XML to restore the output type. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ domToMutation: function(xmlElement) { this.updateType_(xmlElement.getAttribute('type')); - } + }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. }; Blockly.Blocks['text_prompt'] = { @@ -678,6 +693,7 @@ Blockly.Constants.Text.TEXT_QUOTES_EXTENSION = function() { Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN = { /** * Create XML to represent number of text inputs. + * Backwards compatible serialization implementation. * @return {!Element} XML storage element. * @this {Blockly.Block} */ @@ -688,6 +704,7 @@ Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN = { }, /** * Parse XML to restore the text inputs. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ @@ -695,6 +712,23 @@ Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN = { this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10); this.updateShape_(); }, + /** + * Returns the state of this block as a JSON serializable object. + * @return {{itemCount: number}} The state of this block, ie the item count. + */ + saveExtraState: function() { + return { + 'itemCount': this.itemCount_, + }; + }, + /** + * Applies the given state to this block. + * @param {*} state The state to apply to this block, ie the item count. + */ + loadExtraState: function(state) { + this.itemCount_ = state['itemCount']; + this.updateShape_(); + }, /** * Populate the mutator's dialog with this block's components. * @param {!Blockly.Workspace} workspace Mutator's workspace. @@ -829,6 +863,7 @@ Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION = function() { Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = { /** * Create XML to represent whether there is an 'AT' input. + * Backwards compatible serialization implementation. * @return {!Element} XML storage element. * @this {Blockly.Block} */ @@ -839,6 +874,7 @@ Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = { }, /** * Parse XML to restore the 'AT' input. + * Backwards compatible serialization implementation. * @param {!Element} xmlElement XML storage element. * @this {Blockly.Block} */ @@ -848,6 +884,12 @@ Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = { var isAt = (xmlElement.getAttribute('at') != 'false'); this.updateAt_(isAt); }, + + // This block does not need JSO serialization hooks (saveExtraState and + // loadExtraState) because the state of this object is already encoded in the + // dropdown values. + // XML hooks are kept for backwards compatibility. + /** * Create or delete an input for the numeric index. * @param {boolean} isAt True if the input should exist. diff --git a/core/block.js b/core/block.js index d0d066ad930..eb072da342f 100644 --- a/core/block.js +++ b/core/block.js @@ -1335,9 +1335,10 @@ Block.prototype.isEnabled = function() { */ Block.prototype.setEnabled = function(enabled) { if (this.isEnabled() != enabled) { - Events.fire(new (Events.get(Events.BLOCK_CHANGE))( - this, 'disabled', null, this.disabled, !enabled)); + const oldValue = this.disabled; this.disabled = !enabled; + Events.fire(new (Events.get(Events.BLOCK_CHANGE))( + this, 'disabled', null, oldValue, !enabled)); } }; diff --git a/core/serialization/workspaces.js b/core/serialization/workspaces.js index 4b82ef7cab1..581ca867a80 100644 --- a/core/serialization/workspaces.js +++ b/core/serialization/workspaces.js @@ -41,8 +41,7 @@ const save = function(workspace) { const blockStates = []; for (let block of workspace.getTopBlocks(false)) { - const blockState = - blocks.save(block, {addCoordinates: true}); + const blockState = blocks.save(block, {addCoordinates: true}); if (blockState) { blockStates.push(blockState); } diff --git a/tests/deps.js b/tests/deps.js index adcd3e2a911..8fe9efacbf2 100644 --- a/tests/deps.js +++ b/tests/deps.js @@ -1,10 +1,10 @@ goog.addDependency('../../blocks/colour.js', ['Blockly.Blocks.colour', 'Blockly.Constants.Colour'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldColour', 'Blockly.FieldLabel']); -goog.addDependency('../../blocks/lists.js', ['Blockly.Constants.Lists'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.Mutator']); +goog.addDependency('../../blocks/lists.js', ['Blockly.Constants.Lists'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.Mutator'], {'lang': 'es5'}); goog.addDependency('../../blocks/logic.js', ['Blockly.Blocks.logic', 'Blockly.Constants.Logic'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.Mutator']); goog.addDependency('../../blocks/loops.js', ['Blockly.Blocks.loops', 'Blockly.Constants.Loops'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.FieldNumber', 'Blockly.FieldVariable', 'Blockly.Warning']); -goog.addDependency('../../blocks/math.js', ['Blockly.Blocks.math', 'Blockly.Constants.Math'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.FieldNumber', 'Blockly.FieldVariable']); -goog.addDependency('../../blocks/procedures.js', ['Blockly.Blocks.procedures'], ['Blockly', 'Blockly.Blocks', 'Blockly.Comment', 'Blockly.FieldCheckbox', 'Blockly.FieldLabel', 'Blockly.FieldTextInput', 'Blockly.Mutator', 'Blockly.Warning'], {'lang': 'es5'}); -goog.addDependency('../../blocks/text.js', ['Blockly.Blocks.texts', 'Blockly.Constants.Text'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldMultilineInput', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Mutator']); +goog.addDependency('../../blocks/math.js', ['Blockly.Blocks.math', 'Blockly.Constants.Math'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldLabel', 'Blockly.FieldNumber', 'Blockly.FieldVariable'], {'lang': 'es5'}); +goog.addDependency('../../blocks/procedures.js', ['Blockly.Blocks.procedures'], ['Blockly', 'Blockly.Blocks', 'Blockly.Comment', 'Blockly.FieldCheckbox', 'Blockly.FieldLabel', 'Blockly.FieldTextInput', 'Blockly.Mutator', 'Blockly.Warning'], {'lang': 'es6'}); +goog.addDependency('../../blocks/text.js', ['Blockly.Blocks.texts', 'Blockly.Constants.Text'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldMultilineInput', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Mutator'], {'lang': 'es5'}); goog.addDependency('../../blocks/variables.js', ['Blockly.Blocks.variables', 'Blockly.Constants.Variables'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldLabel', 'Blockly.FieldVariable']); goog.addDependency('../../blocks/variables_dynamic.js', ['Blockly.Constants.VariablesDynamic'], ['Blockly', 'Blockly.Blocks', 'Blockly.FieldLabel', 'Blockly.FieldVariable']); goog.addDependency('../../core/block.js', ['Blockly.Block'], ['Blockly.ASTNode', 'Blockly.Blocks', 'Blockly.Connection', 'Blockly.Events', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Extensions', 'Blockly.Input', 'Blockly.Tooltip', 'Blockly.common', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.fieldRegistry', 'Blockly.inputTypes', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.idGenerator', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'}); diff --git a/tests/mocha/serializer_test.js b/tests/mocha/serializer_test.js index 3da2ff50045..466c16859c7 100644 --- a/tests/mocha/serializer_test.js +++ b/tests/mocha/serializer_test.js @@ -1313,6 +1313,30 @@ Serializer.Connections.testSuites = [ ]; Serializer.Mutations = new SerializerTestSuite('Mutations'); +Serializer.Mutations.ListGetIndex = new SerializerTestCase('ListGetIndex', + '' + + '' + + '' + + 'REMOVE' + + 'LAST' + + '' + + ''); +Serializer.Mutations.ListSetIndex = new SerializerTestCase('ListSetIndex', + '' + + '' + + '' + + 'SET' + + 'LAST' + + '' + + ''); +Serializer.Mutations.ListGetSublist = new SerializerTestCase('ListGetSublist', + '' + + '' + + '' + + 'FIRST' + + 'LAST' + + '' + + ''); Serializer.Mutations.MathNumberProperty = new SerializerTestCase( 'MathNumberProperty', '' + @@ -1371,6 +1395,9 @@ Serializer.Mutations.TextPrompt = new SerializerTestCase( '' + ''); Serializer.Mutations.testCases = [ + Serializer.Mutations.ListGetIndex, + Serializer.Mutations.ListSetIndex, + Serializer.Mutations.ListGetSublist, Serializer.Mutations.MathNumberProperty, Serializer.Mutations.MathOnList, Serializer.Mutations.TextJoin, @@ -1621,10 +1648,45 @@ Serializer.Mutations.Procedure.NoStatements = new SerializerTestCase( 'do something' + '' + ''); +Serializer.Mutations.Procedure.IfReturn = new SerializerTestCase( + 'IfReturn', + '' + + '' + + 'do something' + + '' + + '' + + '' + + '' + + '' + + '' + + ''); +Serializer.Mutations.Procedure.Caller = new SerializerTestCase( + 'Caller', + '' + + '' + + 'x' + + 'y' + + '' + + '' + + '' + + '' + + '' + + '' + + 'do something' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + ''); Serializer.Mutations.Procedure.testCases = [ Serializer.Mutations.Procedure.NoMutation, Serializer.Mutations.Procedure.Variables, Serializer.Mutations.Procedure.NoStatements, + Serializer.Mutations.Procedure.IfReturn, + Serializer.Mutations.Procedure.Caller, ]; Serializer.Mutations.Procedure.Names = new SerializerTestSuite('Names'); @@ -1773,5 +1835,4 @@ var runSerializerTestSuite = (serializer, deserializer, testSuite) => { runSerializerTestSuite(null, null, Serializer); Serializer.Icons.skip = true; -Serializer.Mutations.skip = true; runSerializerTestSuite(state => state, state => state, Serializer);