mirror of
https://github.com/google/blockly.git
synced 2026-01-10 18:37:09 +01:00
Merge pull request #2208 from rachel-fenichel/testing/mocha
Mocha testing
This commit is contained in:
182
tests/mocha/block_test.js
Normal file
182
tests/mocha/block_test.js
Normal file
@@ -0,0 +1,182 @@
|
||||
|
||||
// Declare some globals to make eslint happier.
|
||||
// TODO: make an eslint config that applies to this directory and put this
|
||||
// configuration in that file, instead of inline.
|
||||
/* global suite, test, setup, teardown */
|
||||
|
||||
/* global assertNull, assertEquals */
|
||||
|
||||
suite('Blocks', function() {
|
||||
|
||||
suite('Unplug', function() {
|
||||
function assertUnpluggedNoheal(blocks) {
|
||||
// A has nothing connected to it.
|
||||
assertEquals(0, blocks.A.getChildren().length);
|
||||
// B and C are still connected.
|
||||
assertEquals(blocks.B, blocks.C.getParent());
|
||||
// B is the top of its stack.
|
||||
assertNull(blocks.B.getParent());
|
||||
}
|
||||
|
||||
function assertUnpluggedHealed(blocks) {
|
||||
// A and C are connected.
|
||||
assertEquals(1, blocks.A.getChildren().length);
|
||||
assertEquals(blocks.A, blocks.C.getParent());
|
||||
// B has nothing connected to it.
|
||||
assertEquals(0, blocks.B.getChildren().length);
|
||||
// B is the top of its stack.
|
||||
assertNull(blocks.B.getParent());
|
||||
}
|
||||
|
||||
setup(function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "stack_block",
|
||||
"message0": "",
|
||||
"previousStatement": null,
|
||||
"nextStatement": null
|
||||
},
|
||||
{
|
||||
"type": "row_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "INPUT"
|
||||
}
|
||||
],
|
||||
"output": null
|
||||
}]);
|
||||
|
||||
this.workspace = new Blockly.Workspace();
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
delete Blockly.Blocks['stack_block'];
|
||||
delete Blockly.Blocks['row_block'];
|
||||
|
||||
this.workspace.dispose();
|
||||
});
|
||||
|
||||
suite('Row', function() {
|
||||
setup(function() {
|
||||
var blockA = this.workspace.newBlock('row_block');
|
||||
var blockB = this.workspace.newBlock('row_block');
|
||||
var blockC = this.workspace.newBlock('row_block');
|
||||
|
||||
blockA.inputList[0].connection.connect(blockB.outputConnection);
|
||||
blockB.inputList[0].connection.connect(blockC.outputConnection);
|
||||
|
||||
assertEquals(blockB, blockC.getParent());
|
||||
|
||||
this.blocks = {
|
||||
A: blockA,
|
||||
B: blockB,
|
||||
C: blockC
|
||||
};
|
||||
});
|
||||
|
||||
test('Don\'t heal', function() {
|
||||
this.blocks.B.unplug(false);
|
||||
assertUnpluggedNoheal(this.blocks);
|
||||
});
|
||||
|
||||
test('Heal', function() {
|
||||
this.blocks.B.unplug(true);
|
||||
// Each block has only one input, and the types work.
|
||||
assertUnpluggedHealed(this.blocks);
|
||||
});
|
||||
|
||||
test('Heal with bad checks', function() {
|
||||
var blocks = this.blocks;
|
||||
|
||||
// A and C can't connect, but both can connect to B.
|
||||
blocks.A.inputList[0].connection.setCheck('type1');
|
||||
blocks.C.outputConnection.setCheck('type2');
|
||||
|
||||
// Each block has only one input, but the types don't work.
|
||||
blocks.B.unplug(true);
|
||||
assertUnpluggedNoheal(blocks);
|
||||
});
|
||||
|
||||
test('Parent has multiple inputs', function() {
|
||||
var blocks = this.blocks;
|
||||
// Add extra input to parent
|
||||
blocks.A.appendValueInput("INPUT").setCheck(null);
|
||||
blocks.B.unplug(true);
|
||||
assertUnpluggedHealed(blocks);
|
||||
});
|
||||
|
||||
test('Middle block has multiple inputs', function() {
|
||||
var blocks = this.blocks;
|
||||
// Add extra input to middle block
|
||||
blocks.B.appendValueInput("INPUT").setCheck(null);
|
||||
blocks.B.unplug(true);
|
||||
assertUnpluggedNoheal(blocks);
|
||||
});
|
||||
|
||||
test('Child block has multiple inputs', function() {
|
||||
var blocks = this.blocks;
|
||||
// Add extra input to child block
|
||||
blocks.C.appendValueInput("INPUT").setCheck(null);
|
||||
// Child block input count doesn't matter.
|
||||
blocks.B.unplug(true);
|
||||
assertUnpluggedHealed(blocks);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
suite('Stack', function() {
|
||||
setup(function() {
|
||||
var blockA = this.workspace.newBlock('stack_block');
|
||||
var blockB = this.workspace.newBlock('stack_block');
|
||||
var blockC = this.workspace.newBlock('stack_block');
|
||||
|
||||
blockA.nextConnection.connect(blockB.previousConnection);
|
||||
blockB.nextConnection.connect(blockC.previousConnection);
|
||||
|
||||
assertEquals(blockB, blockC.getParent());
|
||||
|
||||
this.blocks = {
|
||||
A: blockA,
|
||||
B: blockB,
|
||||
C: blockC
|
||||
};
|
||||
});
|
||||
|
||||
test('Don\'t heal', function() {
|
||||
this.blocks.B.unplug();
|
||||
assertUnpluggedNoheal(this.blocks);
|
||||
});
|
||||
|
||||
test('Heal', function() {
|
||||
this.blocks.B.unplug(true);
|
||||
assertUnpluggedHealed(this.blocks);
|
||||
});
|
||||
|
||||
test('Heal with bad checks', function() {
|
||||
var blocks = this.blocks;
|
||||
// A and C can't connect, but both can connect to B.
|
||||
blocks.A.nextConnection.setCheck('type1');
|
||||
blocks.C.previousConnection.setCheck('type2');
|
||||
|
||||
// The types don't work.
|
||||
blocks.B.unplug(true);
|
||||
|
||||
// Stack blocks unplug before checking whether the types match.
|
||||
// TODO (#1994): Check types before unplugging.
|
||||
// A has nothing connected to it.
|
||||
assertEquals(0, blocks.A.getChildren().length);
|
||||
// B has nothing connected to it.
|
||||
assertEquals(0, blocks.B.getChildren().length);
|
||||
// C has nothing connected to it.
|
||||
assertEquals(0, blocks.C.getChildren().length);
|
||||
// A is the top of its stack.
|
||||
assertNull(blocks.A.getParent());
|
||||
// B is the top of its stack.
|
||||
assertNull(blocks.B.getParent());
|
||||
// C is the top of its stack.
|
||||
assertNull(blocks.C.getParent());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
386
tests/mocha/event_test.js
Normal file
386
tests/mocha/event_test.js
Normal file
@@ -0,0 +1,386 @@
|
||||
|
||||
// Declare some globals to make eslint happier.
|
||||
// TODO: make an eslint config that applies to this directory and put this
|
||||
// configuration in that file, instead of inline.
|
||||
/* global suite, test, setup, teardown */
|
||||
/* global sinon */
|
||||
|
||||
/* global assertNotNull, assertNotUndefined, assertNull, assertEquals,
|
||||
isEqualArrays, assertUndefined */
|
||||
suite('Events', function() {
|
||||
setup(function() {
|
||||
this.workspace = new Blockly.Workspace();
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
'type': 'field_variable_test_block',
|
||||
'message0': '%1',
|
||||
'args0': [
|
||||
{
|
||||
'type': 'field_variable',
|
||||
'name': 'VAR',
|
||||
'variable': 'item'
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
'type': 'simple_test_block',
|
||||
'message0': 'simple test block'
|
||||
}]);
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
delete Blockly.Blocks['field_variable_test_block'];
|
||||
delete Blockly.Blocks['simple_test_block'];
|
||||
this.workspace.dispose();
|
||||
|
||||
// Clear Blockly.Event state.
|
||||
Blockly.Events.setGroup(false);
|
||||
Blockly.Events.disabled_ = 0;
|
||||
});
|
||||
|
||||
function checkExactEventValues(event, values) {
|
||||
var keys = Object.keys(values);
|
||||
for (var i = 0, field; field = keys[i]; i++) {
|
||||
assertEquals(values[field], event[field]);
|
||||
}
|
||||
}
|
||||
|
||||
function checkCreateEventValues(event, block, ids, type) {
|
||||
var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block));
|
||||
var result_xml = Blockly.Xml.domToText(event.xml);
|
||||
assertEquals(expected_xml, result_xml);
|
||||
isEqualArrays(ids, event.ids);
|
||||
assertEquals(type, event.type);
|
||||
}
|
||||
|
||||
function checkDeleteEventValues(event, block, ids, type) {
|
||||
var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block));
|
||||
var result_xml = Blockly.Xml.domToText(event.oldXml);
|
||||
assertEquals(expected_xml, result_xml);
|
||||
isEqualArrays(ids, event.ids);
|
||||
assertEquals(type, event.type);
|
||||
}
|
||||
|
||||
suite('Constructors', function() {
|
||||
test('Abstract', function() {
|
||||
var event = new Blockly.Events.Abstract();
|
||||
assertUndefined(event.blockId);
|
||||
assertUndefined(event.workspaceId);
|
||||
assertUndefined(event.varId);
|
||||
checkExactEventValues(event, {'group': '', 'recordUndo': true});
|
||||
});
|
||||
|
||||
test('UI event without block', function() {
|
||||
Blockly.Events.setGroup('testGroup');
|
||||
var event = new Blockly.Events.Ui(null, 'foo', 'bar', 'baz');
|
||||
checkExactEventValues(event,
|
||||
{
|
||||
'blockId': null,
|
||||
'workspaceId': null,
|
||||
'type': 'ui',
|
||||
'oldValue': 'bar',
|
||||
'newValue': 'baz',
|
||||
'element': 'foo',
|
||||
'recordUndo': false,
|
||||
'group': 'testGroup'
|
||||
});
|
||||
});
|
||||
|
||||
suite('With simple blocks', function() {
|
||||
setup(function() {
|
||||
this.FAKE_ID = 'hedgehog';
|
||||
sinon.stub(Blockly.utils, "genUid").returns(this.FAKE_ID);
|
||||
|
||||
// Disable events while constructing the block: this is a test of the
|
||||
// Blockly.Event constructors, not the block constructor.
|
||||
Blockly.Events.disable();
|
||||
this.block = new Blockly.Block(this.workspace, 'simple_test_block');
|
||||
Blockly.Events.enable();
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
});
|
||||
|
||||
test('Block base', function() {
|
||||
var event = new Blockly.Events.BlockBase(this.block);
|
||||
assertUndefined(event.varId);
|
||||
checkExactEventValues(event,
|
||||
{
|
||||
'blockId': this.FAKE_ID,
|
||||
'workspaceId': this.workspace.id,
|
||||
'group': '',
|
||||
'recordUndo': true
|
||||
});
|
||||
});
|
||||
|
||||
test('Create', function() {
|
||||
var event = new Blockly.Events.Create(this.block);
|
||||
checkCreateEventValues(event, this.block, [this.FAKE_ID], 'create');
|
||||
});
|
||||
|
||||
test('Block create', function() {
|
||||
var event = new Blockly.Events.BlockCreate(this.block);
|
||||
checkCreateEventValues(event, this.block, [this.FAKE_ID], 'create');
|
||||
});
|
||||
|
||||
test('Delete', function() {
|
||||
var event = new Blockly.Events.Delete(this.block);
|
||||
checkDeleteEventValues(event, this.block, [this.FAKE_ID], 'delete');
|
||||
});
|
||||
|
||||
test('Block delete', function() {
|
||||
var event = new Blockly.Events.BlockDelete(this.block);
|
||||
checkDeleteEventValues(event, this.block, [this.FAKE_ID], 'delete');
|
||||
});
|
||||
|
||||
test('UI event with block', function() {
|
||||
Blockly.Events.setGroup('testGroup');
|
||||
var event = new Blockly.Events.Ui(this.block, 'foo', 'bar', 'baz');
|
||||
checkExactEventValues(event,
|
||||
{
|
||||
'blockId': this.FAKE_ID,
|
||||
'workspaceId': this.workspace.id,
|
||||
'type': 'ui',
|
||||
'oldValue': 'bar',
|
||||
'newValue': 'baz',
|
||||
'element': 'foo',
|
||||
'recordUndo': false,
|
||||
'group': 'testGroup'
|
||||
});
|
||||
});
|
||||
|
||||
suite('Move', function() {
|
||||
test('Move by coordinate', function() {
|
||||
var coordinate = new goog.math.Coordinate(3, 4);
|
||||
this.block.xy_ = coordinate;
|
||||
|
||||
var event = new Blockly.Events.Move(this.block);
|
||||
checkExactEventValues(event,
|
||||
{'oldCoordinate': coordinate, 'type': 'move'});
|
||||
});
|
||||
|
||||
test('Block move by coordinate', function() {
|
||||
var coordinate = new goog.math.Coordinate(3, 4);
|
||||
this.block.xy_ = coordinate;
|
||||
|
||||
var event = new Blockly.Events.BlockMove(this.block);
|
||||
checkExactEventValues(event,
|
||||
{'oldCoordinate': coordinate, 'type': 'move'});
|
||||
});
|
||||
|
||||
suite('Move by parent', function() {
|
||||
setup(function() {
|
||||
sinon.stub(Blockly.utils, "genUid").returns("parent");
|
||||
Blockly.Events.disable();
|
||||
this.parentBlock = new Blockly.Block(this.workspace, 'simple_test_block');
|
||||
Blockly.Events.enable();
|
||||
sinon.restore();
|
||||
|
||||
this.block.parentBlock_ = this.parentBlock;
|
||||
this.block.xy_ = new goog.math.Coordinate(3, 4);
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
this.block.parentBlock_ = null;
|
||||
});
|
||||
|
||||
test('Move by parent', function() {
|
||||
// Expect the oldParentId to be set but not the oldCoordinate to be set.
|
||||
var event = new Blockly.Events.Move(this.block);
|
||||
checkExactEventValues(event, {'oldCoordinate': undefined,
|
||||
'oldParentId': 'parent', 'type': 'move'});
|
||||
});
|
||||
|
||||
test('Block move by parent', function() {
|
||||
// Expect the oldParentId to be set but not the oldCoordinate to be set.
|
||||
var event = new Blockly.Events.BlockMove(this.block);
|
||||
checkExactEventValues(event, {'oldCoordinate': undefined,
|
||||
'oldParentId': 'parent', 'type': 'move'});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('With variable getter blocks', function() {
|
||||
setup(function() {
|
||||
// Disable events while constructing the block: this is a test of the
|
||||
// Blockly.Event constructors, not the block constructor.
|
||||
Blockly.Events.disable();
|
||||
this.block = new Blockly.Block(this.workspace, 'field_variable_test_block');
|
||||
Blockly.Events.enable();
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
|
||||
});
|
||||
|
||||
test('Change', function() {
|
||||
var event =
|
||||
new Blockly.Events.Change(this.block, 'field', 'VAR', 'id1', 'id2');
|
||||
checkExactEventValues(event, {'element': 'field', 'name': 'VAR',
|
||||
'oldValue': 'id1', 'newValue': 'id2', 'type': 'change'});
|
||||
});
|
||||
|
||||
test('Block change', function() {
|
||||
var event = new Blockly.Events.BlockChange(
|
||||
this.block, 'field', 'VAR', 'id1', 'id2');
|
||||
checkExactEventValues(event, {'element': 'field', 'name': 'VAR',
|
||||
'oldValue': 'id1', 'newValue': 'id2', 'type': 'change'});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Variable events', function() {
|
||||
setup(function() {
|
||||
this.variable = this.workspace.createVariable('name1', 'type1', 'id1');
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if a variable with the given values exists.
|
||||
* @param {Blockly.Workspace|Blockly.VariableMap} container The workspace or
|
||||
* variableMap the checked variable belongs to.
|
||||
* @param {!string} name The expected name of the variable.
|
||||
* @param {!string} type The expected type of the variable.
|
||||
* @param {!string} id The expected id of the variable.
|
||||
*/
|
||||
function checkVariableValues(container, name, type, id) {
|
||||
var variable = container.getVariableById(id);
|
||||
assertNotUndefined(variable);
|
||||
assertEquals(name, variable.name);
|
||||
assertEquals(type, variable.type);
|
||||
assertEquals(id, variable.getId());
|
||||
}
|
||||
suite('Constructors', function() {
|
||||
test('Var base', function() {
|
||||
var event = new Blockly.Events.VarBase(this.variable);
|
||||
assertUndefined(event.blockId);
|
||||
checkExactEventValues(event, {'varId': 'id1',
|
||||
'workspaceId': this.workspace.id, 'group': '', 'recordUndo': true});
|
||||
});
|
||||
|
||||
test('Var create', function() {
|
||||
var event = new Blockly.Events.VarCreate(this.variable);
|
||||
checkExactEventValues(event, {'varName': 'name1', 'varType': 'type1',
|
||||
'type': 'var_create'});
|
||||
});
|
||||
|
||||
test('Var delete', function() {
|
||||
var event = new Blockly.Events.VarDelete(this.variable);
|
||||
checkExactEventValues(event, {'varName': 'name1', 'varType': 'type1',
|
||||
'varId':'id1', 'type': 'var_delete'});
|
||||
});
|
||||
|
||||
test('Var rename', function() {
|
||||
var event = new Blockly.Events.VarRename(this.variable, 'name2');
|
||||
checkExactEventValues(event, {'varId': 'id1', 'oldName': 'name1',
|
||||
'newName': 'name2', 'type': 'var_rename'});
|
||||
});
|
||||
});
|
||||
|
||||
suite('fromJson', function() {
|
||||
test('Var create', function() {
|
||||
var event = new Blockly.Events.VarCreate(this.variable);
|
||||
var event2 = new Blockly.Events.VarCreate(null);
|
||||
var json = event.toJson();
|
||||
event2.fromJson(json);
|
||||
|
||||
assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson()));
|
||||
});
|
||||
test('Var delete', function() {
|
||||
var event = new Blockly.Events.VarDelete(this.variable);
|
||||
var event2 = new Blockly.Events.VarDelete(null);
|
||||
var json = event.toJson();
|
||||
event2.fromJson(json);
|
||||
|
||||
assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson()));
|
||||
});
|
||||
test('Var rename', function() {
|
||||
var event = new Blockly.Events.VarRename(this.variable, '');
|
||||
var event2 = new Blockly.Events.VarRename(null);
|
||||
var json = event.toJson();
|
||||
event2.fromJson(json);
|
||||
|
||||
assertEquals(JSON.stringify(json), JSON.stringify(event2.toJson()));
|
||||
});
|
||||
});
|
||||
|
||||
suite('toJson', function() {
|
||||
test('Var create', function() {
|
||||
var variable = this.workspace.createVariable('name1', 'type1', 'id1');
|
||||
var event = new Blockly.Events.VarCreate(variable);
|
||||
var json = event.toJson();
|
||||
var expectedJson = ({type: "var_create", varId: "id1", varType: "type1",
|
||||
varName: "name1"});
|
||||
|
||||
assertEquals(JSON.stringify(expectedJson), JSON.stringify(json));
|
||||
});
|
||||
|
||||
test('Var delete', function() {
|
||||
var event = new Blockly.Events.VarDelete(this.variable);
|
||||
var json = event.toJson();
|
||||
var expectedJson = ({type: "var_delete", varId: "id1", varType: "type1",
|
||||
varName: "name1"});
|
||||
|
||||
assertEquals(JSON.stringify(expectedJson), JSON.stringify(json));
|
||||
});
|
||||
|
||||
test('Var rename', function() {
|
||||
var event = new Blockly.Events.VarRename(this.variable, 'name2');
|
||||
var json = event.toJson();
|
||||
var expectedJson = ({type: "var_rename", varId: "id1", oldName: "name1",
|
||||
newName: "name2"});
|
||||
|
||||
assertEquals(JSON.stringify(expectedJson), JSON.stringify(json));
|
||||
});
|
||||
});
|
||||
|
||||
suite.skip('Run Forward', function() {
|
||||
test('Var create', function() {
|
||||
var json = {type: "var_create", varId: "id1", varType: "type1",
|
||||
varName: "name1"};
|
||||
var event = Blockly.Events.fromJson(json, this.workspace);
|
||||
assertNull(this.workspace.getVariableById('id1'));
|
||||
event.run(true);
|
||||
checkVariableValues(this.workspace, 'name1', 'type1', 'id1');
|
||||
});
|
||||
|
||||
test('Var delete', function() {
|
||||
var event = new Blockly.Events.VarDelete(this.variable);
|
||||
assertNotNull(this.workspace.getVariableById('id1'));
|
||||
event.run(true);
|
||||
assertNull(this.workspace.getVariableById('id1'));
|
||||
});
|
||||
|
||||
test('Var rename', function() {
|
||||
var event = new Blockly.Events.VarRename(this.variable, 'name2');
|
||||
event.run(true);
|
||||
assertNull(this.workspace.getVariable('name1'));
|
||||
checkVariableValues(this.workspace, 'name2', 'type1', 'id1');
|
||||
});
|
||||
});
|
||||
suite.skip('Run Backward', function() {
|
||||
test('Var create', function() {
|
||||
var variable = this.workspace.createVariable('name1', 'type1', 'id1');
|
||||
var event = new Blockly.Events.VarCreate(variable);
|
||||
assertNotNull(this.workspace.getVariableById('id1'));
|
||||
event.run(false);
|
||||
});
|
||||
|
||||
test('Var delete', function() {
|
||||
var json = {type: "var_delete", varId: "id1", varType: "type1",
|
||||
varName: "name1"};
|
||||
var event = Blockly.Events.fromJson(json, this.workspace);
|
||||
assertNull(this.workspace.getVariableById('id1'));
|
||||
event.run(false);
|
||||
checkVariableValues(this.workspace, 'name1', 'type1', 'id1');
|
||||
});
|
||||
|
||||
test('Var rename', function() {
|
||||
var event = new Blockly.Events.VarRename(this.variable, 'name2');
|
||||
event.run(false);
|
||||
assertNull(this.workspace.getVariable('name2'));
|
||||
checkVariableValues(this.workspace, 'name1', 'type1', 'id1');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
161
tests/mocha/field_variable_test.js
Normal file
161
tests/mocha/field_variable_test.js
Normal file
@@ -0,0 +1,161 @@
|
||||
|
||||
// Declare some globals to make eslint happier.
|
||||
// TODO: make an eslint config that applies to this directory and put this
|
||||
// configuration in that file, instead of inline.
|
||||
/* global suite, test, chai, setup, teardown */
|
||||
|
||||
/* global assertNull, assertEquals, isEqualArrays */
|
||||
|
||||
suite('Variable Fields', function() {
|
||||
function getMockBlock(workspace) {
|
||||
return {
|
||||
'workspace': workspace,
|
||||
'isShadow': function() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
function fieldVariable_createAndInitField(workspace) {
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = getMockBlock(workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
// No view to initialize, but still need to init the model.
|
||||
fieldVariable.initModel();
|
||||
return fieldVariable;
|
||||
}
|
||||
|
||||
setup(function() {
|
||||
this.workspace = new Blockly.Workspace();
|
||||
});
|
||||
teardown(function() {
|
||||
this.workspace.dispose();
|
||||
});
|
||||
|
||||
test('Constructor', function() {
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
// The field does not have a variable until after init() is called.
|
||||
assertEquals('', fieldVariable.getText());
|
||||
assertNull(fieldVariable.getValue());
|
||||
});
|
||||
|
||||
test('Set value by ID', function() {
|
||||
this.workspace.createVariable('name2', null, 'id2');
|
||||
|
||||
var fieldVariable = fieldVariable_createAndInitField(this.workspace);
|
||||
var oldId = fieldVariable.getValue();
|
||||
|
||||
fieldVariable.setValue('id2');
|
||||
// Setting value by ID gives us the right text as well.
|
||||
assertEquals('name2', fieldVariable.getText());
|
||||
assertEquals('id2', fieldVariable.getValue());
|
||||
chai.assert.notEqual(oldId, fieldVariable.getValue());
|
||||
});
|
||||
|
||||
test('Set value: variable does not exist', function() {
|
||||
var fieldVariable = fieldVariable_createAndInitField(this.workspace);
|
||||
chai.assert.throws(function() {
|
||||
fieldVariable.setValue('id1');
|
||||
});
|
||||
});
|
||||
|
||||
test('Dropdown contains variables', function() {
|
||||
// Expect that the dropdown options will contain the variables that exist
|
||||
this.workspace.createVariable('name1', '', 'id1');
|
||||
this.workspace.createVariable('name2', '', 'id2');
|
||||
var fieldVariable = fieldVariable_createAndInitField(this.workspace);
|
||||
|
||||
// Expect that variables created after field creation will show up too.
|
||||
this.workspace.createVariable('name3', '', 'id3');
|
||||
|
||||
var result_options = Blockly.FieldVariable.dropdownCreate.call(
|
||||
fieldVariable);
|
||||
|
||||
// Expect three variable options and a rename option.
|
||||
assertEquals(result_options.length, 4);
|
||||
isEqualArrays(result_options[0], ['name1', 'id1']);
|
||||
isEqualArrays(result_options[1], ['name2', 'id2']);
|
||||
isEqualArrays(result_options[2], ['name3', 'id3']);
|
||||
|
||||
});
|
||||
|
||||
suite('Get variable types', function() {
|
||||
setup(function() {
|
||||
this.workspace.createVariable('name1', 'type1');
|
||||
this.workspace.createVariable('name2', 'type2');
|
||||
});
|
||||
|
||||
test('variableTypes is undefined', function() {
|
||||
// Expect that since variableTypes is undefined, only type empty string
|
||||
// will be returned (regardless of what types are available on the workspace).
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
isEqualArrays(resultTypes, ['']);
|
||||
});
|
||||
|
||||
test('variableTypes is explicit', function() {
|
||||
// Expect that since variableTypes is defined, it will be the return
|
||||
// value, regardless of what types are available on the workspace.
|
||||
var fieldVariable = new Blockly.FieldVariable(
|
||||
'name1', null, ['type1', 'type2'], 'type1');
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
isEqualArrays(resultTypes, ['type1', 'type2']);
|
||||
assertEquals('Default type was wrong', 'type1',
|
||||
fieldVariable.defaultType_);
|
||||
});
|
||||
|
||||
test('variableTypes is null', function() {
|
||||
// Expect all variable types to be returned.
|
||||
// The field does not need to be initialized to do this--it just needs
|
||||
// a pointer to the workspace.
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = getMockBlock(this.workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
fieldVariable.variableTypes = null;
|
||||
|
||||
var resultTypes = fieldVariable.getVariableTypes_();
|
||||
// The empty string is always one of the options.
|
||||
isEqualArrays(resultTypes, ['type1', 'type2', '']);
|
||||
});
|
||||
|
||||
test('variableTypes is the empty list', function() {
|
||||
var fieldVariable = new Blockly.FieldVariable('name1');
|
||||
var mockBlock = getMockBlock(this.workspace);
|
||||
fieldVariable.setSourceBlock(mockBlock);
|
||||
fieldVariable.variableTypes = [];
|
||||
|
||||
chai.assert.throws(function() {
|
||||
fieldVariable.getVariableTypes_();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('Default types', function() {
|
||||
test('Default type exists', function() {
|
||||
var fieldVariable = new Blockly.FieldVariable(null, null, ['b'], 'b');
|
||||
assertEquals('The variable field\'s default type should be "b"',
|
||||
'b', fieldVariable.defaultType_);
|
||||
});
|
||||
|
||||
test('No default type', function() {
|
||||
var fieldVariable = new Blockly.FieldVariable(null);
|
||||
assertEquals('The variable field\'s default type should be the empty string',
|
||||
'', fieldVariable.defaultType_);
|
||||
assertNull('The variable field\'s allowed types should be null',
|
||||
fieldVariable.variableTypes);
|
||||
});
|
||||
|
||||
test('Default type mismatch', function() {
|
||||
// Invalid default type when creating a variable field.
|
||||
chai.assert.throws(function() {
|
||||
var _fieldVariable = new Blockly.FieldVariable(null, null, ['a'], 'b');
|
||||
});
|
||||
});
|
||||
|
||||
test('Default type mismatch with empty array', function() {
|
||||
// Invalid default type when creating a variable field.
|
||||
chai.assert.throws(function() {
|
||||
var _fieldVariable = new Blockly.FieldVariable(null, null, ['a']);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
31
tests/mocha/index.html
Normal file
31
tests/mocha/index.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mocha Tests for Blockly</title>
|
||||
|
||||
<link href="https://unpkg.com/mocha@5.2.0/mocha.css" rel="stylesheet" />
|
||||
<script src="../../blockly_uncompressed.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="mocha"></div>
|
||||
<script src="https://unpkg.com/chai/chai.js"></script>
|
||||
<script src="https://unpkg.com/mocha@5.2.0/mocha.js"></script>
|
||||
<script src="https://unpkg.com/sinon/pkg/sinon.js"></script>
|
||||
<script>
|
||||
mocha.setup({
|
||||
ui: 'tdd'
|
||||
});
|
||||
</script>
|
||||
<script src="test_helpers.js"></script>
|
||||
<script src="block_test.js"></script>
|
||||
<script src="event_test.js"></script>
|
||||
<script src="field_variable_test.js"></script>
|
||||
<script src="utils_test.js"></script>
|
||||
|
||||
<script>
|
||||
mocha.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
3
tests/mocha/mocha.opts
Normal file
3
tests/mocha/mocha.opts
Normal file
@@ -0,0 +1,3 @@
|
||||
--ui tdd
|
||||
--file ../blockly_uncompressed.js
|
||||
--reporter landing
|
||||
109
tests/mocha/test_helpers.js
Normal file
109
tests/mocha/test_helpers.js
Normal file
@@ -0,0 +1,109 @@
|
||||
/* global chai */
|
||||
/* exported assertEquals, assertTrue, assertFalse, assertNull, assertNotNull,
|
||||
isEqualArrays, assertUndefined, assertNotUndefined */
|
||||
function _argumentsIncludeComments(expectedNumberOfNonCommentArgs, args) {
|
||||
return args.length == expectedNumberOfNonCommentArgs + 1;
|
||||
}
|
||||
|
||||
function _commentArg(expectedNumberOfNonCommentArgs, args) {
|
||||
if (_argumentsIncludeComments(expectedNumberOfNonCommentArgs, args)) {
|
||||
return args[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function _nonCommentArg(desiredNonCommentArgIndex, expectedNumberOfNonCommentArgs, args) {
|
||||
return _argumentsIncludeComments(expectedNumberOfNonCommentArgs, args) ?
|
||||
args[desiredNonCommentArgIndex] :
|
||||
args[desiredNonCommentArgIndex - 1];
|
||||
}
|
||||
|
||||
function _validateArguments(expectedNumberOfNonCommentArgs, args) {
|
||||
if (!( args.length == expectedNumberOfNonCommentArgs ||
|
||||
(args.length == expectedNumberOfNonCommentArgs + 1 && (typeof(args[0]) == 'string') || args[0] == null))) {
|
||||
throw new Error('Incorrect arguments passed to assert function');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Converts from JSUnit assertEquals to chai.assert.equal.
|
||||
*/
|
||||
function assertEquals() {
|
||||
_validateArguments(2, arguments);
|
||||
var var1 = _nonCommentArg(1, 2, arguments);
|
||||
var var2 = _nonCommentArg(2, 2, arguments);
|
||||
var comment = _commentArg(2, arguments);
|
||||
chai.assert.equal(var1, var2, comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from JSUnit assertTrue to chai.assert.isTrue.
|
||||
*/
|
||||
function assertTrue() {
|
||||
_validateArguments(1, arguments);
|
||||
var commentArg = _commentArg(1, arguments);
|
||||
var booleanValue = _nonCommentArg(1, 1, arguments);
|
||||
if (typeof(booleanValue) != 'boolean') {
|
||||
throw new Error('Bad argument to assertTrue(boolean)');
|
||||
}
|
||||
|
||||
chai.assert.isTrue(booleanValue, commentArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from JSUnit assertFalse to chai.assert.isNotTrue.
|
||||
*/
|
||||
function assertFalse() {
|
||||
_validateArguments(1, arguments);
|
||||
var commentArg = _commentArg(1, arguments);
|
||||
var booleanValue = _nonCommentArg(1, 1, arguments);
|
||||
|
||||
if (typeof(booleanValue) != 'boolean') {
|
||||
throw new Error('Bad argument to assertFalse(boolean)');
|
||||
}
|
||||
|
||||
chai.assert.isNotTrue(booleanValue, commentArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from JSUnit assertNull to chai.assert.isNull.
|
||||
*/
|
||||
function assertNull() {
|
||||
_validateArguments(1, arguments);
|
||||
var commentArg = _commentArg(1, arguments);
|
||||
var val = _nonCommentArg(1, 1, arguments);
|
||||
chai.assert.isNull(val, commentArg);
|
||||
}
|
||||
|
||||
function assertNotNull() {
|
||||
_validateArguments(1, arguments);
|
||||
var commentArg = _commentArg(1, arguments);
|
||||
var val = _nonCommentArg(1, 1, arguments);
|
||||
chai.assert.isNotNull(val, commentArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that two arrays have the same content.
|
||||
* @param {!Array.<string>} array1 The first array.
|
||||
* @param {!Array.<string>} array2 The second array.
|
||||
*/
|
||||
function isEqualArrays(array1, array2) {
|
||||
assertEquals(array1.length, array2.length);
|
||||
for (var i = 0; i < array1.length; i++) {
|
||||
assertEquals(array1[i], array2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function assertUndefined() {
|
||||
_validateArguments(1, arguments);
|
||||
var commentArg = _commentArg(1, arguments);
|
||||
var val = _nonCommentArg(1, 1, arguments);
|
||||
chai.assert.isUndefined(val, commentArg);
|
||||
}
|
||||
|
||||
function assertNotUndefined() {
|
||||
_validateArguments(1, arguments);
|
||||
var commentArg = _commentArg(1, arguments);
|
||||
var val = _nonCommentArg(1, 1, arguments);
|
||||
chai.assert.isNotUndefined(val, commentArg);
|
||||
}
|
||||
91
tests/mocha/utils_test.js
Normal file
91
tests/mocha/utils_test.js
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
// Declare some globals to make eslint happier.
|
||||
// TODO: make an eslint config that applies to this directory and put this
|
||||
// configuration in that file, instead of inline.
|
||||
/* global suite, test, chai, assertFalse, assertTrue, assertEquals */
|
||||
|
||||
suite('Utils', function() {
|
||||
test('genUid', function() {
|
||||
var uuids = {};
|
||||
chai.assert.equal([1,2,3].indexOf(4), -1);
|
||||
for (var i = 0; i < 1000; i++) {
|
||||
var uuid = Blockly.utils.genUid();
|
||||
chai.assert.isFalse(uuid in uuids, 'UUID different: ' + uuid);
|
||||
uuids[uuid] = true;
|
||||
}
|
||||
});
|
||||
test('addClass', function() {
|
||||
var p = document.createElement('p');
|
||||
Blockly.utils.addClass(p, 'one');
|
||||
assertEquals('Adding "one"', 'one', p.className);
|
||||
Blockly.utils.addClass(p, 'one');
|
||||
assertEquals('Adding duplicate "one"', 'one', p.className);
|
||||
Blockly.utils.addClass(p, 'two');
|
||||
assertEquals('Adding "two"', 'one two', p.className);
|
||||
Blockly.utils.addClass(p, 'two');
|
||||
assertEquals('Adding duplicate "two"', 'one two', p.className);
|
||||
Blockly.utils.addClass(p, 'three');
|
||||
assertEquals('Adding "three"', 'one two three', p.className);
|
||||
});
|
||||
|
||||
test('hasClass', function() {
|
||||
var p = document.createElement('p');
|
||||
p.className = ' one three two three ';
|
||||
assertTrue('Has "one"', Blockly.utils.hasClass(p, 'one'));
|
||||
assertTrue('Has "two"', Blockly.utils.hasClass(p, 'two'));
|
||||
assertTrue('Has "three"', Blockly.utils.hasClass(p, 'three'));
|
||||
assertFalse('Has no "four"', Blockly.utils.hasClass(p, 'four'));
|
||||
assertFalse('Has no "t"', Blockly.utils.hasClass(p, 't'));
|
||||
});
|
||||
|
||||
test('removeClass', function() {
|
||||
var p = document.createElement('p');
|
||||
p.className = ' one three two three ';
|
||||
Blockly.utils.removeClass(p, 'two');
|
||||
assertEquals('Removing "two"', 'one three three', p.className);
|
||||
Blockly.utils.removeClass(p, 'four');
|
||||
assertEquals('Removing "four"', 'one three three', p.className);
|
||||
Blockly.utils.removeClass(p, 'three');
|
||||
assertEquals('Removing "three"', 'one', p.className);
|
||||
Blockly.utils.removeClass(p, 'ne');
|
||||
assertEquals('Removing "ne"', 'one', p.className);
|
||||
Blockly.utils.removeClass(p, 'one');
|
||||
assertEquals('Removing "one"', '', p.className);
|
||||
Blockly.utils.removeClass(p, 'zero');
|
||||
assertEquals('Removing "zero"', '', p.className);
|
||||
});
|
||||
|
||||
test('shortest string length', function() {
|
||||
var len = Blockly.utils.shortestStringLength('one,two,three,four,five'.split(','));
|
||||
assertEquals('Length of "one"', 3, len);
|
||||
len = Blockly.utils.shortestStringLength('one,two,three,four,five,'.split(','));
|
||||
assertEquals('Length of ""', 0, len);
|
||||
len = Blockly.utils.shortestStringLength(['Hello World']);
|
||||
assertEquals('List of one', 11, len);
|
||||
len = Blockly.utils.shortestStringLength([]);
|
||||
assertEquals('Empty list', 0, len);
|
||||
});
|
||||
|
||||
test('comment word prefix', function() {
|
||||
var len = Blockly.utils.commonWordPrefix('one,two,three,four,five'.split(','));
|
||||
assertEquals('No prefix', 0, len);
|
||||
len = Blockly.utils.commonWordPrefix('Xone,Xtwo,Xthree,Xfour,Xfive'.split(','));
|
||||
assertEquals('No word prefix', 0, len);
|
||||
len = Blockly.utils.commonWordPrefix('abc de,abc de,abc de,abc de'.split(','));
|
||||
assertEquals('Full equality', 6, len);
|
||||
len = Blockly.utils.commonWordPrefix('abc deX,abc deY'.split(','));
|
||||
assertEquals('One word prefix', 4, len);
|
||||
len = Blockly.utils.commonWordPrefix('abc de,abc deY'.split(','));
|
||||
assertEquals('Overflow no', 4, len);
|
||||
len = Blockly.utils.commonWordPrefix('abc de,abc de Y'.split(','));
|
||||
assertEquals('Overflow yes', 6, len);
|
||||
len = Blockly.utils.commonWordPrefix(['Hello World']);
|
||||
assertEquals('List of one', 11, len);
|
||||
len = Blockly.utils.commonWordPrefix([]);
|
||||
assertEquals('Empty list', 0, len);
|
||||
len = Blockly.utils.commonWordPrefix('turn left,turn right'.split(','));
|
||||
assertEquals('No prefix due to &nbsp;', 0, len);
|
||||
len = Blockly.utils.commonWordPrefix('turn\u00A0left,turn\u00A0right'.split(','));
|
||||
assertEquals('No prefix due to \\u00A0', 0, len);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user