Files
kami-parse-server/spec/ParseUser.spec.js
2016-01-28 10:58:12 -08:00

1596 lines
49 KiB
JavaScript

// This is a port of the test suite:
// hungry/js/test/parse_user_test.js
//
// Things that we didn't port:
// Tests that involve revocable sessions.
// Tests that involve sending password reset emails.
var request = require('request');
var crypto = require('../crypto');
describe('Parse.User testing', () => {
it("user sign up class method", (done) => {
Parse.User.signUp("asdf", "zxcv", null, {
success: function(user) {
ok(user.getSessionToken());
done();
}
});
});
it("user sign up instance method", (done) => {
var user = new Parse.User();
user.setPassword("asdf");
user.setUsername("zxcv");
user.signUp(null, {
success: function(user) {
ok(user.getSessionToken());
done();
},
error: function(userAgain, error) {
ok(undefined, error);
}
});
});
it("user login wrong username", (done) => {
Parse.User.signUp("asdf", "zxcv", null, {
success: function(user) {
Parse.User.logIn("non_existent_user", "asdf3",
expectError(Parse.Error.OBJECT_NOT_FOUND, done));
}
});
});
it("user login wrong password", (done) => {
Parse.User.signUp("asdf", "zxcv", null, {
success: function(user) {
Parse.User.logIn("asdf", "asdfWrong",
expectError(Parse.Error.OBJECT_NOT_FOUND, done));
}
});
});
it("user login", (done) => {
Parse.User.signUp("asdf", "zxcv", null, {
success: function(user) {
Parse.User.logIn("asdf", "zxcv", {
success: function(user) {
equal(user.get("username"), "asdf");
done();
}
});
}
});
});
it("become", (done) => {
var user = null;
var sessionToken = null;
Parse.Promise.as().then(function() {
return Parse.User.signUp("Jason", "Parse", { "code": "red" });
}).then(function(newUser) {
equal(Parse.User.current(), newUser);
user = newUser;
sessionToken = newUser.getSessionToken();
ok(sessionToken);
Parse.User.logOut();
ok(!Parse.User.current());
return Parse.User.become(sessionToken);
}).then(function(newUser) {
equal(Parse.User.current(), newUser);
ok(newUser);
equal(newUser.id, user.id);
equal(newUser.get("username"), "Jason");
equal(newUser.get("code"), "red");
Parse.User.logOut();
ok(!Parse.User.current());
return Parse.User.become("somegarbage");
}).then(function() {
// This should have failed actually.
ok(false, "Shouldn't have been able to log in with garbage session token.");
}, function(error) {
ok(error);
// Handle the error.
return Parse.Promise.as();
}).then(function() {
done();
}, function(error) {
ok(false, error);
done();
});
});
it("cannot save non-authed user", (done) => {
var user = new Parse.User();
user.set({
"password": "asdf",
"email": "asdf@example.com",
"username": "zxcv"
});
user.signUp(null, {
success: function(userAgain) {
equal(userAgain, user);
var query = new Parse.Query(Parse.User);
query.get(user.id, {
success: function(userNotAuthed) {
user = new Parse.User();
user.set({
"username": "hacker",
"password": "password"
});
user.signUp(null, {
success: function(userAgain) {
equal(userAgain, user);
userNotAuthed.set("username", "changed");
userNotAuthed.save().then(fail, (err) => {
expect(err.code).toEqual(Parse.Error.SESSION_MISSING);
done();
});
},
error: function(model, error) {
ok(undefined, error);
}
});
},
error: function(model, error) {
ok(undefined, error);
}
});
}
});
});
it("cannot delete non-authed user", (done) => {
var user = new Parse.User();
user.signUp({
"password": "asdf",
"email": "asdf@example.com",
"username": "zxcv"
}, {
success: function() {
var query = new Parse.Query(Parse.User);
query.get(user.id, {
success: function(userNotAuthed) {
user = new Parse.User();
user.signUp({
"username": "hacker",
"password": "password"
}, {
success: function(userAgain) {
equal(userAgain, user);
userNotAuthed.set("username", "changed");
userNotAuthed.destroy(expectError(
Parse.Error.SESSION_MISSING, done));
}
});
}
});
}
});
});
it("cannot saveAll with non-authed user", (done) => {
var user = new Parse.User();
user.signUp({
"password": "asdf",
"email": "asdf@example.com",
"username": "zxcv"
}, {
success: function() {
var query = new Parse.Query(Parse.User);
query.get(user.id, {
success: function(userNotAuthed) {
user = new Parse.User();
user.signUp({
username: "hacker",
password: "password"
}, {
success: function() {
query.get(user.id, {
success: function(userNotAuthedNotChanged) {
userNotAuthed.set("username", "changed");
var object = new TestObject();
object.save({
user: userNotAuthedNotChanged
}, {
success: function(object) {
var item1 = new TestObject();
item1.save({
number: 0
}, {
success: function(item1) {
item1.set("number", 1);
var item2 = new TestObject();
item2.set("number", 2);
Parse.Object.saveAll(
[item1, item2, userNotAuthed],
expectError(Parse.Error.SESSION_MISSING, done));
}
});
}
});
}
});
}
});
}
});
}
});
});
it("current user", (done) => {
var user = new Parse.User();
user.set("password", "asdf");
user.set("email", "asdf@example.com");
user.set("username", "zxcv");
user.signUp(null, {
success: function() {
var currentUser = Parse.User.current();
equal(user.id, currentUser.id);
ok(user.getSessionToken());
var currentUserAgain = Parse.User.current();
// should be the same object
equal(currentUser, currentUserAgain);
// test logging out the current user
Parse.User.logOut();
equal(Parse.User.current(), null);
done();
}
});
});
it("user.isCurrent", (done) => {
var user1 = new Parse.User();
var user2 = new Parse.User();
var user3 = new Parse.User();
user1.set("username", "a");
user2.set("username", "b");
user3.set("username", "c");
user1.set("password", "password");
user2.set("password", "password");
user3.set("password", "password");
user1.signUp(null, {
success: function () {
equal(user1.isCurrent(), true);
equal(user2.isCurrent(), false);
equal(user3.isCurrent(), false);
user2.signUp(null, {
success: function() {
equal(user1.isCurrent(), false);
equal(user2.isCurrent(), true);
equal(user3.isCurrent(), false);
user3.signUp(null, {
success: function() {
equal(user1.isCurrent(), false);
equal(user2.isCurrent(), false);
equal(user3.isCurrent(), true);
Parse.User.logIn("a", "password", {
success: function(user1) {
equal(user1.isCurrent(), true);
equal(user2.isCurrent(), false);
equal(user3.isCurrent(), false);
Parse.User.logIn("b", "password", {
success: function(user2) {
equal(user1.isCurrent(), false);
equal(user2.isCurrent(), true);
equal(user3.isCurrent(), false);
Parse.User.logIn("b", "password", {
success: function(user3) {
equal(user1.isCurrent(), false);
equal(user2.isCurrent(), true);
equal(user3.isCurrent(), true);
Parse.User.logOut();
equal(user3.isCurrent(), false);
done();
}
});
}
});
}
});
}
});
}
});
}
});
});
it("user associations", (done) => {
var child = new TestObject();
child.save(null, {
success: function() {
var user = new Parse.User();
user.set("password", "asdf");
user.set("email", "asdf@example.com");
user.set("username", "zxcv");
user.set("child", child);
user.signUp(null, {
success: function() {
var object = new TestObject();
object.set("user", user);
object.save(null, {
success: function() {
var query = new Parse.Query(TestObject);
query.get(object.id, {
success: function(objectAgain) {
var userAgain = objectAgain.get("user");
userAgain.fetch({
success: function() {
equal(user.id, userAgain.id);
equal(userAgain.get("child").id, child.id);
done();
}
});
}
});
}
});
}
});
}
});
});
it("user queries", (done) => {
var user = new Parse.User();
user.set("password", "asdf");
user.set("email", "asdf@example.com");
user.set("username", "zxcv");
user.signUp(null, {
success: function() {
var query = new Parse.Query(Parse.User);
query.get(user.id, {
success: function(userAgain) {
equal(userAgain.id, user.id);
query.find({
success: function(users) {
equal(users.length, 1);
equal(users[0].id, user.id);
ok(userAgain.get("email"), "asdf@example.com");
done();
}
});
}
});
}
});
});
function signUpAll(list, optionsOrCallback) {
var promise = Parse.Promise.as();
list.forEach((user) => {
promise = promise.then(function() {
return user.signUp();
});
});
promise = promise.then(function() { return list; });
return promise._thenRunCallbacks(optionsOrCallback);
}
it("contained in user array queries", (done) => {
var USERS = 4;
var MESSAGES = 5;
// Make a list of users.
var userList = range(USERS).map(function(i) {
var user = new Parse.User();
user.set("password", "user_num_" + i);
user.set("email", "user_num_" + i + "@example.com");
user.set("username", "xinglblog_num_" + i);
return user;
});
signUpAll(userList, function(users) {
// Make a list of messages.
var messageList = range(MESSAGES).map(function(i) {
var message = new TestObject();
message.set("to", users[(i + 1) % USERS]);
message.set("from", users[i % USERS]);
return message;
});
// Save all the messages.
Parse.Object.saveAll(messageList, function(messages) {
// Assemble an "in" list.
var inList = [users[0], users[3], users[3]]; // Intentional dupe
var query = new Parse.Query(TestObject);
query.containedIn("from", inList);
query.find({
success: function(results) {
equal(results.length, 3);
done();
}
});
});
});
});
it("saving a user signs them up but doesn't log them in", (done) => {
var user = new Parse.User();
user.save({
password: "asdf",
email: "asdf@example.com",
username: "zxcv"
}, {
success: function() {
equal(Parse.User.current(), null);
done();
}
});
});
it("user updates", (done) => {
var user = new Parse.User();
user.signUp({
password: "asdf",
email: "asdf@example.com",
username: "zxcv"
}, {
success: function(user) {
user.set("username", "test");
user.save(null, {
success: function() {
equal(Object.keys(user.attributes).length, 6);
ok(user.attributes["username"]);
ok(user.attributes["email"]);
user.destroy({
success: function() {
var query = new Parse.Query(Parse.User);
query.get(user.id, {
error: function(model, error) {
// The user should no longer exist.
equal(error.code, Parse.Error.OBJECT_NOT_FOUND);
done();
}
});
},
error: function(model, error) {
ok(undefined, error);
}
});
},
error: function(model, error) {
ok(undefined, error);
}
});
},
error: function(model, error) {
ok(undefined, error);
}
});
});
it("count users", (done) => {
var james = new Parse.User();
james.set("username", "james");
james.set("password", "mypass");
james.signUp(null, {
success: function() {
var kevin = new Parse.User();
kevin.set("username", "kevin");
kevin.set("password", "mypass");
kevin.signUp(null, {
success: function() {
var query = new Parse.Query(Parse.User);
query.count({
success: function(count) {
equal(count, 2);
done();
}
});
}
});
}
});
});
it("user sign up with container class", (done) => {
Parse.User.signUp("ilya", "mypass", { "array": ["hello"] }, {
success: function() {
done();
}
});
});
it("user modified while saving", (done) => {
Parse.Object.disableSingleInstance();
var user = new Parse.User();
user.set("username", "alice");
user.set("password", "password");
user.signUp(null, {
success: function(userAgain) {
equal(userAgain.get("username"), "bob");
ok(userAgain.dirty("username"));
var query = new Parse.Query(Parse.User);
query.get(user.id, {
success: function(freshUser) {
equal(freshUser.id, user.id);
equal(freshUser.get("username"), "alice");
Parse.Object.enableSingleInstance();
done();
}
});
}
});
ok(user.set("username", "bob"));
});
it("user modified while saving with unsaved child", (done) => {
Parse.Object.disableSingleInstance();
var user = new Parse.User();
user.set("username", "alice");
user.set("password", "password");
user.set("child", new TestObject());
user.signUp(null, {
success: function(userAgain) {
equal(userAgain.get("username"), "bob");
// Should be dirty, but it depends on batch support.
// ok(userAgain.dirty("username"));
var query = new Parse.Query(Parse.User);
query.get(user.id, {
success: function(freshUser) {
equal(freshUser.id, user.id);
// Should be alice, but it depends on batch support.
equal(freshUser.get("username"), "bob");
Parse.Object.enableSingleInstance();
done();
}
});
}
});
ok(user.set("username", "bob"));
});
it("user loaded from localStorage from signup", (done) => {
Parse.User.signUp("alice", "password", null, {
success: function(alice) {
ok(alice.id, "Alice should have an objectId");
ok(alice.getSessionToken(), "Alice should have a session token");
equal(alice.get("password"), undefined,
"Alice should not have a password");
// Simulate the environment getting reset.
Parse.User._currentUser = null;
Parse.User._currentUserMatchesDisk = false;
var aliceAgain = Parse.User.current();
equal(aliceAgain.get("username"), "alice");
equal(aliceAgain.id, alice.id, "currentUser should have objectId");
ok(aliceAgain.getSessionToken(),
"currentUser should have a sessionToken");
equal(alice.get("password"), undefined,
"currentUser should not have password");
done();
}
});
});
it("user loaded from localStorage from login", (done) => {
Parse.User.signUp("alice", "password", null, {
success: function(alice) {
var id = alice.id;
Parse.User.logOut();
Parse.User.logIn("alice", "password", {
success: function(user) {
// Force the current user to read from disk
delete Parse.User._currentUser;
delete Parse.User._currentUserMatchesDisk;
var userFromDisk = Parse.User.current();
equal(userFromDisk.get("password"), undefined,
"password should not be in attributes");
equal(userFromDisk.id, id, "id should be set");
ok(userFromDisk.getSessionToken(),
"currentUser should have a sessionToken");
done();
}
});
}
});
});
it("saving user after browser refresh", (done) => {
var _ = Parse._;
var id;
Parse.User.signUp("alice", "password", null).then(function(alice) {
id = alice.id;
Parse.User.logOut();
return Parse.User.logIn("alice", "password");
}).then(function() {
// Simulate browser refresh by force-reloading user from localStorage
Parse.User._clearCache();
// Test that this save works correctly
return Parse.User.current().save({some_field: 1});
}).then(function() {
// Check the user in memory just after save operation
var userInMemory = Parse.User.current();
equal(userInMemory.getUsername(), "alice",
"saving user should not remove existing fields");
equal(userInMemory.get('some_field'), 1,
"saving user should save specified field");
equal(userInMemory.get("password"), undefined,
"password should not be in attributes after saving user");
equal(userInMemory.get("objectId"), undefined,
"objectId should not be in attributes after saving user");
equal(userInMemory.get("_id"), undefined,
"_id should not be in attributes after saving user");
equal(userInMemory.id, id, "id should be set");
expect(userInMemory.updatedAt instanceof Date).toBe(true);
ok(userInMemory.createdAt instanceof Date);
ok(userInMemory.getSessionToken(),
"user should have a sessionToken after saving");
// Force the current user to read from localStorage, and check again
delete Parse.User._currentUser;
delete Parse.User._currentUserMatchesDisk;
var userFromDisk = Parse.User.current();
equal(userFromDisk.getUsername(), "alice",
"userFromDisk should have previously existing fields");
equal(userFromDisk.get('some_field'), 1,
"userFromDisk should have saved field");
equal(userFromDisk.get("password"), undefined,
"password should not be in attributes of userFromDisk");
equal(userFromDisk.get("objectId"), undefined,
"objectId should not be in attributes of userFromDisk");
equal(userFromDisk.get("_id"), undefined,
"_id should not be in attributes of userFromDisk");
equal(userFromDisk.id, id, "id should be set on userFromDisk");
ok(userFromDisk.updatedAt instanceof Date);
ok(userFromDisk.createdAt instanceof Date);
ok(userFromDisk.getSessionToken(),
"userFromDisk should have a sessionToken");
done();
}, function(error) {
ok(false, error);
done();
});
});
it("user with missing username", (done) => {
var user = new Parse.User();
user.set("password", "foo");
user.signUp(null, {
success: function() {
ok(null, "This should have failed");
done();
},
error: function(userAgain, error) {
equal(error.code, Parse.Error.OTHER_CAUSE);
done();
}
});
});
it("user with missing password", (done) => {
var user = new Parse.User();
user.set("username", "foo");
user.signUp(null, {
success: function() {
ok(null, "This should have failed");
done();
},
error: function(userAgain, error) {
equal(error.code, Parse.Error.OTHER_CAUSE);
done();
}
});
});
it("user stupid subclassing", (done) => {
var SuperUser = Parse.Object.extend("User");
var user = new SuperUser();
user.set("username", "bob");
user.set("password", "welcome");
ok(user instanceof Parse.User, "Subclassing User should have worked");
user.signUp(null, {
success: function() {
done();
},
error: function() {
ok(false, "Signing up should have worked");
done();
}
});
});
it("user signup class method uses subclassing", (done) => {
var SuperUser = Parse.User.extend({
secret: function() {
return 1337;
}
});
Parse.User.signUp("bob", "welcome", null, {
success: function(user) {
ok(user instanceof SuperUser, "Subclassing User should have worked");
equal(user.secret(), 1337);
done();
},
error: function() {
ok(false, "Signing up should have worked");
done();
}
});
});
it("user on disk gets updated after save", (done) => {
var SuperUser = Parse.User.extend({
isSuper: function() {
return true;
}
});
Parse.User.signUp("bob", "welcome", null, {
success: function(user) {
// Modify the user and save.
user.save("secret", 1337, {
success: function() {
// Force the current user to read from disk
delete Parse.User._currentUser;
delete Parse.User._currentUserMatchesDisk;
var userFromDisk = Parse.User.current();
equal(userFromDisk.get("secret"), 1337);
ok(userFromDisk.isSuper(), "The subclass should have been used");
done();
},
error: function() {
ok(false, "Saving should have worked");
done();
}
});
},
error: function() {
ok(false, "Sign up should have worked");
done();
}
});
});
it("current user isn't dirty", (done) => {
Parse.User.signUp("andrew", "oppa", { style: "gangnam" }, expectSuccess({
success: function(user) {
ok(!user.dirty("style"), "The user just signed up.");
Parse.User._currentUser = null;
Parse.User._currentUserMatchesDisk = false;
var userAgain = Parse.User.current();
ok(!userAgain.dirty("style"), "The user was just read from disk.");
done();
}
}));
});
// Note that this mocks out client-side Facebook action rather than
// server-side.
var getMockFacebookProvider = function() {
return {
userId: "8675309",
authToken: "jenny",
expiration: new Date().toJSON(),
shouldError: false,
loggedOut: false,
synchronizedUserId: null,
synchronizedAuthToken: null,
synchronizedExpiration: null,
authenticate: function(options) {
if (this.shouldError) {
options.error(this, "An error occurred");
} else if (this.shouldCancel) {
options.error(this, null);
} else {
options.success(this, {
id: this.userId,
access_token: this.authToken,
expiration_date: this.expiration
});
}
},
restoreAuthentication: function(authData) {
if (!authData) {
this.synchronizedUserId = null;
this.synchronizedAuthToken = null;
this.synchronizedExpiration = null;
return true;
}
this.synchronizedUserId = authData.id;
this.synchronizedAuthToken = authData.access_token;
this.synchronizedExpiration = authData.expiration_date;
return true;
},
getAuthType: function() {
return "facebook";
},
deauthenticate: function() {
this.loggedOut = true;
this.restoreAuthentication(null);
}
};
};
var ExtendedUser = Parse.User.extend({
extended: function() {
return true;
}
});
it("log in with provider", (done) => {
var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", {
success: function(model) {
ok(model instanceof Parse.User, "Model should be a Parse.User");
strictEqual(Parse.User.current(), model);
ok(model.extended(), "Should have used subclass.");
strictEqual(provider.userId, provider.synchronizedUserId);
strictEqual(provider.authToken, provider.synchronizedAuthToken);
strictEqual(provider.expiration, provider.synchronizedExpiration);
ok(model._isLinked("facebook"), "User should be linked to facebook");
done();
},
error: function(model, error) {
ok(false, "linking should have worked");
done();
}
});
});
it("log in with provider twice", (done) => {
var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", {
success: function(model) {
ok(model instanceof Parse.User, "Model should be a Parse.User");
strictEqual(Parse.User.current(), model);
ok(model.extended(), "Should have used the subclass.");
strictEqual(provider.userId, provider.synchronizedUserId);
strictEqual(provider.authToken, provider.synchronizedAuthToken);
strictEqual(provider.expiration, provider.synchronizedExpiration);
ok(model._isLinked("facebook"), "User should be linked to facebook");
Parse.User.logOut();
ok(provider.loggedOut);
provider.loggedOut = false;
Parse.User._logInWith("facebook", {
success: function(innerModel) {
ok(innerModel instanceof Parse.User,
"Model should be a Parse.User");
ok(innerModel === Parse.User.current(),
"Returned model should be the current user");
ok(provider.userId === provider.synchronizedUserId);
ok(provider.authToken === provider.synchronizedAuthToken);
ok(innerModel._isLinked("facebook"),
"User should be linked to facebook");
ok(innerModel.existed(), "User should not be newly-created");
done();
},
error: function(model, error) {
ok(false, "LogIn should have worked");
done();
}
});
},
error: function(model, error) {
ok(false, "LogIn should have worked");
done();
}
});
});
it("log in with provider failed", (done) => {
var provider = getMockFacebookProvider();
provider.shouldError = true;
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", {
success: function(model) {
ok(false, "logIn should not have succeeded");
},
error: function(model, error) {
ok(error, "Error should be non-null");
done();
}
});
});
it("log in with provider cancelled", (done) => {
var provider = getMockFacebookProvider();
provider.shouldCancel = true;
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", {
success: function(model) {
ok(false, "logIn should not have succeeded");
},
error: function(model, error) {
ok(error === null, "Error should be null");
done();
}
});
});
it("link with provider", (done) => {
var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
var user = new Parse.User();
user.set("username", "testLinkWithProvider");
user.set("password", "mypass");
user.signUp(null, {
success: function(model) {
user._linkWith("facebook", {
success: function(model) {
ok(model instanceof Parse.User, "Model should be a Parse.User");
strictEqual(Parse.User.current(), model);
strictEqual(provider.userId, provider.synchronizedUserId);
strictEqual(provider.authToken, provider.synchronizedAuthToken);
strictEqual(provider.expiration, provider.synchronizedExpiration);
ok(model._isLinked("facebook"), "User should be linked");
done();
},
error: function(model, error) {
ok(false, "linking should have succeeded");
done();
}
});
},
error: function(model, error) {
ok(false, "signup should not have failed");
done();
}
});
});
// What this means is, only one Parse User can be linked to a
// particular Facebook account.
it("link with provider for already linked user", (done) => {
var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
var user = new Parse.User();
user.set("username", "testLinkWithProviderToAlreadyLinkedUser");
user.set("password", "mypass");
user.signUp(null, {
success: function(model) {
user._linkWith("facebook", {
success: function(model) {
ok(model instanceof Parse.User, "Model should be a Parse.User");
strictEqual(Parse.User.current(), model);
strictEqual(provider.userId, provider.synchronizedUserId);
strictEqual(provider.authToken, provider.synchronizedAuthToken);
strictEqual(provider.expiration, provider.synchronizedExpiration);
ok(model._isLinked("facebook"), "User should be linked.");
var user2 = new Parse.User();
user2.set("username", "testLinkWithProviderToAlreadyLinkedUser2");
user2.set("password", "mypass");
user2.signUp(null, {
success: function(model) {
user2._linkWith('facebook', {
success: fail,
error: function(model, error) {
expect(error.code).toEqual(
Parse.Error.ACCOUNT_ALREADY_LINKED);
done();
},
});
},
error: function(model, error) {
ok(false, "linking should have failed");
done();
}
});
},
error: function(model, error) {
ok(false, "linking should have succeeded");
done();
}
});
},
error: function(model, error) {
ok(false, "signup should not have failed");
done();
}
});
});
it("link with provider failed", (done) => {
var provider = getMockFacebookProvider();
provider.shouldError = true;
Parse.User._registerAuthenticationProvider(provider);
var user = new Parse.User();
user.set("username", "testLinkWithProvider");
user.set("password", "mypass");
user.signUp(null, {
success: function(model) {
user._linkWith("facebook", {
success: function(model) {
ok(false, "linking should fail");
done();
},
error: function(model, error) {
ok(error, "Linking should fail");
ok(!model._isLinked("facebook"),
"User should not be linked to facebook");
done();
}
});
},
error: function(model, error) {
ok(false, "signup should not have failed");
done();
}
});
});
it("link with provider cancelled", (done) => {
var provider = getMockFacebookProvider();
provider.shouldCancel = true;
Parse.User._registerAuthenticationProvider(provider);
var user = new Parse.User();
user.set("username", "testLinkWithProvider");
user.set("password", "mypass");
user.signUp(null, {
success: function(model) {
user._linkWith("facebook", {
success: function(model) {
ok(false, "linking should fail");
done();
},
error: function(model, error) {
ok(!error, "Linking should be cancelled");
ok(!model._isLinked("facebook"),
"User should not be linked to facebook");
done();
}
});
},
error: function(model, error) {
ok(false, "signup should not have failed");
done();
}
});
});
it("unlink with provider", (done) => {
var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", {
success: function(model) {
ok(model instanceof Parse.User, "Model should be a Parse.User.");
strictEqual(Parse.User.current(), model);
ok(model.extended(), "Should have used the subclass.");
strictEqual(provider.userId, provider.synchronizedUserId);
strictEqual(provider.authToken, provider.synchronizedAuthToken);
strictEqual(provider.expiration, provider.synchronizedExpiration);
ok(model._isLinked("facebook"), "User should be linked to facebook.");
model._unlinkFrom("facebook", {
success: function(model) {
ok(!model._isLinked("facebook"), "User should not be linked.");
ok(!provider.synchronizedUserId, "User id should be cleared.");
ok(!provider.synchronizedAuthToken,
"Auth token should be cleared.");
ok(!provider.synchronizedExpiration,
"Expiration should be cleared.");
done();
},
error: function(model, error) {
ok(false, "unlinking should succeed");
done();
}
});
},
error: function(model, error) {
ok(false, "linking should have worked");
done();
}
});
});
it("unlink and link", (done) => {
var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", {
success: function(model) {
ok(model instanceof Parse.User, "Model should be a Parse.User");
strictEqual(Parse.User.current(), model);
ok(model.extended(), "Should have used the subclass.");
strictEqual(provider.userId, provider.synchronizedUserId);
strictEqual(provider.authToken, provider.synchronizedAuthToken);
strictEqual(provider.expiration, provider.synchronizedExpiration);
ok(model._isLinked("facebook"), "User should be linked to facebook");
model._unlinkFrom("facebook", {
success: function(model) {
ok(!model._isLinked("facebook"),
"User should not be linked to facebook");
ok(!provider.synchronizedUserId, "User id should be cleared");
ok(!provider.synchronizedAuthToken, "Auth token should be cleared");
ok(!provider.synchronizedExpiration,
"Expiration should be cleared");
model._linkWith("facebook", {
success: function(model) {
ok(provider.synchronizedUserId, "User id should have a value");
ok(provider.synchronizedAuthToken,
"Auth token should have a value");
ok(provider.synchronizedExpiration,
"Expiration should have a value");
ok(model._isLinked("facebook"),
"User should be linked to facebook");
done();
},
error: function(model, error) {
ok(false, "linking again should succeed");
done();
}
});
},
error: function(model, error) {
ok(false, "unlinking should succeed");
done();
}
});
},
error: function(model, error) {
ok(false, "linking should have worked");
done();
}
});
});
it('set password then change password', (done) => {
Parse.User.signUp('bob', 'barker').then((bob) => {
bob.setPassword('meower');
return bob.save();
}).then(() => {
return Parse.User.logIn('bob', 'meower');
}).then((bob) => {
expect(bob.getUsername()).toEqual('bob');
done();
}, (e) => {
console.log(e);
fail();
});
});
it("authenticated check", (done) => {
var user = new Parse.User();
user.set("username", "darkhelmet");
user.set("password", "onetwothreefour");
ok(!user.authenticated());
user.signUp(null, expectSuccess({
success: function(result) {
ok(user.authenticated());
done();
}
}));
});
it("log in with explicit facebook auth data", (done) => {
Parse.FacebookUtils.logIn({
id: "8675309",
access_token: "jenny",
expiration_date: new Date().toJSON()
}, expectSuccess({success: done}));
});
it("log in async with explicit facebook auth data", (done) => {
Parse.FacebookUtils.logIn({
id: "8675309",
access_token: "jenny",
expiration_date: new Date().toJSON()
}).then(function() {
done();
}, function(error) {
ok(false, error);
done();
});
});
it("link with explicit facebook auth data", (done) => {
Parse.User.signUp("mask", "open sesame", null, expectSuccess({
success: function(user) {
Parse.FacebookUtils.link(user, {
id: "8675309",
access_token: "jenny",
expiration_date: new Date().toJSON()
}).then(done, (error) => {
fail(error);
done();
});
}
}));
});
it("link async with explicit facebook auth data", (done) => {
Parse.User.signUp("mask", "open sesame", null, expectSuccess({
success: function(user) {
Parse.FacebookUtils.link(user, {
id: "8675309",
access_token: "jenny",
expiration_date: new Date().toJSON()
}).then(function() {
done();
}, function(error) {
ok(false, error);
done();
});
}
}));
});
it("async methods", (done) => {
var data = { foo: "bar" };
Parse.User.signUp("finn", "human", data).then(function(user) {
equal(Parse.User.current(), user);
equal(user.get("foo"), "bar");
return Parse.User.logOut();
}).then(function() {
return Parse.User.logIn("finn", "human");
}).then(function(user) {
equal(user, Parse.User.current());
equal(user.get("foo"), "bar");
return Parse.User.logOut();
}).then(function() {
var user = new Parse.User();
user.set("username", "jake");
user.set("password", "dog");
user.set("foo", "baz");
return user.signUp();
}).then(function(user) {
equal(user, Parse.User.current());
equal(user.get("foo"), "baz");
user = new Parse.User();
user.set("username", "jake");
user.set("password", "dog");
return user.logIn();
}).then(function(user) {
equal(user, Parse.User.current());
equal(user.get("foo"), "baz");
var userAgain = new Parse.User();
userAgain.id = user.id;
return userAgain.fetch();
}).then(function(userAgain) {
equal(userAgain.get("foo"), "baz");
done();
});
});
it("querying for users doesn't get session tokens", (done) => {
Parse.Promise.as().then(function() {
return Parse.User.signUp("finn", "human", { foo: "bar" });
}).then(function() {
Parse.User.logOut();
var user = new Parse.User();
user.set("username", "jake");
user.set("password", "dog");
user.set("foo", "baz");
return user.signUp();
}).then(function() {
Parse.User.logOut();
var query = new Parse.Query(Parse.User);
return query.find();
}).then(function(users) {
equal(users.length, 2);
for (var user of users) {
ok(!user.getSessionToken(), "user should not have a session token.");
}
done();
}, function(error) {
ok(false, error);
done();
});
});
it("querying for users only gets the expected fields", (done) => {
Parse.Promise.as().then(() => {
return Parse.User.signUp("finn", "human", { foo: "bar" });
}).then(() => {
request.get({
headers: {'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest'},
url: 'http://localhost:8378/1/users',
}, (error, response, body) => {
expect(error).toBe(null);
var b = JSON.parse(body);
expect(b.results.length).toEqual(1);
var user = b.results[0];
expect(Object.keys(user).length).toEqual(5);
done();
});
});
});
it('user save should fail with invalid email', (done) => {
var user = new Parse.User();
user.set('username', 'teste');
user.set('password', 'test');
user.set('email', 'invalid');
user.signUp().then(() => {
fail('Should not have been able to save.');
done();
}, (error) => {
expect(error.code).toEqual(125);
done();
});
});
it('user signup should error if email taken', (done) => {
var user = new Parse.User();
user.set('username', 'test1');
user.set('password', 'test');
user.set('email', 'test@test.com');
user.signUp().then(() => {
var user2 = new Parse.User();
user2.set('username', 'test2');
user2.set('password', 'test');
user2.set('email', 'test@test.com');
return user2.signUp();
}).then(() => {
fail('Should not have been able to sign up.');
done();
}, (error) => {
done();
});
});
it('user cannot update email to existing user', (done) => {
var user = new Parse.User();
user.set('username', 'test1');
user.set('password', 'test');
user.set('email', 'test@test.com');
user.signUp().then(() => {
var user2 = new Parse.User();
user2.set('username', 'test2');
user2.set('password', 'test');
return user2.signUp();
}).then((user2) => {
user2.set('email', 'test@test.com');
return user2.save();
}).then(() => {
fail('Should not have been able to sign up.');
done();
}, (error) => {
done();
});
});
it('create session from user', (done) => {
Parse.Promise.as().then(() => {
return Parse.User.signUp("finn", "human", { foo: "bar" });
}).then((user) => {
request.post({
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Session-Token': user.getSessionToken(),
'X-Parse-REST-API-Key': 'rest'
},
url: 'http://localhost:8378/1/sessions',
}, (error, response, body) => {
expect(error).toBe(null);
var b = JSON.parse(body);
expect(typeof b.sessionToken).toEqual('string');
expect(typeof b.createdWith).toEqual('object');
expect(b.createdWith.action).toEqual('create');
expect(typeof b.user).toEqual('object');
expect(b.user.objectId).toEqual(user.id);
done();
});
});
});
it('user get session from token', (done) => {
Parse.Promise.as().then(() => {
return Parse.User.signUp("finn", "human", { foo: "bar" });
}).then((user) => {
request.get({
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Session-Token': user.getSessionToken(),
'X-Parse-REST-API-Key': 'rest'
},
url: 'http://localhost:8378/1/sessions/me',
}, (error, response, body) => {
expect(error).toBe(null);
var b = JSON.parse(body);
expect(typeof b.sessionToken).toEqual('string');
expect(typeof b.createdWith).toEqual('object');
expect(b.createdWith.action).toEqual('login');
expect(typeof b.user).toEqual('object');
expect(b.user.objectId).toEqual(user.id);
done();
});
});
});
it('user update session with other field', (done) => {
Parse.Promise.as().then(() => {
return Parse.User.signUp("finn", "human", { foo: "bar" });
}).then((user) => {
request.get({
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Session-Token': user.getSessionToken(),
'X-Parse-REST-API-Key': 'rest'
},
url: 'http://localhost:8378/1/sessions/me',
}, (error, response, body) => {
expect(error).toBe(null);
var b = JSON.parse(body);
request.put({
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Session-Token': user.getSessionToken()
},
url: 'http://localhost:8378/1/sessions/' + b.objectId,
body: JSON.stringify({ foo: 'bar' })
}, (error, response, body) => {
expect(error).toBe(null);
var b = JSON.parse(body);
done();
});
});
});
});
it('get session only for current user', (done) => {
Parse.Promise.as().then(() => {
return Parse.User.signUp("test1", "test", { foo: "bar" });
}).then(() => {
return Parse.User.signUp("test2", "test", { foo: "bar" });
}).then((user) => {
request.get({
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Session-Token': user.getSessionToken(),
'X-Parse-REST-API-Key': 'rest'
},
url: 'http://localhost:8378/1/sessions'
}, (error, response, body) => {
expect(error).toBe(null);
var b = JSON.parse(body);
expect(b.results.length).toEqual(1);
expect(typeof b.results[0].user).toEqual('object');
expect(b.results[0].user.objectId).toEqual(user.id);
done();
});
});
});
it('delete session by object', (done) => {
Parse.Promise.as().then(() => {
return Parse.User.signUp("test1", "test", { foo: "bar" });
}).then(() => {
return Parse.User.signUp("test2", "test", { foo: "bar" });
}).then((user) => {
request.get({
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Session-Token': user.getSessionToken(),
'X-Parse-REST-API-Key': 'rest'
},
url: 'http://localhost:8378/1/sessions'
}, (error, response, body) => {
expect(error).toBe(null);
var b = JSON.parse(body);
expect(b.results.length).toEqual(1);
var objId = b.results[0].objectId;
request.del({
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Session-Token': user.getSessionToken(),
'X-Parse-REST-API-Key': 'rest'
},
url: 'http://localhost:8378/1/sessions/' + objId
}, (error, response, body) => {
expect(error).toBe(null);
request.get({
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Session-Token': user.getSessionToken(),
'X-Parse-REST-API-Key': 'rest'
},
url: 'http://localhost:8378/1/sessions'
}, (error, response, body) => {
expect(error).toBe(null);
var b = JSON.parse(body);
expect(b.code).toEqual(209);
done();
});
});
});
});
});
it('password format matches hosted parse', (done) => {
var hashed = '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie';
crypto.compare('test', hashed)
.then((pass) => {
expect(pass).toBe(true);
done();
}, (e) => {
fail('Password format did not match.');
done();
});
});
it('changing password clears sessions', (done) => {
var sessionToken = null;
Parse.Promise.as().then(function() {
return Parse.User.signUp("fosco", "parse");
}).then(function(newUser) {
equal(Parse.User.current(), newUser);
sessionToken = newUser.getSessionToken();
ok(sessionToken);
newUser.set('password', 'facebook');
return newUser.save();
}).then(function() {
return Parse.User.become(sessionToken);
}).then(function(newUser) {
fail('Session should have been invalidated');
done();
}, function() {
done();
});
});
});