test(change detect): Port change detect tests for mode
More the change detect tests that exercise various detection modes to use the Dart pre-generated change detectors in addition to the `dynamic` and `JIT` change detectors. See #502
This commit is contained in:
parent
2cc2196140
commit
ddd5a235c3
|
@ -208,7 +208,7 @@ class _CodegenState {
|
||||||
var detectorFieldNames = _genGetDetectorFieldNames();
|
var detectorFieldNames = _genGetDetectorFieldNames();
|
||||||
for (var i = 0; i < detectorFieldNames.length; ++i) {
|
for (var i = 0; i < detectorFieldNames.length; ++i) {
|
||||||
buf.writeln('${detectorFieldNames[i]} = directives.getDetectorFor('
|
buf.writeln('${detectorFieldNames[i]} = directives.getDetectorFor('
|
||||||
'$_DIRECTIVES_ACCESSOR[$i].directiveIndex)');
|
'$_DIRECTIVES_ACCESSOR[$i].directiveIndex);');
|
||||||
}
|
}
|
||||||
return '$buf';
|
return '$buf';
|
||||||
}
|
}
|
||||||
|
|
|
@ -401,7 +401,95 @@ export function main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO(kegluneq): Insert describe('mode', ...) testcases.
|
describe('mode', () => {
|
||||||
|
var _createWithoutHydrate = function(expression: string) {
|
||||||
|
var registry = null;
|
||||||
|
return _getProtoChangeDetector(getDefinition(expression).cdDef, registry).instantiate(new TestDispatcher());
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should set the mode to CHECK_ALWAYS when the default change detection is used',
|
||||||
|
() => {
|
||||||
|
var cd = _createWithoutHydrate('emptyUsingDefaultStrategy');
|
||||||
|
expect(cd.mode).toEqual(null);
|
||||||
|
|
||||||
|
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||||
|
expect(cd.mode).toEqual(CHECK_ALWAYS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the mode to CHECK_ONCE when the push change detection is used', () => {
|
||||||
|
var cd = _createWithoutHydrate('emptyUsingOnPushStrategy');
|
||||||
|
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||||
|
|
||||||
|
expect(cd.mode).toEqual(CHECK_ONCE);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not check a detached change detector', () => {
|
||||||
|
var val = _createChangeDetector('a', new TestData('value'));
|
||||||
|
|
||||||
|
val.changeDetector.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||||
|
val.changeDetector.mode = DETACHED;
|
||||||
|
val.changeDetector.detectChanges();
|
||||||
|
|
||||||
|
expect(val.dispatcher.log).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not check a checked change detector', () => {
|
||||||
|
var val = _createChangeDetector('a', new TestData('value'));
|
||||||
|
|
||||||
|
val.changeDetector.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||||
|
val.changeDetector.mode = CHECKED;
|
||||||
|
val.changeDetector.detectChanges();
|
||||||
|
|
||||||
|
expect(val.dispatcher.log).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change CHECK_ONCE to CHECKED', () => {
|
||||||
|
var cd = _createChangeDetector('10').changeDetector;
|
||||||
|
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||||
|
cd.mode = CHECK_ONCE;
|
||||||
|
|
||||||
|
cd.detectChanges();
|
||||||
|
|
||||||
|
expect(cd.mode).toEqual(CHECKED);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change the CHECK_ALWAYS', () => {
|
||||||
|
var cd = _createChangeDetector('10').changeDetector;
|
||||||
|
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||||
|
cd.mode = CHECK_ALWAYS;
|
||||||
|
|
||||||
|
cd.detectChanges();
|
||||||
|
|
||||||
|
expect(cd.mode).toEqual(CHECK_ALWAYS);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('marking ON_PUSH detectors as CHECK_ONCE after an update', () => {
|
||||||
|
var checkedDetector;
|
||||||
|
var directives;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
checkedDetector = _createWithoutHydrate('emptyUsingOnPushStrategy');
|
||||||
|
checkedDetector.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||||
|
checkedDetector.mode = CHECKED;
|
||||||
|
|
||||||
|
var targetDirective = new TestData(null);
|
||||||
|
directives = new FakeDirectives([targetDirective], [checkedDetector]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the mode to CHECK_ONCE when a binding is updated', () => {
|
||||||
|
var cd = _createWithoutHydrate('onPushRecordsUsingDefaultStrategy');
|
||||||
|
cd.hydrate(_DEFAULT_CONTEXT, null, directives);
|
||||||
|
|
||||||
|
expect(checkedDetector.mode).toEqual(CHECKED);
|
||||||
|
|
||||||
|
// evaluate the record, update the targetDirective, and mark its detector as
|
||||||
|
// CHECK_ONCE
|
||||||
|
cd.detectChanges();
|
||||||
|
|
||||||
|
expect(checkedDetector.mode).toEqual(CHECK_ONCE);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('markPathToRootAsCheckOnce', () => {
|
describe('markPathToRootAsCheckOnce', () => {
|
||||||
function changeDetector(mode, parent) {
|
function changeDetector(mode, parent) {
|
||||||
|
@ -595,21 +683,6 @@ export function main() {
|
||||||
|
|
||||||
function dirs(directives: List<any>) { return new FakeDirectives(directives, []); }
|
function dirs(directives: List<any>) { return new FakeDirectives(directives, []); }
|
||||||
|
|
||||||
function createChangeDetector(propName: string, exp: string, context = _DEFAULT_CONTEXT,
|
|
||||||
registry = null) {
|
|
||||||
var dispatcher = new TestDispatcher();
|
|
||||||
|
|
||||||
var locals = null;
|
|
||||||
var variableBindings = [];
|
|
||||||
|
|
||||||
var records = [BindingRecord.createForElement(ast(exp), 0, propName)];
|
|
||||||
var pcd = createProtoChangeDetector(records, variableBindings, [], registry);
|
|
||||||
var cd = pcd.instantiate(dispatcher);
|
|
||||||
cd.hydrate(context, locals, null);
|
|
||||||
|
|
||||||
return {"changeDetector": cd, "dispatcher": dispatcher};
|
|
||||||
}
|
|
||||||
|
|
||||||
describe(`${name} change detection`, () => {
|
describe(`${name} change detection`, () => {
|
||||||
var dispatcher;
|
var dispatcher;
|
||||||
|
|
||||||
|
@ -879,113 +952,6 @@ export function main() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("mode", () => {
|
|
||||||
it("should set the mode to CHECK_ALWAYS when the default change detection is used",
|
|
||||||
() => {
|
|
||||||
var proto = createProtoChangeDetector([], [], [], null, DEFAULT);
|
|
||||||
var cd = proto.instantiate(null);
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(null);
|
|
||||||
|
|
||||||
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(CHECK_ALWAYS);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set the mode to CHECK_ONCE when the push change detection is used", () => {
|
|
||||||
var proto = createProtoChangeDetector([], [], [], null, ON_PUSH);
|
|
||||||
var cd = proto.instantiate(null);
|
|
||||||
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(CHECK_ONCE);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not check a detached change detector", () => {
|
|
||||||
var c = createChangeDetector('name', 'a', new TestData("value"));
|
|
||||||
var cd = c["changeDetector"];
|
|
||||||
var dispatcher = c["dispatcher"];
|
|
||||||
|
|
||||||
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
|
||||||
cd.mode = DETACHED;
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
expect(dispatcher.log).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not check a checked change detector", () => {
|
|
||||||
var c = createChangeDetector('name', 'a', new TestData("value"));
|
|
||||||
var cd = c["changeDetector"];
|
|
||||||
var dispatcher = c["dispatcher"];
|
|
||||||
|
|
||||||
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
|
||||||
cd.mode = CHECKED;
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
expect(dispatcher.log).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should change CHECK_ONCE to CHECKED", () => {
|
|
||||||
var cd = createProtoChangeDetector([]).instantiate(null);
|
|
||||||
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
|
||||||
cd.mode = CHECK_ONCE;
|
|
||||||
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(CHECKED);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not change the CHECK_ALWAYS", () => {
|
|
||||||
var cd = createProtoChangeDetector([]).instantiate(null);
|
|
||||||
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
|
||||||
cd.mode = CHECK_ALWAYS;
|
|
||||||
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
expect(cd.mode).toEqual(CHECK_ALWAYS);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("marking ON_PUSH detectors as CHECK_ONCE after an update", () => {
|
|
||||||
var checkedDetector;
|
|
||||||
var dirRecordWithOnPush;
|
|
||||||
var updateDirWithOnPushRecord;
|
|
||||||
var directives;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
var proto = createProtoChangeDetector([], [], [], null, ON_PUSH);
|
|
||||||
checkedDetector = proto.instantiate(null);
|
|
||||||
checkedDetector.hydrate(_DEFAULT_CONTEXT, null, null);
|
|
||||||
checkedDetector.mode = CHECKED;
|
|
||||||
|
|
||||||
// this directive is a component with ON_PUSH change detection
|
|
||||||
dirRecordWithOnPush = new DirectiveRecord(
|
|
||||||
{directiveIndex: new DirectiveIndex(0, 0), changeDetection: ON_PUSH});
|
|
||||||
|
|
||||||
// a record updating a component
|
|
||||||
updateDirWithOnPushRecord = BindingRecord.createForDirective(
|
|
||||||
ast("42"), "a", (o, v) => o.a = v, dirRecordWithOnPush);
|
|
||||||
|
|
||||||
var targetDirective = new TestData(null);
|
|
||||||
directives = new FakeDirectives([targetDirective], [checkedDetector]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set the mode to CHECK_ONCE when a binding is updated", () => {
|
|
||||||
var proto = createProtoChangeDetector([updateDirWithOnPushRecord], [],
|
|
||||||
[dirRecordWithOnPush]);
|
|
||||||
|
|
||||||
var cd = proto.instantiate(null);
|
|
||||||
cd.hydrate(_DEFAULT_CONTEXT, null, directives);
|
|
||||||
|
|
||||||
expect(checkedDetector.mode).toEqual(CHECKED);
|
|
||||||
|
|
||||||
// evaluate the record, update the targetDirective, and mark its detector as
|
|
||||||
// CHECK_ONCE
|
|
||||||
cd.detectChanges();
|
|
||||||
|
|
||||||
expect(checkedDetector.mode).toEqual(CHECK_ONCE);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
import {isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||||
import {
|
import {
|
||||||
|
DEFAULT,
|
||||||
|
ON_PUSH,
|
||||||
BindingRecord,
|
BindingRecord,
|
||||||
ChangeDetectorDefinition,
|
ChangeDetectorDefinition,
|
||||||
|
DirectiveIndex,
|
||||||
|
DirectiveRecord,
|
||||||
Lexer,
|
Lexer,
|
||||||
Locals,
|
Locals,
|
||||||
Parser
|
Parser
|
||||||
|
@ -34,26 +38,31 @@ export var PROP_NAME = 'propName';
|
||||||
* In this case, we expect `id` and `expression` to be the same string.
|
* In this case, we expect `id` and `expression` to be the same string.
|
||||||
*/
|
*/
|
||||||
export function getDefinition(id: string): TestDefinition {
|
export function getDefinition(id: string): TestDefinition {
|
||||||
var expression = null;
|
var testDef = null;
|
||||||
var locals = null;
|
if (StringMapWrapper.contains(_ExpressionWithLocals.availableDefinitions, id)) {
|
||||||
if (MapWrapper.contains(_availableDefinitionsWithLocals, id)) {
|
let val = StringMapWrapper.get(_ExpressionWithLocals.availableDefinitions, id);
|
||||||
var val = MapWrapper.get(_availableDefinitionsWithLocals, id);
|
let cdDef = val.createChangeDetectorDefinition();
|
||||||
expression = val.expression;
|
cdDef.id = id;
|
||||||
locals = val.locals;
|
testDef = new TestDefinition(id, cdDef, val.locals);
|
||||||
|
} else if (StringMapWrapper.contains(_ExpressionWithMode.availableDefinitions, id)) {
|
||||||
|
let val = StringMapWrapper.get(_ExpressionWithMode.availableDefinitions, id);
|
||||||
|
let cdDef = val.createChangeDetectorDefinition();
|
||||||
|
cdDef.id = id;
|
||||||
|
testDef = new TestDefinition(id, cdDef, null);
|
||||||
} else if (ListWrapper.indexOf(_availableDefinitions, id) >= 0) {
|
} else if (ListWrapper.indexOf(_availableDefinitions, id) >= 0) {
|
||||||
expression = id;
|
var strategy = null;
|
||||||
|
var variableBindings = [];
|
||||||
|
var bindingRecords = _createBindingRecords(id);
|
||||||
|
var directiveRecords = [];
|
||||||
|
let cdDef = new ChangeDetectorDefinition(id, strategy, variableBindings, bindingRecords,
|
||||||
|
directiveRecords);
|
||||||
|
testDef = new TestDefinition(id, cdDef, null);
|
||||||
}
|
}
|
||||||
if (isBlank(expression)) {
|
if (isBlank(testDef)) {
|
||||||
throw `No ChangeDetectorDefinition for ${id} available. Please modify this file if necessary.`;
|
throw `No ChangeDetectorDefinition for ${id} available. Please modify this file if necessary.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
var strategy = null;
|
return testDef;
|
||||||
var variableBindings = isPresent(locals) ? _convertLocalsToVariableBindings(locals) : [];
|
|
||||||
var bindingRecords = _createBindingRecords(expression);
|
|
||||||
var directiveRecords = [];
|
|
||||||
var cdDef = new ChangeDetectorDefinition(id, strategy, variableBindings, bindingRecords,
|
|
||||||
directiveRecords);
|
|
||||||
return new TestDefinition(id, cdDef, locals);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TestDefinition {
|
export class TestDefinition {
|
||||||
|
@ -68,12 +77,80 @@ export function getAllDefinitions(): List<TestDefinition> {
|
||||||
return ListWrapper.map(_availableDefinitions, (id) => getDefinition(id));
|
return ListWrapper.map(_availableDefinitions, (id) => getDefinition(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _ExpressionWithLocals {
|
||||||
|
constructor(private _expression: string, public locals: Locals) {}
|
||||||
|
|
||||||
|
createChangeDetectorDefinition(): ChangeDetectorDefinition {
|
||||||
|
var strategy = null;
|
||||||
|
var variableBindings = _convertLocalsToVariableBindings(this.locals);
|
||||||
|
var bindingRecords = _createBindingRecords(this._expression);
|
||||||
|
var directiveRecords = [];
|
||||||
|
return new ChangeDetectorDefinition('(empty id)', strategy, variableBindings, bindingRecords,
|
||||||
|
directiveRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from test id to _ExpressionWithLocals.
|
||||||
|
* Tests in this map define an expression and local values which those expressions refer to.
|
||||||
|
*/
|
||||||
|
static availableDefinitions: StringMap<string, _ExpressionWithLocals> = {
|
||||||
|
'valueFromLocals': new _ExpressionWithLocals(
|
||||||
|
'key', new Locals(null, MapWrapper.createFromPairs([['key', 'value']]))),
|
||||||
|
'functionFromLocals': new _ExpressionWithLocals(
|
||||||
|
'key()', new Locals(null, MapWrapper.createFromPairs([['key', () => 'value']]))),
|
||||||
|
'nestedLocals': new _ExpressionWithLocals(
|
||||||
|
'key', new Locals(new Locals(null, MapWrapper.createFromPairs([['key', 'value']])),
|
||||||
|
MapWrapper.create())),
|
||||||
|
'fallbackLocals': new _ExpressionWithLocals(
|
||||||
|
'name', new Locals(null, MapWrapper.createFromPairs([['key', 'value']]))),
|
||||||
|
'contextNestedPropertyWithLocals': new _ExpressionWithLocals(
|
||||||
|
'address.city', new Locals(null, MapWrapper.createFromPairs([['city', 'MTV']]))),
|
||||||
|
'localPropertyWithSimilarContext': new _ExpressionWithLocals(
|
||||||
|
'city', new Locals(null, MapWrapper.createFromPairs([['city', 'MTV']])))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ExpressionWithMode {
|
||||||
|
constructor(private _strategy: string, private _withRecords: boolean) {}
|
||||||
|
|
||||||
|
createChangeDetectorDefinition(): ChangeDetectorDefinition {
|
||||||
|
var variableBindings = [];
|
||||||
|
var bindingRecords = null;
|
||||||
|
var directiveRecords = null;
|
||||||
|
if (this._withRecords) {
|
||||||
|
var dirRecordWithOnPush =
|
||||||
|
new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0), changeDetection: ON_PUSH});
|
||||||
|
var updateDirWithOnPushRecord =
|
||||||
|
BindingRecord.createForDirective(_parser.parseBinding('42', 'location'), 'a',
|
||||||
|
(o, v) => (<any>o).a = v, dirRecordWithOnPush);
|
||||||
|
bindingRecords = [updateDirWithOnPushRecord];
|
||||||
|
directiveRecords = [dirRecordWithOnPush];
|
||||||
|
} else {
|
||||||
|
bindingRecords = [];
|
||||||
|
directiveRecords = [];
|
||||||
|
}
|
||||||
|
return new ChangeDetectorDefinition('(empty id)', this._strategy, variableBindings,
|
||||||
|
bindingRecords, directiveRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from test id to _ExpressionWithMode.
|
||||||
|
* Definitions in this map define conditions which allow testing various change detector modes.
|
||||||
|
*/
|
||||||
|
static availableDefinitions: StringMap<string, _ExpressionWithMode> = {
|
||||||
|
'emptyUsingDefaultStrategy': new _ExpressionWithMode(DEFAULT, false),
|
||||||
|
'emptyUsingOnPushStrategy': new _ExpressionWithMode(ON_PUSH, false),
|
||||||
|
'onPushRecordsUsingDefaultStrategy': new _ExpressionWithMode(DEFAULT, true)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of all test definitions this config supplies.
|
* The list of all test definitions this config supplies.
|
||||||
* Items in this list that do not appear in other structures define tests with expressions
|
* Items in this list that do not appear in other structures define tests with expressions
|
||||||
* equivalent to their ids.
|
* equivalent to their ids.
|
||||||
*/
|
*/
|
||||||
var _availableDefinitions = [
|
var _availableDefinitions = ListWrapper.concat(
|
||||||
|
[
|
||||||
'10',
|
'10',
|
||||||
'"str"',
|
'"str"',
|
||||||
'"a\n\nb"',
|
'"a\n\nb"',
|
||||||
|
@ -121,53 +198,7 @@ var _availableDefinitions = [
|
||||||
'address?.toString()',
|
'address?.toString()',
|
||||||
'sayHi("Jim")',
|
'sayHi("Jim")',
|
||||||
'a()(99)',
|
'a()(99)',
|
||||||
'a.sayHi("Jim")',
|
'a.sayHi("Jim")'
|
||||||
'valueFromLocals',
|
|
||||||
'functionFromLocals',
|
|
||||||
'nestedLocals',
|
|
||||||
'fallbackLocals',
|
|
||||||
'contextNestedPropertyWithLocals',
|
|
||||||
'localPropertyWithSimilarContext'
|
|
||||||
];
|
|
||||||
|
|
||||||
class _ExpressionWithLocals {
|
|
||||||
constructor(public expression: string, public locals: Locals) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map from test id to _ExpressionWithLocals.
|
|
||||||
* Tests in this map define an expression and local values which those expressions refer to.
|
|
||||||
*/
|
|
||||||
var _availableDefinitionsWithLocals = MapWrapper.createFromPairs([
|
|
||||||
[
|
|
||||||
'valueFromLocals',
|
|
||||||
new _ExpressionWithLocals('key',
|
|
||||||
new Locals(null, MapWrapper.createFromPairs([['key', 'value']])))
|
|
||||||
],
|
],
|
||||||
[
|
ListWrapper.concat(StringMapWrapper.keys(_ExpressionWithLocals.availableDefinitions),
|
||||||
'functionFromLocals',
|
StringMapWrapper.keys(_ExpressionWithMode.availableDefinitions)));
|
||||||
new _ExpressionWithLocals(
|
|
||||||
'key()', new Locals(null, MapWrapper.createFromPairs([['key', () => 'value']])))
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'nestedLocals',
|
|
||||||
new _ExpressionWithLocals(
|
|
||||||
'key', new Locals(new Locals(null, MapWrapper.createFromPairs([['key', 'value']])),
|
|
||||||
MapWrapper.create()))
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'fallbackLocals',
|
|
||||||
new _ExpressionWithLocals('name',
|
|
||||||
new Locals(null, MapWrapper.createFromPairs([['key', 'value']])))
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'contextNestedPropertyWithLocals',
|
|
||||||
new _ExpressionWithLocals('address.city',
|
|
||||||
new Locals(null, MapWrapper.createFromPairs([['city', 'MTV']])))
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'localPropertyWithSimilarContext',
|
|
||||||
new _ExpressionWithLocals('city',
|
|
||||||
new Locals(null, MapWrapper.createFromPairs([['city', 'MTV']])))
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
Loading…
Reference in New Issue