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

[Pre-work] Prepare @tracked decorator #16903

Merged
merged 13 commits into from
Aug 28, 2018
13 changes: 9 additions & 4 deletions packages/ember-metal/lib/tracked.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,17 @@ class Tracker {

@param dependencies Optional dependents to be tracked.
*/
export function tracked(...dependencies: string[]): MethodDecorator;
export function tracked(target: unknown, key: PropertyKey): any;
export function tracked(
_target: object,
key: string,
target: unknown,
key: PropertyKey,
descriptor: PropertyDescriptor
): PropertyDescriptor {
if ('value' in descriptor) {
): PropertyDescriptor;
export function tracked(...dependencies: any[]): any {
let [, key, descriptor] = dependencies;

if (descriptor === undefined || 'initializer' in descriptor) {
return descriptorForDataProperty(key, descriptor);
} else {
return descriptorForAccessor(key, descriptor);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,62 +1,64 @@
import { createWithDescriptors } from './support';
import { get, set, tracked } from '../..';

import { moduleFor, AbstractTestCase } from 'internal-test-helpers';
import { EMBER_METAL_TRACKED_PROPERTIES } from '@ember/canary-features';
import { AbstractTestCase, moduleFor } from 'internal-test-helpers';

if (EMBER_METAL_TRACKED_PROPERTIES) {
moduleFor(
'tracked getters',
'@tracked getters',
class extends AbstractTestCase {
['@test works without get'](assert) {
['@test works without get'](assert: Assert) {
let count = 0;

class Count {
@tracked
get foo() {
count++;
return `computed foo`;
}
}

tracked(Count.prototype, 'foo', Object.getOwnPropertyDescriptor(Count.prototype, 'foo'));

let obj = new Count();

assert.equal(obj.foo, 'computed foo', 'should return value');
assert.equal(count, 1, 'should have invoked computed property');
}

['@test defining computed property should invoke property on get'](assert) {
['@test defining computed property should invoke property on get'](assert: Assert) {
let count = 0;

class Count {
@tracked
get foo() {
count++;
return `computed foo`;
}
}

tracked(Count.prototype, 'foo', Object.getOwnPropertyDescriptor(Count.prototype, 'foo'));

let obj = new Count();

assert.equal(get(obj, 'foo'), 'computed foo', 'should return value');
assert.equal(count, 1, 'should have invoked computed property');
}

['@test defining computed property should invoke property on set'](assert) {
['@test defining computed property should invoke property on set'](assert: Assert) {
let count = 0;

let obj = createWithDescriptors({
class Foo {
__foo = '';

@tracked
get foo() {
return this.__foo;
},
}

set foo(value) {
count++;
this.__foo = `computed ${value}`;
},
});
}
}

let obj = new Foo();

assert.equal(set(obj, 'foo', 'bar'), 'bar', 'should return set value');
assert.equal(count, 1, 'should have invoked computed property');
Expand Down
86 changes: 0 additions & 86 deletions packages/ember-metal/tests/tracked/get_test.js

This file was deleted.

115 changes: 115 additions & 0 deletions packages/ember-metal/tests/tracked/get_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { EMBER_METAL_TRACKED_PROPERTIES } from '@ember/canary-features';
import { AbstractTestCase, moduleFor } from 'internal-test-helpers';
import { get, getWithDefault, tracked } from '../..';

if (EMBER_METAL_TRACKED_PROPERTIES) {
function createObj() {
class Obj {
@tracked string = 'string';
@tracked number = 23;
@tracked boolTrue = true;
@tracked boolFalse = false;
@tracked nullValue = null;
}

return new Obj();
}

moduleFor(
'@tracked decorator: get',
class extends AbstractTestCase {
'@test should get arbitrary properties on an object'() {
let obj = createObj();

for (let key in obj) {
this.assert.equal(get(obj, key), obj[key], key);
}
}

'@test should retrieve a number key on an object'() {
class Obj {
@tracked 1 = 'first';
}

let obj = new Obj();

this.assert.equal(get(obj, '1'), 'first');
}

'@test should retrieve an empty key on an object'() {
class Obj {
@tracked '' = 'empty';
}

let obj = new Obj();

this.assert.equal(get(obj, ''), 'empty');
}

'@test should get a @tracked path'() {
class Key {
@tracked value = 'value';
}

class Path {
@tracked key = new Key();
}

class Obj {
@tracked path = new Path();
}

let obj = new Obj();

this.assert.equal(get(obj, 'path.key.value'), 'value');
}

'@test should not access a property more than once'() {
let count = 20;

class Count {
@tracked
get id() {
return ++count;
}
}

let obj = new Count();

get(obj, 'id');

this.assert.equal(count, 21);
}
}
);

moduleFor(
'@tracked decorator: getWithDefault',
class extends AbstractTestCase {
['@test should get arbitrary properties on an object']() {
let obj = createObj();

for (let key in obj) {
this.assert.equal(getWithDefault(obj, key as any, 'fail'), obj[key], key);
}

class Obj {
@tracked undef: string | undefined = undefined;
}

let obj2 = new Obj();

this.assert.equal(
getWithDefault(obj2, 'undef', 'default'),
'default',
'explicit undefined retrieves the default'
);
this.assert.equal(
getWithDefault(obj2, 'not-present' as any, 'default'),
'default',
'non-present key retrieves the default'
);
}
}
);
}
44 changes: 0 additions & 44 deletions packages/ember-metal/tests/tracked/set_test.js

This file was deleted.

50 changes: 50 additions & 0 deletions packages/ember-metal/tests/tracked/set_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { AbstractTestCase, moduleFor } from 'internal-test-helpers';
import { get, set, tracked } from '../..';

import { EMBER_METAL_TRACKED_PROPERTIES } from '@ember/canary-features';

if (EMBER_METAL_TRACKED_PROPERTIES) {
const createObj = () => {
class Obj {
@tracked string = 'string';
@tracked number = 23;
@tracked boolTrue = true;
@tracked boolFalse = false;
@tracked nullValue = null;
@tracked undefinedValue = undefined;
}

return new Obj();
};

moduleFor(
'@tracked set',
class extends AbstractTestCase {
['@test should set arbitrary properties on an object'](assert: Assert) {
let obj = createObj();

class Obj {
@tracked undefinedValue = 'emberjs';
}

let newObj = new Obj();

for (let key in obj) {
assert.equal(set(newObj, key, obj[key]), obj[key], 'should return value');
assert.equal(get(newObj, key), obj[key], 'should set value');
}
}

['@test should set a number key on an object'](assert: Assert) {
class Obj {
@tracked 1 = 'original';
}

let obj = new Obj();

set(obj, '1', 'first');
assert.equal(obj[1], 'first');
}
}
);
}
Loading