Merge pull request #43 from brianpilati/master

Edited - Finished the doAsk and answer functionality and brought the project under test.
This commit is contained in:
Shane M. Clements 2014-03-10 21:36:20 -06:00
commit 623dce5402
43 changed files with 1825 additions and 75 deletions

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
*.swp
test/lib/*
.DS_Store
logs
npm-debug.log
node_modules

View file

@ -19,3 +19,50 @@ Running the HTML5 player on your own website, or locally, you will need to have
PHP so that the `proxy.php` file can be used to load assets from the same domain. This is done to be compatible with Javascript security models in today's browsers. To test the HTML5 player against the Flash player you can use the compare.html web page.
See the file `TESTING.md` for more details.
Unit Tests
----------
The tests are written using Karma and there should be a 100% passing rate in order to commit any code to the project.
The expectation is to add a unit test for any code that you contribute to the project.
Install Node (NPM) (https://npmjs.org/)
---------------------------------------
Brew:
```
$ brew install npm
```
Mac Ports:
```
$ port install npm
```
In your local scratch directory
```
$ npm install
```
Local copy of jQuery
--------------------
```
$ cd test/lib
$ curl http://code.jquery.com/jquery-1.11.0.min.js > jquery-1.11.0.min.js
```
To Run the tests
----------------
```
$ ./scripts/test.sh
```
To configure the unit tests
---------------------------
The karam.conf.js file is location in the config directory

View file

@ -8,35 +8,17 @@
<script src=//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js></script>
<script src=//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js></script>
<script src=js/util/Timer.js></script>
<script src=js/util/OffsetBuffer.js></script>
<script src=js/util/Color.js></script>
<script src=js/util/Rectangle.js></script>
<script src=js/Sprite.js></script>
<script src=js/Reporter.js></script>
<script src=js/Stage.js></script>
<script src=js/sound/WAVFile.js></script>
<script src=js/sound/SoundDecoder.js></script>
<script src=js/sound/SoundBank.js></script>
<script src=js/sound/NotePlayer.js></script>
<script src=soundbank/Instr.js></script>
<script src=js/IO.js></script>
<script src=js/primitives/VarListPrims.js></script>
<script src=js/primitives/MotionAndPenPrims.js></script>
<script src=js/primitives/LooksPrims.js></script>
<script src=js/primitives/SensingPrims.js></script>
<script src=js/primitives/SoundPrims.js></script>
<script src=js/primitives/Primitives.js></script>
<script src=js/Interpreter.js></script>
<script src=js/Runtime.js></script>
<script src=js/Scratch.js></script>
<script>
$(document).ready(function() {
var project_id = location.hash && parseInt(location.hash.substr(1)) || 10000160;
var scratch = new Scratch(project_id);
});
</script>
<script>
var flashLog = null;
var project_id = location.hash && parseInt(location.hash.substr(1)) || 10000160;
$(function() {
// The flashvars tell flash about the project data (and autostart=true)
var flashvars = {
@ -133,3 +115,26 @@
</div>
<textarea id=flash-debug readonly></textarea>
</div>
<script src=js/util/Timer.js></script>
<script src=js/util/OffsetBuffer.js></script>
<script src=js/util/Color.js></script>
<script src=js/util/Rectangle.js></script>
<script src=js/Sprite.js></script>
<script src=js/Reporter.js></script>
<script src=js/Stage.js></script>
<script src=js/sound/WAVFile.js></script>
<script src=js/sound/SoundDecoder.js></script>
<script src=js/sound/SoundBank.js></script>
<script src=js/sound/NotePlayer.js></script>
<script src=soundbank/Instr.js></script>
<script src=js/IO.js></script>
<script src=js/primitives/VarListPrims.js></script>
<script src=js/primitives/MotionAndPenPrims.js></script>
<script src=js/primitives/LooksPrims.js></script>
<script src=js/primitives/SensingPrims.js></script>
<script src=js/primitives/SoundPrims.js></script>
<script src=js/primitives/Primitives.js></script>
<script src=js/Interpreter.js></script>
<script src=js/Runtime.js></script>
<script src=js/Scratch.js></script>

37
config/karma.conf.js Normal file
View file

@ -0,0 +1,37 @@
module.exports = function(config){
config.set({
basePath : '../',
files : [
'test/artifacts/**/*.js',
'test/lib/**/*.js',
'test/unit/**/*.js',
'js/sound/SoundDecoder.js',
'js/sound/**/*.js',
'js/util/**/*.js',
'js/**/*.js',
'node_modules/jasmine-jquery/lib/jasmine-jquery.js',
'node_modules/underscore/underscore.js'
],
exclude : [
],
preprocessors: {
'*.html': ['html2js']
},
autoWatch : true,
frameworks: ['jasmine'],
browsers : ['Chrome'],
plugins : [
'karma-jasmine',
'jasmine-jquery',
'karma-html2js-preprocessor',
'karma-chrome-launcher',
'karma-firefox-launcher'
]
})}

BIN
img/ask-bottom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

BIN
img/ask-button.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View file

@ -12,31 +12,12 @@
<script src=//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js></script>
<script src=js/util/Timer.js></script>
<script src=js/util/OffsetBuffer.js></script>
<script src=js/util/Color.js></script>
<script src=js/util/Rectangle.js></script>
<script src=js/Sprite.js></script>
<script src=js/Reporter.js></script>
<script src=js/Stage.js></script>
<script src=js/sound/WAVFile.js></script>
<script src=js/sound/SoundDecoder.js></script>
<script src=js/sound/SoundBank.js></script>
<script src=js/sound/NotePlayer.js></script>
<script src=soundbank/Instr.js></script>
<script src=js/IO.js></script>
<script src=js/primitives/VarListPrims.js></script>
<script src=js/primitives/MotionAndPenPrims.js></script>
<script src=js/primitives/LooksPrims.js></script>
<script src=js/primitives/SensingPrims.js></script>
<script src=js/primitives/SoundPrims.js></script>
<script src=js/primitives/Primitives.js></script>
<script src=js/Interpreter.js></script>
<script src=js/Runtime.js></script>
<script src=js/Scratch.js></script>
<script>
<script type="text/javascript">
$(document).ready(function() {
var project_id = location.hash && parseInt(location.hash.substr(1)) || 10000160;
var scratch = new Scratch(project_id);
});
</script>
<div id=player-container>
@ -68,3 +49,27 @@
<h1>Scratch HTML5 player</h1>
<p>The Scratch HTML5 player is still in development. Feedback is welcome! Please report any bugs (or differences from the Flash player) <a href=https://github.com/LLK/scratch-html5>on Github</a>.</p>
<script src=js/util/Timer.js></script>
<script src=js/util/OffsetBuffer.js></script>
<script src=js/util/Color.js></script>
<script src=js/util/Rectangle.js></script>
<script src=js/Sprite.js></script>
<script src=js/Reporter.js></script>
<script src=js/Stage.js></script>
<script src=js/sound/WAVFile.js></script>
<script src=js/sound/SoundDecoder.js></script>
<script src=js/sound/SoundBank.js></script>
<script src=js/sound/NotePlayer.js></script>
<script src=soundbank/Instr.js></script>
<script src=js/IO.js></script>
<script src=js/primitives/VarListPrims.js></script>
<script src=js/primitives/MotionAndPenPrims.js></script>
<script src=js/primitives/LooksPrims.js></script>
<script src=js/primitives/SensingPrims.js></script>
<script src=js/primitives/SoundPrims.js></script>
<script src=js/primitives/Primitives.js></script>
<script src=js/Interpreter.js></script>
<script src=js/Runtime.js></script>
<!-- <script src=js/Scratch.js></script> -->
<script type="text/JavaScript" src="js/Scratch.js"></script>

