Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUGFIX release] Ensure tag updates are buffered #18698

Merged
merged 2 commits into from
Jan 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,14 @@
},
"devDependencies": {
"@babel/preset-env": "^7.6.0",
"@glimmer/compiler": "0.38.5-alpha.3",
"@glimmer/compiler": "0.38.5-alpha.4",
"@glimmer/env": "^0.1.7",
"@glimmer/interfaces": "0.38.5-alpha.3",
"@glimmer/node": "0.38.5-alpha.3",
"@glimmer/opcode-compiler": "0.38.5-alpha.3",
"@glimmer/program": "0.38.5-alpha.3",
"@glimmer/reference": "0.38.5-alpha.3",
"@glimmer/runtime": "0.38.5-alpha.3",
"@glimmer/interfaces": "0.38.5-alpha.4",
"@glimmer/node": "0.38.5-alpha.4",
"@glimmer/opcode-compiler": "0.38.5-alpha.4",
"@glimmer/program": "0.38.5-alpha.4",
"@glimmer/reference": "0.38.5-alpha.4",
"@glimmer/runtime": "0.38.5-alpha.4",
"@types/qunit": "^2.5.4",
"@types/rsvp": "^4.0.3",
"@typescript-eslint/parser": "^2.7.0",
Expand Down
183 changes: 183 additions & 0 deletions packages/@ember/-internals/metal/tests/computed_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1042,3 +1042,186 @@ moduleFor(
}
}
);

class LazyObject {
value = 123;

@computed('_value')
get value() {
return get(this, '_value');
}

set value(value) {
set(this, '_value', value);
}

static create() {
let obj = new LazyObject();

// ensure a tag exists for the value computed
get(obj, 'value');

return obj;
}
}

moduleFor(
'computed - lazy dependencies',
class extends AbstractTestCase {
'@test computed properties with lazy dependencies work as expected'(assert) {
let calledCount = 0;
let lazyObject = LazyObject.create();

class ObjectWithLazyDep {
@computed('lazyObject.value')
get someProp() {
return ++calledCount;
}

@computed('otherProp')
get lazyObject() {
return lazyObject;
}
}

let obj = new ObjectWithLazyDep();

// Get someProp and setup the lazy dependency
assert.equal(obj.someProp, 1, 'called the first time');
assert.equal(obj.someProp, 1, 'returned cached value the second time');

// Finish the lazy dependency
assert.equal(obj.lazyObject.value, 123, 'lazyObject returns expected value');
assert.equal(
obj.someProp,
1,
'someProp was not dirtied by propB being calculated for the first time'
);

set(lazyObject, 'value', 456);
assert.equal(obj.someProp, 2, 'someProp dirtied by lazyObject.value changing');

set(lazyObject, 'value', 789);
assert.equal(
obj.someProp,
3,
'someProp still dirtied by otherProp when lazyObject.value is dirty'
);
}

'@test computed properties with lazy dependencies do not dirty until dependencies have been read at least once'(
assert
) {
let calledCount = 0;
let lazyObject = LazyObject.create();

class ObjectWithLazyDep {
@computed('lazyObject.value')
get someProp() {
return ++calledCount;
}

@computed('otherProp')
get lazyObject() {
return lazyObject;
}
}

let obj = new ObjectWithLazyDep();

assert.equal(obj.someProp, 1, 'called the first time');
assert.equal(obj.someProp, 1, 'returned cached value the second time');

// dirty the object value before the dependency has been finished
set(lazyObject, 'value', 456);

assert.equal(obj.lazyObject.value, 456, 'propB returns expected value');
assert.equal(
obj.someProp,
1,
'someProp was not dirtied by propB being dirtied before it has been calculated'
);
}

'@test computed properties with lazy dependencies work correctly if lazy dependency is more recent'(
assert
) {
let calledCount = 0;
let lazyObject = LazyObject.create();

class ObjectWithLazyDep {
@computed('lazyObject.value')
get someProp() {
return ++calledCount;
}

@computed('otherProp')
get lazyObject() {
return lazyObject;
}
}

let obj = new ObjectWithLazyDep();

set(lazyObject, 'value', 456);

assert.equal(obj.someProp, 1, 'called the first time');
assert.equal(obj.someProp, 1, 'returned cached value the second time');

assert.equal(obj.lazyObject.value, 456, 'lazyObject returns expected value');

assert.equal(
obj.someProp,
1,
'someProp was not dirtied by lazyObject being dirtied before it has been calculated'
);
}
}
);

moduleFor(
'computed - observer interop',
class extends AbstractTestCase {
async '@test observers that do not consume computed properties still work'(assert) {
assert.expect(2);

class Foo {
otherProp = 123;

@computed('otherProp')
get someProp() {
return this.otherProp;
}
}

let foo = new Foo();

addObserver(
foo,
'otherProp',
foo,
() => assert.ok(true, 'otherProp observer called when it was changed'),
false
);

addObserver(
foo,
'someProp',
foo,
() => assert.ok(false, 'someProp observer called when it was not changed'),
false
);

set(foo, 'otherProp', 456);

await runLoopSettled();

assert.equal(get(foo, 'someProp'), 456, '');

addObserver(foo, 'anotherProp', foo, () => {}, false);
set(foo, 'anotherProp', 123);

await runLoopSettled();
}
}
);
Loading