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() {