Switched test suite to Mocha and added linting

This commit is contained in:
jwngr
2015-07-05 20:38:35 -07:00
parent bdf932d440
commit dbbc5158e2
18 changed files with 849 additions and 2418 deletions

152
.eslintrc Normal file
View File

@@ -0,0 +1,152 @@
{
"env": {
"node": true,
"browser": true
},
"globals": {
"define" : false
},
"rules": {
/**
* Strict mode
*/
"strict": [2, "global"], // http://eslint.org/docs/rules/strict
/**
* Variables
*/
"no-shadow": 2, // http://eslint.org/docs/rules/no-shadow
"no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names
"no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars
"vars": "local",
"args": "after-used"
}],
"no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define
/**
* Node.js
*/
"no-process-exit": 0, // http://eslint.org/docs/rules/no-process-exit
"no-sync": 2, // http://eslint.org/docs/rules/no-sync
/**
* Possible errors
*/
"comma-dangle": [2, "never"], // http://eslint.org/docs/rules/comma-dangle
"no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign
"no-console": 1, // http://eslint.org/docs/rules/no-console
"no-debugger": 1, // http://eslint.org/docs/rules/no-debugger
"no-alert": 1, // http://eslint.org/docs/rules/no-alert
"no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition
"no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys
"no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case
"no-empty": 2, // http://eslint.org/docs/rules/no-empty
"no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign
"no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast
"no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi
"no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign
"no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations
"no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp
"no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace
"no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls
"no-reserved-keys": 2, // http://eslint.org/docs/rules/no-reserved-keys
"no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays
"no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable
"use-isnan": 2, // http://eslint.org/docs/rules/use-isnan
"block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var
/**
* Best practices
*/
"consistent-return": 2, // http://eslint.org/docs/rules/consistent-return
"curly": [2, "all"], // http://eslint.org/docs/rules/curly
"default-case": 2, // http://eslint.org/docs/rules/default-case
"dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation
"allowKeywords": true
}],
"eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq
"guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in
"no-caller": 2, // http://eslint.org/docs/rules/no-caller
"no-else-return": 2, // http://eslint.org/docs/rules/no-else-return
"no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null
"no-eval": 2, // http://eslint.org/docs/rules/no-eval
"no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native
"no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind
"no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough
"no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal
"no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval
"no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks
"no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func
"no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str
"no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign
"no-new": 2, // http://eslint.org/docs/rules/no-new
"no-new-func": 2, // http://eslint.org/docs/rules/no-new-func
"no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers
"no-octal": 2, // http://eslint.org/docs/rules/no-octal
"no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape
//"no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign
"no-proto": 2, // http://eslint.org/docs/rules/no-proto
"no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare
"no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign
"no-script-url": 2, // http://eslint.org/docs/rules/no-script-url
"no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare
"no-sequences": 2, // http://eslint.org/docs/rules/no-sequences
"no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal
"no-with": 2, // http://eslint.org/docs/rules/no-with
"radix": 2, // http://eslint.org/docs/rules/radix
//"vars-on-top": 2, // http://eslint.org/docs/rules/vars-on-top
"wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife
"yoda": 2, // http://eslint.org/docs/rules/yoda
/**
* Style
*/
"indent": [2, 2], // http://eslint.org/docs/rules/indent
"brace-style": [2, // http://eslint.org/docs/rules/brace-style
"1tbs", {
"allowSingleLine": true
}],
"quotes": [
2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes
],
"camelcase": [2, { // http://eslint.org/docs/rules/camelcase
"properties": "never"
}],
"comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing
"before": false,
"after": true
}],
"comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style
"eol-last": 2, // http://eslint.org/docs/rules/eol-last
//"func-names": 1, // http://eslint.org/docs/rules/func-names
"key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing
"beforeColon": false,
"afterColon": true
}],
"new-cap": [2, { // http://eslint.org/docs/rules/new-cap
"newIsCap": true
}],
"no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines
"max": 2
}],
"no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary
"no-new-object": 2, // http://eslint.org/docs/rules/no-new-object
"no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func
"no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces
"no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func
"no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle
"one-var": [2, "never"], // http://eslint.org/docs/rules/one-var
"padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks
"semi": [2, "always"], // http://eslint.org/docs/rules/semi
"semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing
"before": false,
"after": true
}],
"space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords
"space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks
"space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
"space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
"space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case
"spaced-line-comment": 2, // http://eslint.org/docs/rules/spaced-line-comment
}
}

6
.gitignore vendored
View File

@@ -1,4 +1,4 @@
/dist/
dist/
coverage/
node_modules/
/bower_components/
tests/coverage
bower_components/

View File

@@ -1,19 +0,0 @@
{
"predef": [
"define",
"module",
"Firebase"
],
"bitwise": true,
"curly": true,
"eqeqeq": true,
"forin": true,
"freeze": true,
"indent": 2,
"latedef": true,
"quotmark": "double",
"strict": true,
"trailing": true,
"undef": true,
"unused": true
}

