Skip to content

Commit

Permalink
Release v0.8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
bendrucker committed Dec 21, 2014
1 parent 4d5a4d0 commit 4e82c74
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 14 deletions.
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mockfirebase",
"version": "0.7.0",
"version": "0.8.0",
"homepage": "https://github.com/katowulf/mockfirebase",
"authors": [
"Kato"
Expand Down
254 changes: 242 additions & 12 deletions browser/mockfirebase.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/** mockfirebase - v0.7.0
/** mockfirebase - v0.8.0
https://github.com/katowulf/mockfirebase
* Copyright (c) 2014 Kato
* License: MIT */
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.mockfirebase=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';

exports.MockFirebase = require('./firebase');
/** @deprecated */
exports.MockFirebaseSimpleLogin = require('./login');

},{"./firebase":15,"./login":16}],2:[function(require,module,exports){
Expand Down Expand Up @@ -1507,7 +1508,7 @@ Buffer.prototype.copy = function (target, target_start, start, end) {

var len = end - start

if (len < 100 || !Buffer.TYPED_ARRAY_SUPPORT) {
if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
for (var i = 0; i < len; i++) {
target[i + target_start] = this[i + start]
}
Expand Down Expand Up @@ -1576,6 +1577,7 @@ var BP = Buffer.prototype
* Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods
*/
Buffer._augment = function (arr) {
arr.constructor = Buffer
arr._isBuffer = true

// save reference to original Uint8Array get/set methods before overwriting
Expand Down Expand Up @@ -9557,6 +9559,12 @@ function MockFirebase(currentPath, data, parent, name) {

// stores the last auto id generated by push() for tests
this._lastAutoId = null;

this._authUserData = null;
this._authListeners = [];
this._authCompletionListeners = [];
this._users = {};
this._uidCounter = 1;
}

MockFirebase.prototype = {
Expand Down Expand Up @@ -9701,7 +9709,7 @@ MockFirebase.prototype = {
*
* @param {string} event
* @param {string} key
* @param data
* @param [data]
* @param {string} [prevChild]
* @param [pri]
* @returns {MockFirebase}
Expand All @@ -9727,6 +9735,29 @@ MockFirebase.prototype = {
return this;
},

/**
* Modifies authentication state and changes the current user credentials. This will trigger
* any onAuth() listeners in the next flush() operation.
*
* @param {Object|null} userData if an object, it should contain all field specified here: https://www.firebase.com/docs/web/api/firebase/onauth.html
*/
changeAuthState: function (userData) {
var self = this;
this._defer(function() {
if (!_.isEqual(self._authUserData, userData)) {
self._authUserData = _.isObject(userData) ? userData : null;
self._triggerAuthEvent();
}
});
},

/**
* Retrieve an email user that was added with createUser()
*/
getEmailUser: function(email) {
return this._users.hasOwnProperty(email) ? _.extend({}, this._users[email]) : null;
},

/*****************************************************
* Firebase API methods
*****************************************************/
Expand Down Expand Up @@ -9943,26 +9974,150 @@ MockFirebase.prototype = {
return [valueFn, finishedFn, applyLocally];
},

/**********************************************************
* AUTHENTICATION METHODS
**********************************************************/

/**
* If token is valid and parses, returns the contents of token as exected. If not, the error is returned.
* Does not change behavior in any way (since we don't really auth anywhere)
*
* @param {String} token
* @param {Function} [callback]
* @deprecated
*/
auth: function(token, callback) {
//todo invoke callback with the parsed token contents
var err = this._nextErr('auth');
if (callback) {
console.warn('FIREBASE WARNING: FirebaseRef.auth() being deprecated. Please use FirebaseRef.authWithCustomToken() instead.');
this._authEvent('auth', callback);
},

/**
* If token is valid and parses, returns the contents of token as exected. If not, the error is returned.
* Does not change behavior in any way (since we don't really auth anywhere)
*
* @param {String} token
* @param {Function} [onComplete]
*/
authWithCustomToken: function(token, onComplete) {
this._authEvent('authWithCustomToken', onComplete);
},

authAnonymously: function(onComplete) {
this._authEvent('authAnonymously', onComplete);
},

authWithPassword: function(credentials, onComplete) {
this._authEvent('authWithPassword', onComplete);
},

authWithOAuthPopup: function(provider, onComplete) {
this._authEvent('authWithOAuthPopup', onComplete);
},

authWithOAuthRedirect: function(provider, onComplete) {
this._authEvent('authWithOAuthRedirect', onComplete);
},

authWithOAuthToken: function(provider, credentials, onComplete) {
this._authEvent('authWithOAuthToken', onComplete);
},

_authEvent: function(method, callback) {
var err = this._nextErr(method);
if (!callback) return;
if (err) {
// if an error occurs, we defer the error report until the next flush()
// event is triggered
this._defer(function() {
var auth = { auth: { id: 'test', _token: token }, expires: (new Date()).to_i / 1000 };
if( err === null ) {
callback(null, auth);
} else {
callback(err);
}
callback(err, null);
});
}
else {
// if there is no error, then we just add our callback to the listener
// stack and wait for the next changeAuthState() call.
this._authCompletionListeners.push({fn: callback});
}
},

getAuth: function() {
return this._authUserData;
},

onAuth: function(onComplete, context) {
this._authListeners.push({fn: onComplete, ctx: context});
},

offAuth: function(onComplete, context) {
var index = _.findIndex(this._authListeners, function(v) {
return v.fn === onComplete && v.ctx === context;
});
if (index > -1) {
this._authListeners.splice(index, 1);
}
},

unauth: function() {
if (this._authUserData !== null) {
this._authUserData = null;
this._triggerAuthEvent();
}
},

createUser: function(credentials, onComplete) {
var err = this._nextErr('createUser');
var users = this._users;
this._defer(_.bind(function() {
var user = null;
err = err ||
this._validateCreds('createUser', credentials, ['email', 'password']) ||
this._validateNewEmail(credentials);
if( !err ) {
var key = credentials.email;
users[key] = {uid: this._nextUid(), email: key, password: credentials.password};
user = {uid: users[key].uid};
}
onComplete(err, user);
}, this));
},

changePassword: function(credentials, onComplete) {
var err = this._nextErr('changePassword');
this._defer(_.bind(function() {
err = err ||
this._validateCreds('changePassword', credentials, ['email', 'oldPassword', 'newPassword']) ||
this._validateExistingEmail(credentials) ||
this._validPass(credentials, 'oldPassword');
if( !err ) {
var key = credentials.email;
var user = this._users[key];
user.password = credentials.newPassword;
}
onComplete(err);
}, this));
},

removeUser: function(credentials, onComplete) {
var err = this._nextErr('removeUser');
this._defer(_.bind(function() {
err = err ||
this._validateCreds('removeUser', credentials, ['email', 'password']) ||
this._validateExistingEmail(credentials) ||
this._validPass(credentials, 'password');
if( !err ) {
delete this._users[credentials.email];
}
onComplete(err);
}, this));
},

resetPassword: function(credentials, onComplete) {
var err = this._nextErr('resetPassword');
this._defer(_.bind(function() {
err = err ||
this._validateCreds('resetPassword', credentials, ['email']) ||
this._validateExistingEmail(credentials);
onComplete(err);
}, this));
},

/**
Expand All @@ -9985,6 +10140,65 @@ MockFirebase.prototype = {
* Private/internal methods
*****************************************************/

_nextUid: function() {
return 'simplelogin:'+(this._uidCounter++);
},

_validateNewEmail: function(creds) {
creds = _.assign({}, creds);
if( this._users.hasOwnProperty(creds.email) ) {
var err = new Error('The specified email address is already in use.');
err.code = 'EMAIL_TAKEN';
return err;
}
return null;
},

_validateExistingEmail: function(creds) {
creds = _.assign({}, creds);
if( !this._users.hasOwnProperty(creds.email) ) {
var err = new Error('The specified user does not exist.');
err.code = 'INVALID_USER';
return err;
}
return null;
},

_validateCreds: function(method, creds, fields) {
var err = this._validObj(creds, method, 'First');
var i = 0;
while (err === null && i < fields.length) {
err = this._validArg(method, creds, 'First', fields[i], 'string');
i++;
}
return err;
},

_validPass: function(obj, name) {
var err = null;
var key = obj.email;
if( obj[name] !== this._users[key].password ) {
err = new Error('The specified password is incorrect.');
err.code = 'INVALID_PASSWORD';
}
return err;
},

_validObj: function(obj, method, position) {
if( !_.isObject(obj) ) {
return new Error('Firebase.' + method + ' failed: ' + position + ' argument must be a valid object.');
}
return null;
},

_validArg: function(method, obj, position, name, type) {
if( !obj.hasOwnProperty(name) || typeof(obj[name]) !== type ) {
return new Error('Firebase.' + method + ' failed: ' + position +
' argument must contain the key "' + name + '" with type "' + type + '"');
}
return null;
},

_childChanged: function(ref) {
var events = [];
var childKey = ref.key();
Expand Down Expand Up @@ -10107,6 +10321,21 @@ MockFirebase.prototype = {
}
},

_triggerAuthEvent: function() {
var list = this._authCompletionListeners;
// clear the completion list before triggering callbacks
this._authCompletionListeners = [];
var user = this._authUserData;
// trigger completion listeners first
_.forEach(list, function(parts) {
parts.fn.call(parts.ctx, null, _.cloneDeep(user));
});
// then trigger onAuth listeners
_.forEach(this._authListeners, function(parts) {
parts.fn.call(parts.ctx, _.cloneDeep(user));
});
},

_updateOrAdd: function(key, data, events) {
var exists = _.isObject(this.data) && this.data.hasOwnProperty(key);
if( !exists ) {
Expand Down Expand Up @@ -10217,6 +10446,7 @@ var md5 = require('MD5');

/*******************************************************************************
* SIMPLE LOGIN
* @deprecated
******************************************************************************/
function MockFirebaseSimpleLogin (ref, callback, userData) {
// allows test units to monitor the callback function to make sure
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mockfirebase",
"version": "0.7.0",
"version": "0.8.0",
"description": "An experimental Firebase stub/spy library for writing unit tests (not supported by Firebase)",
"main": "./src",
"scripts": {
Expand Down

0 comments on commit 4e82c74

Please sign in to comment.