diff --git a/package.json b/package.json
index 197468803..7b4faaa12 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 9c49d9ec1..81f95b1cb 100644
--- a/src/engine/runtime.js
+++ b/src/engine/runtime.js
@@ -22,6 +22,7 @@ var defaultBlockPackages = {
 
 /**
  * Manages targets, scripts, and the sequencer.
+ * @constructor
  */
 var Runtime = function () {
     // Bind event emitter
@@ -609,7 +610,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();
     }
 };
@@ -819,7 +820,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 24e1d67b7..0b5b4b97b 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 <ascii@media.mit.edu>
+ * @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();
+});