View File

@@ -2,9 +2,7 @@ language: node_js
node_js:
- '0.10'
install:
- npm install -g bower
- npm install
- bower install
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start

View File

@@ -32,10 +32,7 @@
"changelog.txt"
],
"dependencies": {
"react": "0.12.x",
"firebase": "2.0.x"
},
"devDependencies": {
"jasmine": "~2.0.0"
"react": "0.13.x",
"firebase": "2.2.x"
}
}

View File

@@ -1,2 +0,0 @@
return ReactFireMixin;
}));

View File

@@ -1,26 +0,0 @@
/*!
* ReactFire is an open-source JavaScript library that allows you to add a
* realtime data source to your React apps by providing and easy way to let
* Firebase populate the state of React components.
*
* ReactFire 0.0.0
* https://github.com/firebase/reactfire/
* License: MIT
*/
;(function (root, factory) {
"use strict";
if (typeof define === "function" && define.amd) {
// AMD
define([], function() {
return (root.ReactFireMixin = factory());
});
} else if (typeof exports === "object") {
// CommonJS
module.exports = factory();
} else {
// Global variables
root.ReactFireMixin = factory();
}
}(this, function() {
"use strict";

View File

@@ -1,123 +1,94 @@
'use strict';
/**************/
/* REQUIRES */
/**************/
var gulp = require("gulp");
var gulp = require('gulp');
var runSequence = require('run-sequence');
// File IO
var streamqueue = require("streamqueue");
var concat = require("gulp-concat");
var jshint = require("gulp-jshint");
var uglify = require("gulp-uglify");
var exit = require('gulp-exit');
var eslint = require('gulp-eslint');
var uglify = require('gulp-uglify');
var extReplace = require('gulp-ext-replace');
// Testing
var karma = require("gulp-karma");
// Determine if this is being run in Travis
var travis = false;
var mocha = require('gulp-mocha');
var istanbul = require('gulp-istanbul');
/****************/
/* FILE PATHS */
/****************/
var paths = {
destDir: "dist",
destDir: 'dist',
scripts: {
src: {
dir: "src",
files: [
"src/*.js"
]
},
dest: {
dir: "dist",
files: {
unminified: "reactfire.js",
minified: "reactfire.min.js"
}
}
},
srcFiles: [
'src/reactfire.js'
],
tests: {
config: "tests/karma.conf.js",
files: [
"bower_components/firebase/firebase.js",
"tests/phantomjs-es5-shim.js",
"bower_components/react/react-with-addons.js",
"src/*.js",
"tests/specs/*.spec.js"
]
}
testFiles: [
'tests/helpers.js',
'tests/reactfire.spec.js'
]
};
/***********/
/* TASKS */
/***********/
/* Lints, minifies, and concatenates the script files */
gulp.task("scripts", function() {
// Concatenate all src files together
var stream = streamqueue({ objectMode: true });
stream.queue(gulp.src("build/header"));
stream.queue(gulp.src(paths.scripts.src.files));
stream.queue(gulp.src("build/footer"));
// Lints the JavaScript files
gulp.task('lint', function() {
var filesToLint = paths.srcFiles.concat(paths.testFiles).concat(['gulpfile.js']);
return gulp.src(filesToLint)
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
// Output the final concatenated script file
return stream.done()
// Rename file
.pipe(concat(paths.scripts.dest.files.unminified))
// Lint
.pipe(jshint())
.pipe(jshint.reporter("jshint-stylish"))
.pipe(jshint.reporter("fail"))
.on("error", function(error) {
if (travis) {
throw error;
}
})
/* Builds the distribution files */
gulp.task('build', function() {
return gulp.src(paths.srcFiles)
// Write un-minified version
.pipe(gulp.dest(paths.scripts.dest.dir))
.pipe(gulp.dest(paths.destDir))
// Minify
.pipe(uglify({
preserveComments: "some"
preserveComments: 'some'
}))
// Rename file
.pipe(concat(paths.scripts.dest.files.minified))
// Change the file extension
.pipe(extReplace('.min.js'))
// Write minified version to the distribution directory
.pipe(gulp.dest(paths.scripts.dest.dir));
// Write minified version
.pipe(gulp.dest(paths.destDir));
});
/* Uses the Karma test runner to run the Jasmine tests */
gulp.task("test", function() {
return gulp.src(paths.tests.files)
.pipe(karma({
configFile: paths.tests.config,
browsers: travis ? ["Firefox"] : ["Chrome"],
action: "run"
}))
.on("error", function(error) {
throw error;
// Runs the Mocha test suite
gulp.task('test', function() {
return gulp.src(paths.srcFiles)
.pipe(istanbul())
.pipe(istanbul.hookRequire())
.on('finish', function() {
gulp.src(paths.testFiles)
.pipe(mocha({
reporter: 'spec',
timeout: 5000
}))
.pipe(istanbul.writeReports())
.pipe(exit());
});
});
/* Re-runs the "scripts" task every time a script file changes */
gulp.task("watch", function() {
gulp.watch(["build/*", paths.scripts.src.dir + "/**/*"], ["scripts"]);
// Re-lints and re-builds every time a source file changes
gulp.task('watch', function() {
gulp.watch([paths.srcFiles], ['lint', 'build']);
});
/* Builds the distribution files */
gulp.task("build", ["scripts"]);
/* Tasks to be run within Travis CI */
gulp.task("travis", function() {
travis = true;
gulp.start("build", "test");
// Default task
gulp.task('default', function(done) {
runSequence('lint', 'build', 'test', function(error) {
done(error && error.err);
});
});
/* Runs the "scripts" and "test" tasks by default */
gulp.task("default", ["build", "test"]);

View File

@@ -32,28 +32,24 @@
"package.json"
],
"dependencies": {
"firebase": "2.0.x",
"react": "0.12.x"
"firebase": "2.2.x",
"react": "0.13.x"
},
"devDependencies": {
"coveralls": "^2.11.1",
"gulp": "^3.8.7",
"gulp-concat": "^2.2.0",
"gulp-jshint": "^1.5.1",
"gulp-karma": "0.0.4",
"gulp-uglify": "^0.2.1",
"jshint-stylish": "^0.2.0",
"karma": "^0.12.16",
"karma-chrome-launcher": "^0.1.5",
"karma-coverage": "^0.2.4",
"karma-failed-reporter": "0.0.2",
"karma-firefox-launcher": "^0.1.3",
"karma-jasmine": "~0.2.0",
"karma-spec-reporter": "0.0.13",
"streamqueue": "^0.1.1"
"chai": "^3.0.0",
"coveralls": "^2.11.2",
"gulp": "^3.9.0",
"gulp-eslint": "^0.15.0",
"gulp-exit": "0.0.2",
"gulp-ext-replace": "^0.2.0",
"gulp-istanbul": "^0.10.0",
"gulp-mocha": "^2.1.2",
"gulp-uglify": "^1.2.0",
"jsdom": "3.x.x",
"run-sequence": "^1.1.1"
},
"scripts": {
"test": "gulp test",
"travis": "gulp travis"
"travis": "gulp"
}
}

View File

@@ -1,146 +1,165 @@
var ReactFireMixin = {
/********************/
/* MIXIN LIFETIME */
/********************/
/* Initializes the Firebase binding refs array */
componentWillMount: function() {
this.firebaseRefs = {};
this.firebaseListeners = {};
},
/*!
* ReactFire is an open-source JavaScript library that allows you to add a
* realtime data source to your React apps by providing and easy way to let
* Firebase populate the state of React components.
*
* ReactFire 0.0.0
* https://github.com/firebase/reactfire/
* License: MIT
*/
/* eslint "strict": [2, "function"] */
(function(root, factory) {
'use strict';
/* Removes any remaining Firebase bindings */
componentWillUnmount: function() {
for (var key in this.firebaseRefs) {
if (this.firebaseRefs.hasOwnProperty(key)) {
this.unbind(key);
}
}
},
/*************/
/* BINDING */
/*************/
/* Creates a binding between Firebase and the inputted bind variable as an array */
bindAsArray: function(firebaseRef, bindVar, cancelCallback) {
this._bind(firebaseRef, bindVar, cancelCallback, true);
},
/* Creates a binding between Firebase and the inputted bind variable as an object */
bindAsObject: function(firebaseRef, bindVar, cancelCallback) {
this._bind(firebaseRef, bindVar, cancelCallback, false);
},
/* Creates a binding between Firebase and the inputted bind variable as either an array or object */
_bind: function(firebaseRef, bindVar, cancelCallback, bindAsArray) {
this._validateBindVar(bindVar);
var errorMessage, errorCode;
if (Object.prototype.toString.call(firebaseRef) !== "[object Object]") {
errorMessage = "firebaseRef must be an instance of Firebase";
errorCode = "INVALID_FIREBASE_REF";
}
else if (typeof bindAsArray !== "boolean") {
errorMessage = "bindAsArray must be a boolean. Got: " + bindAsArray;
errorCode = "INVALID_BIND_AS_ARRAY";
}
if (typeof errorMessage !== "undefined") {
var error = new Error("ReactFire: " + errorMessage);
error.code = errorCode;
throw error;
}
this.firebaseRefs[bindVar] = firebaseRef.ref();
this.firebaseListeners[bindVar] = firebaseRef.on("value", function(dataSnapshot) {
var newState = {};
if (bindAsArray) {
newState[bindVar] = this._toArray(dataSnapshot.val());
}
else {
newState[bindVar] = dataSnapshot.val();
}
this.setState(newState);
}.bind(this), cancelCallback);
},
/* Removes the binding between Firebase and the inputted bind variable */
unbind: function(bindVar) {
this._validateBindVar(bindVar);
if (typeof this.firebaseRefs[bindVar] === "undefined") {
var error = new Error("ReactFire: unexpected value for bindVar. \"" + bindVar + "\" was either never bound or has already been unbound");
error.code = "UNBOUND_BIND_VARIABLE";
throw error;
}
this.firebaseRefs[bindVar].off("value", this.firebaseListeners[bindVar]);
delete this.firebaseRefs[bindVar];
delete this.firebaseListeners[bindVar];
},
/*************/
/* HELPERS */
/*************/
/* Validates the name of the variable which is being bound */
_validateBindVar: function(bindVar) {
var errorMessage;
if (typeof bindVar !== "string") {
errorMessage = "bindVar must be a string. Got: " + bindVar;
}
else if (bindVar.length === 0) {
errorMessage = "bindVar must be a non-empty string. Got: \"\"";
}
else if (bindVar.length > 768) {
// Firebase can only stored child paths up to 768 characters
errorMessage = "bindVar is too long to be stored in Firebase. Got: " + bindVar;
}
else if (/[\[\].#$\/\u0000-\u001F\u007F]/.test(bindVar)) {
// Firebase does not allow node keys to contain the following characters
errorMessage = "bindVar cannot contain any of the following characters: . # $ ] [ /. Got: " + bindVar;
}
if (typeof errorMessage !== "undefined") {
var error = new Error("ReactFire: " + errorMessage);
error.code = "INVALID_BIND_VARIABLE";
throw error;
}
},
/* Returns true if the inputted object is a JavaScript array */
_isArray: function(obj) {
return (Object.prototype.toString.call(obj) === "[object Array]");
},
/* Converts a Firebase object to a JavaScript array */
_toArray: function(obj) {
var item;
var out = [];
if (obj) {
if (this._isArray(obj)) {
for (var i = 0, length = obj.length; i < length; i++) {
item = obj[i];
if (item !== undefined && item !== null) {
out.push({ $key: i, $value: item });
}
}
}
else if (typeof(obj) === "object") {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
item = obj[key];
if (typeof item !== "object") {
item = { $value: item };
}
item.$key = key;
out.push(item);
}
}
}
}
return out;
/* istanbul ignore next */
if (typeof define === 'function' && define.amd) {
// AMD
define([], function() {
return (root.ReactFireMixin = factory());
});
} else if (typeof exports === 'object') {
// CommonJS
module.exports = factory();
} else {
// Global variables
root.ReactFireMixin = factory();
}
};
}(this, function() {
'use strict';
var ReactFireMixin = {
/********************/
/* MIXIN LIFETIME */
/********************/
/* Initializes the Firebase binding refs array */
componentWillMount: function() {
this.firebaseRefs = {};
this.firebaseListeners = {};
},
/* Removes any remaining Firebase bindings */
componentWillUnmount: function() {
for (var key in this.firebaseRefs) {
if (this.firebaseRefs.hasOwnProperty(key)) {
this.unbind(key);
}
}
},
/*************/
/* BINDING */
/*************/
/* Creates a binding between Firebase and the inputted bind variable as an array */
bindAsArray: function(firebaseRef, bindVar, cancelCallback) {
this._bind(firebaseRef, bindVar, cancelCallback, true);
},
/* Creates a binding between Firebase and the inputted bind variable as an object */
bindAsObject: function(firebaseRef, bindVar, cancelCallback) {
this._bind(firebaseRef, bindVar, cancelCallback, false);
},
/* Throw a formatted error message */
_throwError: function(message) {
throw new Error('ReactFire: ' + message);
},
/* Creates a binding between Firebase and the inputted bind variable as either an array or object */
_bind: function(firebaseRef, bindVar, cancelCallback, bindAsArray) {
this._validateBindVar(bindVar);
if (Object.prototype.toString.call(firebaseRef) !== '[object Object]') {
this._throwError('firebaseRef must be an instance of Firebase');
}
this.firebaseRefs[bindVar] = firebaseRef.ref();
this.firebaseListeners[bindVar] = firebaseRef.on('value', function(dataSnapshot) {
var newState = {};
if (bindAsArray) {
newState[bindVar] = this._toArray(dataSnapshot.val());
} else {
newState[bindVar] = dataSnapshot.val();
}
this.setState(newState);
}.bind(this), cancelCallback);
},
/* Removes the binding between Firebase and the inputted bind variable */
unbind: function(bindVar, callback) {
this._validateBindVar(bindVar);
if (typeof this.firebaseRefs[bindVar] === 'undefined') {
this._throwError('unexpected value for bindVar. "' + bindVar + '" was either never bound or has already been unbound');
}
this.firebaseRefs[bindVar].off('value', this.firebaseListeners[bindVar]);
delete this.firebaseRefs[bindVar];
delete this.firebaseListeners[bindVar];
var newState = {};
newState[bindVar] = undefined;
this.setState(newState, callback);
},
/*************/
/* HELPERS */
/*************/
/* Validates the name of the variable which is being bound */
_validateBindVar: function(bindVar) {
var errorMessage;
if (typeof bindVar !== 'string') {
errorMessage = 'bindVar must be a string. Got: ' + bindVar;
} else if (bindVar.length === 0) {
errorMessage = 'bindVar must be a non-empty string. Got: ""';
} else if (bindVar.length > 768) {
// Firebase can only stored child paths up to 768 characters
errorMessage = 'bindVar is too long to be stored in Firebase. Got: ' + bindVar;
} else if (/[\[\].#$\/\u0000-\u001F\u007F]/.test(bindVar)) {
// Firebase does not allow node keys to contain the following characters
errorMessage = 'bindVar cannot contain any of the following characters: . # $ ] [ /. Got: ' + bindVar;
}
if (typeof errorMessage !== 'undefined') {
this._throwError(errorMessage);
}
},
/* Returns true if the inputted object is a JavaScript array */
_isArray: function(obj) {
return (Object.prototype.toString.call(obj) === '[object Array]');
},
/* Converts a Firebase object to a JavaScript array */
_toArray: function(obj) {
var item;
var out = [];
if (obj) {
if (this._isArray(obj)) {
for (var i = 0, length = obj.length; i < length; i++) {
item = obj[i];
if (item !== undefined && item !== null) {
out.push({ $key: i, $value: item });
}
}
} else if (typeof obj === 'object') {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
item = obj[key];
if (typeof item !== 'object') {
item = { $value: item };
}
item.$key = key;
out.push(item);
}
}
}
}
return out;
}
};
return ReactFireMixin;
}));

8
tests/.eslintrc Normal file
View File

@@ -0,0 +1,8 @@
{
"env": {
"mocha": true
},
"rules": {
"no-unused-expressions": 0
}
}

19
tests/helpers.js Normal file
View File

@@ -0,0 +1,19 @@
'use strict';
module.exports = {
invalidFirebaseRefs: [null, undefined, true, false, [], 0, 5, '', 'a', ['hi', 1]],
invalidBindVars: ['', 1, true, false, [], {}, [1, 2], {a: 1}, null, undefined, 'te.st', 'te$st', 'te[st', 'te]st', 'te#st', 'te/st', 'a#i]$da[s', 'te/nst', 'te/rst', 'te/u0000st', 'te/u0015st', 'te/007Fst', Array(800).join('a')],
/* Returns a random alphabetic string of variable length */
generateRandomString: function() {
var possibleCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var numPossibleCharacters = possibleCharacters.length;
var text = '';
for (var i = 0; i < 10; i++) {
text += possibleCharacters.charAt(Math.floor(Math.random() * numPossibleCharacters));
}
return text;
}
};

View File

@@ -1,28 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>ReactFire Test Suite</title>
<!-- Jasmine -->
<script src="../bower_components/jasmine/lib/jasmine-core/jasmine.js"></script>
<script src="../bower_components/jasmine/lib/jasmine-core/jasmine-html.js"></script>
<script src="../bower_components/jasmine/lib/jasmine-core/boot.js"></script>
<link rel="stylesheet" href="../bower_components/jasmine/lib/jasmine-core/jasmine.css">
<!-- React -->
<script src="../bower_components/react/react-with-addons.js"></script>
<!-- Firebase -->
<script src="../bower_components/firebase/firebase.js"></script>
<!-- ReactFire -->
<script src="../src/reactfire.js"></script>
<!-- Jasmine specs -->
<script src="specs/common.spec.js"></script>
<script src="specs/reactfire.spec.js"></script>
</head>
<body>
</body>
</html>

View File

@@ -1,25 +0,0 @@
module.exports = function(config) {
config.set({
frameworks: ["jasmine"],
autowatch: false,
singleRun: true,
preprocessors: {
"../src/*.js": "coverage"
},
reporters: ["spec", "failed", "coverage"],
coverageReporter: {
reporters: [
{
type: "lcovonly",
dir: "coverage",
subdir: "."
},
{
type: "text-summary"
}
]
}
});
};

File diff suppressed because it is too large Load Diff

432
tests/reactfire.spec.js Normal file
View File

@@ -0,0 +1,432 @@
'use strict';
// Mocha / Chai
var chai = require('chai');
var expect = chai.expect;
// React
var React = require('react/addons');
var ReactTestUtils = React.addons.TestUtils;
// ReactFire
var Firebase = require('firebase');
var ReactFireMixin = require('../src/reactfire.js');
// JSDom
var jsdom = require('jsdom');
global.document = jsdom.jsdom(); // Needed for ReactTestUtils shallow renderer
document.createElement = null; // Needed for Firebase
// Test helpers
var TH = require('./helpers.js');
// Get a reference to a random demo Firebase
var demoFirebaseUrl = 'https://' + TH.generateRandomString() + '.firebaseio-demo.com';
describe('ReactFire', function() {
var firebaseRef;
var shallowRenderer;
beforeEach(function(done) {
shallowRenderer = ReactTestUtils.createRenderer();
firebaseRef = new Firebase(demoFirebaseUrl);
firebaseRef.remove(function(error) {
if (error) {
done(error);
} else {
firebaseRef = firebaseRef.child(TH.generateRandomString());
done();
}
});
});
describe('bindAsArray()', function() {
it('throws error given invalid Firebase reference', function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
TH.invalidFirebaseRefs.forEach(function(invalidFirebaseRef) {
expect(function() {
_this.bindAsArray(invalidFirebaseRef, 'items');
}).to.throw('ReactFire: firebaseRef must be an instance of Firebase');
});
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('throws error given invalid bind variable', function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
TH.invalidBindVars.forEach(function(invalidBindVar) {
expect(function() {
_this.bindAsArray(firebaseRef, invalidBindVar);
}).to.throw(/bindVar/);
});
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('binds array items which are objects', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, 'items');
firebaseRef.set({
first: { index: 0 },
second: { index: 1 },
third: { index: 2 }
}, function() {
expect(this.state.items).to.deep.equal([
{ '$key': 'first', index: 0 },
{ '$key': 'second', index: 1 },
{ '$key': 'third', index: 2 }
]);
done();
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('binds array items which are primitives', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, 'items');
firebaseRef.set(['first', 'second', 'third'], function() {
expect(this.state.items).to.deep.equal([
{ '$key': 0, '$value': 'first' },
{ '$key': 1, '$value': 'second' },
{ '$key': 2, '$value': 'third' }
]);
done();
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('binds sparse arrays', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, 'items');
firebaseRef.set({ 0: 'a', 2: 'b', 5: 'c' }, function() {
expect(this.state).to.deep.equal({
items: [
{ $key: 0, $value: 'a' },
{ $key: 2, $value: 'b' },
{ $key: 5, $value: 'c' }
]
});
done();
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('binds with limit queries', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef.limitToLast(2), 'items');
firebaseRef.set({ a: 1, b: 2, c: 3 }, function() {
expect(this.state).to.deep.equal({
items: [
{ $key: 'b', $value: 2 },
{ $key: 'c', $value: 3 }
]
});
done();
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
});
describe('bindAsObject()', function() {
it('throws error given invalid Firebase reference', function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
TH.invalidFirebaseRefs.forEach(function(invalidFirebaseRef) {
expect(function() {
_this.bindAsObject(invalidFirebaseRef, 'items');
}).to.throw('ReactFire: firebaseRef must be an instance of Firebase');
});
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('throws error given invalid bind variable', function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
TH.invalidBindVars.forEach(function(invalidBindVar) {
expect(function() {
_this.bindAsObject(firebaseRef, invalidBindVar);
}).to.throw(/bindVar/);
});
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('binds objects', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsObject(firebaseRef, 'items');
var obj = {
first: { index: 0 },
second: { index: 1 },
third: { index: 2 }
};
firebaseRef.set(obj, function() {
expect(this.state.items).to.deep.equal(obj);
done();
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('binds with limit queries', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsObject(firebaseRef.limitToLast(2), 'items');
firebaseRef.set({
first: { index: 0 },
second: { index: 1 },
third: { index: 2 }
}, function() {
expect(this.state.items).to.deep.equal({
second: { index: 1 },
third: { index: 2 }
});
done();
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
});
describe('unbind()', function() {
it('throws error given invalid bind variable', function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
TH.invalidBindVars.forEach(function(invalidBindVar) {
expect(function() {
_this.unbind(invalidBindVar);
}).to.throw(/bindVar/);
});
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('throws error given unbound bind variable', function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
expect(function() {
_this.unbind('items');
}).to.throw(/bindVar/);
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('unbinds the state bound to Firebase as an array', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, 'items');
firebaseRef.set({
first: { index: 0 },
second: { index: 1 },
third: { index: 2 }
}, function() {
this.unbind('items', function() {
expect(this.state.items).to.be.undefined;
done();
});
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('unbinds the state bound to Firebase as an object', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsObject(firebaseRef, 'items');
firebaseRef.set({
first: { index: 0 },
second: { index: 1 },
third: { index: 2 }
}, function() {
this.unbind('items', function() {
expect(this.state.items).to.be.undefined;
done();
});
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
it('unbinds the state bound to Firebase limit query', function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsObject(firebaseRef.limitToLast(2), 'items');
firebaseRef.set({
first: { index: 0 },
second: { index: 1 },
third: { index: 2 }
}, function() {
this.unbind('items', function() {
expect(this.state.items).to.be.undefined;
done();
});
}.bind(this));
},
render: function() {
return React.DOM.div(null);
}
});
shallowRenderer.render(React.createElement(TestComponent));
});
});
});

View File

@@ -1,61 +0,0 @@
/*************/
/* GLOBALS */
/*************/
// Override the default timeout interval for Jasmine
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
// Get a reference to a random demo Firebase
var demoFirebaseUrl = "https://" + generateRandomString() + ".firebaseio-demo.com";
// React test addon
var ReactTestUtils = React.addons.TestUtils;
// Define examples of valid and invalid parameters
var invalidFirebaseRefs = [null, undefined, true, false, [], 0, 5, "", "a", ["hi", 1]];
var validBindVars = ["a", "testing", "(e@Xi:4t>*E2)hc<5oa:1s6{B0d?u", Array(743).join("a")];
var invalidBindVars = ["", 1, true, false, [], {}, [1, 2], {a: 1}, null, undefined, "te.st", "te$st", "te[st", "te]st", "te#st", "te/st", "a#i]$da[s", "te/nst", "te/rst", "te/u0000st", "te/u0015st", "te/007Fst", Array(800).join("a")];
/**********************/
/* HELPER FUNCTIONS */
/**********************/
/* Helper function which runs before each Jasmine test has started */
function beforeEachHelper(done) {
// Create a new firebase ref with a new context
firebaseRef = new Firebase(demoFirebaseUrl, Firebase.Context());
// Reset the Firebase
firebaseRef.remove(function() {
// Create a new firebase ref at a random node
firebaseRef = firebaseRef.child(generateRandomString());
done();
});
}
/* Helper function which runs after each Jasmine test has completed */
function afterEachHelper(done) {
React.unmountComponentAtNode(document.body);
done();
}
/* Returns a random alphabetic string of variable length */
function generateRandomString() {
var possibleCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var numPossibleCharacters = possibleCharacters.length;
var text = "";
for (var i = 0; i < 10; i++) {
text += possibleCharacters.charAt(Math.floor(Math.random() * numPossibleCharacters));
}
return text;
}
/* Returns the current data in the Firebase */
function getFirebaseData() {
return new RSVP.Promise(function(resolve, reject) {
firebaseRef.once("value", function(dataSnapshot) {
resolve(dataSnapshot.val());
});
});
};

View File

@@ -1,568 +0,0 @@
describe("ReactFireMixin Tests:", function() {
beforeEach(function(done) {
beforeEachHelper(done);
});
afterEach(function(done) {
afterEachHelper(done);
});
describe("bindAsArray():", function() {
it("bindAsArray() throws errors given invalid Firebase refs", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
invalidFirebaseRefs.forEach(function(invalidFirebaseRef) {
try {
_this.bindAsArray(invalidFirebaseRef, "items");
expect("Function should throw error given parameter: " + invalidFirebaseRef).toBeFalsy();
} catch (error) {
expect(error.code).toEqual("INVALID_FIREBASE_REF");
}
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsArray() throws errors given invalid bind variables", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
invalidBindVars.forEach(function(invalidBindVar) {
try {
_this.bindAsArray(firebaseRef, invalidBindVar);
expect("Function should throw error given parameter: " + invalidBindVar).toBeFalsy();
} catch (error) {
expect(error.code).toEqual("INVALID_BIND_VARIABLE");
}
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsArray() does not throw errors given valid inputs", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
validBindVars.forEach(function(validBindVar) {
expect(function() { _this.bindAsArray(firebaseRef, validBindVar); }).not.toThrow();
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsArray() does not throw an error given a limit query", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
expect(function() { _this.bindAsArray(firebaseRef.limitToLast(10), "items"); }).not.toThrow();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsArray() binds to remote Firebase data as an array", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, "items");
},
componentDidMount: function() {
firebaseRef.set({ a: 1, b: 2, c: 3 });
},
componentDidUpdate: function(prevProps, prevState) {
expect(this.state).toEqual({
items: [
{ $key: "a", $value: 1 },
{ $key: "b", $value: 2 },
{ $key: "c", $value: 3 }
]
});
done();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsArray() binds to remote Firebase data as an array (limit query)", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef.limitToLast(2), "items");
},
componentDidMount: function() {
firebaseRef.set({ a: 1, b: 2, c: 3 });
},
componentDidUpdate: function(prevProps, prevState) {
expect(this.state).toEqual({
items: [
{ $key: "b", $value: 2 },
{ $key: "c", $value: 3 }
]
});
done();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsArray() makes $key available on array items when they are objects", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, "items");
},
componentDidMount: function() {
firebaseRef.set({ first: { index: 1 }, second: { index: 2 }, third: { index: 3 } });
},
componentDidUpdate: function(prevProps, prevState) {
expect(this.state.items.map(function(item) { return item.$key; })).toEqual(["first", "second", "third"]);
done();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsArray() makes $key available on array items when they are primitives", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, "items");
},
componentDidMount: function() {
firebaseRef.set(["first", "second", "third"]);
},
componentDidUpdate: function(prevProps, prevState) {
expect(this.state.items.map(function(item) { return item.$key; })).toEqual([0, 1, 2]);
expect(this.state.items.map(function(item) { return item.$value; })).toEqual(["first", "second", "third"]);
done();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsArray() properly binds to sparse arrays", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, "items");
},
componentDidMount: function() {
firebaseRef.set({ 0: 'a', 2: 'b', 5: 'c' });
},
componentDidUpdate: function(prevProps, prevState) {
expect(this.state).toEqual({
items: [
{ $key: 0, $value: 'a' },
{ $key: 2, $value: 'b' },
{ $key: 5, $value: 'c' }
]
});
done();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
});
describe("bindAsObject():", function() {
it("bindAsObject() throws errors given invalid Firebase refs", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
invalidFirebaseRefs.forEach(function(invalidFirebaseRef) {
try {
_this.bindAsObject(invalidFirebaseRef, "items");
expect("Function should throw error given parameter: " + invalidFirebaseRef).toBeFalsy();
} catch (error) {
expect(error.code).toEqual("INVALID_FIREBASE_REF");
}
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsObject() throws errors given invalid bind variables", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
invalidBindVars.forEach(function(invalidBindVar) {
try {
_this.bindAsObject(firebaseRef, invalidBindVar);
expect("Function should throw error given parameter: " + invalidBindVar).toBeFalsy();
} catch (error) {
expect(error.code).toEqual("INVALID_BIND_VARIABLE");
}
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsObject() does not throw errors given valid inputs", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
validBindVars.forEach(function(validBindVar) {
expect(function() { _this.bindAsObject(firebaseRef, validBindVar); }).not.toThrow();
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsObject() does not throw an error given a limit query", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
expect(function() { _this.bindAsObject(firebaseRef.limitToLast(10), "items"); }).not.toThrow();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsObject() binds to remote Firebase data as an object", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsObject(firebaseRef, "items");
},
componentDidMount: function() {
firebaseRef.set({ a: 1, b: 2, c: 3 });
},
componentDidUpdate: function(prevProps, prevState) {
expect(this.state).toEqual({ items: { a: 1, b: 2, c: 3 } });
done();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("bindAsObject() binds to remote Firebase data as an object (limit query)", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsObject(firebaseRef.limitToLast(2), "items");
},
componentDidMount: function() {
firebaseRef.set({ a: 1, b: 2, c: 3 });
},
componentDidUpdate: function(prevProps, prevState) {
expect(this.state).toEqual({ items: { b: 2, c: 3 } });
done();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
});
describe("unbind():", function() {
it("unbind() throws errors given invalid bind variables", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
invalidBindVars.forEach(function(invalidBindVar) {
try {
_this.unbind(invalidBindVar);
expect("Function should throw error given parameter: " + invalidBindVar).toBeFalsy();
} catch (error) {
expect(error.code).toEqual("INVALID_BIND_VARIABLE");
}
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("unbind() throws errors given unbound bind variable", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
validBindVars.forEach(function(validBindVar) {
try {
_this.unbind(validBindVar);
expect("Function should throw error given parameter: " + validBindVar).toBeFalsy();
} catch (error) {
expect(error.code).toEqual("UNBOUND_BIND_VARIABLE");
}
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("unbind() does not throw errors given valid bind variables", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
validBindVars.forEach(function(validBindVar) {
_this.bindAsArray(firebaseRef, validBindVar);
expect(function() { _this.unbind(validBindVar); }).not.toThrow();
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("unbind() does not throw an error given a limit query", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
validBindVars.forEach(function(validBindVar) {
_this.bindAsArray(firebaseRef.limitToLast(10), validBindVar);
expect(function() { _this.unbind(validBindVar); }).not.toThrow();
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("unbind() unbinds the state bound to Firebase as an array", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsArray(firebaseRef, "items");
this.unbind("items");
},
componentDidMount: function() {
firebaseRef.set({ a: 1, b: 2, c: 3 }, function() {
this.setTimeout(done, 250);
});
},
componentDidUpdate: function(prevProps, prevState) {
expect("Should not be here").toBeFalsy();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("unbind() unbinds the state bound to Firebase as an object", function(done) {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
this.bindAsObject(firebaseRef, "items");
this.unbind("items");
},
componentDidMount: function() {
firebaseRef.set({ a: 1, b: 2, c: 3 }, function() {
this.setTimeout(done, 250);
});
},
componentDidUpdate: function(prevProps, prevState) {
expect("Should not be here").toBeFalsy();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
});
describe("_bind():", function() {
it("_bind() throws errors given invalid third input parameter", function() {
var nonBooleanParams = [null, undefined, [], {}, 0, 5, "", "a", {a : 1}, ["hi", 1]];
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
nonBooleanParams.forEach(function(nonBooleanParam) {
try {
_this._bind(firebaseRef, "items", nonBooleanParam);
expect("Function should throw error given parameter: " + nonBooleanParam).toBeFalsy();
} catch (error) {
expect(error.code).toEqual("INVALID_BIND_AS_ARRAY");
}
});
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
it("_bind() does not throw error given valid inputs", function() {
var TestComponent = React.createClass({
mixins: [ReactFireMixin],
componentWillMount: function() {
var _this = this;
expect(function() { _this._bind(firebaseRef, "items", function() {}, true); }).not.toThrow();
expect(function() { _this._bind(firebaseRef, "items", function() {}, false); }).not.toThrow();
},
render: function() {
return React.DOM.div(null, "Testing");
}
});
React.render(new TestComponent(), document.body);
});
});
});