From be272aadad829880c3bb9a85a816c475c3306741 Mon Sep 17 00:00:00 2001 From: James Talmage Date: Wed, 21 Oct 2015 23:38:39 -0400 Subject: [PATCH 1/4] drop mockfirebase for offline firebase-copy --- .travis.yml | 7 ++-- index.js | 86 +++++++++++++++++++++++++++++++-------------- package.json | 5 +-- test/server.spec.js | 43 ++++++++++++----------- 4 files changed, 89 insertions(+), 52 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1cf03be..e1182c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,9 @@ language: node_js node_js: - - "0.10" - - "0.12" - - "4.0.0" + - "stable" +# - "0.10" +# - "0.12" + before_script: - npm install -g grunt-cli sudo: false diff --git a/index.js b/index.js index 9073bb4..6d83a1c 100644 --- a/index.js +++ b/index.js @@ -8,10 +8,12 @@ var _ = require('lodash'); var WebSocketServer = require('ws').Server; -var mockfirebase = require('mockfirebase'); var Ruleset = require('targaryen/lib/ruleset'); var RuleDataSnapshot = require('targaryen/lib/rule-data-snapshot'); var firebaseHash = require('./lib/firebaseHash'); +var Promise = require('bluebird'); // jshint ignore:line +var firebaseCopy = require('firebase-copy'); +var co = require('co'); var loggingEnabled = false; @@ -20,11 +22,33 @@ function _log(message) { console.log('[firebase-server] ' + message); } } +function getSnap(ref) { + return new Promise(function (resolve) { + ref.once('value', function (snap) { + resolve(snap); + }); + }); +} + +function getValue(ref) { + return getSnap(ref).then(function (snap) { + return snap.val(); + }); +} + +function getExport(ref) { + return getSnap(ref).then(function (snap) { + return snap.exportVal(); + }); +} function FirebaseServer(port, name, data) { + this.Firebase = firebaseCopy(); this.name = name || 'mock.firebase.server'; - this.mockFb = new mockfirebase.MockFirebase('https://' + this.name + '/', data); - this.mockFb.autoFlush(1); + this.Firebase.goOffline(); + this.baseRef = new this.Firebase('ws://fakeserver.firebaseio.com'); + + this.baseRef.set(data || null); this._wss = new WebSocketServer({ port: port @@ -57,11 +81,11 @@ FirebaseServer.prototype = { send({d: {r: requestId, b: {s: 'permission_denied', d: 'Permission denied'}}, t: 'd'}); } - function handleListen(requestId, path, fbRef) { + var handleListen = co.wrap(function *(requestId, path, fbRef) { _log('Client listen ' + path); if (server._ruleset) { - var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(fbRef.root().getData())); + var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(yield getExport(fbRef.root()))); var result = server._ruleset.tryRead(path, dataSnap); if (!result.allowed) { _log('Permission denied for client to read from ' + path + ': ' + result.info); @@ -70,24 +94,24 @@ FirebaseServer.prototype = { return; } - var currentData = fbRef.getData(); + var currentData = yield getExport(fbRef); if ((typeof currentData !== 'undefined') && (currentData !== null)) { - pushData(path, fbRef.getData()); + pushData(path, currentData); } send({d: {r: requestId, b: {s: 'ok', d: {}}}, t: 'd'}); fbRef.on('value', function (snap) { if (snap.val()) { - pushData(path, fbRef.getData()); + pushData(path, snap.exportVal()); } }); - } + }); - function handleUpdate(requestId, path, fbRef, newData) { + var handleUpdate = co.wrap(function *(requestId, path, fbRef, newData) { _log('Client update ' + path); if (server._ruleset) { - var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(fbRef.root().getData())); - var mergedData = _.assign(fbRef.getData(), newData); + var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(yield getExport(fbRef.root()))); + var mergedData = _.assign(yield getExport(fbRef), newData); var result = server._ruleset.tryWrite(path, dataSnap, mergedData); if (!result.allowed) { _log('Permission denied for client to write to ' + path + ': ' + result.info); @@ -96,17 +120,17 @@ FirebaseServer.prototype = { return; } - fbRef.update(newData, function () { - // TODO check for failure + fbRef.update(newData); + setTimeout(function () { send({d: {r: requestId, b: {s: 'ok', d: {}}}, t: 'd'}); }); - } + }); - function handleSet(requestId, path, fbRef, newData, hash) { + var handleSet = co.wrap(function *(requestId, path, fbRef, newData, hash) { _log('Client set ' + path); if (server._ruleset) { - var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(fbRef.root().getData())); + var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(yield getExport(fbRef.root()))); var result = server._ruleset.tryWrite(path, dataSnap, newData); if (!result.allowed) { _log('Permission denied for client to write to ' + path + ': ' + result.info); @@ -116,20 +140,22 @@ FirebaseServer.prototype = { } if (typeof hash !== 'undefined') { - var calculatedHash = firebaseHash(fbRef.getData()); + var snap = yield getSnap(fbRef); + var calculatedHash = firebaseHash(snap.exportVal()); if (hash !== calculatedHash) { - pushData(path, fbRef.getData()); + pushData(path, snap.exportVal()); send({d: {r: requestId, b: {s: 'datastale', d: 'Transaction hash does not match'}}, t: 'd'}); return; } } - fbRef.set(newData, function () { + fbRef.set(newData); + setTimeout(co.wrap (function *() { // TODO check for failure - pushData(path, fbRef.getData()); + pushData(path, yield getExport(fbRef)); send({d: {r: requestId, b: {s: 'ok', d: {}}}, t: 'd'}); - }); - } + })); + }); ws.on('message', function (data) { _log('Client message: ' + data); @@ -143,7 +169,7 @@ FirebaseServer.prototype = { path = parsed.d.b.p.substr(1); } var requestId = parsed.d.r; - var fbRef = path ? this.mockFb.child(path) : this.mockFb; + var fbRef = path ? this.baseRef.child(path) : this.baseRef; if (parsed.d.a === 'l' || parsed.d.a === 'q') { handleListen(requestId, path, fbRef); } @@ -163,8 +189,16 @@ FirebaseServer.prototype = { this._ruleset = new Ruleset(rules); }, - getData: function () { - return this.mockFb.getData(); + getSnap: function (ref) { + return getSnap(ref || this.baseRef); + }, + + getValue: function (ref) { + return getValue(ref || this.baseRef); + }, + + getExport: function (ref) { + return getExport(ref || this.baseRef); }, close: function () { diff --git a/package.json b/package.json index eb1ed4d..40e2b49 100644 --- a/package.json +++ b/package.json @@ -36,13 +36,14 @@ "grunt-contrib-jshint": "^0.11.2", "grunt-mocha-cov": "^0.4.0", "load-grunt-tasks": "^3.2.0", - "lodash": "^3.9.3", "mocha": "^2.2.5", "mockery": "^1.4.0" }, "dependencies": { + "co": "^4.6.0", + "firebase-copy": "^0.1.1", "lodash": "^3.10.1", - "mockfirebase": "^0.11.0", + "bluebird": "^1.2.0", "targaryen": "^1.1.4", "ws": "0.7.2" } diff --git a/test/server.spec.js b/test/server.spec.js index d3eb0f5..fc95993 100644 --- a/test/server.spec.js +++ b/test/server.spec.js @@ -15,6 +15,7 @@ var assert = require('assert'); var Firebase; var FirebaseServer = require('../index'); +var co = require('co'); // Firebase has strict requirements about the hostname format. So we provide a dummy // hostname and then change the URL to localhost inside the faye-websocket's Client @@ -104,9 +105,9 @@ describe('Firebase Server', function () { client.child('states').update({ NY: 'New York', CA: 'Toronto' - }, function (err) { + }, co.wrap(function *(err) { assert.ok(!err, 'update() call returned an error'); - assert.deepEqual(server.getData(), { + assert.deepEqual(yield server.getValue(), { states: { NY: 'New York', CA: 'Toronto', @@ -115,7 +116,7 @@ describe('Firebase Server', function () { } }); done(); - }); + })); }); }); @@ -125,13 +126,13 @@ describe('Firebase Server', function () { var client = new Firebase(newServerUrl()); client.set({ 'foo': 'bar' - }, function (err) { + }, co.wrap(function *(err) { assert.ok(!err, 'set() call returned an error'); - assert.deepEqual(server.getData(), { + assert.deepEqual(yield server.getValue(), { 'foo': 'bar' }); done(); - }); + })); }); }); @@ -142,13 +143,13 @@ describe('Firebase Server', function () { 'child2': 5 }); var client = new Firebase(newServerUrl()); - client.child('child1').remove(function (err) { + client.child('child1').remove(co.wrap(function *(err) { assert.ok(!err, 'remove() call returned an error'); - assert.deepEqual(server.getData(), { + assert.deepEqual(yield server.getValue(), { 'child2': 5 }); done(); - }); + })); }); it('should trigger a "value" event with null', function (done) { @@ -176,13 +177,13 @@ describe('Firebase Server', function () { client.child('users').child('wilma').transaction(function (currentData) { assert.equal(currentData, null); return {name: {first: 'Wilma', last: 'Flintstone'}}; - }, function (error, committed, snapshot) { + }, co.wrap(function *(error, committed, snapshot) { assert.equal(error, null); assert.equal(committed, true); assert.deepEqual(snapshot.val(), {name: {first: 'Wilma', last: 'Flintstone'}}); - assert.deepEqual(server.getData(), {users: {wilma: {name: {first: 'Wilma', last: 'Flintstone'}}}}); + assert.deepEqual(yield server.getValue(), {users: {wilma: {name: {first: 'Wilma', last: 'Flintstone'}}}}); done(); - }); + })); }); it('should return existing data inside the updateFunction function', function (done) { @@ -235,13 +236,13 @@ describe('Firebase Server', function () { } else { return; } - }, function (error, committed, snapshot) { + }, co.wrap(function *(error, committed, snapshot) { assert.equal(error, null); assert.equal(committed, false); assert.deepEqual(snapshot.val(), {name: {first: 'Uri', last: 'Shaked'}}); - assert.deepEqual(server.getData(), {users: {uri: {name: {first: 'Uri', last: 'Shaked'}}}}); + assert.deepEqual(yield server.getValue(), {users: {uri: {name: {first: 'Uri', last: 'Shaked'}}}}); done(); - }); + })); }); }); @@ -279,14 +280,14 @@ describe('Firebase Server', function () { var client = new Firebase(newServerUrl()); client.set({ 'foo': 'bar' - }, function (err) { + }, co.wrap(function *(err) { assert.ok(err, 'set() should have returned an error'); assert.equal(err.code, 'PERMISSION_DENIED'); - assert.deepEqual(server.getData(), { + assert.deepEqual(yield server.getValue(), { Firebase: 'great!' }); done(); - }); + })); }); it('should forbid updates when there is no write permission', function(done) { @@ -302,14 +303,14 @@ describe('Firebase Server', function () { var client = new Firebase(newServerUrl()); client.update({ 'foo': 'bar' - }, function (err) { + }, co.wrap(function *(err) { assert.ok(err, 'update() should have returned an error'); assert.equal(err.code, 'PERMISSION_DENIED'); - assert.deepEqual(server.getData(), { + assert.deepEqual(yield server.getValue(), { Firebase: 'great!' }); done(); - }); + })); }); }); }); From 2753379b4e79c7ff68647b6b025b2192e5b1f33c Mon Sep 17 00:00:00 2001 From: James Talmage Date: Fri, 23 Oct 2015 11:54:39 -0400 Subject: [PATCH 2/4] fix coverage reports switches to istanbul --- .gitignore | 1 + .npmignore | 2 -- .travis.yml | 5 +++-- Gruntfile.js | 45 --------------------------------------------- package.json | 25 +++++++++++-------------- 5 files changed, 15 insertions(+), 63 deletions(-) delete mode 100644 .npmignore delete mode 100644 Gruntfile.js diff --git a/.gitignore b/.gitignore index 6684c76..80b1aac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /.idea /node_modules +/coverage diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 7a1537b..0000000 --- a/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea -node_modules diff --git a/.travis.yml b/.travis.yml index e1182c7..67642fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ node_js: # - "0.10" # - "0.12" -before_script: - - npm install -g grunt-cli +after_script: + - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js + sudo: false diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 537c906..0000000 --- a/Gruntfile.js +++ /dev/null @@ -1,45 +0,0 @@ -/* License: MIT. - * Copyright (C) 2013, 2014, Uri Shaked. - */ - -'use strict'; - -module.exports = function (grunt) { - require('load-grunt-tasks')(grunt); - - grunt.initConfig({ - jshint: { - options: { - jshintrc: '.jshintrc' - }, - all: [ - 'Gruntfile.js', - 'index.js', - 'lib/*.js', - 'test/*.js' - ] - }, - mochacov: { - all: ['test/*.spec.js'], - test: { - options: { - reporter: 'spec' - } - }, - coverage: { - options: { - reporter: 'mocha-lcov-reporter', - coveralls: true - } - } - } - }); - - var testTasks = ['jshint', 'mochacov:test']; - if (process.env.TRAVIS === 'true') { - testTasks.push('mochacov:coverage'); - } - grunt.registerTask('test', testTasks); - - grunt.registerTask('default', ['test']); -}; diff --git a/package.json b/package.json index 40e2b49..c50ba82 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,9 @@ "description": "Simple Firebase Server", "main": "index.js", "scripts": { - "test": "grunt test" + "test": "npm run lint && npm run cover", + "cover": "istanbul cover ./node_modules/.bin/_mocha", + "lint": "jshint index.js lib/*.js test/*.js" }, "repository": { "type": "git", @@ -20,22 +22,17 @@ "url": "https://github.com/urish/firebase-server/issues" }, "homepage": "https://github.com/urish/firebase-server", - "config": { - "blanket": { - "pattern": [ - "lib", - "index.js" - ], - "data-cover-never": "node_modules" - } - }, + "files": [ + "index.js", + "lib/*.js", + "CHANGELOG.md" + ], "devDependencies": { + "coveralls": "^2.11.4", "faye-websocket": "0.10.0", "firebase": "^2.2.5", - "grunt": "^0.4.5", - "grunt-contrib-jshint": "^0.11.2", - "grunt-mocha-cov": "^0.4.0", - "load-grunt-tasks": "^3.2.0", + "istanbul": "^0.4.0", + "jshint": "^2.8.0", "mocha": "^2.2.5", "mockery": "^1.4.0" }, From 8aa2e8121793eb5b27abd4c73f2e764a8bb45e17 Mon Sep 17 00:00:00 2001 From: James Talmage Date: Fri, 23 Oct 2015 12:05:42 -0400 Subject: [PATCH 3/4] enable tests on Node 0.10, and 0.12 --- .travis.yml | 4 ++-- package.json | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 67642fe..e318181 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: node_js node_js: - "stable" -# - "0.10" -# - "0.12" + - "0.10" + - "0.12" after_script: - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js diff --git a/package.json b/package.json index c50ba82..3eb8534 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "test": "npm run lint && npm run cover", - "cover": "istanbul cover ./node_modules/.bin/_mocha", + "cover": "istanbul cover ./node_modules/.bin/_mocha -- $(node-version --lt-4.0.0 --compilers js:babel/register)", + "debug": "mocha $(node-version --lt-4.0.0 --compilers js:babel/register)", "lint": "jshint index.js lib/*.js test/*.js" }, "repository": { @@ -28,13 +29,15 @@ "CHANGELOG.md" ], "devDependencies": { + "babel": "^5.8.23", "coveralls": "^2.11.4", "faye-websocket": "0.10.0", "firebase": "^2.2.5", "istanbul": "^0.4.0", "jshint": "^2.8.0", "mocha": "^2.2.5", - "mockery": "^1.4.0" + "mockery": "^1.4.0", + "node-version-cli": "^1.1.4" }, "dependencies": { "co": "^4.6.0", From 43f0f068ab22fb3967573cec43a216672c05c806 Mon Sep 17 00:00:00 2001 From: James Talmage Date: Fri, 23 Oct 2015 14:40:21 -0400 Subject: [PATCH 4/4] reimplement in es5 --- index.js | 139 ++++++++++++++++++++++++------------------ package.json | 10 +-- test/es5-only-test.js | 95 +++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+), 62 deletions(-) create mode 100644 test/es5-only-test.js diff --git a/index.js b/index.js index 6d83a1c..c9cc51e 100644 --- a/index.js +++ b/index.js @@ -11,9 +11,8 @@ var WebSocketServer = require('ws').Server; var Ruleset = require('targaryen/lib/ruleset'); var RuleDataSnapshot = require('targaryen/lib/rule-data-snapshot'); var firebaseHash = require('./lib/firebaseHash'); -var Promise = require('bluebird'); // jshint ignore:line +var Promise = require('native-or-bluebird'); // jshint ignore:line var firebaseCopy = require('firebase-copy'); -var co = require('co'); var loggingEnabled = false; @@ -22,6 +21,7 @@ function _log(message) { console.log('[firebase-server] ' + message); } } + function getSnap(ref) { return new Promise(function (resolve) { ref.once('value', function (snap) { @@ -81,81 +81,104 @@ FirebaseServer.prototype = { send({d: {r: requestId, b: {s: 'permission_denied', d: 'Permission denied'}}, t: 'd'}); } - var handleListen = co.wrap(function *(requestId, path, fbRef) { - _log('Client listen ' + path); + function ruleSnapshot(fbRef) { + return getExport(fbRef.root()).then(function (exportVal) { + return new RuleDataSnapshot(RuleDataSnapshot.convert(exportVal)); + }); + } + function tryRead(requestId, path, fbRef) { if (server._ruleset) { - var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(yield getExport(fbRef.root()))); - var result = server._ruleset.tryRead(path, dataSnap); - if (!result.allowed) { - _log('Permission denied for client to read from ' + path + ': ' + result.info); - permissionDenied(requestId); - } - return; + return ruleSnapshot(fbRef).then(function (dataSnap) { + var result = server._ruleset.tryRead(path, dataSnap); + if (!result.allowed) { + permissionDenied(requestId); + throw new Error('Permission denied for client to read from ' + path + ': ' + result.info); + } + return true; + }); } + return Promise.resolve(true); + } - var currentData = yield getExport(fbRef); - if ((typeof currentData !== 'undefined') && (currentData !== null)) { - pushData(path, currentData); + function tryWrite(requestId, path, fbRef, newData) { + if (server._ruleset) { + return ruleSnapshot(fbRef).then(function (dataSnap) { + var result = server._ruleset.tryWrite(path, dataSnap, newData); + if (!result.allowed) { + permissionDenied(requestId); + throw new Error('Permission denied for client to write to ' + path + ': ' + result.info); + } + return true; + }); } - send({d: {r: requestId, b: {s: 'ok', d: {}}}, t: 'd'}); - fbRef.on('value', function (snap) { - if (snap.val()) { - pushData(path, snap.exportVal()); - } - }); - }); + return Promise.resolve(true); + } + + function handleListen(requestId, path, fbRef) { + _log('Client listen ' + path); + + tryRead(requestId, path, fbRef) + .then(function () { + var sendOk = true; + fbRef.on('value', function (snap) { + if (snap.val()) { + pushData(path, snap.exportVal()); + } + if (sendOk) { + sendOk = false; + send({d: {r: requestId, b: {s: 'ok', d: {}}}, t: 'd'}); + } + }); + }) + .catch(_log); + } - var handleUpdate = co.wrap(function *(requestId, path, fbRef, newData) { + function handleUpdate(requestId, path, fbRef, newData) { _log('Client update ' + path); + var checkPermission = Promise.resolve(true); + if (server._ruleset) { - var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(yield getExport(fbRef.root()))); - var mergedData = _.assign(yield getExport(fbRef), newData); - var result = server._ruleset.tryWrite(path, dataSnap, mergedData); - if (!result.allowed) { - _log('Permission denied for client to write to ' + path + ': ' + result.info); - permissionDenied(requestId); - } - return; + checkPermission = getExport(fbRef).then(function (currentData) { + var mergedData = _.assign(currentData, newData); + return tryWrite(requestId, path, fbRef, mergedData); + }); } - fbRef.update(newData); - setTimeout(function () { + checkPermission.then(function () { + fbRef.update(newData); send({d: {r: requestId, b: {s: 'ok', d: {}}}, t: 'd'}); - }); - }); + }).catch(_log); + } - var handleSet = co.wrap(function *(requestId, path, fbRef, newData, hash) { + function handleSet(requestId, path, fbRef, newData, hash) { _log('Client set ' + path); - if (server._ruleset) { - var dataSnap = new RuleDataSnapshot(RuleDataSnapshot.convert(yield getExport(fbRef.root()))); - var result = server._ruleset.tryWrite(path, dataSnap, newData); - if (!result.allowed) { - _log('Permission denied for client to write to ' + path + ': ' + result.info); - permissionDenied(requestId); - } - return; - } + var progress = + tryWrite(requestId, path, fbRef, newData); if (typeof hash !== 'undefined') { - var snap = yield getSnap(fbRef); - var calculatedHash = firebaseHash(snap.exportVal()); - if (hash !== calculatedHash) { - pushData(path, snap.exportVal()); - send({d: {r: requestId, b: {s: 'datastale', d: 'Transaction hash does not match'}}, t: 'd'}); - return; - } + progress = progress.then(function () { + return getSnap(fbRef); + }).then (function (snap) { + var calculatedHash = firebaseHash(snap.exportVal()); + if (hash !== calculatedHash) { + pushData(path, snap.exportVal()); + send({d: {r: requestId, b: {s: 'datastale', d: 'Transaction hash does not match'}}, t: 'd'}); + throw new Error('Transaction hash does not match: ' + hash + ' !==' + calculatedHash); + } + }); } - fbRef.set(newData); - setTimeout(co.wrap (function *() { - // TODO check for failure - pushData(path, yield getExport(fbRef)); - send({d: {r: requestId, b: {s: 'ok', d: {}}}, t: 'd'}); - })); - }); + progress.then(function () { + fbRef.set(newData); + fbRef.once('value', function (snap) { + pushData(path, snap.exportVal()); + send({d: {r: requestId, b: {s: 'ok', d: {}}}, t: 'd'}); + }); + }).catch(_log); + } ws.on('message', function (data) { _log('Client message: ' + data); diff --git a/package.json b/package.json index 3eb8534..e77a36a 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,9 @@ "description": "Simple Firebase Server", "main": "index.js", "scripts": { - "test": "npm run lint && npm run cover", - "cover": "istanbul cover ./node_modules/.bin/_mocha -- $(node-version --lt-4.0.0 --compilers js:babel/register)", + "test": "npm run lint && npm run cover && npm run test-es5", + "cover": "istanbul cover ./node_modules/.bin/_mocha -- $(node-version --lt-4.0.0 --compilers js:babel/register) test/*.spec.js", + "test-es5": "mocha test/es5-only-test.js", "debug": "mocha $(node-version --lt-4.0.0 --compilers js:babel/register)", "lint": "jshint index.js lib/*.js test/*.js" }, @@ -30,6 +31,8 @@ ], "devDependencies": { "babel": "^5.8.23", + "bluebird": "^1.2.0", + "co": "^4.6.0", "coveralls": "^2.11.4", "faye-websocket": "0.10.0", "firebase": "^2.2.5", @@ -40,10 +43,9 @@ "node-version-cli": "^1.1.4" }, "dependencies": { - "co": "^4.6.0", "firebase-copy": "^0.1.1", "lodash": "^3.10.1", - "bluebird": "^1.2.0", + "native-or-bluebird": "^1.2.0", "targaryen": "^1.1.4", "ws": "0.7.2" } diff --git a/test/es5-only-test.js b/test/es5-only-test.js new file mode 100644 index 0000000..3dbd749 --- /dev/null +++ b/test/es5-only-test.js @@ -0,0 +1,95 @@ +/* License: MIT. + * Copyright (C) 2013, 2014, 2015, Uri Shaked. + */ + +// COPY OF ES5 based tests to prove basic functionality without using babel. + +'use strict'; + +/* global beforeEach, afterEach, describe, it */ + +var PORT = 45000; + +var mockery = require('mockery'); +var originalWebsocket = require('faye-websocket'); +var _ = require('lodash'); +var assert = require('assert'); + +var Firebase; +var FirebaseServer = require('../index'); + +// Firebase has strict requirements about the hostname format. So we provide a dummy +// hostname and then change the URL to localhost inside the faye-websocket's Client +// constructor. +var websocketMock = _.defaults({ + Client: function (url) { + url = url.replace(/dummy\d+\.firebaseio\.test/i, 'localhost').replace('wss://', 'ws://'); + return new originalWebsocket.Client(url); + } +}, originalWebsocket); +mockery.registerMock('faye-websocket', websocketMock); + +describe('ES5 Only Tests', function () { + var server; + var sequentialConnectionId = 0; + + beforeEach(function () { + mockery.enable({ + warnOnUnregistered: false + }); + + Firebase = require('firebase'); + }); + + afterEach(function () { + if (server) { + server.close(); + server = null; + } + }); + + function newServerUrl() { + return 'ws://dummy' + (sequentialConnectionId++) + '.firebaseio.test:' + PORT; + } + + it('should successfully accept a client connection', function (done) { + server = new FirebaseServer(PORT, 'localhost:' + PORT); + var client = new Firebase(newServerUrl()); + client.once('value', function (snap) { + assert.equal(snap.val(), null); + done(); + }); + }); + + it('should accept initial data as the third constructor parameter', function (done) { + server = new FirebaseServer(PORT, 'localhost:' + PORT, { + Firebase: 'great!' + }); + var client = new Firebase(newServerUrl()); + client.on('value', function (snap) { + if (snap.val() === null) { + return; + } + assert.deepEqual(snap.val(), { + Firebase: 'great!' + }); + client.off('value'); + done(); + }); + }); + + it('should return the correct value for child nodes', function (done) { + server = new FirebaseServer(PORT, 'localhost:' + PORT, { + states: { + CA: 'California', + AL: 'Alabama', + KY: 'Kentucky' + } + }); + var client = new Firebase(newServerUrl()); + client.child('states').child('CA').once('value', function (snap) { + assert.equal(snap.val(), 'California'); + done(); + }); + }); +});