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

1740 lines
50 KiB
JavaScript

// This is a port of the test suite:
// hungry/js/test/parse_object_test.js
//
// Things we didn't port:
// Tests that aren't async, because they only test the client.
// Tests that use Relations, because we intentionally do not support
// relations.
// Tests that use 'testDestroy', because they have a complex
// dependency on the terrible qunit start/stop mechanism.
// Tests for unfetching, since that behaves differently in
// single-instance mode and we don't want these tests to run in
// single-instance mode.
describe('Parse.Object testing', () => {
it("create", function(done) {
create({ "test" : "test" }, function(model, response) {
ok(model.id, "Should have an objectId set");
equal(model.get("test"), "test", "Should have the right attribute");
done();
});
});
it("update", function(done) {
create({ "test" : "test" }, function(model, response) {
var t2 = new TestObject({ objectId: model.id });
t2.set("test", "changed");
t2.save(null, {
success: function(model, response) {
equal(model.get("test"), "changed", "Update should have succeeded");
done();
}
});
});
});
it("save without null", function(done) {
var object = new TestObject();
object.set("favoritePony", "Rainbow Dash");
object.save({
success: function(objectAgain) {
equal(objectAgain, object);
done();
},
error: function(objectAgain, error) {
ok(null, "Error " + error.code + ": " + error.message);
done();
}
});
});
it("save cycle", function(done) {
var a = new Parse.Object("TestObject");
var b = new Parse.Object("TestObject");
a.set("b", b);
a.save().then(function() {
b.set("a", a);
return b.save();
}).then(function() {
ok(a.id);
ok(b.id);
strictEqual(a.get("b"), b);
strictEqual(b.get("a"), a);
}).then(function() {
done();
}, function(error) {
ok(false, error);
done();
});
});
it("get", function(done) {
create({ "test" : "test" }, function(model, response) {
var t2 = new TestObject({ objectId: model.id });
t2.fetch({
success: function(model2, response) {
equal(model2.get("test"), "test", "Update should have succeeded");
ok(model2.id);
equal(model2.id, model.id, "Ids should match");
done();
}
});
});
});
it("delete", function(done) {
var t = new TestObject();
t.set("test", "test");
t.save(null, {
success: function() {
t.destroy({
success: function() {
var t2 = new TestObject({ objectId: t.id });
t2.fetch().then(fail, done);
}
});
}
});
});
it("find", function(done) {
var t = new TestObject();
t.set("foo", "bar");
t.save(null, {
success: function() {
var query = new Parse.Query(TestObject);
query.equalTo("foo", "bar");
query.find({
success: function(results) {
equal(results.length, 1);
done();
}
});
}
});
});
it("relational fields", function(done) {
var item = new Item();
item.set("property", "x");
var container = new Container();
container.set("item", item);
Parse.Object.saveAll([item, container], {
success: function() {
var query = new Parse.Query(Container);
query.find({
success: function(results) {
equal(results.length, 1);
var containerAgain = results[0];
var itemAgain = containerAgain.get("item");
itemAgain.fetch({
success: function() {
equal(itemAgain.get("property"), "x");
done();
}
});
}
});
}
});
});
it("save adds no data keys (other than createdAt and updatedAt)",
function(done) {
var object = new TestObject();
object.save(null, {
success: function() {
var keys = Object.keys(object.attributes).sort();
equal(keys.length, 2);
done();
}
});
});
it("recursive save", function(done) {
var item = new Item();
item.set("property", "x");
var container = new Container();
container.set("item", item);
container.save(null, {
success: function() {
var query = new Parse.Query(Container);
query.find({
success: function(results) {
equal(results.length, 1);
var containerAgain = results[0];
var itemAgain = containerAgain.get("item");
itemAgain.fetch({
success: function() {
equal(itemAgain.get("property"), "x");
done();
}
});
}
});
}
});
});
it("fetch", function(done) {
var item = new Item({ foo: "bar" });
item.save(null, {
success: function() {
var itemAgain = new Item();
itemAgain.id = item.id;
itemAgain.fetch({
success: function() {
itemAgain.save({ foo: "baz" }, {
success: function() {
item.fetch({
success: function() {
equal(item.get("foo"), itemAgain.get("foo"));
done();
}
});
}
});
}
});
}
});
});
it("createdAt doesn't change", function(done) {
var object = new TestObject({ foo: "bar" });
object.save(null, {
success: function() {
var objectAgain = new TestObject();
objectAgain.id = object.id;
objectAgain.fetch({
success: function() {
equal(object.createdAt.getTime(), objectAgain.createdAt.getTime());
done();
}
});
}
});
});
it("createdAt and updatedAt exposed", function(done) {
var object = new TestObject({ foo: "bar" });
object.save(null, {
success: function() {
notEqual(object.updatedAt, undefined);
notEqual(object.createdAt, undefined);
done();
}
});
});
it("updatedAt gets updated", function(done) {
var object = new TestObject({ foo: "bar" });
object.save(null, {
success: function() {
ok(object.updatedAt, "initial save should cause updatedAt to exist");
var firstUpdatedAt = object.updatedAt;
object.save({ foo: "baz" }, {
success: function() {
ok(object.updatedAt, "two saves should cause updatedAt to exist");
notEqual(firstUpdatedAt, object.updatedAt);
done();
}
});
}
});
});
it("createdAt is reasonable", function(done) {
var startTime = new Date();
var object = new TestObject({ foo: "bar" });
object.save(null, {
success: function() {
var endTime = new Date();
var startDiff = Math.abs(startTime.getTime() -
object.createdAt.getTime());
ok(startDiff < 5000);
var endDiff = Math.abs(endTime.getTime() -
object.createdAt.getTime());
ok(endDiff < 5000);
done();
}
});
});
it("can set null", function(done) {
var obj = new Parse.Object("TestObject");
obj.set("foo", null);
obj.save(null, {
success: function(obj) {
equal(obj.get("foo"), null);
done();
},
error: function(obj, error) {
ok(false, error.message);
done();
}
});
});
it("can set boolean", function(done) {
var obj = new Parse.Object("TestObject");
obj.set("yes", true);
obj.set("no", false);
obj.save(null, {
success: function(obj) {
equal(obj.get("yes"), true);
equal(obj.get("no"), false);
done();
},
error: function(obj, error) {
ok(false, error.message);
done();
}
});
});
it('cannot set invalid date', function(done) {
var obj = new Parse.Object('TestObject');
obj.set('when', new Date(Date.parse(null)));
try {
obj.save();
} catch (e) {
ok(true);
done();
return;
}
ok(false, 'Saving an invalid date should throw');
done();
});
it("invalid class name", function(done) {
var item = new Parse.Object("Foo^bar");
item.save(null, {
success: function(item) {
ok(false, "The name should have been invalid.");
done();
},
error: function(item, error) {
// Because the class name is invalid, the router will not be able to route
// it, so it will actually return a -1 error code.
// equal(error.code, Parse.Error.INVALID_CLASS_NAME);
done();
}
});
});
it("invalid key name", function(done) {
var item = new Parse.Object("Item");
ok(!item.set({"foo^bar": "baz"}),
'Item should not be updated with invalid key.');
item.save({ "foo^bar": "baz" }).then(fail, done);
});
it("simple field deletion", function(done) {
var simple = new Parse.Object("SimpleObject");
simple.save({
foo: "bar"
}, {
success: function(simple) {
simple.unset("foo");
ok(!simple.has("foo"), "foo should have been unset.");
ok(simple.dirty("foo"), "foo should be dirty.");
ok(simple.dirty(), "the whole object should be dirty.");
simple.save(null, {
success: function(simple) {
ok(!simple.has("foo"), "foo should have been unset.");
ok(!simple.dirty("foo"), "the whole object was just saved.");
ok(!simple.dirty(), "the whole object was just saved.");
var query = new Parse.Query("SimpleObject");
query.get(simple.id, {
success: function(simpleAgain) {
ok(!simpleAgain.has("foo"), "foo should have been removed.");
done();
},
error: function(simpleAgain, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simple, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simple, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
});
it("field deletion before first save", function(done) {
var simple = new Parse.Object("SimpleObject");
simple.set("foo", "bar");
simple.unset("foo");
ok(!simple.has("foo"), "foo should have been unset.");
ok(simple.dirty("foo"), "foo should be dirty.");
ok(simple.dirty(), "the whole object should be dirty.");
simple.save(null, {
success: function(simple) {
ok(!simple.has("foo"), "foo should have been unset.");
ok(!simple.dirty("foo"), "the whole object was just saved.");
ok(!simple.dirty(), "the whole object was just saved.");
var query = new Parse.Query("SimpleObject");
query.get(simple.id, {
success: function(simpleAgain) {
ok(!simpleAgain.has("foo"), "foo should have been removed.");
done();
},
error: function(simpleAgain, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simple, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
});
it("relation deletion", function(done) {
var simple = new Parse.Object("SimpleObject");
var child = new Parse.Object("Child");
simple.save({
child: child
}, {
success: function(simple) {
simple.unset("child");
ok(!simple.has("child"), "child should have been unset.");
ok(simple.dirty("child"), "child should be dirty.");
ok(simple.dirty(), "the whole object should be dirty.");
simple.save(null, {
success: function(simple) {
ok(!simple.has("child"), "child should have been unset.");
ok(!simple.dirty("child"), "the whole object was just saved.");
ok(!simple.dirty(), "the whole object was just saved.");
var query = new Parse.Query("SimpleObject");
query.get(simple.id, {
success: function(simpleAgain) {
ok(!simpleAgain.has("child"), "child should have been removed.");
done();
},
error: function(simpleAgain, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simple, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simple, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
});
it("deleted keys get cleared", function(done) {
var simpleObject = new Parse.Object("SimpleObject");
simpleObject.set("foo", "bar");
simpleObject.unset("foo");
simpleObject.save(null, {
success: function(simpleObject) {
simpleObject.set("foo", "baz");
simpleObject.save(null, {
success: function(simpleObject) {
var query = new Parse.Query("SimpleObject");
query.get(simpleObject.id, {
success: function(simpleObjectAgain) {
equal(simpleObjectAgain.get("foo"), "baz");
done();
},
error: function(simpleObject, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simpleObject, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simpleObject, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
});
it("setting after deleting", function(done) {
var simpleObject = new Parse.Object("SimpleObject");
simpleObject.set("foo", "bar");
simpleObject.save(null, {
success: function(simpleObject) {
simpleObject.unset("foo");
simpleObject.set("foo", "baz");
simpleObject.save(null, {
success: function(simpleObject) {
var query = new Parse.Query("SimpleObject");
query.get(simpleObject.id, {
success: function(simpleObjectAgain) {
equal(simpleObjectAgain.get("foo"), "baz");
done();
},
error: function(simpleObject, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simpleObject, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
},
error: function(simpleObject, error) {
ok(false, "Error " + error.code + ": " + error.message);
done();
}
});
});
it("increment", function(done) {
var simple = new Parse.Object("SimpleObject");
simple.save({
foo: 5
}, {
success: function(simple) {
simple.increment("foo");
equal(simple.get("foo"), 6);
ok(simple.dirty("foo"), "foo should be dirty.");
ok(simple.dirty(), "the whole object should be dirty.");
simple.save(null, {
success: function(simple) {
equal(simple.get("foo"), 6);
ok(!simple.dirty("foo"), "the whole object was just saved.");
ok(!simple.dirty(), "the whole object was just saved.");
var query = new Parse.Query("SimpleObject");
query.get(simple.id, {
success: function(simpleAgain) {
equal(simpleAgain.get("foo"), 6);
done();
}
});
}
});
}
});
});
it("addUnique", function(done) {
var x1 = new Parse.Object('X');
x1.set('stuff', [1, 2]);
x1.save().then(() => {
var objectId = x1.id;
var x2 = new Parse.Object('X', {objectId: objectId});
x2.addUnique('stuff', 2);
x2.addUnique('stuff', 3);
expect(x2.get('stuff')).toEqual([2, 3]);
return x2.save();
}).then(() => {
var query = new Parse.Query('X');
return query.get(x1.id);
}).then((x3) => {
expect(x3.get('stuff')).toEqual([1, 2, 3]);
done();
}, (error) => {
fail(error);
done();
});
});
it("dirty attributes", function(done) {
var object = new Parse.Object("TestObject");
object.set("cat", "good");
object.set("dog", "bad");
object.save({
success: function(object) {
ok(!object.dirty());
ok(!object.dirty("cat"));
ok(!object.dirty("dog"));
object.set("dog", "okay");
ok(object.dirty());
ok(!object.dirty("cat"));
ok(object.dirty("dog"));
done();
},
error: function(object, error) {
ok(false, "This should have saved.");
done();
}
});
});
it("dirty keys", function(done) {
var object = new Parse.Object("TestObject");
object.set("gogo", "good");
object.set("sito", "sexy");
ok(object.dirty());
var dirtyKeys = object.dirtyKeys();
equal(dirtyKeys.length, 2);
ok(arrayContains(dirtyKeys, "gogo"));
ok(arrayContains(dirtyKeys, "sito"));
object.save().then(function(obj) {
ok(!obj.dirty());
dirtyKeys = obj.dirtyKeys();
equal(dirtyKeys.length, 0);
ok(!arrayContains(dirtyKeys, "gogo"));
ok(!arrayContains(dirtyKeys, "sito"));
// try removing keys
obj.unset("sito");
ok(obj.dirty());
dirtyKeys = obj.dirtyKeys();
equal(dirtyKeys.length, 1);
ok(!arrayContains(dirtyKeys, "gogo"));
ok(arrayContains(dirtyKeys, "sito"));
return obj.save();
}).then(function(obj) {
ok(!obj.dirty());
equal(obj.get("gogo"), "good");
equal(obj.get("sito"), undefined);
dirtyKeys = obj.dirtyKeys();
equal(dirtyKeys.length, 0);
ok(!arrayContains(dirtyKeys, "gogo"));
ok(!arrayContains(dirtyKeys, "sito"));
done();
});
});
it("length attribute", function(done) {
Parse.User.signUp("bob", "password", null, {
success: function(user) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject({
length: 5,
ACL: new Parse.ACL(user) // ACLs cause things like validation to run
});
equal(obj.get("length"), 5);
ok(obj.get("ACL") instanceof Parse.ACL);
obj.save(null, {
success: function(obj) {
equal(obj.get("length"), 5);
ok(obj.get("ACL") instanceof Parse.ACL);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(obj) {
equal(obj.get("length"), 5);
ok(obj.get("ACL") instanceof Parse.ACL);
var query = new Parse.Query(TestObject);
query.find({
success: function(results) {
obj = results[0];
equal(obj.get("length"), 5);
ok(obj.get("ACL") instanceof Parse.ACL);
done();
},
error: function(error) {
ok(false, error.code + ": " + error.message);
done();
}
});
},
error: function(obj, error) {
ok(false, error.code + ": " + error.message);
done();
}
});
},
error: function(obj, error) {
ok(false, error.code + ": " + error.message);
done();
}
});
},
error: function(user, error) {
ok(false, error.code + ": " + error.message);
done();
}
});
});
it("old attribute unset then unset", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.set("x", 3);
obj.save({
success: function() {
obj.unset("x");
obj.unset("x");
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
}
});
});
it("new attribute unset then unset", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.set("x", 5);
obj.unset("x");
obj.unset("x");
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
});
it("unknown attribute unset then unset", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.unset("x");
obj.unset("x");
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
});
it("old attribute unset then clear", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.set("x", 3);
obj.save({
success: function() {
obj.unset("x");
obj.clear();
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
}
});
});
it("new attribute unset then clear", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.set("x", 5);
obj.unset("x");
obj.clear();
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
});
it("unknown attribute unset then clear", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.unset("x");
obj.clear();
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
});
it("old attribute clear then unset", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.set("x", 3);
obj.save({
success: function() {
obj.clear();
obj.unset("x");
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
}
});
});
it("new attribute clear then unset", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.set("x", 5);
obj.clear();
obj.unset("x");
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
});
it("unknown attribute clear then unset", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.clear();
obj.unset("x");
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
});
it("old attribute clear then clear", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.set("x", 3);
obj.save({
success: function() {
obj.clear();
obj.clear();
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
}
});
});
it("new attribute clear then clear", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.set("x", 5);
obj.clear();
obj.clear();
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
});
it("unknown attribute clear then clear", function(done) {
var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject();
obj.clear();
obj.clear();
obj.save({
success: function() {
equal(obj.has("x"), false);
equal(obj.get("x"), undefined);
var query = new Parse.Query(TestObject);
query.get(obj.id, {
success: function(objAgain) {
equal(objAgain.has("x"), false);
equal(objAgain.get("x"), undefined);
done();
}
});
}
});
});
it("saving children in an array", function(done) {
var Parent = Parse.Object.extend("Parent");
var Child = Parse.Object.extend("Child");
var child1 = new Child();
var child2 = new Child();
var parent = new Parent();
child1.set('name', 'jamie');
child2.set('name', 'cersei');
parent.set('children', [child1, child2]);
parent.save(null, {
success: function(parent) {
var query = new Parse.Query(Child);
query.ascending('name');
query.find({
success: function(results) {
equal(results.length, 2);
equal(results[0].get('name'), 'cersei');
equal(results[1].get('name'), 'jamie');
done();
}
});
},
error: function(error) {
fail(error);
done();
}
});
});
it("two saves at the same time", function(done) {
var object = new Parse.Object("TestObject");
var firstSave = true;
var success = function() {
if (firstSave) {
firstSave = false;
return;
}
var query = new Parse.Query("TestObject");
query.find({
success: function(results) {
equal(results.length, 1);
equal(results[0].get("cat"), "meow");
equal(results[0].get("dog"), "bark");
done();
}
});
};
var options = { success: success, error: fail };
object.save({ cat: "meow" }, options);
object.save({ dog: "bark" }, options);
});
// The schema-checking parts of this are working.
// We dropped the part where number can be reset to a correctly
// typed field and saved okay, since that appears to be borked in
// the client.
// If this fails, it's probably a schema issue.
it('many saves after a failure', function(done) {
// Make a class with a number in the schema.
var o1 = new Parse.Object('TestObject');
o1.set('number', 1);
var object = null;
o1.save().then(() => {
object = new Parse.Object('TestObject');
object.set('number', 'two');
return object.save();
}).then(fail, (error) => {
expect(error.code).toEqual(Parse.Error.INCORRECT_TYPE);
object.set('other', 'foo');
return object.save();
}).then(fail, (error) => {
expect(error.code).toEqual(Parse.Error.INCORRECT_TYPE);
object.set('other', 'bar');
return object.save();
}).then(fail, (error) => {
expect(error.code).toEqual(Parse.Error.INCORRECT_TYPE);
done();
});
});
it("is not dirty after save", function(done) {
var obj = new Parse.Object("TestObject");
obj.save(expectSuccess({
success: function() {
obj.set({ "content": "x" });
obj.fetch(expectSuccess({
success: function(){
equal(false, obj.dirty("content"));
done();
}
}));
}
}));
});
it("add with an object", function(done) {
var child = new Parse.Object("Person");
var parent = new Parse.Object("Person");
Parse.Promise.as().then(function() {
return child.save();
}).then(function() {
parent.add("children", child);
return parent.save();
}).then(function() {
var query = new Parse.Query("Person");
return query.get(parent.id);
}).then(function(parentAgain) {
equal(parentAgain.get("children")[0].id, child.id);
}).then(function() {
done();
}, function(error) {
ok(false, error);
done();
});
});
it("toJSON saved object", function(done) {
var _ = Parse._;
create({ "foo" : "bar" }, function(model, response) {
var objJSON = model.toJSON();
ok(objJSON.foo, "expected json to contain key 'foo'");
ok(objJSON.objectId, "expected json to contain key 'objectId'");
ok(objJSON.createdAt, "expected json to contain key 'createdAt'");
ok(objJSON.updatedAt, "expected json to contain key 'updatedAt'");
done();
});
});
it("remove object from array", function(done) {
var obj = new TestObject();
obj.save(null, expectSuccess({
success: function() {
var container = new TestObject();
container.add("array", obj);
equal(container.get("array").length, 1);
container.save(null, expectSuccess({
success: function() {
var objAgain = new TestObject();
objAgain.id = obj.id;
container.remove("array", objAgain);
equal(container.get("array").length, 0);
done();
}
}));
}
}));
});
it("async methods", function(done) {
var obj = new TestObject();
obj.set("time", "adventure");
obj.save().then(function(obj) {
ok(obj.id, "objectId should not be null.");
var objAgain = new TestObject();
objAgain.id = obj.id;
return objAgain.fetch();
}).then(function(objAgain) {
equal(objAgain.get("time"), "adventure");
return objAgain.destroy();
}).then(function() {
var query = new Parse.Query(TestObject);
return query.find();
}).then(function(results) {
equal(results.length, 0);
}).then(function() {
done();
});
});
it("fail validation with promise", function(done) {
var PickyEater = Parse.Object.extend("PickyEater", {
validate: function(attrs) {
if (attrs.meal === "tomatoes") {
return "Ew. Tomatoes are gross.";
}
return Parse.Object.prototype.validate.apply(this, arguments);
}
});
var bryan = new PickyEater();
bryan.save({
meal: "burrito"
}).then(function() {
return bryan.save({
meal: "tomatoes"
});
}, function(error) {
ok(false, "Save should have succeeded.");
}).then(function() {
ok(false, "Save should have failed.");
}, function(error) {
equal(error, "Ew. Tomatoes are gross.");
done();
});
});
it("beforeSave doesn't make object dirty with new field", function(done) {
var restController = Parse.CoreManager.getRESTController();
var r = restController.request;
restController.request = function() {
return r.apply(this, arguments).then(function(result) {
result.aDate = {"__type":"Date", "iso":"2014-06-24T06:06:06.452Z"};
return result;
});
};
var obj = new Parse.Object("Thing");
obj.save().then(function() {
ok(!obj.dirty(), "The object should not be dirty");
ok(obj.get('aDate'));
}).always(function() {
restController.request = r;
done();
});
});
it("beforeSave doesn't make object dirty with existing field", function(done) {
var restController = Parse.CoreManager.getRESTController();
var r = restController.request;
restController.request = function() {
return r.apply(this, arguments).then(function(result) {
result.aDate = {"__type":"Date", "iso":"2014-06-24T06:06:06.452Z"};
return result;
});
};
var now = new Date();
var obj = new Parse.Object("Thing");
var promise = obj.save();
obj.set('aDate', now);
promise.then(function() {
ok(obj.dirty(), "The object should be dirty");
equal(now, obj.get('aDate'));
}).always(function() {
restController.request = r;
done();
});
});
it("bytes work", function(done) {
Parse.Promise.as().then(function() {
var obj = new TestObject();
obj.set("bytes", { __type: "Bytes", base64: "ZnJveW8=" });
return obj.save();
}).then(function(obj) {
var query = new Parse.Query(TestObject);
return query.get(obj.id);
}).then(function(obj) {
equal(obj.get("bytes").__type, "Bytes");
equal(obj.get("bytes").base64, "ZnJveW8=");
done();
}, function(error) {
ok(false, JSON.stringify(error));
done();
});
});
it("destroyAll no objects", function(done) {
Parse.Object.destroyAll([], function(success, error) {
ok(success && !error, "Should be able to destroy no objects");
done();
});
});
it("destroyAll new objects only", function(done) {
var objects = [new TestObject(), new TestObject()];
Parse.Object.destroyAll(objects, function(success, error) {
ok(success && !error, "Should be able to destroy only new objects");
done();
});
});
it("fetchAll", function(done) {
var numItems = 11;
var container = new Container();
var items = [];
for (var i = 0; i < numItems; i++) {
var item = new Item();
item.set("x", i);
items.push(item);
}
Parse.Object.saveAll(items).then(function() {
container.set("items", items);
return container.save();
}).then(function() {
var query = new Parse.Query(Container);
return query.get(container.id);
}).then(function(containerAgain) {
var itemsAgain = containerAgain.get("items");
if (!itemsAgain || !itemsAgain.forEach) {
fail('no itemsAgain retrieved', itemsAgain);
done();
return;
}
equal(itemsAgain.length, numItems, "Should get the array back");
itemsAgain.forEach(function(item, i) {
var newValue = i*2;
item.set("x", newValue);
});
return Parse.Object.saveAll(itemsAgain);
}).then(function() {
return Parse.Object.fetchAll(items);
}).then(function(fetchedItemsAgain) {
equal(fetchedItemsAgain.length, numItems,
"Number of items fetched should not change");
fetchedItemsAgain.forEach(function(item, i) {
equal(item.get("x"), i*2);
});
done();
});
});
it("fetchAll no objects", function(done) {
Parse.Object.fetchAll([], function(success, error) {
ok(success && !error, "Should be able to fetchAll no objects");
done();
});
});
it("fetchAll updates dates", function(done) {
var updatedObject;
var object = new TestObject();
object.set("x", 7);
object.save().then(function() {
var query = new Parse.Query(TestObject);
return query.find(object.id);
}).then(function(results) {
updatedObject = results[0];
updatedObject.set("x", 11);
return updatedObject.save();
}).then(function() {
return Parse.Object.fetchAll([object]);
}).then(function() {
equal(object.createdAt.getTime(), updatedObject.createdAt.getTime());
equal(object.updatedAt.getTime(), updatedObject.updatedAt.getTime());
done();
});
});
it("fetchAll backbone-style callbacks", function(done) {
var numItems = 11;
var container = new Container();
var items = [];
for (var i = 0; i < numItems; i++) {
var item = new Item();
item.set("x", i);
items.push(item);
}
Parse.Object.saveAll(items).then(function() {
container.set("items", items);
return container.save();
}).then(function() {
var query = new Parse.Query(Container);
return query.get(container.id);
}).then(function(containerAgain) {
var itemsAgain = containerAgain.get("items");
if (!itemsAgain || !itemsAgain.forEach) {
fail('no itemsAgain retrieved', itemsAgain);
done();
return;
}
equal(itemsAgain.length, numItems, "Should get the array back");
itemsAgain.forEach(function(item, i) {
var newValue = i*2;
item.set("x", newValue);
});
return Parse.Object.saveAll(itemsAgain);
}).then(function() {
return Parse.Object.fetchAll(items, {
success: function(fetchedItemsAgain) {
equal(fetchedItemsAgain.length, numItems,
"Number of items fetched should not change");
fetchedItemsAgain.forEach(function(item, i) {
equal(item.get("x"), i*2);
});
done();
},
error: function(error) {
ok(false, "Failed to fetchAll");
done();
}
});
});
});
it("fetchAll error on multiple classes", function(done) {
var container = new Container();
container.set("item", new Item());
container.set("subcontainer", new Container());
return container.save().then(function() {
var query = new Parse.Query(Container);
return query.get(container.id);
}).then(function(containerAgain) {
var subContainerAgain = containerAgain.get("subcontainer");
var itemAgain = containerAgain.get("item");
var multiClassArray = [subContainerAgain, itemAgain];
return Parse.Object.fetchAll(
multiClassArray,
expectError(Parse.Error.INVALID_CLASS_NAME, done));
});
});
it("fetchAll error on unsaved object", function(done) {
var unsavedObjectArray = [new TestObject()];
Parse.Object.fetchAll(unsavedObjectArray,
expectError(Parse.Error.MISSING_OBJECT_ID, done));
});
it("fetchAll error on deleted object", function(done) {
var numItems = 11;
var container = new Container();
var subContainer = new Container();
var items = [];
for (var i = 0; i < numItems; i++) {
var item = new Item();
item.set("x", i);
items.push(item);
}
Parse.Object.saveAll(items).then(function() {
var query = new Parse.Query(Item);
return query.get(items[0].id);
}).then(function(objectToDelete) {
return objectToDelete.destroy();
}).then(function(deletedObject) {
var nonExistentObject = new Item({ objectId: deletedObject.id });
var nonExistentObjectArray = [nonExistentObject, items[1]];
return Parse.Object.fetchAll(
nonExistentObjectArray,
expectError(Parse.Error.OBJECT_NOT_FOUND, done));
});
});
// TODO: Verify that with Sessions, this test is wrong... A fetch on
// user should not bring down a session token.
notWorking("fetchAll User attributes get merged", function(done) {
var sameUser;
var user = new Parse.User();
user.set("username", "asdf");
user.set("password", "zxcv");
user.set("foo", "bar");
user.signUp().then(function() {
Parse.User.logOut();
var query = new Parse.Query(Parse.User);
return query.get(user.id);
}).then(function(userAgain) {
user = userAgain;
sameUser = new Parse.User();
sameUser.set("username", "asdf");
sameUser.set("password", "zxcv");
return sameUser.logIn();
}).then(function() {
ok(!user.getSessionToken(), "user should not have a sessionToken");
ok(sameUser.getSessionToken(), "sameUser should have a sessionToken");
sameUser.set("baz", "qux");
return sameUser.save();
}).then(function() {
return Parse.Object.fetchAll([user]);
}).then(function() {
equal(user.getSessionToken(), sameUser.getSessionToken());
equal(user.createdAt.getTime(), sameUser.createdAt.getTime());
equal(user.updatedAt.getTime(), sameUser.updatedAt.getTime());
Parse.User.logOut();
done();
});
});
it("fetchAllIfNeeded", function(done) {
var numItems = 11;
var container = new Container();
var items = [];
for (var i = 0; i < numItems; i++) {
var item = new Item();
item.set("x", i);
items.push(item);
}
Parse.Object.saveAll(items).then(function() {
container.set("items", items);
return container.save();
}).then(function() {
var query = new Parse.Query(Container);
return query.get(container.id);
}).then(function(containerAgain) {
var itemsAgain = containerAgain.get("items");
if (!itemsAgain || !itemsAgain.forEach) {
fail('no itemsAgain retrieved', itemsAgain);
done();
return;
}
itemsAgain.forEach(function(item, i) {
item.set("x", i*2);
});
return Parse.Object.saveAll(itemsAgain);
}).then(function() {
return Parse.Object.fetchAllIfNeeded(items);
}).then(function(fetchedItems) {
equal(fetchedItems.length, numItems,
"Number of items should not change");
fetchedItems.forEach(function(item, i) {
equal(item.get("x"), i);
});
done();
});
});
it("fetchAllIfNeeded backbone-style callbacks", function(done) {
var numItems = 11;
var container = new Container();
var items = [];
for (var i = 0; i < numItems; i++) {
var item = new Item();
item.set("x", i);
items.push(item);
}
Parse.Object.saveAll(items).then(function() {
container.set("items", items);
return container.save();
}).then(function() {
var query = new Parse.Query(Container);
return query.get(container.id);
}).then(function(containerAgain) {
var itemsAgain = containerAgain.get("items");
if (!itemsAgain || !itemsAgain.forEach) {
fail('no itemsAgain retrieved', itemsAgain);
done();
return;
}
itemsAgain.forEach(function(item, i) {
item.set("x", i*2);
});
return Parse.Object.saveAll(itemsAgain);
}).then(function() {
var items = container.get("items");
return Parse.Object.fetchAllIfNeeded(items, {
success: function(fetchedItems) {
equal(fetchedItems.length, numItems,
"Number of items should not change");
fetchedItems.forEach(function(item, j) {
equal(item.get("x"), j);
});
done();
},
error: function(error) {
ok(false, "Failed to fetchAll");
done();
}
});
});
});
it("fetchAllIfNeeded no objects", function(done) {
Parse.Object.fetchAllIfNeeded([], function(success, error) {
ok(success && !error, "Should be able to fetchAll no objects");
done();
});
});
it("fetchAllIfNeeded unsaved object", function(done) {
var unsavedObjectArray = [new TestObject()];
Parse.Object.fetchAllIfNeeded(
unsavedObjectArray,
expectError(Parse.Error.MISSING_OBJECT_ID, done));
});
it("fetchAllIfNeeded error on multiple classes", function(done) {
var container = new Container();
container.set("item", new Item());
container.set("subcontainer", new Container());
return container.save().then(function() {
var query = new Parse.Query(Container);
return query.get(container.id);
}).then(function(containerAgain) {
var subContainerAgain = containerAgain.get("subcontainer");
var itemAgain = containerAgain.get("item");
var multiClassArray = [subContainerAgain, itemAgain];
return Parse.Object.fetchAllIfNeeded(
multiClassArray,
expectError(Parse.Error.INVALID_CLASS_NAME, done));
});
});
it("Objects with className User", function(done) {
equal(Parse.CoreManager.get('PERFORM_USER_REWRITE'), true);
var User1 = Parse.Object.extend({
className: "User"
});
equal(User1.className, "_User",
"className is rewritten by default");
Parse.User.allowCustomUserClass(true);
equal(Parse.CoreManager.get('PERFORM_USER_REWRITE'), false);
var User2 = Parse.Object.extend({
className: "User"
});
equal(User2.className, "User",
"className is not rewritten when allowCustomUserClass(true)");
// Set back to default so as not to break other tests.
Parse.User.allowCustomUserClass(false);
equal(Parse.CoreManager.get('PERFORM_USER_REWRITE'), true, "PERFORM_USER_REWRITE is reset");
var user = new User2();
user.set("name", "Me");
user.save({height: 181}, expectSuccess({
success: function(user) {
equal(user.get("name"), "Me");
equal(user.get("height"), 181);
var query = new Parse.Query(User2);
query.get(user.id, expectSuccess({
success: function(user) {
equal(user.className, "User");
equal(user.get("name"), "Me");
equal(user.get("height"), 181);
done();
}
}));
}
}));
});
it("create without data", function(done) {
var t1 = new TestObject({ "test" : "test" });
t1.save().then(function(t1) {
var t2 = TestObject.createWithoutData(t1.id);
return t2.fetch();
}).then(function(t2) {
equal(t2.get("test"), "test", "Fetch should have grabbed " +
"'test' property.");
var t3 = TestObject.createWithoutData(t2.id);
t3.set("test", "not test");
return t3.fetch();
}).then(function(t3) {
equal(t3.get("test"), "test",
"Fetch should have grabbed server 'test' property.");
done();
}, function(error) {
ok(false, error);
done();
});
});
it("remove from new field creates array key", (done) => {
var obj = new TestObject();
obj.remove('shouldBeArray', 'foo');
obj.save().then(() => {
var query = new Parse.Query('TestObject');
return query.get(obj.id);
}).then((objAgain) => {
var arr = objAgain.get('shouldBeArray');
ok(Array.isArray(arr), 'Should have created array key');
ok(!arr || arr.length === 0, 'Should have an empty array.');
done();
});
});
it("increment with type conflict fails", (done) => {
var obj = new TestObject();
obj.set('astring', 'foo');
obj.save().then(() => {
var obj2 = new TestObject();
obj2.increment('astring');
return obj2.save();
}).then((obj2) => {
fail('Should not have saved.');
done();
}, (error) => {
expect(error.code).toEqual(111);
done();
});
});
it("increment with empty field solidifies type", (done) => {
var obj = new TestObject();
obj.increment('aninc');
obj.save().then(() => {
var obj2 = new TestObject();
obj2.set('aninc', 'foo');
return obj2.save();
}).then(() => {
fail('Should not have saved.');
done();
}, (error) => {
expect(error.code).toEqual(111);
done();
});
});
it("increment update with type conflict fails", (done) => {
var obj = new TestObject();
obj.set('someString', 'foo');
obj.save().then((objAgain) => {
var obj2 = new TestObject();
obj2.id = objAgain.id;
obj2.increment('someString');
return obj2.save();
}).then(() => {
fail('Should not have saved.');
done();
}, (error) => {
expect(error.code).toEqual(111);
done();
});
});
it('dictionary fetched pointers do not lose data on fetch', (done) => {
var parent = new Parse.Object('Parent');
var dict = {};
for (var i = 0; i < 5; i++) {
var proc = (iter) => {
var child = new Parse.Object('Child');
child.set('name', 'testname' + i);
dict[iter] = child;
};
proc(i);
}
parent.set('childDict', dict);
parent.save().then(() => {
return parent.fetch();
}).then((parentAgain) => {
var dictAgain = parentAgain.get('childDict');
if (!dictAgain) {
fail('Should have been a dictionary.');
return done();
}
expect(typeof dictAgain).toEqual('object');
expect(typeof dictAgain['0']).toEqual('object');
expect(typeof dictAgain['1']).toEqual('object');
expect(typeof dictAgain['2']).toEqual('object');
expect(typeof dictAgain['3']).toEqual('object');
expect(typeof dictAgain['4']).toEqual('object');
done();
});
});
});