adopted-ember-addons / ember-changeset

Ember.js flavored changesets, inspired by Ecto
http://bit.ly/ember-changeset-demo
MIT License
431 stars 141 forks source link

Setting values at one level of a (nested) EmberData changeset should not overwrite other levels (mergeDeep) #669

Open flynnawtc opened 1 year ago

flynnawtc commented 1 year ago

Version

master

Test Case

` test('#set set with Ember Data Object should not change other nested ember-data objects', async function (assert) {

let store = this.owner.lookup('service:store');

let mockDogModel = store.createRecord('dog', { breed: 'jazzy' });
let mockProfileModel = store.createRecord('profile', {pet: mockDogModel});
let mockUserModel = store.createRecord('user', {
  profile: mockProfileModel,
  save: function () {
    return Promise.resolve(this);
  },
});

let dummyChangeset = Changeset(mockUserModel);

//Check our initial values - these all pass
//assert.strictEqual(dummyChangeset.profile.pet.breed, 'jazzy', 'should not change');  //fails as it is a proxy within a proxy within a model - requires the use of 'get'
assert.strictEqual(dummyChangeset.get('profile.pet.breed'), 'jazzy', 'should not change using get #1');
assert.strictEqual(dummyChangeset.get('profile.pet').breed, 'jazzy', 'should not change using get #2');
assert.strictEqual(dummyChangeset.get('profile').pet.breed, 'jazzy', 'should not change using get #3');

//test fails using either form of setter
//dummyChangeset.set('profile.lastName', 'Mysurname');
set(dummyChangeset, 'profile.lastName', 'Mysurname');

//Log changeset.changes and changeset._changes
let changes = dummyChangeset.changes;
console.log("changes", changes);
console.log("_changes", dummyChangeset._changes);

assert.strictEqual(changes[0].value, 'Mysurname', 'changes with nested key Ember.set');

//Check values after setting unrelated field - these all pass
//assert.strictEqual(dummyChangeset.profile.pet.breed, 'jazzy', 'should not change after other set');  //fails as it is a proxy within a proxy within a model - requires the use of 'get'
assert.strictEqual(dummyChangeset.get('profile.pet.breed'), 'jazzy', 'should not change after other set using get #1');
assert.strictEqual(dummyChangeset.get('profile.pet').breed, 'jazzy', 'should not change after other set using get #2');
assert.strictEqual(dummyChangeset.get('profile').pet.breed, 'jazzy', 'should not change after other set using get #3');

dummyChangeset.execute();
console.log("changes2", changes);
console.log("_changes2", dummyChangeset._changes);

//Recheck values after executing change on unrelated field - these tests FAIL
//assert.strictEqual(dummyChangeset.profile.pet.breed, 'jazzy', 'should not change after execute');  //fails as it is a proxy within a proxy within a model - requires the use of 'get'
assert.strictEqual(dummyChangeset.get('profile.pet.breed'), 'jazzy', 'should not change after execute using get #1');
assert.strictEqual(dummyChangeset.get('profile.pet').breed, 'jazzy', 'should not change after execute using get #2');
assert.strictEqual(dummyChangeset.get('profile').pet.breed, 'jazzy', 'should not change after execute using get #3');

//What did we actually get?
console.log(dummyChangeset.get('profile.pet'));   //returns Proxy(ObjectTreeNode)

}); `

Steps to reproduce

Execute the test above (add to tests/unit/changeset-test.js)

Expected Behavior

All tests would pass - the setting of the profile surname should have no effect on the breed of the pet

Actual Behavior

After calling execute(), the value of profile.pet has been set to a Proxy(objectTreeNode) instead of being left unchanged

changes/_changes as logged before execute() image

changes/_changes as logged after execute() image

Note empty 'profile.pet' element in the _changes The value of dummyChangeSet.profile.pet is being set to this 'empty' object, instead of applying the (non-existent) changes to the existing profile.pet object. As best I can tell this is because BOTH the hasEmberDataProperty() and propertyIsOnObject() are returning false for profile.pet When logged to the console, dummyChangeset.get('profile.pet') shows: image