diff --git a/README.md b/README.md index 6e548805e..cd14f003f 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,6 @@ Open a Command Prompt or Terminal in the repository and run: ```bash npm start ``` -Or on Windows: -```bash -StartServerWindows.bat -``` ## Playground To run the Playground, make sure the dev server's running and go to [http://localhost:8073/](http://localhost:8073/) - you will be directed to the playground, which demonstrates various tools and internal state. diff --git a/package.json b/package.json index 79c04ad03..503d6dcf3 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "version": "./node_modules/.bin/json -f package.json -I -e \"this.repository.sha = '$(git log -n1 --pretty=format:%H)'\"" }, "devDependencies": { + "adm-zip": "0.4.7", "babel-eslint": "7.0.0", "copy-webpack-plugin": "3.0.1", "eslint": "3.8.1", diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 9ad73ff80..80b86d926 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -23,6 +23,7 @@ var defaultBlockPackages = { /** * Manages targets, scripts, and the sequencer. + * @constructor */ var Runtime = function () { // Bind event emitter @@ -444,12 +445,24 @@ Runtime.prototype.startHats = function (requestedHatOpcode, // Not the right hat. return; } + // Match any requested fields. // For example: ensures that broadcasts match. // This needs to happen before the block is evaluated // (i.e., before the predicate can be run) because "broadcast and wait" // needs to have a precise collection of started threads. var hatFields = target.blocks.getFields(topBlockId); + + // If no fields are present, check inputs (horizontal blocks) + if (Object.keys(hatFields).length === 0) { + var hatInputs = target.blocks.getInputs(topBlockId); + for (var input in hatInputs) { + var id = hatInputs[input].block; + var fields = target.blocks.getFields(id); + hatFields = Object.assign(fields, hatFields); + } + } + if (optMatchFields) { for (var matchField in optMatchFields) { if (hatFields[matchField].value !== @@ -459,6 +472,7 @@ Runtime.prototype.startHats = function (requestedHatOpcode, } } } + // Look up metadata for the relevant hat. var hatMeta = instance._hats[requestedHatOpcode]; if (hatMeta.restartExistingThreads) { @@ -606,7 +620,7 @@ Runtime.prototype.setEditingTarget = function (editingTarget) { Runtime.prototype.setCompatibilityMode = function (compatibilityModeOn) { this.compatibilityMode = compatibilityModeOn; if (this._steppingInterval) { - self.clearInterval(this._steppingInterval); + clearInterval(this._steppingInterval); this.start(); } }; @@ -816,7 +830,7 @@ Runtime.prototype.start = function () { interval = Runtime.THREAD_STEP_INTERVAL_COMPATIBILITY; } this.currentStepTime = interval; - this._steppingInterval = self.setInterval(function () { + this._steppingInterval = setInterval(function () { this._step(); }.bind(this), interval); }; diff --git a/src/index.js b/src/index.js index 7faf7fb9a..8e9b4a940 100644 --- a/src/index.js +++ b/src/index.js @@ -6,8 +6,7 @@ var sb2import = require('./import/sb2import'); /** * Handles connections between blocks, stage, and extensions. - * - * @author Andrew Sliwinski + * @constructor */ var VirtualMachine = function () { var instance = this; diff --git a/test/fixtures/control.sb2 b/test/fixtures/control.sb2 new file mode 100644 index 000000000..ea758168b Binary files /dev/null and b/test/fixtures/control.sb2 differ diff --git a/test/fixtures/data.sb2 b/test/fixtures/data.sb2 new file mode 100644 index 000000000..96bba0e69 Binary files /dev/null and b/test/fixtures/data.sb2 differ diff --git a/test/fixtures/default.json b/test/fixtures/default.json deleted file mode 100644 index af478a4e2..000000000 --- a/test/fixtures/default.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "objName": "Stage", - "sounds": [{ - "soundName": "pop", - "soundID": -1, - "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", - "sampleCount": 258, - "rate": 11025, - "format": "" - }], - "costumes": [{ - "costumeName": "backdrop1", - "baseLayerID": -1, - "baseLayerMD5": "739b5e2a2435f6e1ec2993791b423146.png", - "bitmapResolution": 1, - "rotationCenterX": 240, - "rotationCenterY": 180 - }], - "currentCostumeIndex": 0, - "penLayerMD5": "5c81a336fab8be57adc039a8a2b33ca9.png", - "penLayerID": -1, - "tempoBPM": 60, - "videoAlpha": 0.5, - "children": [{ - "objName": "Sprite1", - "sounds": [{ - "soundName": "meow", - "soundID": -1, - "md5": "83c36d806dc92327b9e7049a565c6bff.wav", - "sampleCount": 18688, - "rate": 22050, - "format": "" - }], - "costumes": [{ - "costumeName": "costume1", - "baseLayerID": -1, - "baseLayerMD5": "09dc888b0b7df19f70d81588ae73420e.svg", - "bitmapResolution": 1, - "rotationCenterX": 47, - "rotationCenterY": 55 - }, - { - "costumeName": "costume2", - "baseLayerID": -1, - "baseLayerMD5": "3696356a03a8d938318876a593572843.svg", - "bitmapResolution": 1, - "rotationCenterX": 47, - "rotationCenterY": 55 - }], - "currentCostumeIndex": 0, - "scratchX": 0, - "scratchY": 0, - "scale": 1, - "direction": 90, - "rotationStyle": "normal", - "isDraggable": false, - "indexInLibrary": 1, - "visible": true, - "spriteInfo": { - } - }], - "info": { - "videoOn": false, - "userAgent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/50.0.2661.102 Safari\/537.36", - "swfVersion": "v446", - "scriptCount": 0, - "spriteCount": 1, - "hasCloudData": false, - "flashVersion": "MAC 21,0,0,242" - } -} diff --git a/test/fixtures/default.sb2 b/test/fixtures/default.sb2 new file mode 100644 index 000000000..1736d2dda Binary files /dev/null and b/test/fixtures/default.sb2 differ diff --git a/test/fixtures/demo.json b/test/fixtures/demo.json deleted file mode 100644 index b10376ec7..000000000 --- a/test/fixtures/demo.json +++ /dev/null @@ -1,359 +0,0 @@ -{ - "objName": "Stage", - "variables": [{ - "name": "x", - "value": "1", - "isPersistent": false - }, - { - "name": "y", - "value": "1", - "isPersistent": false - }, - { - "name": "z", - "value": "1", - "isPersistent": false - }, - { - "name": "d", - "value": "1", - "isPersistent": false - }, - { - "name": "a", - "value": 4, - "isPersistent": false - }], - "lists": [{ - "listName": "D# Minor Pentatonic", - "contents": ["78", - "75", - "73", - "75", - "70", - "78", - "73", - "75", - "75", - "78", - "75", - "73", - "75", - "70", - "75", - "78", - "73", - "75", - "78", - "75", - "73", - "75", - "70", - "73", - "68", - "70", - "66", - "68", - "63"], - "isPersistent": false, - "x": 5, - "y": 32, - "width": 125, - "height": 206, - "visible": true - }], - "scripts": [[52, - 8, - [["whenIReceive", "start"], - ["setVar:to:", "a", "1"], - ["doRepeat", - ["lineCountOfList:", "D# Minor Pentatonic"], - [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "a"], "D# Minor Pentatonic"], 0.5], ["changeVar:by:", "a", 1]]]]], - [53, - 186, - [["whenIReceive", "start"], - ["setVar:to:", "x", "1"], - ["rest:elapsed:from:", 7.25], - ["doRepeat", - ["lineCountOfList:", "D# Minor Pentatonic"], - [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "x"], "D# Minor Pentatonic"], 0.25], ["changeVar:by:", "x", 1]]]]], - [48, - 557, - [["whenIReceive", "start"], - ["setVar:to:", "z", "1"], - ["rest:elapsed:from:", 13], - ["doRepeat", - ["lineCountOfList:", "D# Minor Pentatonic"], - [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "z"], "D# Minor Pentatonic"], 0.0625], ["changeVar:by:", "z", 1]]]]], - [49, - 368, - [["whenIReceive", "start"], - ["setVar:to:", "y", "1"], - ["rest:elapsed:from:", 11], - ["doRepeat", - ["lineCountOfList:", "D# Minor Pentatonic"], - [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "y"], "D# Minor Pentatonic"], 0.125], ["changeVar:by:", "y", 1]]]]], - [52, - 745, - [["whenIReceive", "start"], - ["setVar:to:", "d", "1"], - ["rest:elapsed:from:", 13.5], - ["doRepeat", - ["lineCountOfList:", "D# Minor Pentatonic"], - [["noteOn:duration:elapsed:from:", ["getLine:ofList:", ["readVariable", "d"], "D# Minor Pentatonic"], 0.03125], ["changeVar:by:", "d", 1]]]]]], - "sounds": [{ - "soundName": "pop", - "soundID": 0, - "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", - "sampleCount": 258, - "rate": 11025, - "format": "" - }], - "costumes": [{ - "costumeName": "backdrop1", - "baseLayerID": 4, - "baseLayerMD5": "b61b1077b0ea1931abee9dbbfa7903ff.png", - "bitmapResolution": 2, - "rotationCenterX": 480, - "rotationCenterY": 360 - }], - "currentCostumeIndex": 0, - "penLayerMD5": "5c81a336fab8be57adc039a8a2b33ca9.png", - "penLayerID": 0, - "tempoBPM": 60, - "videoAlpha": 0.5, - "children": [{ - "objName": "Indicator", - "scripts": [[247.85, - 32.8, - [["procDef", "foo %n", ["bar"], [1], false], - ["hide"], - ["clearPenTrails"], - ["penColor:", 5968094], - ["say:", ["getParam", "bar", "r"]], - ["stopScripts", "this script"]]], - [41, 36, [["whenGreenFlag"], ["call", "foo %n", 1]]]], - "sounds": [{ - "soundName": "pop", - "soundID": 0, - "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", - "sampleCount": 258, - "rate": 11025, - "format": "" - }], - "costumes": [{ - "costumeName": "costume1", - "baseLayerID": 1, - "baseLayerMD5": "d36f6603ec293d2c2198d3ea05109fe0.png", - "bitmapResolution": 2, - "rotationCenterX": 0, - "rotationCenterY": 0 - }], - "currentCostumeIndex": 0, - "scratchX": 22, - "scratchY": -26, - "scale": 1, - "direction": 90, - "rotationStyle": "normal", - "isDraggable": false, - "indexInLibrary": 3, - "visible": false, - "spriteInfo": { - } - }, - { - "target": "Stage", - "cmd": "timer", - "param": null, - "color": 2926050, - "label": "timer", - "mode": 1, - "sliderMin": 0, - "sliderMax": 100, - "isDiscrete": true, - "x": 5, - "y": 5, - "visible": false - }, - { - "target": "Stage", - "cmd": "getVar:", - "param": "x", - "color": 15629590, - "label": "x", - "mode": 1, - "sliderMin": 0, - "sliderMax": 100, - "isDiscrete": true, - "x": 5, - "y": 268, - "visible": true - }, - { - "target": "Stage", - "cmd": "getVar:", - "param": "y", - "color": 15629590, - "label": "y", - "mode": 1, - "sliderMin": 0, - "sliderMax": 100, - "isDiscrete": true, - "x": 5, - "y": 295, - "visible": true - }, - { - "target": "Stage", - "cmd": "getVar:", - "param": "z", - "color": 15629590, - "label": "z", - "mode": 1, - "sliderMin": 0, - "sliderMax": 100, - "isDiscrete": true, - "x": 78, - "y": 268, - "visible": true - }, - { - "objName": "Play", - "scripts": [[32, 33, [["whenClicked"], ["broadcast:", "start"]]]], - "sounds": [{ - "soundName": "pop", - "soundID": 0, - "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", - "sampleCount": 258, - "rate": 11025, - "format": "" - }], - "costumes": [{ - "costumeName": "costume1", - "baseLayerID": 2, - "baseLayerMD5": "30f811366ae3a53e6447932cc7f0212d.png", - "bitmapResolution": 2, - "rotationCenterX": 68, - "rotationCenterY": 115 - }], - "currentCostumeIndex": 0, - "scratchX": 2, - "scratchY": -48, - "scale": 1, - "direction": 90, - "rotationStyle": "normal", - "isDraggable": false, - "indexInLibrary": 1, - "visible": true, - "spriteInfo": { - } - }, - { - "target": "Stage", - "cmd": "getVar:", - "param": "d", - "color": 15629590, - "label": "d", - "mode": 1, - "sliderMin": 0, - "sliderMax": 100, - "isDiscrete": true, - "x": 5, - "y": 241, - "visible": true - }, - { - "target": "Stage", - "cmd": "getVar:", - "param": "a", - "color": 15629590, - "label": "a", - "mode": 1, - "sliderMin": 0, - "sliderMax": 100, - "isDiscrete": true, - "x": 78, - "y": 241, - "visible": true - }, - { - "objName": "Stop", - "scripts": [[45, 104, [["whenClicked"], ["stopScripts", "all"]]]], - "sounds": [{ - "soundName": "pop", - "soundID": 0, - "md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav", - "sampleCount": 258, - "rate": 11025, - "format": "" - }], - "costumes": [{ - "costumeName": "costume1", - "baseLayerID": 3, - "baseLayerMD5": "3de406f265b8d664406adf7c70762514.png", - "bitmapResolution": 2, - "rotationCenterX": 68, - "rotationCenterY": 70 - }], - "currentCostumeIndex": 0, - "scratchX": 121, - "scratchY": -33, - "scale": 1, - "direction": 90, - "rotationStyle": "normal", - "isDraggable": false, - "indexInLibrary": 2, - "visible": true, - "spriteInfo": { - } - }, - { - "listName": "D# Minor Pentatonic", - "contents": ["78", - "75", - "73", - "75", - "70", - "78", - "73", - "75", - "75", - "78", - "75", - "73", - "75", - "70", - "75", - "78", - "73", - "75", - "78", - "75", - "73", - "75", - "70", - "73", - "68", - "70", - "66", - "68", - "63"], - "isPersistent": false, - "x": 5, - "y": 32, - "width": 125, - "height": 206, - "visible": true - }], - "info": { - "spriteCount": 3, - "projectID": "118381369", - "videoOn": false, - "hasCloudData": false, - "userAgent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/53.0.2785.143 Safari\/537.36", - "scriptCount": 9, - "flashVersion": "MAC 23,0,0,185", - "swfVersion": "v450.1" - } -} diff --git a/test/fixtures/event.sb2 b/test/fixtures/event.sb2 new file mode 100644 index 000000000..6533f292a Binary files /dev/null and b/test/fixtures/event.sb2 differ diff --git a/test/fixtures/extract.js b/test/fixtures/extract.js new file mode 100644 index 000000000..fc33cf9ae --- /dev/null +++ b/test/fixtures/extract.js @@ -0,0 +1,6 @@ +var AdmZip = require('adm-zip'); + +module.exports = function (path) { + var zip = new AdmZip(path); + return zip.readAsText('project.json', 'utf8'); +}; diff --git a/test/fixtures/looks.sb2 b/test/fixtures/looks.sb2 new file mode 100644 index 000000000..6f38c99e7 Binary files /dev/null and b/test/fixtures/looks.sb2 differ diff --git a/test/fixtures/motion.sb2 b/test/fixtures/motion.sb2 new file mode 100644 index 000000000..41bf29048 Binary files /dev/null and b/test/fixtures/motion.sb2 differ diff --git a/test/integration/control.js b/test/integration/control.js new file mode 100644 index 000000000..fba8ed9c3 --- /dev/null +++ b/test/integration/control.js @@ -0,0 +1,35 @@ +var path = require('path'); +var test = require('tap').test; +var extract = require('../fixtures/extract'); +var VirtualMachine = require('../../src/index'); + +var uri = path.resolve(__dirname, '../fixtures/control.sb2'); +var project = extract(uri); + +test('control project', function (t) { + var vm = new VirtualMachine(); + + // Evaluate playground data and exit + vm.on('playgroundData', function (e) { + var threads = JSON.parse(e.threads); + t.ok(threads.length > 0); + t.end(); + process.nextTick(process.exit); + }); + + // Start VM, load project, and run + t.doesNotThrow(function () { + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + vm.loadProject(project); + vm.greenFlag(); + }); + + // After two seconds, get playground data and stop + setTimeout(function () { + vm.getPlaygroundData(); + vm.stopAll(); + }, 2000); +}); diff --git a/test/integration/data.js b/test/integration/data.js new file mode 100644 index 000000000..de169e028 --- /dev/null +++ b/test/integration/data.js @@ -0,0 +1,34 @@ +var path = require('path'); +var test = require('tap').test; +var extract = require('../fixtures/extract'); +var VirtualMachine = require('../../src/index'); + +var uri = path.resolve(__dirname, '../fixtures/data.sb2'); +var project = extract(uri); + +test('data project', function (t) { + var vm = new VirtualMachine(); + + // Evaluate playground data and exit + vm.on('playgroundData', function () { + // @todo Additional tests + t.end(); + process.nextTick(process.exit); + }); + + // Start VM, load project, and run + t.doesNotThrow(function () { + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + vm.loadProject(project); + vm.greenFlag(); + }); + + // After two seconds, get playground data and stop + setTimeout(function () { + vm.getPlaygroundData(); + vm.stopAll(); + }, 2000); +}); diff --git a/test/integration/event.js b/test/integration/event.js new file mode 100644 index 000000000..a70493161 --- /dev/null +++ b/test/integration/event.js @@ -0,0 +1,35 @@ +var path = require('path'); +var test = require('tap').test; +var extract = require('../fixtures/extract'); +var VirtualMachine = require('../../src/index'); + +var uri = path.resolve(__dirname, '../fixtures/event.sb2'); +var project = extract(uri); + +test('event project', function (t) { + var vm = new VirtualMachine(); + + // Evaluate playground data and exit + vm.on('playgroundData', function (e) { + var threads = JSON.parse(e.threads); + t.ok(threads.length > 0); + t.end(); + process.nextTick(process.exit); + }); + + // Start VM, load project, and run + t.doesNotThrow(function () { + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + vm.loadProject(project); + vm.greenFlag(); + }); + + // After two seconds, get playground data and stop + setTimeout(function () { + vm.getPlaygroundData(); + vm.stopAll(); + }, 2000); +}); diff --git a/test/integration/index.js b/test/integration/index.js deleted file mode 100644 index 06bdcf37b..000000000 --- a/test/integration/index.js +++ /dev/null @@ -1,26 +0,0 @@ -var test = require('tap').test; -var VirtualMachine = require('../../src/index'); - -test('spec', function (t) { - var vm = new VirtualMachine(); - - t.type(VirtualMachine, 'function'); - t.type(vm, 'object'); - t.end(); -}); - -test('create', function (t) { - t.end(); -}); - -test('move', function (t) { - t.end(); -}); - -test('change', function (t) { - t.end(); -}); - -test('delete', function (t) { - t.end(); -}); diff --git a/test/integration/looks.js b/test/integration/looks.js new file mode 100644 index 000000000..f8b52ae45 --- /dev/null +++ b/test/integration/looks.js @@ -0,0 +1,35 @@ +var path = require('path'); +var test = require('tap').test; +var extract = require('../fixtures/extract'); +var VirtualMachine = require('../../src/index'); + +var uri = path.resolve(__dirname, '../fixtures/looks.sb2'); +var project = extract(uri); + +test('looks project', function (t) { + var vm = new VirtualMachine(); + + // Evaluate playground data and exit + vm.on('playgroundData', function (e) { + var threads = JSON.parse(e.threads); + t.ok(threads.length === 0); + t.end(); + process.nextTick(process.exit); + }); + + // Start VM, load project, and run + t.doesNotThrow(function () { + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + vm.loadProject(project); + vm.greenFlag(); + }); + + // After two seconds, get playground data and stop + setTimeout(function () { + vm.getPlaygroundData(); + vm.stopAll(); + }, 2000); +}); diff --git a/test/integration/motion.js b/test/integration/motion.js new file mode 100644 index 000000000..cb620a687 --- /dev/null +++ b/test/integration/motion.js @@ -0,0 +1,35 @@ +var path = require('path'); +var test = require('tap').test; +var extract = require('../fixtures/extract'); +var VirtualMachine = require('../../src/index'); + +var uri = path.resolve(__dirname, '../fixtures/motion.sb2'); +var project = extract(uri); + +test('motion project', function (t) { + var vm = new VirtualMachine(); + + // Evaluate playground data and exit + vm.on('playgroundData', function (e) { + var threads = JSON.parse(e.threads); + t.ok(threads.length === 0); + t.end(); + process.nextTick(process.exit); + }); + + // Start VM, load project, and run + t.doesNotThrow(function () { + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + vm.loadProject(project); + vm.greenFlag(); + }); + + // After two seconds, get playground data and stop + setTimeout(function () { + vm.getPlaygroundData(); + vm.stopAll(); + }, 2000); +}); diff --git a/test/unit/import_sb2.js b/test/unit/import_sb2.js index 5072b208a..900563735 100644 --- a/test/unit/import_sb2.js +++ b/test/unit/import_sb2.js @@ -1,6 +1,6 @@ -var fs = require('fs'); var path = require('path'); var test = require('tap').test; +var extract = require('../fixtures/extract'); var renderedTarget = require('../../src/sprites/rendered-target'); var runtime = require('../../src/engine/runtime'); @@ -13,46 +13,8 @@ test('spec', function (t) { test('default', function (t) { // Get SB2 JSON (string) - var uri = path.resolve(__dirname, '../fixtures/default.json'); - var file = fs.readFileSync(uri, 'utf8'); - - // Create runtime instance & load SB2 into it - var rt = new runtime(); - sb2(file, rt); - - // Test - t.type(file, 'string'); - t.type(rt, 'object'); - t.type(rt.targets, 'object'); - - t.ok(rt.targets[0] instanceof renderedTarget); - t.type(rt.targets[0].id, 'string'); - t.type(rt.targets[0].blocks, 'object'); - t.type(rt.targets[0].variables, 'object'); - t.type(rt.targets[0].lists, 'object'); - - t.equal(rt.targets[0].isOriginal, true); - t.equal(rt.targets[0].currentCostume, 0); - t.equal(rt.targets[0].isOriginal, true); - t.equal(rt.targets[0].isStage, true); - - t.ok(rt.targets[1] instanceof renderedTarget); - t.type(rt.targets[1].id, 'string'); - t.type(rt.targets[1].blocks, 'object'); - t.type(rt.targets[1].variables, 'object'); - t.type(rt.targets[1].lists, 'object'); - - t.equal(rt.targets[1].isOriginal, true); - t.equal(rt.targets[1].currentCostume, 0); - t.equal(rt.targets[1].isOriginal, true); - t.equal(rt.targets[1].isStage, false); - t.end(); -}); - -test('demo', function (t) { - // Get SB2 JSON (string) - var uri = path.resolve(__dirname, '../fixtures/demo.json'); - var file = fs.readFileSync(uri, 'utf8'); + var uri = path.resolve(__dirname, '../fixtures/default.sb2'); + var file = extract(uri); // Create runtime instance & load SB2 into it var rt = new runtime(); diff --git a/test/unit/spec.js b/test/unit/spec.js new file mode 100644 index 000000000..68485bf9d --- /dev/null +++ b/test/unit/spec.js @@ -0,0 +1,33 @@ +var test = require('tap').test; +var VirtualMachine = require('../../src/index'); + +test('interface', function (t) { + var vm = new VirtualMachine(); + t.type(vm, 'object'); + t.type(vm.start, 'function'); + t.type(vm.greenFlag, 'function'); + t.type(vm.setTurboMode, 'function'); + t.type(vm.setCompatibilityMode, 'function'); + t.type(vm.stopAll, 'function'); + t.type(vm.clear, 'function'); + + t.type(vm.getPlaygroundData, 'function'); + t.type(vm.postIOData, 'function'); + + t.type(vm.loadProject, 'function'); + t.type(vm.addSprite2, 'function'); + t.type(vm.addCostume, 'function'); + t.type(vm.addBackdrop, 'function'); + t.type(vm.renameSprite, 'function'); + t.type(vm.deleteSprite, 'function'); + + t.type(vm.attachRenderer, 'function'); + t.type(vm.blockListener, 'function'); + t.type(vm.flyoutBlockListener, 'function'); + t.type(vm.setEditingTarget, 'function'); + + t.type(vm.emitTargetsUpdate, 'function'); + t.type(vm.emitWorkspaceUpdate, 'function'); + t.type(vm.postSpriteInfo, 'function'); + t.end(); +});