diff --git a/src/virtual-machine.js b/src/virtual-machine.js index 1a1d7c036..79513103f 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -836,6 +836,7 @@ class VirtualMachine extends EventEmitter { /** * Delete a sprite and all its clones. * @param {string} targetId ID of a target whose sprite to delete. + * @return {Function} Returns a function to restore the sprite that was deleted */ deleteSprite (targetId) { const target = this.runtime.getTargetById(targetId); @@ -849,6 +850,8 @@ class VirtualMachine extends EventEmitter { if (!sprite) { throw new Error('No sprite associated with this target.'); } + const spritePromise = this.exportSprite(targetId, 'uint8array'); + const restoreSprite = () => spritePromise.then(spriteBuffer => this.addSprite(spriteBuffer)); this.runtime.requestRemoveMonitorByTargetId(targetId); const currentEditingTarget = this.editingTarget; for (let i = 0; i < sprite.clones.length; i++) { @@ -867,9 +870,10 @@ class VirtualMachine extends EventEmitter { } // Sprite object should be deleted by GC. this.emitTargetsUpdate(); - } else { - throw new Error('No target with the provided id.'); + return restoreSprite; } + + throw new Error('No target with the provided id.'); } /** diff --git a/test/integration/delete-and-restore-sprite.js b/test/integration/delete-and-restore-sprite.js new file mode 100644 index 000000000..9ed1c781c --- /dev/null +++ b/test/integration/delete-and-restore-sprite.js @@ -0,0 +1,65 @@ +const path = require('path'); +const test = require('tap').test; +const makeTestStorage = require('../fixtures/make-test-storage'); +const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; + +const VirtualMachine = require('../../src/virtual-machine'); +// const RenderedTarget = require('../../src/sprites/rendered-target'); + +const projectUri = path.resolve(__dirname, '../fixtures/default.sb2'); +const project = readFileToBuffer(projectUri); + +const vm = new VirtualMachine(); + +test('spec', t => { + t.type(vm.deleteSprite, 'function'); + t.end(); +}); + +test('default cat', t => { + // Get default cat from .sprite2 + // const uri = path.resolve(__dirname, '../fixtures/example_sprite.sprite2'); + // const sprite = readFileToBuffer(uri); + + vm.attachStorage(makeTestStorage()); + + // Evaluate playground data and exit + vm.on('playgroundData', e => { + const threads = JSON.parse(e.threads); + t.ok(threads.length === 0); + t.end(); + process.nextTick(process.exit); + }); + + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + t.doesNotThrow(() => { + vm.loadProject(project).then(() => { + + t.equal(vm.runtime.targets.length, 2); // stage and default sprite + + const defaultSprite = vm.runtime.targets[1]; + + // Delete the sprite + const addSpriteBack = vm.deleteSprite(vm.runtime.targets[1].id); + + t.equal(vm.runtime.targets.length, 1); + + t.type(addSpriteBack, 'function'); + + addSpriteBack().then(() => { + t.equal(vm.runtime.targets.length, 2); + t.equal(vm.runtime.targets[1].getName(), defaultSprite.getName()); + + vm.greenFlag(); + + setTimeout(() => { + vm.getPlaygroundData(); + vm.stopAll(); + }, 1000); + }); + }); + }); +});