mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-23 14:32:59 -05:00
840ffb5df0
Newer versions of `tap` run more asynchronously, so sometimes using `process.nextTick(process.exit)` to end a test would prevent the test from completing correctly. Removing all instances of `process.nextTick(process.exit)` put tests into three categories: * the test still worked correctly -- no fixup needed. * the test would hang because the VM's `_steppingInterval` was keeping Node alive. These tests call a new `quit()` method which ends the stepping interval. * the `load-extensions` test needed special attention because the "Video Sensing" extension starts its own loop using `setTimeout`. I added a `_stopLoop()` method on the extension and directly call that from the test. I'm not completely happy with this solution but anything more general would likely require a change to the extension spec, so I'm leaving that as a followup task.
463 lines
10 KiB
JavaScript
463 lines
10 KiB
JavaScript
const tap = require('tap');
|
|
const path = require('path');
|
|
const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer;
|
|
const makeTestStorage = require('../fixtures/make-test-storage');
|
|
const VirtualMachine = require('../../src/virtual-machine');
|
|
|
|
let vm;
|
|
let projectChanged;
|
|
let blockContainer;
|
|
|
|
tap.beforeEach(() => {
|
|
const projectUri = path.resolve(__dirname, '../fixtures/default.sb2');
|
|
const project = readFileToBuffer(projectUri);
|
|
|
|
vm = new VirtualMachine();
|
|
|
|
vm.runtime.addListener('PROJECT_CHANGED', () => {
|
|
projectChanged = true;
|
|
});
|
|
|
|
vm.attachStorage(makeTestStorage());
|
|
return vm.loadProject(project).then(() => {
|
|
blockContainer = vm.editingTarget.blocks;
|
|
|
|
// Add mock blocks to use for tests
|
|
blockContainer.createBlock({
|
|
id: 'a parent block',
|
|
opcode: 'my_testParentBlock',
|
|
fields: {},
|
|
inputs: {}
|
|
});
|
|
|
|
|
|
blockContainer.createBlock({
|
|
id: 'a new block',
|
|
opcode: 'my_testBlock',
|
|
topLevel: true,
|
|
x: -10,
|
|
y: 35,
|
|
fields: {
|
|
A_FIELD: {
|
|
name: 'A_FIELD',
|
|
value: 10
|
|
}
|
|
},
|
|
inputs: {},
|
|
parent: 'a block'
|
|
});
|
|
|
|
// Reset project changes from new blocks
|
|
projectChanged = false;
|
|
|
|
});
|
|
});
|
|
|
|
const test = tap.test;
|
|
|
|
test('Creating a block should emit a project changed event', t => {
|
|
blockContainer.createBlock({
|
|
id: 'another block',
|
|
opcode: 'my_testBlock',
|
|
topLevel: true
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Deleting a block should emit a project changed event', t => {
|
|
blockContainer.deleteBlock('a new block');
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Changing a block should emit a project changed event', t => {
|
|
blockContainer.changeBlock({
|
|
element: 'field',
|
|
id: 'a new block',
|
|
name: 'A_FIELD',
|
|
value: 300
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
projectChanged = false;
|
|
|
|
blockContainer.changeBlock({
|
|
element: 'checkbox',
|
|
id: 'a new block',
|
|
value: true
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
projectChanged = false;
|
|
|
|
blockContainer.changeBlock({
|
|
element: 'mutation',
|
|
id: 'a new block',
|
|
value: '<mutation></mutation>'
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
|
|
t.end();
|
|
});
|
|
|
|
test('Moving a block to a new position should emit a project changed event', t => {
|
|
blockContainer.moveBlock({
|
|
id: 'a new block',
|
|
newCoordinate: {
|
|
x: -40,
|
|
y: 350
|
|
}
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Connecting a block to a new parent should emit a project changed event', t => {
|
|
blockContainer.createBlock({
|
|
id: 'another block',
|
|
opcode: 'my_testBlock'
|
|
});
|
|
|
|
projectChanged = false;
|
|
|
|
blockContainer.moveBlock({
|
|
id: 'a new block',
|
|
newParent: 'another block'
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Disconnecting a block from another should emit a project changed event', t => {
|
|
blockContainer.moveBlock({
|
|
id: 'a new block',
|
|
oldParent: 'a parent block'
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Creating a local variable should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'var_create',
|
|
varId: 'a new variable',
|
|
varName: 'foo',
|
|
varType: '',
|
|
isLocal: true,
|
|
isCloud: false
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
|
|
projectChanged = false;
|
|
|
|
// Creating the same variable twice should not emit a project changed event
|
|
blockContainer.blocklyListen({
|
|
type: 'var_create',
|
|
varId: 'a new variable',
|
|
varName: 'foo',
|
|
varType: '',
|
|
isLocal: true,
|
|
isCloud: false
|
|
});
|
|
|
|
t.equal(projectChanged, false);
|
|
|
|
t.end();
|
|
});
|
|
|
|
test('Creating a global variable should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'var_create',
|
|
varId: 'a new variable',
|
|
varName: 'foo',
|
|
varType: '',
|
|
isLocal: false,
|
|
isCloud: false
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
|
|
projectChanged = false;
|
|
|
|
// Creating the same variable twice should not emit a project changed event
|
|
blockContainer.blocklyListen({
|
|
type: 'var_create',
|
|
varId: 'a new variable',
|
|
varName: 'foo',
|
|
varType: '',
|
|
isLocal: false,
|
|
isCloud: false
|
|
});
|
|
|
|
t.equal(projectChanged, false);
|
|
|
|
t.end();
|
|
});
|
|
|
|
test('Renaming a variable should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'var_create',
|
|
varId: 'a new variable',
|
|
varName: 'foo',
|
|
varType: '',
|
|
isLocal: false,
|
|
isCloud: false
|
|
});
|
|
|
|
projectChanged = false;
|
|
|
|
blockContainer.blocklyListen({
|
|
type: 'var_rename',
|
|
varId: 'a new variable',
|
|
oldName: 'foo',
|
|
newName: 'bar'
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Deleting a variable should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'var_create',
|
|
varId: 'a new variable',
|
|
varName: 'foo',
|
|
varType: '',
|
|
isLocal: false,
|
|
isCloud: false
|
|
});
|
|
|
|
projectChanged = false;
|
|
|
|
blockContainer.blocklyListen({
|
|
type: 'var_delete',
|
|
varId: 'a new variable',
|
|
varName: 'foo',
|
|
varType: '',
|
|
isLocal: false,
|
|
isCloud: false
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Creating a block comment should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_create',
|
|
blockId: 'a new block',
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Creating a workspace comment should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_create',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Changing a comment should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_create',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
projectChanged = false;
|
|
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_change',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
newContents_: {
|
|
minimized: true
|
|
},
|
|
oldContents_: {
|
|
minimized: false
|
|
}
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Attempting to change a comment that does not exist should not emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_change',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
newContents_: {
|
|
minimized: true
|
|
},
|
|
oldContents_: {
|
|
minimized: false
|
|
}
|
|
});
|
|
|
|
t.equal(projectChanged, false);
|
|
t.end();
|
|
});
|
|
|
|
test('Deleting a block comment should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_create',
|
|
blockId: 'a new block',
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
projectChanged = false;
|
|
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_delete',
|
|
blockId: 'a new block',
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Deleting a workspace comment should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_create',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
projectChanged = false;
|
|
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_delete',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|
|
|
|
test('Deleting a comment that does not exist should not emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_delete',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
t.equal(projectChanged, false);
|
|
t.end();
|
|
});
|
|
|
|
test('Moving a comment should emit a project changed event', t => {
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_create',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
height: 250,
|
|
width: 400,
|
|
xy: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
minimized: false,
|
|
text: 'comment'
|
|
});
|
|
|
|
projectChanged = false;
|
|
|
|
blockContainer.blocklyListen({
|
|
type: 'comment_move',
|
|
blockId: null,
|
|
commentId: 'a new comment',
|
|
oldCoordinate_: {
|
|
x: -40,
|
|
y: 27
|
|
},
|
|
newCoordinate_: {
|
|
x: -35,
|
|
y: 50
|
|
}
|
|
});
|
|
|
|
t.equal(projectChanged, true);
|
|
t.end();
|
|
});
|