diff --git a/tests/jsunit/extensions_test.js b/tests/jsunit/extensions_test.js deleted file mode 100644 index 43bb66deb..000000000 --- a/tests/jsunit/extensions_test.js +++ /dev/null @@ -1,643 +0,0 @@ -/** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - - /** - * @fileoverview Tests for Blockly.Extensions - * @author Anm@anm.me (Andrew n marshall) - */ -'use strict'; - -function test_extension() { - var workspace = new Blockly.Workspace(); - var block; - try { - assertUndefined(Blockly.Extensions.ALL_['extensions_test']); - - var numCallsToBefore = 0; - var numCallsToAfter = 0; - - // Extension defined before the block type is defined. - Blockly.Extensions.register('extensions_test_before', function () { - numCallsToBefore++; - this.extendedWithBefore = true; - }); - - Blockly.defineBlocksWithJsonArray([{ - "type": "extension_test_block", - "message0": "extension_test_block", - "extensions": ["extensions_test_before", "extensions_test_after"] - }]); - - // Extension defined after the block type (but before instantiation). - Blockly.Extensions.register('extensions_test_after', function () { - numCallsToAfter++; - this.extendedWithAfter = true; - }); - - assert(typeof Blockly.Extensions.ALL_['extensions_test_before'] == 'function'); - assert(typeof Blockly.Extensions.ALL_['extensions_test_after'] == 'function'); - assertEquals(0, numCallsToBefore); - assertEquals(0, numCallsToAfter); - - block = new Blockly.Block(workspace, 'extension_test_block'); - - assertEquals(1, numCallsToBefore); - assertEquals(1, numCallsToAfter); - assert(block.extendedWithBefore); - assert(block.extendedWithAfter); - } finally { - block && block.dispose(); - workspace.dispose(); - - delete Blockly.Extensions.ALL_['extensions_test_before']; - delete Blockly.Extensions.ALL_['extensions_test_after']; - delete Blockly.Blocks['extension_test_block']; - } -} - -function test_extension_missing() { - var workspace = new Blockly.Workspace(); - var block; - var exceptionWasThrown = false; - try { - assertUndefined(Blockly.Extensions.ALL_['missing_extension']); - Blockly.defineBlocksWithJsonArray([{ - "type": "missing_extension_block", - "message0": "missing_extension_block", - "extensions": ["missing_extension"] - }]); - - block = new Blockly.Block(workspace, 'missing_extension_block'); - } catch (e) { - // Expected. - exceptionWasThrown = true; - } finally { - block && block.dispose(); - workspace.dispose(); - delete Blockly.Blocks['missing_extension_block']; - } - assert(exceptionWasThrown); -} - -function test_extension_not_a_function() { - var exceptionWasThrown = false; - try { - assertUndefined(Blockly.Extensions.ALL_['extension_just_a_string']); - Blockly.Extensions.register('extension_just_a_string', 'extension_just_a_string'); - } catch (e) { - // Expected. - exceptionWasThrown = true; - } finally { - delete Blockly.Extensions.ALL_['extension_just_a_string']; - } - assert(exceptionWasThrown); - - var exceptionWasThrown = false; - try { - assertUndefined(Blockly.Extensions.ALL_['extension_is_null']); - Blockly.Extensions.register('extension_is_null', null); - } catch (e) { - // Expected. - exceptionWasThrown = true; - } finally { - delete Blockly.Extensions.ALL_['extension_is_null']; - } - assert(exceptionWasThrown); - - var exceptionWasThrown = false; - try { - assertUndefined(Blockly.Extensions.ALL_['extension_is_undefined']); - Blockly.Extensions.register('extension_is_undefined'); - } catch (e) { - // Expected. - exceptionWasThrown = true; - } finally { - delete Blockly.Extensions.ALL_['extension_is_undefined']; - } - assert(exceptionWasThrown); -} - -function test_parent_tooltip_when_inline() { - var defaultTooltip = "defaultTooltip"; - var parentTooltip = "parentTooltip"; - - var workspace = new Blockly.Workspace(); - var block; - try { - Blockly.defineBlocksWithJsonArray([ - { - "type": "test_parent_tooltip_when_inline", - "message0": "test_parent_tooltip_when_inline", - "output": true, - "tooltip": defaultTooltip, - "extensions": ["parent_tooltip_when_inline"] - }, - { - "type": "test_parent", - "message0": "%1", - "args0": [ - { - "type": "input_value", - "name": "INPUT" - } - ], - "tooltip": parentTooltip - } - ]); - - block = new Blockly.Block(workspace, 'test_parent_tooltip_when_inline'); - - // Tooltip is dynamic after extension initialization. - assert(typeof block.tooltip == 'function'); - assertEquals(block.tooltip(), defaultTooltip); - - // Tooltip is normal before connected to parent. - var parent = new Blockly.Block(workspace, 'test_parent'); - assertEquals(parent.tooltip, parentTooltip); - assertFalse(!!parent.inputsInline); - - // Tooltip is normal when parent is not inline. - parent.getInput('INPUT').connection.connect(block.outputConnection); - assertEquals(block.getParent(), parent); - assertEquals(block.tooltip(), defaultTooltip); - - // Tooltip is parent's when parent is inline. - parent.setInputsInline(true); - assertEquals(block.tooltip(), parentTooltip); - - // Tooltip revert when disconnected. - parent.getInput('INPUT').connection.disconnect(); - assert(!block.getParent()); - assertEquals(block.tooltip(), defaultTooltip); - } finally { - block && block.dispose(); - workspace.dispose(); - - delete Blockly.Blocks['test_parent_tooltip_when_inline']; - delete Blockly.Blocks['test_parent']; - } -} - -function test_mixin_extension() { - var TEST_MIXIN = { - field: 'FIELD', - method: function() { - console.log('TEXT_MIXIN method()'); - } - }; - - var workspace = new Blockly.Workspace(); - var block; - try { - assertUndefined(Blockly.Extensions.ALL_['mixin_test']); - - // Extension defined before the block type is defined. - Blockly.Extensions.registerMixin('mixin_test', TEST_MIXIN); - assert(typeof Blockly.Extensions.ALL_['mixin_test'] == 'function'); - - Blockly.defineBlocksWithJsonArray([{ - "type": "test_block_mixin", - "message0": "test_block_mixin", - "extensions": ["mixin_test"] - }]); - - block = new Blockly.Block(workspace, 'test_block_mixin'); - - assertEquals(TEST_MIXIN.field, block.field); - assertEquals(TEST_MIXIN.method, block.method); - } finally { - block && block.dispose(); - workspace.dispose(); - - delete Blockly.Extensions.ALL_['mixin_test']; - delete Blockly.Blocks['test_block_mixin']; - } -} - -function test_bad_mixin_overwrites_local_value() { - var TEST_MIXIN_BAD_INPUTLIST = { - inputList: 'bad inputList' // Defined in constructor - }; - - var workspace = new Blockly.Workspace(); - var block; - try { - assertUndefined(Blockly.Extensions.ALL_['mixin_bad_inputList']); - - // Extension defined before the block type is defined. - Blockly.Extensions.registerMixin('mixin_bad_inputList', TEST_MIXIN_BAD_INPUTLIST); - assert(typeof Blockly.Extensions.ALL_['mixin_bad_inputList'] == 'function'); - - Blockly.defineBlocksWithJsonArray([{ - "type": "test_block_bad_inputList", - "message0": "test_block_bad_inputList", - "extensions": ["mixin_bad_inputList"] - }]); - - try { - block = new Blockly.Block(workspace, 'test_block_bad_inputList'); - } catch (e) { - // Expected Error - assert(e.message.indexOf('inputList') >= 0); // Reference the conflict - return; - } - fail('Expected error when constructing block'); - } finally { - block && block.dispose(); - workspace.dispose(); - - delete Blockly.Extensions.ALL_['mixin_bad_inputList']; - delete Blockly.Blocks['test_block_bad_inputList']; - } -} - -function test_bad_mixin_overwrites_prototype() { - var TEST_MIXIN_BAD_COLOUR = { - colour_: 'bad colour_' // Defined on prototype - }; - - var workspace = new Blockly.Workspace(); - var block; - try { - assertUndefined(Blockly.Extensions.ALL_['mixin_bad_colour_']); - - // Extension defined before the block type is defined. - Blockly.Extensions.registerMixin('mixin_bad_colour_', TEST_MIXIN_BAD_COLOUR); - assert(typeof Blockly.Extensions.ALL_['mixin_bad_colour_'] == 'function'); - - Blockly.defineBlocksWithJsonArray([{ - "type": "test_block_bad_colour", - "message0": "test_block_bad_colour", - "extensions": ["mixin_bad_colour_"] - }]); - - try { - block = new Blockly.Block(workspace, 'test_block_bad_colour'); - } catch (e) { - // Expected Error - assert(e.message.indexOf('colour_') >= 0); // Reference the conflict - return; - } - fail('Expected error when constructing block'); - } finally { - block && block.dispose(); - workspace.dispose(); - - delete Blockly.Extensions.ALL_['mixin_bad_colour_']; - delete Blockly.Blocks['test_block_bad_colour']; - } -} - -function test_mutator_mixin() { - var workspace = new Blockly.Workspace(); - var block; - - try { - Blockly.defineBlocksWithJsonArray([{ - "type": "mutator_test_block", - "message0": "mutator_test_block", - "mutator": "mutator_test" - }]); - - // Events code calls mutationToDom and expects it to give back a meaningful - // value. - Blockly.Events.disable(); - Blockly.Extensions.registerMutator('mutator_test', - { - domToMutation: function() { - return 'domToMutationFn'; - }, - mutationToDom: function() { - return 'mutationToDomFn'; - }, - compose: function() { - return 'composeFn'; - }, - decompose: function() { - return 'decomposeFn'; - } - }); - - block = new Blockly.Block(workspace, 'mutator_test_block'); - - // Make sure all of the functions were installed correctly. - assertEquals(block.domToMutation(), 'domToMutationFn'); - assertEquals(block.mutationToDom(), 'mutationToDomFn'); - assertEquals(block.compose(), 'composeFn'); - assertEquals(block.decompose(), 'decomposeFn'); - } finally { - if (block) { - block.dispose(); - } - workspace.dispose(); - Blockly.Events.enable(); - delete Blockly.Extensions.ALL_['mutator_test']; - } -} - -function test_mutator_mixin_no_dialog() { - var workspace = new Blockly.Workspace(); - var block; - - try { - Blockly.defineBlocksWithJsonArray([{ - "type": "mutator_test_block", - "message0": "mutator_test_block", - "mutator": "mutator_test" - }]); - - // Events code calls mutationToDom and expects it to give back a meaningful - // value. - Blockly.Events.disable(); - assertUndefined(Blockly.Extensions.ALL_['mutator_test']); - Blockly.Extensions.registerMutator('mutator_test', - { - domToMutation: function() { - return 'domToMutationFn'; - }, - mutationToDom: function() { - return 'mutationToDomFn'; - } - }); - - block = new Blockly.Block(workspace, 'mutator_test_block'); - - // Make sure all of the functions were installed correctly. - assertEquals(block.domToMutation(), 'domToMutationFn'); - assertEquals(block.mutationToDom(), 'mutationToDomFn'); - assertFalse(block.hasOwnProperty('compose')); - assertFalse(block.hasOwnProperty('decompose')); - } finally { - if (block) { - block.dispose(); - } - workspace.dispose(); - Blockly.Events.enable(); - delete Blockly.Extensions.ALL_['mutator_test']; - } -} - -// Explicitly check all four things that could be missing. -function test_mutator_mixin_no_decompose_fails() { - var exceptionWasThrown = false; - try { - Blockly.Extensions.registerMutator('mutator_test', - { - domToMutation: function() { - return 'domToMutationFn'; - }, - mutationToDom: function() { - return 'mutationToDomFn'; - }, - compose: function() { - return 'composeFn'; - } - }); - } catch (e) { - // Expected. - exceptionWasThrown = true; - } finally { - delete Blockly.Extensions.ALL_['mutator_test']; - } - assertTrue(exceptionWasThrown); -} - -function test_mutator_mixin_no_compose_fails() { - var exceptionWasThrown = false; - try { - Blockly.Extensions.registerMutator('mutator_test', - { - domToMutation: function() { - return 'domToMutationFn'; - }, - mutationToDom: function() { - return 'mutationToDomFn'; - }, - decompose: function() { - return 'decomposeFn'; - } - }); - } catch (e) { - // Expected. - exceptionWasThrown = true; - } finally { - delete Blockly.Extensions.ALL_['mutator_test']; - } - assertTrue(exceptionWasThrown); -} - -function test_mutator_mixin_no_domToMutation_fails() { - var exceptionWasThrown = false; - try { - Blockly.Extensions.registerMutator('mutator_test', - { - mutationToDom: function() { - return 'mutationToDomFn'; - }, - compose: function() { - return 'composeFn'; - }, - decompose: function() { - return 'decomposeFn'; - } - }); - } catch (e) { - // Expected. - exceptionWasThrown = true; - } finally { - delete Blockly.Extensions.ALL_['mutator_test']; - } - assertTrue(exceptionWasThrown); -} - -function test_mutator_mixin_no_mutationToDom_fails() { - var exceptionWasThrown = false; - try { - Blockly.Extensions.registerMutator('mutator_test', - { - domToMutation: function() { - return 'domToMutationFn'; - }, - compose: function() { - return 'composeFn'; - }, - decompose: function() { - return 'decomposeFn'; - } - }); - } catch (e) { - // Expected. - exceptionWasThrown = true; - } finally { - delete Blockly.Extensions.ALL_['mutator_test']; - } - assertTrue(exceptionWasThrown); -} - -function test_use_mutator_as_extension_fails() { - var workspace = new Blockly.Workspace(); - var block; - var exceptionWasThrown = false; - - try { - Blockly.defineBlocksWithJsonArray([{ - "type": "mutator_test_block", - "message0": "mutator_test_block", - "extensions": ["mutator_test"] - }]); - - Blockly.Events.disable(); - assertUndefined(Blockly.Extensions.ALL_['mutator_test']); - Blockly.Extensions.registerMutator('mutator_test', - { - domToMutation: function() { - return 'domToMutationFn'; - }, - mutationToDom: function() { - return 'mutationToDomFn'; - } - }); - - // Events code calls mutationToDom and expects it to give back a meaningful - // value. - block = new Blockly.Block(workspace, 'mutator_test_block'); - } catch (e) { - // Expected - exceptionWasThrown = true; - // Should have failed on apply, not on register. - assertNotNull(Blockly.Extensions.ALL_['mutator_test']); - } finally { - if (block) { - block.dispose(); - } - workspace.dispose(); - Blockly.Events.enable(); - delete Blockly.Extensions.ALL_['mutator_test']; - } - assertTrue(exceptionWasThrown); -} - -function test_use_mutator_mixin_as_extension_fails() { - var workspace = new Blockly.Workspace(); - var block; - var exceptionWasThrown = false; - - try { - Blockly.defineBlocksWithJsonArray([{ - "type": "mutator_test_block", - "message0": "mutator_test_block", - "extensions": ["mutator_test"] - }]); - - // Events code calls mutationToDom and expects it to give back a meaningful - // value. - Blockly.Events.disable(); - assertUndefined(Blockly.Extensions.ALL_['mutator_test']); - Blockly.Extensions.registerMixin('mutator_test', - { - domToMutation: function() { - return 'domToMutationFn'; - }, - mutationToDom: function() { - return 'mutationToDomFn'; - } - }); - - block = new Blockly.Block(workspace, 'mutator_test_block'); - } catch (e) { - // Expected - exceptionWasThrown = true; - // Should have failed on apply, not on register. - assertNotNull(Blockly.Extensions.ALL_['mutator_test']); - } finally { - if (block) { - block.dispose(); - } - workspace.dispose(); - Blockly.Events.enable(); - delete Blockly.Extensions.ALL_['mutator_test']; - } - assertTrue(exceptionWasThrown); -} - -function test_use_extension_as_mutator_fails() { - var workspace = new Blockly.Workspace(); - var block; - var exceptionWasThrown = false; - - try { - Blockly.defineBlocksWithJsonArray([{ - "type": "mutator_test_block", - "message0": "mutator_test_block", - "mutator": ["extensions_test"] - }]); - - // Events code calls mutationToDom and expects it to give back a meaningful - // value. - Blockly.Events.disable(); - assertUndefined(Blockly.Extensions.ALL_['extensions_test']); - Blockly.Extensions.register('extensions_test', function() { - return 'extensions_test_fn'; - }); - - block = new Blockly.Block(workspace, 'mutator_test_block'); - } catch (e) { - // Expected - exceptionWasThrown = true; - // Should have failed on apply, not on register. - assertNotNull(Blockly.Extensions.ALL_['extensions_test']); - } finally { - if (block) { - block.dispose(); - } - workspace.dispose(); - Blockly.Events.enable(); - delete Blockly.Extensions.ALL_['extensions_test']; - } - assertTrue(exceptionWasThrown); -} - -function test_mutator_mixin_plus_function() { - var workspace = new Blockly.Workspace(); - var block; - var fnWasCalled = false; - - try { - Blockly.defineBlocksWithJsonArray([{ - "type": "mutator_test_block", - "message0": "mutator_test_block", - "mutator": ["extensions_test"] - }]); - - Blockly.Events.disable(); - assertUndefined(Blockly.Extensions.ALL_['extensions_test']); - Blockly.Extensions.registerMutator('extensions_test', - { - domToMutation: function() { - return 'domToMutationFn'; - }, - mutationToDom: function() { - return 'mutationToDomFn'; - } - }, - function() { - fnWasCalled = true; - } - ); - - // Events code calls mutationToDom and expects it to give back a meaningful - // value. - block = new Blockly.Block(workspace, 'mutator_test_block'); - } finally { - if (block) { - block.dispose(); - } - workspace.dispose(); - Blockly.Events.enable(); - delete Blockly.Extensions.ALL_['extensions_test']; - } - assertTrue(fnWasCalled); -} diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html index 221ff2618..f7634f8cd 100644 --- a/tests/jsunit/index.html +++ b/tests/jsunit/index.html @@ -17,7 +17,7 @@ - + diff --git a/tests/mocha/extensions_test.js b/tests/mocha/extensions_test.js new file mode 100644 index 000000000..fcabd8e30 --- /dev/null +++ b/tests/mocha/extensions_test.js @@ -0,0 +1,511 @@ +/** + * @license + * Copyright 2020 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +suite('Extensions', function() { + setup(function() { + this.workspace = new Blockly.Workspace(); + this.blockTypesCleanup_ = []; + this.extensionsCleanup_ = []; + }); + teardown(function() { + var i; + for (i = 0; i < this.blockTypesCleanup_.length; i++) { + var blockType = this.blockTypesCleanup_[i]; + delete Blockly.Blocks[blockType]; + } + for (i = 0; i < this.extensionsCleanup_.length; i++) { + var extension = this.extensionsCleanup_[i]; + delete Blockly.Extensions.ALL_[extension]; + } + this.workspace.dispose(); + // Clear Blockly.Event state. + Blockly.Events.setGroup(false); + Blockly.Events.disabled_ = 0; + sinon.restore(); + }); + + test('Definition before and after block type', function() { + this.extensionsCleanup_.push('extensions_test_before'); + this.extensionsCleanup_.push('extensions_test_after'); + this.blockTypesCleanup_.push('extension_test_block'); + + assertUndefined(Blockly.Extensions.ALL_['extensions_test_before']); + var beforeCallback = sinon.spy(); + // Extension defined before the block type is defined. + Blockly.Extensions.register('extensions_test_before', beforeCallback); + + Blockly.defineBlocksWithJsonArray([{ + "type": "extension_test_block", + "message0": "extension_test_block", + "extensions": ["extensions_test_before", "extensions_test_after"] + }]); + + assertUndefined(Blockly.Extensions.ALL_['extensions_test_after']); + var afterCallback = sinon.spy(); + // Extension defined after the block type (but before instantiation). + Blockly.Extensions.register('extensions_test_after', afterCallback); + + assert(typeof Blockly.Extensions.ALL_['extensions_test_before'] == 'function'); + assert(typeof Blockly.Extensions.ALL_['extensions_test_after'] == 'function'); + sinon.assert.notCalled(beforeCallback); + sinon.assert.notCalled(afterCallback); + + var block = new Blockly.Block(this.workspace, 'extension_test_block'); + + sinon.assert.calledOnce(beforeCallback); + sinon.assert.calledOnce(afterCallback); + sinon.assert.calledOn(beforeCallback, block); + sinon.assert.calledOn(afterCallback, block); + }); + + test('Parent tooltip when inline', function() { + this.blockTypesCleanup_.push('test_parent_tooltip_when_inline'); + this.blockTypesCleanup_.push('test_parent'); + + var defaultTooltip = "defaultTooltip"; + var parentTooltip = "parentTooltip"; + Blockly.defineBlocksWithJsonArray([ + { + "type": "test_parent_tooltip_when_inline", + "message0": "test_parent_tooltip_when_inline", + "output": true, + "tooltip": defaultTooltip, + "extensions": ["parent_tooltip_when_inline"] + }, + { + "type": "test_parent", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "INPUT" + } + ], + "tooltip": parentTooltip + } + ]); + + var block = + new Blockly.Block(this.workspace, 'test_parent_tooltip_when_inline'); + + // Tooltip is dynamic after extension initialization. + assert(typeof block.tooltip == 'function'); + assertEquals(block.tooltip(), defaultTooltip); + + // Tooltip is normal before connected to parent. + var parent = new Blockly.Block(this.workspace, 'test_parent'); + assertEquals(parent.tooltip, parentTooltip); + assertFalse(!!parent.inputsInline); + + // Tooltip is normal when parent is not inline. + parent.getInput('INPUT').connection.connect(block.outputConnection); + assertEquals(block.getParent(), parent); + assertEquals(block.tooltip(), defaultTooltip); + + // Tooltip is parent's when parent is inline. + parent.setInputsInline(true); + assertEquals(block.tooltip(), parentTooltip); + + // Tooltip revert when disconnected. + parent.getInput('INPUT').connection.disconnect(); + assert(!block.getParent()); + assertEquals(block.tooltip(), defaultTooltip); + }); + + suite('Mixin', function() { + test('Basic', function() { + this.extensionsCleanup_.push('mixin_test'); + this.blockTypesCleanup_.push('test_block_mixin'); + + var testMixin = { + field: 'FIELD', + method: function() { + console.log('TEXT_MIXIN method()'); + } + }; + + assertUndefined(Blockly.Extensions.ALL_['mixin_test']); + // Extension defined before the block type is defined. + Blockly.Extensions.registerMixin('mixin_test', testMixin); + + assert(typeof Blockly.Extensions.ALL_['mixin_test'] == 'function'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "test_block_mixin", + "message0": "test_block_mixin", + "extensions": ["mixin_test"] + }]); + + var block = new Blockly.Block(this.workspace, 'test_block_mixin'); + + assertEquals(testMixin.field, block.field); + assertEquals(testMixin.method, block.method); + }); + + suite('Mutator', function() { + test('Basic', function() { + this.extensionsCleanup_.push('mutator_test'); + this.blockTypesCleanup_.push('mutator_test_block'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "mutator_test_block", + "message0": "mutator_test_block", + "mutator": "mutator_test" + }]); + + // Events code calls mutationToDom and expects it to give back a meaningful + // value. + Blockly.Events.disable(); + Blockly.Extensions.registerMutator('mutator_test', + { + domToMutation: function() { + return 'domToMutationFn'; + }, + mutationToDom: function() { + return 'mutationToDomFn'; + }, + compose: function() { + return 'composeFn'; + }, + decompose: function() { + return 'decomposeFn'; + } + }); + + var block = new Blockly.Block(this.workspace, 'mutator_test_block'); + + // Make sure all of the functions were installed correctly. + assertEquals(block.domToMutation(), 'domToMutationFn'); + assertEquals(block.mutationToDom(), 'mutationToDomFn'); + assertEquals(block.compose(), 'composeFn'); + assertEquals(block.decompose(), 'decomposeFn'); + }); + + test('With helper function', function() { + this.extensionsCleanup_.push('extensions_test'); + this.blockTypesCleanup_.push('mutator_test_block'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "mutator_test_block", + "message0": "mutator_test_block", + "mutator": ["extensions_test"] + }]); + + // Events code calls mutationToDom and expects it to give back a + // meaningful value. + Blockly.Events.disable(); + assertUndefined(Blockly.Extensions.ALL_['extensions_test']); + var helperFunctionSpy = sinon.spy(); + Blockly.Extensions.registerMutator('extensions_test', + { + domToMutation: function() { + return 'domToMutationFn'; + }, + mutationToDom: function() { + return 'mutationToDomFn'; + } + }, + helperFunctionSpy + ); + + var _ = new Blockly.Block(this.workspace, 'mutator_test_block'); + + sinon.assert.calledOnce(helperFunctionSpy); + }); + + test('No dialog', function() { + this.extensionsCleanup_.push('mutator_test'); + this.blockTypesCleanup_.push('mutator_test_block'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "mutator_test_block", + "message0": "mutator_test_block", + "mutator": "mutator_test" + }]); + + // Events code calls mutationToDom and expects it to give back a + // meaningful value. + Blockly.Events.disable(); + assertUndefined(Blockly.Extensions.ALL_['mutator_test']); + Blockly.Extensions.registerMutator('mutator_test', + { + domToMutation: function() { + return 'domToMutationFn'; + }, + mutationToDom: function() { + return 'mutationToDomFn'; + } + }); + + var block = new Blockly.Block(this.workspace, 'mutator_test_block'); + + // Make sure all of the functions were installed correctly. + assertEquals(block.domToMutation(), 'domToMutationFn'); + assertEquals(block.mutationToDom(), 'mutationToDomFn'); + assertFalse(block.hasOwnProperty('compose')); + assertFalse(block.hasOwnProperty('decompose')); + }); + }); + }); + + suite('Error cases', function() { + test('Missing extension', function() { + this.blockTypesCleanup_.push('missing_extension_block'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "missing_extension_block", + "message0": "missing_extension_block", + "extensions": ["missing_extension"] + }]); + + assertUndefined(Blockly.Extensions.ALL_['missing_extension']); + var workspace = this.workspace; + chai.assert.throws(function() { + var _ = new Blockly.Block(workspace, 'missing_extension_block'); + }); + }); + + test('Mixin overwrites local value', function() { + this.extensionsCleanup_.push('mixin_bad_inputList'); + this.blockTypesCleanup_.push('test_block_bad_inputList'); + + var TEST_MIXIN_BAD_INPUTLIST = { + inputList: 'bad inputList' // Defined in constructor + }; + + assertUndefined(Blockly.Extensions.ALL_['mixin_bad_inputList']); + // Extension defined before the block type is defined. + Blockly.Extensions.registerMixin('mixin_bad_inputList', TEST_MIXIN_BAD_INPUTLIST); + assert(typeof Blockly.Extensions.ALL_['mixin_bad_inputList'] == 'function'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "test_block_bad_inputList", + "message0": "test_block_bad_inputList", + "extensions": ["mixin_bad_inputList"] + }]); + + var workspace = this.workspace; + chai.assert.throws(function() { + var _ = new Blockly.Block(workspace, 'test_block_bad_inputList'); + }, /inputList/); + }); + + test('Mixin overwrites prototype', function() { + this.extensionsCleanup_.push('mixin_bad_colour_'); + this.blockTypesCleanup_.push('test_block_bad_colour'); + + var TEST_MIXIN_BAD_COLOUR = { + colour_: 'bad colour_' // Defined on prototype + }; + + assertUndefined(Blockly.Extensions.ALL_['mixin_bad_colour_']); + // Extension defined before the block type is defined. + Blockly.Extensions.registerMixin('mixin_bad_colour_', TEST_MIXIN_BAD_COLOUR); + assert(typeof Blockly.Extensions.ALL_['mixin_bad_colour_'] == 'function'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "test_block_bad_colour", + "message0": "test_block_bad_colour", + "extensions": ["mixin_bad_colour_"] + }]); + + var workspace = this.workspace; + chai.assert.throws(function() { + var _ = new Blockly.Block(workspace, 'test_block_bad_colour'); + }, /colour_/); + }); + + test('Use mutator as extension', function() { + this.extensionsCleanup_.push('mutator_test'); + this.blockTypesCleanup_.push('mutator_test_block'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "mutator_test_block", + "message0": "mutator_test_block", + "extensions": ["mutator_test"] + }]); + + // Events code calls mutationToDom and expects it to give back a + // meaningful value. + Blockly.Events.disable(); + assertUndefined(Blockly.Extensions.ALL_['mutator_test']); + Blockly.Extensions.registerMutator('mutator_test', + { + domToMutation: function() { + return 'domToMutationFn'; + }, + mutationToDom: function() { + return 'mutationToDomFn'; + } + }); + + var workspace = this.workspace; + chai.assert.throws(function() { + var _ = new Blockly.Block(workspace, 'mutator_test_block'); + }); + // Should have failed on apply, not on register. + assertNotNull(Blockly.Extensions.ALL_['mutator_test']); + }); + + test('Use mutator mixin as extension', function() { + this.extensionsCleanup_.push('mutator_test'); + this.blockTypesCleanup_.push('mutator_test_block'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "mutator_test_block", + "message0": "mutator_test_block", + "extensions": ["mutator_test"] + }]); + + // Events code calls mutationToDom and expects it to give back a + // meaningful value. + Blockly.Events.disable(); + assertUndefined(Blockly.Extensions.ALL_['mutator_test']); + Blockly.Extensions.registerMixin('mutator_test', + { + domToMutation: function() { + return 'domToMutationFn'; + }, + mutationToDom: function() { + return 'mutationToDomFn'; + } + }); + + var workspace = this.workspace; + chai.assert.throws(function() { + var _ = new Blockly.Block(workspace, 'mutator_test_block'); + }); + // Should have failed on apply, not on register. + assertNotNull(Blockly.Extensions.ALL_['mutator_test']); + }); + + test('Use extension as mutator', function() { + this.extensionsCleanup_.push('extensions_test'); + this.blockTypesCleanup_.push('mutator_test_block'); + + Blockly.defineBlocksWithJsonArray([{ + "type": "mutator_test_block", + "message0": "mutator_test_block", + "mutator": ["extensions_test"] + }]); + + // Events code calls mutationToDom and expects it to give back a + // meaningful value. + Blockly.Events.disable(); + assertUndefined(Blockly.Extensions.ALL_['extensions_test']); + Blockly.Extensions.register('extensions_test', function() { + return 'extensions_test_fn'; + }); + + var workspace = this.workspace; + chai.assert.throws(function() { + var _ = new Blockly.Block(workspace, 'mutator_test_block'); + }); + // Should have failed on apply, not on register. + assertNotNull(Blockly.Extensions.ALL_['extensions_test']); + }); + + suite('register', function() { + test('Just a string', function() { + this.extensionsCleanup_.push('extension_just_a_string'); + assertUndefined(Blockly.Extensions.ALL_['extension_just_a_string']); + chai.assert.throws(function() { + Blockly.Extensions.register('extension_just_a_string', null); + }); + }); + + test('Null', function() { + this.extensionsCleanup_.push('extension_is_null'); + assertUndefined(Blockly.Extensions.ALL_['extension_is_null']); + chai.assert.throws(function() { + Blockly.Extensions.register('extension_is_null', null); + }); + }); + + test('Undefined', function() { + this.extensionsCleanup_.push('extension_is_undefined'); + assertUndefined(Blockly.Extensions.ALL_['extension_is_undefined']); + chai.assert.throws(function() { + Blockly.Extensions.register('extension_is_undefined', null); + }); + }); + }); + + suite('registerMutator', function() { + test('No domToMutation', function() { + this.extensionsCleanup_.push('mutator_test'); + chai.assert.throws(function() { + Blockly.Extensions.registerMutator('mutator_test', + { + mutationToDom: function() { + return 'mutationToDomFn'; + }, + compose: function() { + return 'composeFn'; + }, + decompose: function() { + return 'decomposeFn'; + } + }); + }, /domToMutation/); + }); + + test('No mutationToDom', function() { + this.extensionsCleanup_.push('mutator_test'); + chai.assert.throws(function() { + Blockly.Extensions.registerMutator('mutator_test', + { + domToMutation: function() { + return 'domToMutationFn'; + }, + compose: function() { + return 'composeFn'; + }, + decompose: function() { + return 'decomposeFn'; + } + }); + }, /mutationToDom/); + }); + + test('Has decompose but no compose', function() { + this.extensionsCleanup_.push('mutator_test'); + chai.assert.throws(function() { + Blockly.Extensions.registerMutator('mutator_test', + { + domToMutation: function() { + return 'domToMutationFn'; + }, + mutationToDom: function() { + return 'mutationToDomFn'; + }, + decompose: function() { + return 'decomposeFn'; + } + }); + }, /compose/); + }); + + test('Has compose but no decompose', function() { + this.extensionsCleanup_.push('mutator_test'); + chai.assert.throws(function() { + Blockly.Extensions.registerMutator('mutator_test', + { + domToMutation: function() { + return 'domToMutationFn'; + }, + mutationToDom: function() { + return 'mutationToDomFn'; + }, + compose: function() { + return 'composeFn'; + } + }); + }, /decompose/); + }); + }); + }); +}); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index ee645b79e..c156f3f28 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -33,6 +33,7 @@ + diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index 05635de73..bcf826a23 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -76,6 +76,9 @@ suite('XML', function() { delete Blockly.Blocks[this.blockTypes_[i]]; } this.blockTypes_.length = 0; + // Clear Blockly.Event state. + Blockly.Events.setGroup(false); + Blockly.Events.disabled_ = 0; sinon.restore(); }); suite('textToDom', function() {