View file

@ -40,6 +40,7 @@ var Thread = function(block, target) {
this.tmp = null; // used for thread operations like Timer
this.tmpObj = []; // used for Sprite operations like glide
this.firstTime = true;
this.paused = false;
};
var Interpreter = function() {
@ -135,6 +136,8 @@ Interpreter.prototype.stepActiveThread = function() {
if (b == null) return;
this.yield = false;
while (true) {
if (this.activeThread.paused) return;
++this.opCount;
// Advance the "program counter" to the next block before running the primitive.
// Control flow primitives (e.g. if) may change activeThread.nextBlock.
@ -247,6 +250,10 @@ Interpreter.prototype.targetSprite = function() {
return this.activeThread.target;
};
Interpreter.prototype.targetStage = function() {
return runtime.stage;
};
// Timer
Interpreter.prototype.startTimer = function(secs) {
var waitMSecs = 1000 * secs;

View file

@ -19,7 +19,6 @@ var Reporter = function(data) {
this.cmd = data.cmd;
this.color = data.color;
this.isDiscrete = data.isDiscrete;
this.label = data.label;
this.mode = data.mode;
this.param = data.param;
this.sliderMin = data.sliderMin;
@ -30,11 +29,24 @@ var Reporter = function(data) {
this.y = data.y;
this.z = io.getCount();
//Set the label after hydrating the cmd and param variables
this.label = this.determineReporterLabel();
this.el = null; // jQuery Element for the outer box
this.valueEl = null; // jQ element containing the reporter value
this.slider = null; // slider jQ element
};
Reporter.prototype.determineReporterLabel = function() {
if (this.target === 'Stage' && this.cmd === "getVar:") {
return this.param;
} else if (this.target === 'Stage' && this.param === null) {
return this.cmd;
} else {
return this.target + ': ' + this.param;
}
}
Reporter.prototype.attach = function(scene) {
switch (this.mode) {
case 1: // Normal
@ -77,6 +89,9 @@ Reporter.prototype.update = function() {
var newValue = '';
var target = runtime.spriteNamed(this.target);
switch (this.cmd) {
case 'answer':
newValue = target.askAnswer;
break;
case 'getVar:':
newValue = target.variables[this.param];
break;

View file

@ -88,19 +88,14 @@ Runtime.prototype.stopAll = function() {
interp.activeThread = new Thread(null);
interp.threads = [];
stopAllSounds();
// Hide reporters
// Hide sprite bubbles, resetFilters and doAsk prompts
for (var s = 0; s < runtime.sprites.length; s++) {
if (runtime.sprites[s].hideBubble) {
runtime.sprites[s].hideBubble();
}
if (runtime.sprites[s].hideBubble) runtime.sprites[s].hideBubble();
if (runtime.sprites[s].resetFilters) runtime.sprites[s].resetFilters();
if (runtime.sprites[s].hideAsk) runtime.sprites[s].hideAsk();
}
// Reset graphic effects
runtime.stage.resetFilters();
for (var s = 0; s < runtime.sprites.length; s++) {
if (runtime.sprites[s].resetFilters) {
runtime.sprites[s].resetFilters();
}
}
};
// Step method for execution - called every 33 milliseconds

View file

@ -23,7 +23,7 @@
'use strict';
var runtime, interp, io, iosAudioActive = false;
$(function() {
function Scratch(project_id) {
runtime = new Runtime();
runtime.init();
@ -151,4 +151,4 @@ $(function() {
// Load the requested project and go!
io = new IO();
io.loadProject(project_id);
});
};

View file

@ -73,6 +73,12 @@ var Sprite = function(data) {
this.talkBubbleStyler = null;
this.talkBubbleOn = false;
// HTML element for the ask bubbles
this.askInput = null;
this.askInputField = null;
this.askInputButton = null;
this.askInputOn = false;
// Internal variables used for rendering meshes.
this.textures = [];
this.materials = [];
@ -142,14 +148,27 @@ Sprite.prototype.attach = function(scene) {
this.updateVisible();
this.updateTransform();
if (! this.isStage) {
this.talkBubble = $('<div class="bubble-container"></div>');
this.talkBubble.css('display', 'none');
this.talkBubbleBox = $('<div class="bubble"></div>');
this.talkBubbleStyler = $('<div class="bubble-say"></div>');
this.talkBubble.append(this.talkBubbleBox);
this.talkBubble.append(this.talkBubbleStyler);
}
this.askInput = $('<div class="ask-container"></div>');
this.askInput.css('display', 'none');
this.askInputField = $('<div class="ask-field"></div>');
this.askInputTextField = $('<input type="text" class="ask-text-field"></input>');
this.askInputField.append(this.askInputTextField);
this.askInputButton = $('<div class="ask-button"></div>');
this.bindDoAskButton();
this.askInput.append(this.askInputField);
this.askInput.append(this.askInputButton);
runtime.scene.append(this.talkBubble);
runtime.scene.append(this.askInput);
};
// Load sounds from the server and buffer them
@ -261,13 +280,13 @@ Sprite.prototype.setVisible = function(v) {
Sprite.prototype.updateLayer = function() {
$(this.mesh).css('z-index', this.z);
if (this.talkBubble) this.talkBubble.css('z-index', this.z);
if (this.askInput) this.askInput.css('z-index', this.z);
};
Sprite.prototype.updateVisible = function() {
$(this.mesh).css('display', this.visible ? 'inline' : 'none');
if (this.talkBubbleOn) {
this.talkBubble.css('display', this.visible ? 'inline-block' : 'none');
}
if (this.talkBubbleOn) this.talkBubble.css('display', this.visible ? 'inline-block' : 'none');
if (this.askInputOn) this.askInput.css('display', this.visible ? 'inline-block' : 'none');
};
Sprite.prototype.updateTransform = function() {
@ -347,13 +366,21 @@ Sprite.prototype.showBubble = function(text, type) {
this.talkBubble.css('left', xy[0] + 'px');
this.talkBubble.css('top', xy[1] + 'px');
this.talkBubbleBox.removeClass('say-think-border');
this.talkBubbleBox.removeClass('ask-border');
this.talkBubbleStyler.removeClass('bubble-say');
this.talkBubbleStyler.removeClass('bubble-think');
this.talkBubbleStyler.removeClass('bubble-ask');
if (type == 'say') {
this.talkBubbleBox.addClass('say-think-border');
this.talkBubbleStyler.addClass('bubble-say');
} else if (type == 'think') {
this.talkBubbleBox.addClass('say-think-border');
this.talkBubbleStyler.addClass('bubble-think');
} else if (type == 'doAsk') {
this.talkBubbleBox.addClass('ask-border');
this.talkBubbleStyler.addClass('bubble-ask');
}
if (this.visible) {
@ -367,6 +394,40 @@ Sprite.prototype.hideBubble = function() {
this.talkBubble.css('display', 'none');
};
Sprite.prototype.showAsk = function() {
this.askInputOn = true;
this.askInput.css('z-index', this.z);
this.askInput.css('left', '15px');
this.askInput.css('right', '15px');
this.askInput.css('bottom', '7px');
this.askInput.css('height', '25px');
if (this.visible) {
this.askInput.css('display', 'inline-block');
this.askInputTextField.focus();
}
};
Sprite.prototype.hideAsk = function() {
this.askInputOn = false;
this.askInputTextField.val('');
this.askInput.css('display', 'none');
};
Sprite.prototype.bindDoAskButton = function() {
var self = this;
this.askInputButton.on("keypress click", function(e){
var eType = e.type;
if (eType === 'click' || (eType === 'keypress' && e.which === 13)) {
var stage = interp.targetStage();
stage.askAnswer = $(self.askInputTextField).val();
self.hideBubble();
self.hideAsk();
interp.activeThread.paused = false;
}
});
};
Sprite.prototype.setXY = function(x, y) {
this.scratchX = x;
this.scratchY = y;

View file

@ -33,6 +33,8 @@ var Stage = function(data) {
this.lineCanvas.width = 480;
this.lineCanvas.height = 360;
this.lineCache = this.lineCanvas.getContext('2d');
this.isStage = true;
this.askAnswer = ""; //this is a private variable and should be blank
Sprite.call(this, data);
};

View file

@ -172,12 +172,12 @@ LooksPrims.prototype.primClearEffects = function(b) {
var showBubble = function(b, type) {
var s = interp.targetSprite();
if (s != null) s.showBubble(interp.arg(b, 0), type);
if (s !== null) s.showBubble(interp.arg(b, 0), type);
};
var showBubbleAndWait = function(b, type) {
var s = interp.targetSprite();
if (s == null) return;
if (s === null) return;
if (interp.activeThread.firstTime) {
var text = interp.arg(b, 0);
var secs = interp.numarg(b, 1);

View file

@ -22,6 +22,9 @@ SensingPrims.prototype.addPrimsTo = function(primTable) {
primTable['touchingColor:'] = this.primTouchingColor;
primTable['color:sees:'] = this.primColorTouchingColor;
primTable['doAsk'] = this.primDoAsk;
primTable['answer'] = this.primAnswer;
primTable['keyPressed:'] = this.primKeyPressed;
primTable['mousePressed'] = function(b) { return runtime.mouseDown; };
primTable['mouseX'] = function(b) { return runtime.mousePos[0]; };
@ -174,6 +177,21 @@ var stageColorByColorHitTest = function(target, myColor, otherColor) {
return false;
};
SensingPrims.prototype.primDoAsk= function(b) {
showBubble(b, "doAsk");
var s = interp.targetSprite();
if (s !== null) {
interp.activeThread.paused = true;
s.showAsk();
}
};
SensingPrims.prototype.primAnswer = function(b) {
var s = interp.targetStage();
return (s !== null ? s.askAnswer : undefined);
};
SensingPrims.prototype.primKeyPressed = function(b) {
var key = interp.arg(b, 0);
var ch = key.charCodeAt(0);

11
package.json Normal file
View file

@ -0,0 +1,11 @@
{
"name": "scratch-html5",
"description": "HTML 5 based Scratch project player",
"repository": "https://github.com/LLK/scratch-html5",
"devDependencies": {
"karma" : "~0.10",
"jasmine-jquery" : "1.3.3",
"karma-html2js-preprocessor" : "~0.1.0",
"underscore" : "~1.6.0"
}
}

View file

@ -407,7 +407,6 @@ button#trigger-stop:hover {
max-width: 120px;
min-width: 40px;
padding: 6px 11px 6px 11px;
border: 3px solid rgb(160, 160, 160);
border-radius: 10px;
background: #fff;
font-family: sans-serif;
@ -416,6 +415,20 @@ button#trigger-stop:hover {
color: #000;
text-align: center;
}
.bubble.say-think-border {
border: 3px solid rgb(160, 160, 160);
}
.bubble.ask-border, .ask-container {
border: 3px solid rgb(74, 173, 222);
}
.bubble-ask {
position: absolute;
margin-top: -3px;
margin-left: 8px;
width: 44px;
height: 18px;
background: url(img/ask-bottom.png) transparent no-repeat;
}
.bubble-say {
position: absolute;
margin-top: -3px;
@ -432,3 +445,33 @@ button#trigger-stop:hover {
height: 19px;
background: url(img/think-bottom.png) transparent no-repeat;
}
.ask-container {
position: absolute;
display: inline-block;
padding: 5px 0px 0px 5px;
border-radius: 5px;
background: #fff;
font-family: sans-serif;
font-weight: bold;
font-size: 14px;
color: #000;
}
.ask-container .ask-field .ask-text-field {
width: 405px;
height: 16px;
font-family: sans-serif;
font-weight: light;
font-size: 12px;
background: #EAEAEA;
}
.ask-container .ask-button {
position: absolute;
right: 2px;
top: 2px;
width: 25px;
height: 25px;
background: url(img/ask-button.png) transparent no-repeat;
}

9
scripts/test.sh Executable file
View file

@ -0,0 +1,9 @@
#!/bin/bash
BASE_DIR=`dirname $0`
echo ""
echo "Starting Karma Server (http://karma-runner.github.io)"
echo "-------------------------------------------------------------------"
$BASE_DIR/../node_modules/karma/bin/karma start $BASE_DIR/../config/karma.conf.js $*

25
test/artifacts/IOMock.js Normal file
View file

@ -0,0 +1,25 @@
'use strict';
var ioMock = function() {
var args = createArgs(arguments);
function getArgs(argKey) {
return ((argKey in args) ? args[argKey] : null);
}
function createArgs(methodArgs) {
var args = {};
if (methodArgs.length) {
_.each(methodArgs, function(newObject) {
_.each(newObject, function(value, key) {
args[key] = value;
});
});
}
return args;
}
return {
'getCount' : function() { return getArgs('getCount'); }
}
};

View file

@ -0,0 +1,28 @@
'use strict';
var interpreterMock = function() {
var args = createArgs(arguments);
function getArgs(argKey) {
return ((argKey in args) ? args[argKey] : null);
}
function createArgs(methodArgs) {
var args = {};
if (methodArgs.length) {
_.each(methodArgs, function(newObject) {
_.each(newObject, function(value, key) {
args[key] = value;
});
});
}
return args;
}
return {
'targetSprite' : function() { return getArgs('targetSprite'); },
'arg': function(block, index) { return getArgs('arg');},
'activeThread': new threadMock(),
'targetStage': function() { var rtMock = new runtimeMock(); return rtMock.stage}
}
};

View file

@ -0,0 +1,29 @@
'use strict';
var runtimeMock = function() {
var args = createArgs(arguments);
function getArgs(argKey) {
return ((argKey in args) ? args[argKey] : null);
}
function createArgs(methodArgs) {
var args = {};
if (methodArgs.length) {
_.each(methodArgs, function(newObject) {
_.each(newObject, function(value, key) {
args[key] = value;
});
});
}
return args;
}
return {
'sprites' : [
new spriteMock()
],
'stage': new stageMock()
}
};

View file

@ -0,0 +1,27 @@
'use strict';
var spriteMock = function() {
var args = createArgs(arguments);
function getArgs(argKey) {
return ((argKey in args) ? args[argKey] : null);
}
function createArgs(methodArgs) {
var args = {};
if (methodArgs.length) {
_.each(methodArgs, function(newObject) {
_.each(newObject, function(value, key) {
args[key] = value;
});
});
}
return args;
}
return {
'hideBubble' : function() { return getArgs('hideBubble'); },
'hideAsk': function() { return getArgs('hideAsk');},
'resetFilters': function() { return getArgs('resetFilters');}
}
};

View file

@ -0,0 +1,26 @@
'use strict';
var stageMock = function() {
var args = createArgs(arguments);
function getArgs(argKey) {
return ((argKey in args) ? args[argKey] : null);
}
function createArgs(methodArgs) {
var args = {};
if (methodArgs.length) {
_.each(methodArgs, function(newObject) {
_.each(newObject, function(value, key) {
args[key] = value;
});
});
}
return args;
}
return {
'resetFilters' : function() { return getArgs('resetFilters'); },
'askAnswer' : 12
}
};

View file

@ -0,0 +1,10 @@
'use strict';
var targetMock = function() {
return {
'showBubble' : function() {},
'showAsk' : function() {},
'askAnswer' : 22
};
}

View file

@ -0,0 +1,5 @@
'use strict';
var deepCopy = function(object) {
return jQuery.extend(true, {}, object);
}

View file

@ -0,0 +1,25 @@
'use strict';
var threadMock = function() {
var args = createArgs(arguments);
function getArgs(argKey) {
return ((argKey in args) ? args[argKey] : null);
}
function createArgs(methodArgs) {
var args = {};
if (methodArgs.length) {
_.each(methodArgs, function(newObject) {
_.each(newObject, function(value, key) {
args[key] = value;
});
});
}
return args;
}
return {
'paused' : getArgs('paused')
}
};

View file

@ -0,0 +1,67 @@
var sensingData = {
"objName": "Stage",
"variables": [{
"name": "myAnswer",
"value": 0,
"isPersistent": false
}],
"costumes": [{
"costumeName": "backdrop1",
"baseLayerID": -1,
"baseLayerMD5": "b61b1077b0ea1931abee9dbbfa7903ff.png",
"bitmapResolution": 2,
"rotationCenterX": 480,
"rotationCenterY": 360
}],
"currentCostumeIndex": 0,
"penLayerMD5": "5c81a336fab8be57adc039a8a2b33ca9.png",
"tempoBPM": 60,
"videoAlpha": 0.5,
"children": [{
"objName": "Sprite1",
"variables": [{
"name": "myAnswer2",
"value": 0,
"isPersistent": false
}, {
"name": "answer",
"value": 0,
"isPersistent": false
}],
"scripts": [[42, 40.5, [["whenGreenFlag"], ["doAsk", "What's your name?"]]],
[44.5,
155.5,
[["whenGreenFlag"],
["say:", "Hello!"],
["doIf", ["=", ["timeAndDate", "minute"], "60"], [["say:", ["timestamp"]]]]]]],
"costumes": [{
"costumeName": "costume1",
"baseLayerID": -1,
"baseLayerMD5": "f9a1c175dbe2e5dee472858dd30d16bb.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": {
"projectID": "18926654",
"spriteCount": 1,
"flashVersion": "MAC 12,0,0,70",
"swfVersion": "v396",
"userAgent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10.9; rv:27.0) Gecko\/20100101 Firefox\/27.0",
"videoOn": false,
"scriptCount": 2,
"hasCloudData": false
}
};

View file

@ -0,0 +1,9 @@
'use strict';
var io_base = 'proxy.php?resource=internalapi/';
var project_base = io_base + 'project/';
var project_suffix = '/get/';
var asset_base = io_base + 'asset/';
var asset_suffix = '/get/';
var soundbank_base = 'soundbank/';
var spriteLayerCount = 0;

View file

@ -0,0 +1,47 @@
'use Strict;'
var ReporterValues = function() {
return {
'getStageVariables': function() {
return {
'cmd' : "getVar:",
'color' : 15629590,
'isDiscrete' : true,
'mode' : 1,
'param' : "myAnswer",
'sliderMax' : 100,
'sliderMin' : 0,
'target' : "Stage",
'visible' : true,
'x' : 5,
'y' : 5,
};
}
}
};
/*
Additional Reporter examples
cmd : "getVar:"
color : 15629590
isDiscrete : true
mode : 1
param : "myAnswer2"
sliderMax : 100
sliderMin : 0
target : "Sprite1"
visible : true
x : 5
y : 32
cmd : "getVar:"
color : 15629590
isDiscrete : true
mode : 1
param : "answer"
sliderMax : 100
sliderMin : 0
target : "Sprite1"
visible : true
x : 5
y : 59
*/

View file

@ -0,0 +1,117 @@
'use strict';
var project_id = 123456789;
var returnData = {
"objName": "Stage",
"sounds": [{
"soundName": "pop",
"soundID": -1,
"md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"sampleCount": 258,
"rate": 11025,
"format": ""
}],
"costumes": [{
"costumeName": "Scene 1",
"baseLayerID": -1,
"baseLayerMD5": "510da64cf172d53750dffd23fbf73563.png",
"rotationCenterX": 240,
"rotationCenterY": 180,
"spritesHiddenInScene": null
}],
"currentCostumeIndex": 0,
"penLayerMD5": "279467d0d49e152706ed66539b577c00.png",
"tempoBPM": 60,
"children": [{
"objName": "Sprite1",
"scripts": [[283,
151,
[["whenClicked"],
["clearPenTrails"],
["penColor:", 10485886],
["putPenDown"],
["doForever",
[["gotoX:y:", ["randomFrom:to:", -240, 240], ["randomFrom:to:", -180, 180]], ["changePenShadeBy:", 10]]]]]],
"sounds": [{
"soundName": "pop",
"soundID": -1,
"md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"sampleCount": 258,
"rate": 11025,
"format": ""
}],
"costumes": [{
"costumeName": "Costume1",
"baseLayerID": -1,
"baseLayerMD5": "cce61b6e9ad98ea8c8c2e9556a94b7ab.png",
"rotationCenterX": 47,
"rotationCenterY": 55,
"spritesHiddenInScene": null
},
{
"costumeName": "Costume2",
"baseLayerID": -1,
"baseLayerMD5": "51f6fa1871f17de1a21cdfead7aad574.png",
"rotationCenterX": 47,
"rotationCenterY": 55,
"spritesHiddenInScene": null
}],
"currentCostumeIndex": 0,
"scratchX": 120,
"scratchY": -101,
"scale": 1,
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 0,
"visible": true
},
{
"objName": "fish31",
"scripts": [[181, 138, [["whenClicked"], ["nextCostume"]]]],
"sounds": [{
"soundName": "pop",
"soundID": -1,
"md5": "83a9787d4cb6f3b7632b4ddfebf74367.wav",
"sampleCount": 258,
"rate": 11025,
"format": ""
}],
"costumes": [{
"costumeName": "fish3",
"baseLayerID": -1,
"baseLayerMD5": "5ab571cf8c6e6bcf0ee2443b5df17dcb.png",
"rotationCenterX": 90,
"rotationCenterY": 79,
"spritesHiddenInScene": null
},
{
"costumeName": "crab1-a",
"baseLayerID": -1,
"baseLayerMD5": "110bf75ed212eb072acec2fa2c39456d.png",
"rotationCenterX": 92,
"rotationCenterY": 62,
"spritesHiddenInScene": null
},
{
"costumeName": "ballerina-a",
"baseLayerID": -1,
"baseLayerMD5": "4c789664cc6f69d1ef4678ac8b4cb812.png",
"rotationCenterX": 51,
"rotationCenterY": 84,
"spritesHiddenInScene": null
}],
"currentCostumeIndex": 2,
"scratchX": 108,
"scratchY": -28,
"scale": 1,
"direction": 90,
"rotationStyle": "normal",
"isDraggable": false,
"indexInLibrary": 0,
"visible": true
}],
"info": {
}
};

0
test/lib/.git-keep Normal file
View file

View file

@ -0,0 +1,86 @@
/* jasmine specs for Interpreter.js go here */
describe('Interpreter', function() {
var interp;
beforeEach(function() {
interp = Interpreter;
});
describe('Initialized variables', function() {
var initInterp, realThread, realTimer;
beforeEach(function() {
realThread = Thread;
realTimer = Timer;
Thread = threadMock;
Timer = function() {};
initInterp = new interp();
});
afterEach(function() {
Thread = realThread;
Timer = realTimer;
});
describe('Interpreter Variables', function() {
it('should have a primitiveTable collection', function() {
expect(initInterp.primitiveTable).toEqual({});
});
it('should have a variables collection', function() {
expect(initInterp.variables).toEqual({});
});
it('should have a threads array', function() {
expect(initInterp.threads).toEqual([]);
});
it('should have an activeThread variable', function() {
expect(initInterp.activeThread).toEqual(threadMock());
});
it('should have a WorkTime variable', function() {
expect(initInterp.WorkTime).toBe(30);
});
it('should have a currentMSecs variable', function() {
expect(initInterp.currentMSecs).toBe(null);
});
it('should have a timer variable', function() {
expect(initInterp.timer).toEqual({});
});
it('should have a yield variable', function() {
expect(initInterp.yield).toBe(false);
});
it('should have a doRedraw variable', function() {
expect(initInterp.doRedraw).toBe(false);
});
it('should have an opCount variable', function() {
expect(initInterp.opCount).toBe(0);
});
it('should have a debugOps variable', function() {
expect(initInterp.debugOps).toBe(false);
});
it('should have a debugFunc variable', function() {
expect(initInterp.debugFunc).toBe(null);
});
it('should have an opCount2 variable', function() {
expect(initInterp.opCount2).toBe(0);
});
});
});
describe('TargetStage', function() {
it('should return the target.stage object', function() {
runtime = new runtimeMock();
expect(interp.prototype.targetStage()).toEqual(runtime.stage);
});
});
});

43
test/unit/ioSpec.js Normal file
View file

@ -0,0 +1,43 @@
'use strict';
/* jasmine specs for IO.js go here */
describe('IO', function(){
var io;
beforeEach(function() {
io = new IO();
});
it('should have "null" data', function() {
expect(io.data).toBe(null);
});
it('should have a base', function() {
expect(io.base).toBe(io_base);
});
it('should have a project_base', function() {
expect(io.project_base).toBe(project_base);
});
it('should have a project_suffix', function() {
expect(io.project_suffix).toBe(project_suffix);
});
it('should have an asset_base', function() {
expect(io.asset_base).toBe(asset_base);
});
it('should have an asset_suffix', function() {
expect(io.asset_suffix).toBe(asset_suffix);
});
it('should have an soundbank_base', function() {
expect(io.soundbank_base).toBe(soundbank_base);
});
it('should have a spriteLayerCount', function() {
expect(io.spriteLayerCount).toBe(spriteLayerCount);
});
});

View file

@ -0,0 +1,51 @@
/* jasmine specs for primitives/LooksPrims.js go here */
describe('LooksPrims', function() {
var looksPrims, targetSpriteMock;
beforeEach(function() {
looksPrims = LooksPrims;
targetSpriteMock = targetMock();
});
describe('showBubble for say', function(){
var sayBlock;
beforeEach(function() {
sayBlock = {'args': ['what to say']};
interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': sayBlock});
});
it('should call the showBubble method on the targetedSprite', function() {
spyOn(targetSpriteMock, "showBubble");
showBubble(sayBlock, "say");
expect(targetSpriteMock.showBubble).toHaveBeenCalledWith({args:['what to say']}, 'say');
});
});
describe('showBubble for think', function(){
var thinkBlock;
beforeEach(function() {
thinkBlock = {'args': ['what to think']};
interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': thinkBlock});
});
it('should call the showBubble method on the targetedSprite', function() {
spyOn(targetSpriteMock, "showBubble");
showBubble(thinkBlock, "think");
expect(targetSpriteMock.showBubble).toHaveBeenCalledWith({args:['what to think']}, 'think');
});
});
describe('showBubble for ask', function(){
var askBlock;
beforeEach(function() {
askBlock = {'args': ['what to ask']};
interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': askBlock});
});
it('should call the showBubble method on the targetedSprite', function() {
spyOn(targetSpriteMock, "showBubble");
showBubble(askBlock, "ask");
expect(targetSpriteMock.showBubble).toHaveBeenCalledWith({args:['what to ask']}, 'ask');
});
});
});

108
test/unit/reporterSpec.js Normal file
View file

@ -0,0 +1,108 @@
/* jasmine specs for Reporter.js go here */
describe('Reporter', function() {
var reporter, reporterValues;
beforeEach(function() {
reporter = Reporter;
reporterValues = new ReporterValues();
});
describe('Initialized variables', function() {
var initReporter;
beforeEach(function() {
io = new ioMock({'getCount': 4});
initReporter = new reporter(reporterValues.getStageVariables());
});
describe('Reporter Variables', function() {
it('should have a cmd variable', function() {
expect(initReporter.cmd).toBe('getVar:');
});
it('should have a color variable', function() {
expect(initReporter.color).toBe(15629590);
});
it('should have a isDiscrete variable', function() {
expect(initReporter.isDiscrete).toBe(true);
});
it('should have a mode variable', function() {
expect(initReporter.mode).toBe(1);
});
it('should have a param variable', function() {
expect(initReporter.param).toBe('myAnswer');
});
it('should have a sliderMax variable', function() {
expect(initReporter.sliderMax).toBe(100);
});
it('should have a sliderMin variable', function() {
expect(initReporter.sliderMin).toBe(0);
});
it('should have a target variable', function() {
expect(initReporter.target).toBe('Stage');
});
it('should have a visible variable', function() {
expect(initReporter.visible).toBe(true);
});
it('should have a x variable', function() {
expect(initReporter.x).toBe(5);
});
it('should have a y variable', function() {
expect(initReporter.y).toBe(5);
});
it('should have a z variable', function() {
expect(initReporter.z).toBe(4);
});
it('should have a label variable', function() {
expect(initReporter.label).toBe('myAnswer');
});
it('should have an el variable', function() {
expect(initReporter.el).toBe(null);
});
it('should have an valueEl variable', function() {
expect(initReporter.valueEl).toBe(null);
});
it('should have an slider variable', function() {
expect(initReporter.slider).toBe(null);
});
});
});
describe('determineReporterLabel', function() {
it('should return a stage variable', function() {
reporter.prototype.target = "Stage";
reporter.prototype.param = "myAnswer";
reporter.prototype.cmd = "getVar:";
expect(reporter.prototype.determineReporterLabel()).toBe('myAnswer');
});
it('should return a sprite variable', function() {
reporter.prototype.target = "Sprite 1";
reporter.prototype.param = "localAnswer";
reporter.prototype.cmd = "getVar:";
expect(reporter.prototype.determineReporterLabel()).toBe('Sprite 1: localAnswer');
});
it('should return a stage answer variable', function() {
reporter.prototype.target = "Stage";
reporter.prototype.param = null;
reporter.prototype.cmd = "answer";
expect(reporter.prototype.determineReporterLabel()).toBe('answer');
});
});
});

113
test/unit/runTimeSpec.js Normal file
View file

@ -0,0 +1,113 @@
/* jasmine specs for Runtime.js go here */
describe('Runtime', function() {
var runtimeObj;
beforeEach(function() {
runtimeObj = Runtime;
});
describe('Initialized variables', function() {
var initRuntime, lineCanvas;
beforeEach(function() {
initRuntime = new runtimeObj();
});
describe('Runtime Variables', function() {
it('should have a scene variable', function() {
expect(initRuntime.scene).toBe(null);
});
it('should have a sprites array', function() {
expect(initRuntime.sprites).toEqual([]);
});
it('should have a reporters array', function() {
expect(initRuntime.reporters).toEqual([]);
});
it('should have a keysDown array', function() {
expect(initRuntime.keysDown).toEqual([]);
});
it('should have a mouseDown variable', function() {
expect(initRuntime.mouseDown).toBe(false);
});
it('should have a mousePos array', function() {
expect(initRuntime.mousePos).toEqual([0,0]);
});
it('should have an audioContext variable', function() {
expect(initRuntime.audioContext).toBe(null);
});
it('should have an audoGain variable', function() {
expect(initRuntime.audioGain).toBe(null);
});
it('should have an audioPlaying array', function() {
expect(initRuntime.audioPlaying).toEqual([]);
});
it('should have a notesPlaying array', function() {
expect(initRuntime.notesPlaying).toEqual([]);
});
it('should have a projectLoaded variable', function() {
expect(initRuntime.projectLoaded).toBe(false);
});
});
});
describe('Stop All', function() {
var realThread;
beforeEach(function() {
runtime = new runtimeMock
spyOn(window, "stopAllSounds");
spyOn(runtime.stage, "resetFilters");
spyOn(runtime.sprites[0], "hideBubble");
spyOn(runtime.sprites[0], "resetFilters");
spyOn(runtime.sprites[0], "hideAsk");
realThread = Thread;
Thread = threadMock;
interp = new interpreterMock();
});
afterEach(function() {
Thread = realThread;
});
it('should call a new Thread Object', function() {
runtimeObj.prototype.stopAll();
expect(interp.activeThread).toEqual(new threadMock());
});
it('should intitialize an empty threads array', function() {
runtimeObj.prototype.stopAll();
expect(interp.threads).toEqual([]);
});
it('should call stopAllSounds', function() {
runtimeObj.prototype.stopAll();
expect(window.stopAllSounds).toHaveBeenCalled();
});
it('should call sprites.hideBubble', function() {
runtimeObj.prototype.stopAll();
expect(runtime.sprites[0].hideBubble).toHaveBeenCalled();
});
it('should call sprites.resetFilters', function() {
runtimeObj.prototype.stopAll();
expect(runtime.sprites[0].resetFilters).toHaveBeenCalled();
});
it('should call sprites.hideAsk', function() {
runtimeObj.prototype.stopAll();
expect(runtime.sprites[0].hideAsk).toHaveBeenCalled();
});
});
});

66
test/unit/scratchSpec.js Normal file
View file

@ -0,0 +1,66 @@
/* jasmine specs for Scratch.js go here */
describe('Scratch', function() {
var scratch;
beforeEach(function() {
spyOn(IO.prototype, "loadProject");
spyOn(Runtime.prototype, "init");
spyOn(Interpreter.prototype, "initPrims");
scratch = Scratch;
});
describe('Scratch - Load Project', function(){
beforeEach(function() {
scratch(project_id);
});
it('should call the IO loadProject Method', function() {
expect(IO.prototype.loadProject).toHaveBeenCalled();
});
it('should call the Runtime init method', function() {
expect(Runtime.prototype.init).toHaveBeenCalled();
});
it('should call the Interpreter initPrims method', function() {
expect(Interpreter.prototype.initPrims).toHaveBeenCalled();
});
});
describe('Scratch - Click Green Flag', function(){
beforeEach(function() {
setFixtures('<button id=trigger-green-flag tabindex=2></button><div id="overlay"></div>');
scratch(project_id);
});
it('should not click on the green flag if the project is loading', function() {
runtime.projectLoaded = false;
spyOn(runtime, 'greenFlag');
$('#trigger-green-flag').click();
expect(runtime.greenFlag).not.toHaveBeenCalled();
expect($('#overlay').css('display')).toBe('block');
});
it('should click on the green flag if the project is loaded', function() {
runtime.projectLoaded = true;
spyOn(runtime, 'greenFlag');
$('#trigger-green-flag').click();
expect(runtime.greenFlag).toHaveBeenCalled();
expect($('#overlay').css('display')).toBe('none');
});
});
describe('Scratch - Click Stop', function(){
beforeEach(function() {
setFixtures('<button id=trigger-stop tabindex=3></button>');
scratch(project_id);
});
it('should not click on the green flag if the project is loading', function() {
spyOn(runtime, 'stopAll');
$('#trigger-stop').click();
expect(runtime.stopAll).toHaveBeenCalled();
});
});
});

View file

@ -0,0 +1,112 @@
/* jasmine specs for primitives/SensingPrims.js go here */
describe('SensingPrims', function() {
var sensingPrims;
beforeEach(function() {
sensingPrims = SensingPrims;
realDate = Date;
});
afterEach(function () {
Date = realDate;
});
describe('primTimestamp', function(){
beforeEach(function() {
/* MonkeyPatching the built-in Javascript Date */
var epochDate = new Date(2000, 0, 1);
var nowDate = new Date(2014, 5, 16);
Date = function () {
return (arguments.length ? epochDate : nowDate);
};
});
it('should return the days since 2000', function() {
expect(sensingPrims.prototype.primTimestamp()).toEqual(5280.25);
});
});
describe('primTimeDate', function(){
beforeEach(function() {
/* MonkeyPatching the built-in Javascript Date */
Date = function () {
return {
'getFullYear' : function() { return 2014;},
'getMonth' : function() { return 4;},
'getDate' : function() { return 16;},
'getDay' : function() { return 4;},
'getHours' : function() { return 9;},
'getMinutes' : function() { return 18;},
'getSeconds' : function() { return 36;},
'getTime' : function() {}
};
};
});
it('should return the year', function() {
var block = {'args' : ['year']};
expect(sensingPrims.prototype.primTimeDate(block)).toEqual(2014);
});
it('should return the month of the year', function() {
var block = {'args' : ['month']};
expect(sensingPrims.prototype.primTimeDate(block)).toEqual(5);
});
it('should return the day of the week', function() {
var block = {'args' : ['day of week']};
expect(sensingPrims.prototype.primTimeDate(block)).toEqual(5);
});
it('should return the hour of the day', function() {
var block = {'args' : ['hour']};
expect(sensingPrims.prototype.primTimeDate(block)).toEqual(9);
});
it('should return the minute of the hour', function() {
var block = {'args' : ['minute']};
expect(sensingPrims.prototype.primTimeDate(block)).toEqual(18);
});
it('should return the second of the minute', function() {
var block = {'args' : ['second']};
expect(sensingPrims.prototype.primTimeDate(block)).toEqual(36);
});
it('should return the 0 on year', function() {
var block = {'args' : ['anythingElse']};
expect(sensingPrims.prototype.primTimeDate(block)).toEqual(0);
});
});
describe('primAnswer', function(){
beforeEach(function() {
interp = interpreterMock({'targetSprite': new targetMock()});
});
it('should return the answer variable from the targetedSprite', function() {
expect(sensingPrims.prototype.primAnswer()).toBe(12);
});
});
describe('primDoAsk', function(){
var askBlock, targetSpriteMock;
beforeEach(function() {
targetSpriteMock = targetMock();
askBlock = {'args': 'what to ask'};
interp = interpreterMock({'targetSprite': targetSpriteMock}, {'arg': askBlock});
});
it('should call the showBubble method on the targetedSprite', function() {
spyOn(window, "showBubble");
spyOn(targetSpriteMock, "showAsk");
sensingPrims.prototype.primDoAsk(askBlock);
expect(window.showBubble).toHaveBeenCalledWith({args:'what to ask'}, 'doAsk');
expect(targetSpriteMock.showAsk).toHaveBeenCalled;
expect(interp.activeThread.paused).toBe(true);
});
});
});

390
test/unit/spriteSpec.js Normal file
View file

@ -0,0 +1,390 @@
/* jasmine specs for Sprite.js go here */
describe('Sprite', function() {
var sprite;
beforeEach(function() {
sprite = Sprite;
});
describe('Initialized variables', function() {
var initSprite;
beforeEach(function() {
var spriteObject = sensingData.children[0];
initSprite = new sprite(spriteObject);
});
describe('Sprite Variables', function() {
it('should have a visible variable', function() {
expect(initSprite.visible).toBe(true);
});
});
describe('Pen Variables', function() {
it('should have a penIsDown variable', function() {
expect(initSprite.penIsDown).toBe(false);
});
it('should have a penWidth variable', function() {
expect(initSprite.penWidth).toBe(1);
});
it('should have a penHue variable', function() {
expect(initSprite.penHue).toBe(120);
});
it('should have a penShade variable', function() {
expect(initSprite.penShade).toBe(50);
});
it('should have a penColorCache variable', function() {
expect(initSprite.penColorCache).toBe(0x0000FF);
});
});
describe('Ask Bubble', function() {
it('should have an askInput variable', function() {
expect(initSprite.askInput).toBe(null);
});
it('should have an askInputBox variable', function() {
expect(initSprite.askInputField).toBe(null);
});
it('should have an askInputStyler variable', function() {
expect(initSprite.askInputButton).toBe(null);
});
it('should have an askInputOn variable', function() {
expect(initSprite.askInputOn).toBe(false);
});
});
})
describe('showBubble', function() {
var spriteProto;
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
spriteProto.visible = true;
setFixtures('<div class="bubble-container"></div>');
spriteProto.talkBubble = $('.bubble-container');
spriteProto.talkBubble.css('display', 'none');
spriteProto.talkBubbleBox = $('<div class="bubble"></div>');
spriteProto.talkBubbleStyler = $('<div class="bubble-say"></div>');
spriteProto.talkBubble.append(spriteProto.talkBubbleBox);
spriteProto.talkBubble.append(spriteProto.talkBubbleStyler);
});
describe('Say', function(){
it('should call the showBubble method on the Sprite', function() {
var text = "What to say";
spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);;
spriteProto.showBubble(text, "say");
expect($('.bubble').html()).toBe(text);
expect($('.bubble-say').hasClass('bubble-say')).toBe(true);
expect($('.bubble').hasClass('say-think-border')).toBe(true);
expect($('.bubble-container').css('display')).toBe('inline-block');
});
});
describe('Think', function(){
it('should call the showBubble method on the Sprite', function() {
var text = "What to think";
spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);;
spriteProto.showBubble(text, "think");
expect($('.bubble').html()).toBe(text);
expect($('.bubble-think').hasClass('bubble-think')).toBe(true);
expect($('.bubble').hasClass('say-think-border')).toBe(true);
expect($('.bubble-container').css('display')).toBe('inline-block');
});
});
describe('Ask', function(){
it('should call the showBubble method on the Sprite', function() {
var text = "What to Ask";
spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);;
spriteProto.showBubble(text, "doAsk");
expect($('.bubble').html()).toBe(text);
expect($('.bubble-ask').hasClass('bubble-ask')).toBe(true);
expect($('.bubble').hasClass('ask-border')).toBe(true);
expect($('.bubble-container').css('display')).toBe('inline-block');
});
});
describe('Any Bubble with visible false', function(){
it('should call the showBubble method on the Sprite and not display it', function() {
spriteProto.visible = false;
var text = "What to Ask";
spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);;
spriteProto.showBubble(text, "doAsk");
expect($('.bubble').html()).toBe(text);
expect($('.bubble-ask').hasClass('bubble-ask')).toBe(true);
expect($('.bubble').hasClass('ask-border')).toBe(true);
expect($('.bubble-container').css('display')).toBe('none');
});
});
});
describe('hideBubble', function() {
var spriteProto;
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
setFixtures('<div class="bubble-container"></div>');
spriteProto.talkBubble = $('.bubble-container');
spriteProto.talkBubble.css('display', 'inline');
});
it('should hide the bubble', function() {
spriteProto.hideBubble();
expect($('.bubble-container').css('display')).toBe('none');
expect(spriteProto.talkBubbleOn).toBe(false);
});
});
describe('showAsk', function() {
var spriteProto;
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
spriteProto.visible = true;
spriteProto.z = 22;
setFixtures('<div class="ask-container"></div>');
spriteProto.askInput= $('.ask-container');
spriteProto.askInput.css('display','none');
spriteProto.askInput.css('position','relative');
spriteProto.askInputField = $('<div class="ask-input"></div>');
spriteProto.askInputTextField = $('<input type="text" class="ask-text-field"></input>');
spriteProto.askInputField.append(spriteProto.askInputTextField);
spriteProto.askInputButton = $('<div class="ask-button"></div>');
spriteProto.askInput.append(spriteProto.askInputField);
spriteProto.askInput.append(spriteProto.askInputButton);
});
it('should show the ask input if visible is true', function() {
spriteProto.showAsk();
expect($('.ask-container').css('display')).toBe('inline-block');
expect($('.ask-container').css('z-index')).toBe('22');
expect($('.ask-container').css('left')).toBe('15px');
expect($('.ask-container').css('right')).toBe('15px');
expect($('.ask-container').css('bottom')).toBe('7px');
expect($('.ask-container').css('height')).toBe('25px');
expect($('.ask-container').css('height')).toBe('25px');
expect($('.ask-text-field').is(':focus')).toBe(true);
expect(spriteProto.askInputOn).toBe(true);
});
it('should not show the ask input if visible is false', function() {
spriteProto.visible = false;
spriteProto.showAsk();
expect($('.ask-container').css('display')).toBe('none');
expect($('.ask-text-field').is(':focus')).toBe(false);
});
});
describe('hideAsk', function() {
var spriteProto;
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
setFixtures('<div class="ask-container"></div>');
spriteProto.askInput = $('.ask-container');
spriteProto.askInputTextField = $('<input type="text" class="ask-text-field"></input>');
spriteProto.askInputTextField.val("Delete Me");
spriteProto.askInput.css('display', 'inline');
});
it('should hide the ask input', function() {
spriteProto.hideAsk();
expect($('.ask-container').css('display')).toBe('none');
expect(spriteProto.askInputOn).toBe(false);
expect(spriteProto.askInputTextField.val()).toBe('');
});
});
describe('bindAsk', function() {
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
spriteProto.askInputTextField = $('<input type="text" class="ask-text-field"></input>');
spriteProto.askInputButton = $('<div class="ask-button"></div>');
spyOn(spriteProto, "hideBubble");
spyOn(spriteProto, "hideAsk");
});
it('should bind to the askInputButton and handle a click', function() {
interp = new interpreterMock();
spyOn(interp, "targetStage").andCallThrough();
$(spriteProto.askInputTextField).val('Hellow World');
spriteProto.bindDoAskButton();
$(spriteProto.askInputButton).click();
expect(interp.targetStage).toHaveBeenCalled();
});
it('should bind to the askInputButton and handle a enter/return', function() {
interp = new interpreterMock();
spyOn(interp, "targetStage").andCallThrough();
spriteProto.bindDoAskButton();
var e = $.Event( "keypress", { which: 13 } );
$(spriteProto.askInputButton).trigger(e);
expect(interp.targetStage).toHaveBeenCalled();
});
it('should call hideBubble', function() {
spriteProto.bindDoAskButton();
$(spriteProto.askInputButton).click();
expect(spriteProto.hideBubble).toHaveBeenCalled();
expect(spriteProto.hideAsk).toHaveBeenCalled();
});
it('should call hideAsk', function() {
spriteProto.bindDoAskButton();
$(spriteProto.askInputButton).click();
expect(spriteProto.hideAsk).toHaveBeenCalled();
});
it('should have interp.activeThread.paused be false', function() {
interp = new interpreterMock();
spriteProto.bindDoAskButton();
$(spriteProto.askInputButton).click();
expect(interp.activeThread.paused).toBe(false);
});
});
describe('updateLayer', function() {
var spriteProto;
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
setFixtures('<img class="mesh"></img><div class="bubble-container"></div><div class="ask-container"></div>');
spriteProto.talkBubble = $('.bubble-container');
spriteProto.talkBubble.css('position', 'relative');
spriteProto.askInput = $('.ask-container');
spriteProto.askInput.css('position', 'relative');
spriteProto.mesh = $('.mesh');
spriteProto.mesh.css('position', 'relative');
spriteProto.z = 22;
});
it('should update the mesh z-index', function() {
expect($('.mesh').css('z-index')).toBe('auto');
spriteProto.updateLayer();
expect($('.mesh').css('z-index')).toBe('22');
});
it('should update the talkBubble z-index', function() {
expect($('.bubble-container').css('z-index')).toBe('auto');
spriteProto.updateLayer();
expect($('.bubble-container').css('z-index')).toBe('22');
});
it('should update the askInput z-index', function() {
expect($('.ask-container').css('z-index')).toBe('auto');
spriteProto.updateLayer();
expect($('.ask-container').css('z-index')).toBe('22');
});
});
describe('updateVisible', function() {
var spriteProto;
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
setFixtures('<img class="mesh"></img><div class="bubble-container"></div><div class="ask-container"></div>');
spriteProto.talkBubble = $('.bubble-container');
spriteProto.talkBubble.css('display', 'none');
spriteProto.askInput = $('.ask-container');
spriteProto.askInput.css('display', 'none');
spriteProto.mesh = $('.mesh');
spriteProto.mesh.css('display', 'none');
});
describe('mesh', function() {
it('should update the mesh display on false', function() {
expect($('.mesh').css('display')).toBe('none');
spriteProto.visible = false;
spriteProto.updateVisible();
expect($('.mesh').css('display')).toBe('none');
});
it('should update the mesh display on true', function() {
expect($('.mesh').css('display')).toBe('none');
spriteProto.visible = true;
spriteProto.updateVisible();
expect($('.mesh').css('display')).toBe('inline');
});
});
describe('talkBubble', function() {
it('should update the talkBubble on talkBubble true and visible true', function() {
expect($('.bubble-container').css('display')).toBe('none');
spriteProto.talkBubbleOn = true;
spriteProto.visible = true;
spriteProto.updateVisible();
expect($('.bubble-container').css('display')).toBe('inline-block');
});
it('should update the talkBubble on talkBubble false and visible true', function() {
expect($('.bubble-container').css('display')).toBe('none');
spriteProto.talkBubbleOn = false;
spriteProto.visible = true;
spriteProto.updateVisible();
expect($('.bubble-container').css('display')).toBe('none');
});
it('should update the talkBubble on talkBubble true and visible false', function() {
expect($('.bubble-container').css('display')).toBe('none');
spriteProto.talkBubbleOn = true;
spriteProto.visible = false;
spriteProto.updateVisible();
expect($('.bubble-container').css('display')).toBe('none');
});
});
describe('askContainer', function() {
it('should update the askInput on askInput true and visible true', function() {
expect($('.ask-container').css('display')).toBe('none');
spriteProto.askInputOn = true;
spriteProto.visible = true;
spriteProto.updateVisible();
expect($('.ask-container').css('display')).toBe('inline-block');
});
it('should update the askInput on askInput false and visible true', function() {
expect($('.ask-container').css('display')).toBe('none');
spriteProto.askInputOn = false;
spriteProto.visible = true;
spriteProto.updateVisible();
expect($('.ask-container').css('display')).toBe('none');
});
it('should update the askInput on askInput true and visible false', function() {
expect($('.ask-container').css('display')).toBe('none');
spriteProto.askInputOn = true;
spriteProto.visible = false;
spriteProto.updateVisible();
expect($('.ask-container').css('display')).toBe('none');
});
});
});
describe('setVisible', function() {
var spriteProto;
beforeEach(function() {
spriteProto = deepCopy(sprite.prototype);
spyOn(spriteProto, "updateVisible");
});
it('should set visible to true', function() {
expect(spriteProto.visible).toBe(undefined);
spriteProto.setVisible(true);
expect(spriteProto.visible).toBe(true);
expect(spriteProto.updateVisible).toHaveBeenCalled();
});
it('should set visible to false', function() {
spriteProto.visible = true;
spriteProto.setVisible(false);
expect(spriteProto.visible).toBe(false);
expect(spriteProto.updateVisible).toHaveBeenCalled();
});
});
});

55
test/unit/stageSpec.js Normal file
View file

@ -0,0 +1,55 @@
/* jasmine specs for Stage.js go here */
describe('Stage', function() {
var stage;
beforeEach(function() {
stage = Stage;
});
describe('Initialized variables', function() {
var initStage, lineCanvas;
beforeEach(function() {
spyOn(Sprite, "call");
initStage = new stage(sensingData);
});
describe('Stage Variables', function() {
it('should have a z variable', function() {
expect(initStage.z).toBe(-2);
});
it('should have a penLayerLoaded variable', function() {
expect(initStage.penLayerLoaded).toBe(false);
});
it('should have a lineCanvas element', function() {
expect(initStage.lineCanvas).toBeDefined();
});
it('should have a lineCanvas width', function() {
expect(initStage.lineCanvas.width).toBe(480);
});
it('should have a lineCanvas height', function() {
expect(initStage.lineCanvas.height).toBe(360);
});
it('should have a lineCache variable', function() {
expect(initStage.lineCache).toBeDefined();
});
it('should have a isStage variable', function() {
expect(initStage.isStage).toBe(true);
});
it('should have an askAnswer variable', function() {
expect(initStage.askAnswer).toBe("");
});
it('should have called Sprite.call', function() {
expect(Sprite.call).toHaveBeenCalled();
});
});
});
});

50
test/unit/threadSpec.js Normal file
View file

@ -0,0 +1,50 @@
/* jasmine specs for Interpreter.js -> Thread go here */
describe('Thread', function() {
var thread;
beforeEach(function() {
thread = Thread;
});
describe('Initialized variables', function() {
var initThread;
beforeEach(function() {
initThread = new thread('block', 'target');
});
describe('Thread Variables', function() {
it('should have a nextBlock variable', function() {
expect(initThread.nextBlock).toBe('block');
});
it('should have a firstBlock variable', function() {
expect(initThread.firstBlock).toBe('block');
});
it('should have a stack variable', function() {
expect(initThread.stack).toEqual([]);
});
it('should have a target variable', function() {
expect(initThread.target).toBe('target');
});
it('should have a tmp variable', function() {
expect(initThread.tmp).toBe(null);
});
it('should have a tmpObj variable', function() {
expect(initThread.tmpObj).toEqual([]);
});
it('should have a firstTime variable', function() {
expect(initThread.firstTime).toBe(true);
});
it('should have a paused variable', function() {
expect(initThread.paused).toBe(false);
});
});
});
});

View file

@ -15,8 +15,6 @@ To do:
-Trigger hats (e.g. When Scene Starts?)
-Ask block
-SVGs/Clicks/Correct collisions and bounce
(see Chromium bug https://code.google.com/p/chromium/issues/detail?id=249037).