From ab5616cff7b4430838efcd5e459419c37c215fd6 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 7 Jun 2021 08:14:13 -0700 Subject: [PATCH] Add tests for connecting blocks (#4853) --- tests/mocha/connection_test.js | 629 +++++++++++++++++++++++++++++++++ 1 file changed, 629 insertions(+) diff --git a/tests/mocha/connection_test.js b/tests/mocha/connection_test.js index 3d96c18c5c6..2f7fe090782 100644 --- a/tests/mocha/connection_test.js +++ b/tests/mocha/connection_test.js @@ -1104,4 +1104,633 @@ suite('Connection', function() { }); }); }); + + suite('Connect', function() { + setup(function() { + this.workspace = new Blockly.Workspace(); + Blockly.defineBlocksWithJsonArray([ + { + "type": "stack_block", + "message0": "%1", + "args0": [ + { + "type": "field_input", + "name": "FIELD", + "text": "default" + } + ], + "previousStatement": 'check1', + "nextStatement": 'check1' + }, + { + "type": "stack_block_1to2", + "message0": "", + "previousStatement": 'check1', + "nextStatement": 'check2' + }, + { + "type": "stack_block_2to1", + "message0": "", + "previousStatement": 'check2', + "nextStatement": 'check1' + }, + { + "type": "stack_block_noend", + "message0": "", + "previousStatement": 'check1', + }, + { + "type": "row_block", + "message0": "%1 %2", + "args0": [ + { + "type": "field_input", + "name": "FIELD", + "text": "default" + }, + { + "type": "input_value", + "name": "INPUT", + "check": 'check1' + } + ], + "output": 'check1' + }, + { + "type": "row_block_1to2", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "INPUT", + "check": 'check1' + } + ], + "output": 'check2' + }, + { + "type": "row_block_2to1", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "INPUT", + "check": 'check2' + } + ], + "output": 'check1' + }, + { + "type": "row_block_noend", + "message0": "", + "output": 'check1' + }, + { + "type": "statement_block", + "message0": "%1 %2", + "args0": [ + { + "type": "field_input", + "name": "FIELD", + "text": "default" + }, + { + "type": "input_statement", + "name": "STATEMENT", + "check": 'check1' + } + ], + "previousStatement": 'check1', + "nextStatement": 'check1' + }, + { + "type": "statement_block_1to2", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "STATEMENT", + "check": 'check1' + } + ], + "previousStatement": 'check1', + "nextStatement": 'check2' + }, + { + "type": "statement_block_2to1", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "STATEMENT", + "check": 'check2' + } + ], + "previousStatement": 'check2', + "nextStatement": 'check1' + }, + { + "type": "statement_block_noend", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "STATEMENT", + "check": 'check1' + } + ], + "previousStatement": 'check1', + }, + ]); + + // Used to make sure we don't get stray shadow blocks or anything. + this.assertBlockCount = function(count) { + chai.assert.equal(this.workspace.getAllBlocks().length, count); + }; + }); + + teardown(function() { + sharedTestTeardown.call(this); + }); + + suite('Disconnect from old parent', function() { + test('Value', function() { + var oldParent = this.workspace.newBlock('row_block'); + var newParent = this.workspace.newBlock('row_block'); + var child = this.workspace.newBlock('row_block'); + + oldParent.getInput('INPUT').connection.connect(child.outputConnection); + newParent.getInput('INPUT').connection.connect(child.outputConnection); + + chai.assert.isFalse( + oldParent.getInput('INPUT').connection.isConnected()); + this.assertBlockCount(3); + }); + + test('Statement', function() { + var oldParent = this.workspace.newBlock('statement_block'); + var newParent = this.workspace.newBlock('statement_block'); + var child = this.workspace.newBlock('stack_block'); + + oldParent.getInput('STATEMENT').connection + .connect(child.previousConnection); + newParent.getInput('STATEMENT').connection + .connect(child.previousConnection); + + chai.assert.isFalse( + oldParent.getInput('STATEMENT').connection.isConnected()); + this.assertBlockCount(3); + }); + + test('Next', function() { + var oldParent = this.workspace.newBlock('stack_block'); + var newParent = this.workspace.newBlock('stack_block'); + var child = this.workspace.newBlock('stack_block'); + + oldParent.nextConnection.connect(child.previousConnection); + newParent.nextConnection.connect(child.previousConnection); + + chai.assert.isFalse(oldParent.nextConnection.isConnected()); + this.assertBlockCount(3); + }); + }); + + suite('Shadow dissolves', function() { + test('Value', function() { + var newParent = this.workspace.newBlock('row_block'); + var child = this.workspace.newBlock('row_block'); + var xml = Blockly.Xml.textToDom( + '' + ); + newParent.getInput('INPUT').connection.setShadowDom(xml); + chai.assert.isTrue(newParent.getInputTargetBlock('INPUT').isShadow()); + + newParent.getInput('INPUT').connection.connect(child.outputConnection); + + chai.assert.isFalse(newParent.getInputTargetBlock('INPUT').isShadow()); + this.assertBlockCount(2); + }); + + test('Statement', function() { + var newParent = this.workspace.newBlock('statement_block'); + var child = this.workspace.newBlock('stack_block'); + var xml = Blockly.Xml.textToDom( + '' + ); + newParent.getInput('STATEMENT').connection.setShadowDom(xml); + chai.assert.isTrue( + newParent.getInputTargetBlock('STATEMENT').isShadow()); + + newParent.getInput('STATEMENT').connection + .connect(child.previousConnection); + + chai.assert.isFalse( + newParent.getInputTargetBlock('STATEMENT').isShadow()); + this.assertBlockCount(2); + }); + + test('Next', function() { + var newParent = this.workspace.newBlock('stack_block'); + var child = this.workspace.newBlock('stack_block'); + var xml = Blockly.Xml.textToDom( + '' + ); + newParent.nextConnection.setShadowDom(xml); + chai.assert.isTrue(newParent.getNextBlock().isShadow()); + + newParent.nextConnection.connect(child.previousConnection); + + chai.assert.isFalse(newParent.getNextBlock().isShadow()); + this.assertBlockCount(2); + }); + }); + + suite('Saving shadow values', function() { + test('Value', function() { + var newParent = this.workspace.newBlock('row_block'); + var child = this.workspace.newBlock('row_block'); + var xml = Blockly.Xml.textToDom( + '' + ); + newParent.getInput('INPUT').connection.setShadowDom(xml); + newParent.getInputTargetBlock('INPUT').setFieldValue('new', 'FIELD'); + + newParent.getInput('INPUT').connection.connect(child.outputConnection); + newParent.getInput('INPUT').connection.disconnect(); + + const target = newParent.getInputTargetBlock('INPUT'); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.getFieldValue('FIELD'), 'new'); + this.assertBlockCount(3); + }); + + test('Statement', function() { + var newParent = this.workspace.newBlock('statement_block'); + var child = this.workspace.newBlock('stack_block'); + var xml = Blockly.Xml.textToDom( + '' + ); + newParent.getInput('STATEMENT').connection.setShadowDom(xml); + newParent.getInputTargetBlock('STATEMENT') + .setFieldValue('new', 'FIELD'); + + newParent.getInput('STATEMENT').connection + .connect(child.previousConnection); + newParent.getInput('STATEMENT').connection.disconnect(); + + const target = newParent.getInputTargetBlock('STATEMENT'); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.getFieldValue('FIELD'), 'new'); + this.assertBlockCount(3); + }); + + test('Next', function() { + var newParent = this.workspace.newBlock('stack_block'); + var child = this.workspace.newBlock('stack_block'); + var xml = Blockly.Xml.textToDom( + '' + ); + newParent.nextConnection.setShadowDom(xml); + newParent.getNextBlock().setFieldValue('new', 'FIELD'); + + newParent.nextConnection.connect(child.previousConnection); + newParent.nextConnection.disconnect(); + + const target = newParent.getNextBlock(); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.getFieldValue('FIELD'), 'new'); + this.assertBlockCount(3); + }); + }); + + suite('Reattach or bump orphan', function() { + suite('Value', function() { + // Only one test for this b/c tested by getConnectionForOrphanedOutput. + test('Simple', function() { + var parent = this.workspace.newBlock('row_block'); + var oldChild = this.workspace.newBlock('row_block'); + var newChild = this.workspace.newBlock('row_block'); + parent.getInput('INPUT').connection.connect(oldChild.outputConnection); + var spy = sinon.spy( + Blockly.Connection, 'getConnectionForOrphanedOutput'); + + parent.getInput('INPUT').connection.connect(newChild.outputConnection); + + chai.assert.isTrue(parent.getInput('INPUT').connection.isConnected()); + chai.assert.equal(parent.getInputTargetBlock('INPUT'), newChild); + chai.assert.isTrue(newChild.getInput('INPUT').connection.isConnected()); + chai.assert.equal(newChild.getInputTargetBlock('INPUT'), oldChild); + // Make sure it is actually getting called, so all functionality has + // been tested. + // Future people: if you ever stop calling this function you need to + // add more tests for reattaching orphans. + chai.assert.isTrue(spy.calledOnce); + this.assertBlockCount(3); + }); + + test('Bump', function() { + var parent = this.workspace.newBlock('row_block'); + var oldChild = this.workspace.newBlock('row_block'); + var newChild = this.workspace.newBlock('row_block_noend'); + parent.getInput('INPUT').connection.connect(oldChild.outputConnection); + var spy = sinon.spy(oldChild.outputConnection, 'onFailedConnect'); + + parent.getInput('INPUT').connection.connect(newChild.outputConnection); + + chai.assert.isTrue(parent.getInput('INPUT').connection.isConnected()); + chai.assert.equal(parent.getInputTargetBlock('INPUT'), newChild); + chai.assert.isTrue(spy.calledOnce); + this.assertBlockCount(3); + }); + }); + + suite('Statement', function() { + suite('No shadows', function() { + test('Simple', function() { + var parent = this.workspace.newBlock('statement_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block'); + parent.getInput('STATEMENT').connection + .connect(oldChild.previousConnection); + + parent.getInput('STATEMENT').connection + .connect(newChild.previousConnection); + + chai.assert.isTrue( + parent.getInput('STATEMENT').connection.isConnected()); + chai.assert.equal( + parent.getInputTargetBlock('STATEMENT'), newChild); + chai.assert.isTrue(newChild.nextConnection.isConnected()); + chai.assert.equal(newChild.getNextBlock(), oldChild); + this.assertBlockCount(3); + }); + + test('Bad check in between', function() { + var parent = this.workspace.newBlock('statement_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild1 = this.workspace.newBlock('stack_block_1to2'); + var newChild2 = this.workspace.newBlock('stack_block_2to1'); + parent.getInput('STATEMENT').connection + .connect(oldChild.previousConnection); + newChild1.nextConnection.connect(newChild2.previousConnection); + + parent.getInput('STATEMENT').connection + .connect(newChild1.previousConnection); + + chai.assert.isTrue( + parent.getInput('STATEMENT').connection.isConnected()); + chai.assert.equal( + parent.getInputTargetBlock('STATEMENT'), newChild1); + chai.assert.isTrue(newChild2.nextConnection.isConnected()); + chai.assert.equal(newChild2.getNextBlock(), oldChild); + this.assertBlockCount(4); + }); + + test('Bad check at end', function() { + var parent = this.workspace.newBlock('statement_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block_1to2'); + parent.getInput('STATEMENT').connection + .connect(oldChild.previousConnection); + var spy = sinon.spy(oldChild.previousConnection, 'onFailedConnect'); + + parent.getInput('STATEMENT').connection + .connect(newChild.previousConnection); + + chai.assert.isTrue( + parent.getInput('STATEMENT').connection.isConnected()); + chai.assert.equal( + parent.getInputTargetBlock('STATEMENT'), newChild); + chai.assert.isFalse(newChild.nextConnection.isConnected()); + chai.assert.isTrue(spy.calledOnce); + this.assertBlockCount(3); + }); + + test('No end connection', function() { + var parent = this.workspace.newBlock('statement_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block_noend'); + parent.getInput('STATEMENT').connection + .connect(oldChild.previousConnection); + var spy = sinon.spy(oldChild.previousConnection, 'onFailedConnect'); + + parent.getInput('STATEMENT').connection + .connect(newChild.previousConnection); + + chai.assert.isTrue( + parent.getInput('STATEMENT').connection.isConnected()); + chai.assert.equal( + parent.getInputTargetBlock('STATEMENT'), newChild); + chai.assert.isTrue(spy.calledOnce); + this.assertBlockCount(3); + }); + }); + + suite('Shadows', function() { + test('Simple', function() { + var parent = this.workspace.newBlock('statement_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block'); + parent.getInput('STATEMENT').connection + .connect(oldChild.previousConnection); + var xml = Blockly.Xml.textToDom( + '' + ); + newChild.nextConnection.setShadowDom(xml); + + parent.getInput('STATEMENT').connection + .connect(newChild.previousConnection); + + chai.assert.isTrue( + parent.getInput('STATEMENT').connection.isConnected()); + chai.assert.equal( + parent.getInputTargetBlock('STATEMENT'), newChild); + chai.assert.isTrue(newChild.nextConnection.isConnected()); + chai.assert.equal(newChild.getNextBlock(), oldChild); + this.assertBlockCount(3); + }); + + test('Bad check in between', function() { + var parent = this.workspace.newBlock('statement_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild1 = this.workspace.newBlock('stack_block_1to2'); + var newChild2 = this.workspace.newBlock('stack_block_2to1'); + parent.getInput('STATEMENT').connection + .connect(oldChild.previousConnection); + newChild1.nextConnection.connect(newChild2.previousConnection); + var xml = Blockly.Xml.textToDom( + '' + ); + newChild2.nextConnection.setShadowDom(xml); + + parent.getInput('STATEMENT').connection + .connect(newChild1.previousConnection); + + chai.assert.isTrue( + parent.getInput('STATEMENT').connection.isConnected()); + chai.assert.equal( + parent.getInputTargetBlock('STATEMENT'), newChild1); + chai.assert.isTrue(newChild2.nextConnection.isConnected()); + chai.assert.equal(newChild2.getNextBlock(), oldChild); + this.assertBlockCount(4); + }); + + test('Bad check at end', function() { + var parent = this.workspace.newBlock('statement_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block_1to2'); + parent.getInput('STATEMENT').connection + .connect(oldChild.previousConnection); + var xml = Blockly.Xml.textToDom( + '' + ); + newChild.nextConnection.setShadowDom(xml); + var spy = sinon.spy(oldChild.previousConnection, 'onFailedConnect'); + + parent.getInput('STATEMENT').connection + .connect(newChild.previousConnection); + + chai.assert.isTrue( + parent.getInput('STATEMENT').connection.isConnected()); + chai.assert.equal( + parent.getInputTargetBlock('STATEMENT'), newChild); + chai.assert.isTrue(newChild.nextConnection.isConnected()); + chai.assert.isTrue(newChild.getNextBlock().isShadow()); + chai.assert.isTrue(spy.calledOnce); + this.assertBlockCount(4); + }); + }); + }); + + suite('Next', function() { + suite('No shadows', function() { + test('Simple', function() { + var parent = this.workspace.newBlock('stack_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block'); + parent.nextConnection.connect(oldChild.previousConnection); + + parent.nextConnection.connect(newChild.previousConnection); + + chai.assert.isTrue(parent.nextConnection.isConnected()); + chai.assert.equal(parent.getNextBlock(), newChild); + chai.assert.isTrue(newChild.nextConnection.isConnected()); + chai.assert.equal(newChild.getNextBlock(), oldChild); + this.assertBlockCount(3); + }); + + test('Bad check in between', function() { + var parent = this.workspace.newBlock('stack_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild1 = this.workspace.newBlock('stack_block_1to2'); + var newChild2 = this.workspace.newBlock('stack_block_2to1'); + parent.nextConnection.connect(oldChild.previousConnection); + newChild1.nextConnection.connect(newChild2.previousConnection); + + parent.nextConnection.connect(newChild1.previousConnection); + + chai.assert.isTrue(parent.nextConnection.isConnected()); + chai.assert.equal(parent.getNextBlock(), newChild1); + chai.assert.isTrue(newChild2.nextConnection.isConnected()); + chai.assert.equal(newChild2.getNextBlock(), oldChild); + this.assertBlockCount(4); + }); + + test('Bad check at end', function() { + var parent = this.workspace.newBlock('stack_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block_1to2'); + parent.nextConnection.connect(oldChild.previousConnection); + var spy = sinon.spy(oldChild.previousConnection, 'onFailedConnect'); + + parent.nextConnection.connect(newChild.previousConnection); + + chai.assert.isTrue(parent.nextConnection.isConnected()); + chai.assert.equal(parent.getNextBlock(), newChild); + chai.assert.isFalse(newChild.nextConnection.isConnected()); + chai.assert.isTrue(spy.calledOnce); + this.assertBlockCount(3); + }); + + test('No end connection', function() { + var parent = this.workspace.newBlock('stack_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block_noend'); + parent.nextConnection.connect(oldChild.previousConnection); + var spy = sinon.spy(oldChild.previousConnection, 'onFailedConnect'); + + parent.nextConnection.connect(newChild.previousConnection); + + chai.assert.isTrue(parent.nextConnection.isConnected()); + chai.assert.equal(parent.getNextBlock(), newChild); + chai.assert.isTrue(spy.calledOnce); + this.assertBlockCount(3); + }); + }); + + suite('Shadows', function() { + test('Simple', function() { + var parent = this.workspace.newBlock('stack_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block'); + parent.nextConnection.connect(oldChild.previousConnection); + var xml = Blockly.Xml.textToDom( + '' + ); + newChild.nextConnection.setShadowDom(xml); + + parent.nextConnection.connect(newChild.previousConnection); + + chai.assert.isTrue(parent.nextConnection.isConnected()); + chai.assert.equal(parent.getNextBlock(), newChild); + chai.assert.isTrue(newChild.nextConnection.isConnected()); + chai.assert.equal(newChild.getNextBlock(), oldChild); + this.assertBlockCount(3); + }); + + test('Bad check in between', function() { + var parent = this.workspace.newBlock('stack_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild1 = this.workspace.newBlock('stack_block_1to2'); + var newChild2 = this.workspace.newBlock('stack_block_2to1'); + parent.nextConnection.connect(oldChild.previousConnection); + newChild1.nextConnection.connect(newChild2.previousConnection); + var xml = Blockly.Xml.textToDom( + '' + ); + newChild2.nextConnection.setShadowDom(xml); + + parent.nextConnection.connect(newChild1.previousConnection); + + chai.assert.isTrue(parent.nextConnection.isConnected()); + chai.assert.equal(parent.getNextBlock(), newChild1); + chai.assert.isTrue(newChild2.nextConnection.isConnected()); + chai.assert.equal(newChild2.getNextBlock(), oldChild); + this.assertBlockCount(4); + }); + + test('Bad check at end', function() { + var parent = this.workspace.newBlock('stack_block'); + var oldChild = this.workspace.newBlock('stack_block'); + var newChild = this.workspace.newBlock('stack_block_1to2'); + parent.nextConnection.connect(oldChild.previousConnection); + var xml = Blockly.Xml.textToDom( + '' + ); + newChild.nextConnection.setShadowDom(xml); + var spy = sinon.spy(oldChild.previousConnection, 'onFailedConnect'); + + parent.nextConnection.connect(newChild.previousConnection); + + chai.assert.isTrue(parent.nextConnection.isConnected()); + chai.assert.equal(parent.getNextBlock(), newChild); + chai.assert.isTrue(newChild.nextConnection.isConnected()); + chai.assert.isTrue(newChild.getNextBlock().isShadow()); + chai.assert.isTrue(spy.calledOnce); + this.assertBlockCount(4); + }); + }); + }); + }); + }); });