blob: a11c4851401384092d831d200dd93269079d417c [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
var tests = [
{
name: "Basic object destructuring syntax",
body: function () {
assert.doesNotThrow(function () { eval("var {} = {};"); }, "var object declaration pattern with no identifier is valid syntax");
assert.doesNotThrow(function () { eval("let {} = {};"); }, "let object declaration pattern with no identifier is valid syntax");
assert.doesNotThrow(function () { eval("const {} = {};"); }, "const object declaration pattern with no identifier is valid syntax");
assert.doesNotThrow(function () { eval("({} = {});"); }, "Object pattern as an expression with no identifier is valid syntax");
assert.doesNotThrow(function () { eval("var {x:y} = {};"); }, "var object declaration pattern with a single member is valid syntax");
assert.doesNotThrow(function () { eval("let {x:y} = {};"); }, "let object declaration pattern with a single member is valid syntax");
assert.doesNotThrow(function () { eval("const {x:y} = {};"); }, "const object declaration pattern with a single member is valid syntax");
assert.doesNotThrow(function () { eval("({x:y} = {});"); }, "Object pattern as an expression with a single member is valid syntax");
assert.doesNotThrow(function () { eval("var {x} = {};"); }, "var object declaration pattern with a single member as shorthand is valid syntax");
assert.doesNotThrow(function () { eval("({x:y} = {});"); }, "Object pattern as an expression with a single member as shorthand is valid syntax");
assert.doesNotThrow(function () { eval("var {x} = {}, {y} = {};"); }, "Multiple object pattern in a single var declaration is valid syntax");
}
},
{
name: "Basic object destructuring invalid syntax",
body: function () {
assert.throws(function () { eval("var {};"); }, SyntaxError, "var empty object declaration pattern without an initializer is not valid syntax", "Destructuring declarations must have an initializer");
assert.throws(function () { eval("let {};"); }, SyntaxError, "let empty object declaration pattern without an initializer is not valid syntax", "Destructuring declarations must have an initializer");
assert.throws(function () { eval("const {};"); }, SyntaxError, "const empty object declaration pattern without an initializer is not valid syntax", "Destructuring declarations must have an initializer");
assert.throws(function () { eval("var {a};"); }, SyntaxError, "var object declaration pattern without an initializer is not valid syntax", "Destructuring declarations must have an initializer");
assert.throws(function () { eval("let {a};"); }, SyntaxError, "let object declaration pattern without an initializer is not valid syntax", "Destructuring declarations must have an initializer");
assert.throws(function () { eval("const {a};"); }, SyntaxError, "const object declaration pattern without an initializer is not valid syntax", "Destructuring declarations must have an initializer");
assert.throws(function () { eval("var {,} = {}"); }, SyntaxError, "Object declaration pattern without an identifier is not valid syntax", "Expected identifier, string or number");
assert.throws(function () { eval("({,} = {});"); }, SyntaxError, "Object expression pattern without an identifier is not valid syntax", "Expected identifier, string or number");
assert.throws(function () { eval("var {x:y--} = {};"); }, SyntaxError, "Object declaration pattern with an operator -- is not valid syntax", "Unexpected operator in destructuring expression");
assert.throws(function () { eval("var {x:y+1} = {};"); }, SyntaxError, "Object declaration pattern with an operator + is not valid syntax", "Unexpected operator in destructuring expression");
assert.throws(function () { eval("var y; ({x:y--} = {});"); }, SyntaxError, "Object expression pattern with an operator -- is not valid syntax", "Unexpected operator in destructuring expression");
assert.throws(function () { eval("var y; ({x:y+1} = {});"); }, SyntaxError, "Object expression pattern with an operator + is not valid syntax", "Unexpected operator in destructuring expression");
}
},
{
name: "Object destructuring syntax with initializer",
body: function () {
assert.doesNotThrow(function () { eval("var {x:x = 20} = {};"); }, "var object declaration pattern with default is valid syntax");
assert.doesNotThrow(function () { eval("let {x:x = 20} = {};"); }, "let object declaration pattern with default is valid syntax");
assert.doesNotThrow(function () { eval("const {x:x = 20} = {};"); }, "const object declaration pattern with default is valid syntax");
assert.doesNotThrow(function () { eval("var x; ({x:x = 20} = {});"); }, "Object declaration pattern with default is valid syntax");
assert.doesNotThrow(function () { eval("var {x, x1:y = 20} = {};"); }, "Object declaration pattern with default other than first is valid syntax");
assert.doesNotThrow(function () { eval("var {x:z = 1, x1:y = 20} = {};"); }, "Object declaration pattern with defaults on more than one is valid syntax");
assert.doesNotThrow(function () { eval("var x, y; ({x, x1:y = 20} = {});"); }, "Object expression pattern with default other than first is valid syntax");
assert.doesNotThrow(function () { eval("var z, y; ({x:z = 1, x1:y = 20} = {});"); }, "Object expression pattern with defaults on more than one is valid syntax");
}
},
{
name: "Object destructuring syntax with identifier reference",
body: function () {
assert.throws(function () { eval("function foo() { return {}; }; let {x:foo()} = {};"); }, SyntaxError, "Object declaration pattern with a call expression is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("function foo() { return {}; }; ({x:foo()} = {});"); }, SyntaxError, "Object expression pattern with a call expression is not valid syntax", "Invalid destructuring assignment target");
assert.throws(function () { eval("function foo() { return {}; }; var {x:foo().x} = {};"); }, SyntaxError, "Object declaration pattern with property reference on call is not valid syntax", "Syntax error");
assert.doesNotThrow(function () { eval("var a = {}; ({x:a.x} = {});"); }, "Object expresion pattern with a property reference is valid syntax");
assert.doesNotThrow(function () { eval("let a = {}; ({x:a['x']} = {});"); }, "Object expression pattern with a property reference as index is valid syntax");
assert.doesNotThrow(function () { eval("function foo() { return {}; }; ({x:foo().x} = {});"); }, "Object declaration pattern with property reference on call is valid syntax");
assert.doesNotThrow(function () { eval("function foo() { return {}; }; ({x:foo()['x']} = {});"); }, "Object declaration pattern with property reference as index on call is valid syntax");
assert.throws(function () { eval("class foo { method() { let {x:super()} = {}; } }"); },SyntaxError, "Object declaration pattern with a super call is not valid syntax", "The use of a keyword for an identifier is invalid");
assert.throws(function () { eval("class foo { method() { ({x:super()} = {}); } }"); }, SyntaxError, "Object expression pattern with a super call is not valid syntax", "Invalid use of the 'super' keyword");
assert.throws(function () { eval("class foo { method() { var {x:super.x} = {}; } }"); }, SyntaxError, "Object declaration pattern with a property reference on super is not valid syntax", "The use of a keyword for an identifier is invalid");
assert.doesNotThrow(function () { eval("class foo { method() { ({x:super.x} = {}); } }"); }, "Object expression pattern with a property reference on super is valid syntax");
assert.doesNotThrow(function () { eval("class foo { method() { ({x:super['x']} = {}); } }"); }, "Object expression pattern with a property reference as an index on super is valid syntax");
assert.doesNotThrow(function () { eval("var a = [1], i = 0; ({x:a[i++]} = {});"); }, "Object Destructuring pattern assignment operators inside an identifier reference is valid syntax");
}
},
{
name: "Object destructuring syntax with computed property name",
body: function () {
assert.doesNotThrow(function () { eval("var zee = 'x'; var {[zee]:x1} = {}"); }, "Object declaration pattern with computed property name is valid syntax");
assert.doesNotThrow(function () { eval("var zee = 'x'; var x1; ({[zee]:x1} = {})"); }, "Object expression pattern with computed property name is valid syntax");
assert.doesNotThrow(function () { eval("var zee = 'x'; var {[zee + 'foo']:x1} = {}"); }, "Object declaration pattern with computed property name with add operator is valid syntax");
assert.doesNotThrow(function () { eval("var zee = 'x'; var x1; ({[zee +'foo']:x1} = {})"); }, "Object expression pattern with computed property name with add operator is valid syntax");
}
},
{
name: "Destructing syntax - having rest element as pattern",
body: function () {
assert.doesNotThrow(function () { eval("let [...[a]] = [[]];"); }, "Under declaration, having rest element as array pattern is valid syntax");
assert.doesNotThrow(function () { eval("let a; [...[a]] = [[]];"); }, "Under expression, having rest element as array pattern is valid syntax");
assert.doesNotThrow(function () { eval("let [...{a}] = [{}];"); }, "Under declaration, having rest element as object pattern is valid syntax");
assert.doesNotThrow(function () { eval("let a; [...{a}] = [{}];"); }, "Under expression, having rest element as object pattern is valid syntax");
assert.doesNotThrow(function () { eval("let a; [...[a = 1]] = [[]];"); }, "Under expression, having rest element as array pattern has initializer is valid syntax");
assert.doesNotThrow(function () { eval("let a; [...{a:a = 1}] = [{}];"); }, "Under expression, having rest element as object pattern has initializer is valid syntax");
assert.doesNotThrow(function () { eval("let obj = {x:1}; [...obj.x] = [10];"); }, "Rest element being property reference is valid syntax");
assert.doesNotThrow(function () { eval("let obj = {x:1}; [...obj['x']] = [10];"); }, "Rest element being property reference as index is valid syntax");
assert.doesNotThrow(function () { eval("function foo() { return {x:1}; }; [...foo().x] = [10];"); }, "Rest element being property reference on call expression is valid syntax");
assert.doesNotThrow(function () { eval("function foo() { return {x:1}; }; [...foo()['x']] = [10];"); }, "Rest element being property reference as index on call expression is valid syntax");
assert.doesNotThrow(function () { eval("let [...[...[...a]]] = [[[]]];"); }, "Nesting rest element inside another rest element is valid syntax");
assert.throws(function () { eval("let [...[a+1] = [{}];"); }, SyntaxError, "Under declaration, having rest element as pattern which has operator is not valid syntax", "Unexpected operator in destructuring expression");
assert.throws(function () { eval("let a; [...1+a] = [{}];"); }, SyntaxError, "Under declaration, rest element has operator is not valid syntax", "Invalid destructuring assignment target");
assert.throws(function () { eval("let a; [...[a+1] = [{}];"); }, SyntaxError, "Under expression, having rest element as pattern which has operator is not valid syntax", "Unexpected operator in destructuring expression");
assert.throws(function () { eval("function foo() { return {x:1}; }; [...foo()] = [10];"); }, SyntaxError, "Under expression, having rest element as call expression is not valid syntax", "Invalid destructuring assignment target");
assert.throws(function () { eval("let [...[a] = []] = [[]];"); }, SyntaxError, "Under declaration - rest as array pattern cannot have initializer", "The rest parameter cannot have a default initializer.");
assert.throws(function () { eval("let [...{x} = {}] = [{}];"); }, SyntaxError, "Under declaration - rest as object pattern cannot have initializer", "The rest parameter cannot have a default initializer.");
assert.throws(function () { eval("let a; ([...[a] = []] = [[]]);"); }, SyntaxError, "Under assignment - rest as array pattern cannot have initializer", "The rest parameter cannot have a default initializer.");
assert.throws(function () { eval("let x; ([...{x} = {}] = [{}]);"); }, SyntaxError, "Under assignment - rest as object pattern cannot have initializer", "The rest parameter cannot have a default initializer.");
}
},
{
name: "Object destructuring syntax with repeated identifier",
body: function () {
assert.doesNotThrow(function () { eval("var {a:a, a:a} = {};"); }, "var declaration pattern with a repeated identifier is valid syntax");
assert.throws(function () { eval("let {a:a, a:a} = {};"); }, SyntaxError, "let declaration pattern with a repeated identifier is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("const {a:a, a:a} = {};"); }, SyntaxError, "const declaration pattern with a repeated identifier is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("let {b, b} = {};"); }, SyntaxError, "let declaration pattern with a repeated identifier as shorthand is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("const {b, b} = {};"); }, SyntaxError, "const declaration pattern with a repeated identifier as shorthand is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("let {x:c, y:c} = {};"); }, SyntaxError, "let declaration pattern with a repeated identifier but different matching pattern is not valid syntax", "Let/Const redeclaration");
assert.throws(function () { eval("const {x:c, y:c} = {};"); }, SyntaxError, "const declaration pattern with a repeated identifier but different matching pattern is not valid syntax", "Let/Const redeclaration");
assert.doesNotThrow(function () { eval("let a; ({a:a, a:a} = {});"); }, "Object expression pattern with a repeated identifier is valid syntax");
}
},
{
name: "Object destructuring syntax on misc expressions",
body: function () {
assert.doesNotThrow(function () { eval("let a; ({a:((((a1))))} = {a:20})"); }, "Object expression pattern with parens is valid syntax");
assert.doesNotThrow(function () { eval("let a; ({a:((((a1 = 31))))} = {})"); }, "Object expression pattern with parens and defaults is valid syntax");
assert.doesNotThrow(function () { eval("let a, r1; ({a:a1 = r1} = {})"); }, "Object expression pattern with defaults as reference is valid syntax");
assert.doesNotThrow(function () { eval("let a, r1; ({a:((((a1 = r1))))} = {})"); }, "Object expression pattern with defaults as reference under parens is valid syntax");
assert.doesNotThrow(function () { eval("let a, r1; ({a:a1 = r1 = 44} = {})"); }, "Object expression pattern with chained assignments as defaults is valid syntax");
assert.doesNotThrow(function () { eval("let a, r1; ({a:(a1 = r1 = 44)} = {})"); }, "Object expression pattern with chained assignments as defaults under paren is valid syntax");
assert.throws(function () { eval("let a, r1; ({a:(a1 = r1) = 44} = {})"); }, SyntaxError, "Object expression pattern with chained assignments but paren in between is not valid syntax", "Unexpected operator in destructuring expression");
assert.doesNotThrow(function () { eval("var a; `${({a} = {})}`"); }, "Object expression pattern inside a string template is valid syntax");
assert.throws(function () { eval("for (let {x} = {} of []) {}"); }, SyntaxError, "for.of has declaration pattern with initializer is not valid syntax", "for-of loop head declarations cannot have an initializer");
assert.throws(function () { eval("for (let {x} = {} in []) {}"); }, SyntaxError, "for.in has declaration pattern with initializer is not valid syntax", "for-in loop head declarations cannot have an initializer");
assert.throws(function () { eval("for (var [x] = [] of []) {}"); }, SyntaxError, "for.of has var declaration pattern with initializer is not valid syntax", "for-of loop head declarations cannot have an initializer");
assert.throws(function () { eval("function foo() {for (let {x} = {} of []) {}; }; foo();"); }, SyntaxError, "Inside function - for.of has declaration pattern with initializer is not valid syntax", "for-of loop head declarations cannot have an initializer");
assert.doesNotThrow(function () { eval("var a; [a = class aClass {}] = []"); }, "Expression pattern has class as initializer is valid syntax");
assert.doesNotThrow(function () { eval("var a; for ({x:x = class aClass {}} of []) {}"); }, "for.of's expression pattern has class as initializer is valid syntax");
assert.doesNotThrow(function () { eval("var {x:[...y]} = {x:[1]}"); }, "rest element nesting under object pattern is valid syntax");
assert.throws(function () { eval("let {foo() {}} = {};"); }, SyntaxError, "Invalid object pattern as it has the function short-hand instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("let {get foo() {}} = {};"); }, SyntaxError, "Invalid object pattern as it has the get function short-hand instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("let {set foo() {}} = {};"); }, SyntaxError, "Invalid object pattern as it has the set function short-hand instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("let {get ['foo']() {}} = {};"); }, SyntaxError, "Invalid object pattern as it has the get function name as computed property instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("let {set ['foo'](a) {}} = {};"); }, SyntaxError, "Invalid object pattern as it has the set function name as computed property instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("({foo() {}} = {});"); }, SyntaxError, "Invalid object expression pattern as it has the function short-hand instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("({get foo() {}} = {});"); }, SyntaxError, "Invalid object expression pattern as it has the get function short-hand instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("({set foo(a) {}} = {});"); }, SyntaxError, "Invalid object expression pattern as it has the set function short-hand instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("({get ['foo']() {}} = {});"); }, SyntaxError, "Invalid object expression pattern as it has the get function name as computed property instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("({set ['foo'](a) {}} = {});"); }, SyntaxError, "Invalid object expression pattern as it has the set function name as computed property instead of binding identifier", "Invalid destructuring assignment target");
assert.throws(function () { eval("for(var [z] = function ([a]) { } in []) {}"); }, SyntaxError, "Initializer as function expression is not valid syntax", "for-in loop head declarations cannot have an initializer");
}
},
{
name: "Object destructuring with `get` and `set` identifiers",
body: function () {
var { get } = { get: 1 };
let { set } = { set: 2 };
assert.areEqual(1, get, "`get` is a valid object destructuring name");
assert.areEqual(2, set, "`set` is a valid object destructuring name");
assert.throws(function () { eval("var { get foo() { } } = { get: 1 };"); }, SyntaxError, "getter accessor is not a valid object destructuring name", "Invalid destructuring assignment target");
assert.throws(function () { eval("var { set bar(x) { } } = { set: 2 };"); }, SyntaxError, "setter accessor is not a valid object destructuring name", "Invalid destructuring assignment target");
const { get: x } = { get: 3 };
var { set: y } = { set: 4 };
assert.areEqual(3, x, "`get` is a valid object destructuring name mapping");
assert.areEqual(4, y, "`set` is a valid object destructuring name mapping");
}
},
{
name: "Object destructuring with shorthand initializer",
body: function () {
assert.doesNotThrow(function () { eval("({x = 1} = {});"); }, "Object pattern has shorthand with initializer is a valid syntax");
assert.doesNotThrow(function () { eval("({x, y = 1, z = 2} = {});"); }, "Object pattern has multiple shorthands with initializer is a valid syntax");
assert.throws(function () { eval("var a = 1; ({x, y = 1, z = 2} = {a = 2});"); }, SyntaxError,"Initializer is allowed on shorthand of object pattern but not on object literal", "Expected ':'");
assert.throws(function () { eval("var a = 1; ({x, y = {a = 1}} = {});"); }, SyntaxError,"Object literal is within object pattern but has shorthand initializer is not valid syntax", "Expected ':'");
assert.doesNotThrow(function () { eval("var a = 1; ({x = {a = 1} = {}} = {});"); }, "Chained object patterns have shorthand initializers is a valid syntax");
assert.doesNotThrow(function () { eval("var a = 1; var {x = {a = 1} = {}} = {};"); }, "Chained object declaration pattern have shorthand initializers is a valid syntax");
assert.doesNotThrow(function () { eval("[{x : [{y:{z = 1}}] }] = [{x:[{y:{}}]}];"); }, "Mixed nesting pattern has shorthand initializer is a valid syntax");
assert.doesNotThrow(function () { eval("[{x : [{y:{z = 1}, z1 = 2}] }, {x2 = 3}, {x3 : {y3:[{z3 = 4}]}} ] = [{x:[{y:{}}]}, {}, {x3:{y3:[{}]}}];"); },
"Mixed object patterns both on nested and on same level have initializers on shorthand and is a valid syntax");
assert.doesNotThrow(function () { eval("var [{x : [{y:{z = 1}, z1 = 2}] }, {x2 = 3}, {x3 : {y3:[{z3 = 4}]}} ] = [{x:[{y:{}}]}, {}, {x3:{y3:[{}]}}];"); },
"Declaration - mixed object patterns both on nested and on same level have initializers on shorthand and is a valid syntax");
assert.doesNotThrow(function () { eval("[...{x = 1}] = [{}]"); }, "Object pattern following rest has shorthand initializer is a valid syntax");
{
let a1 = 1;
({x:{a1 = 2}} = {x:{}});
assert.areEqual(a1, 2);
}
assert.throws(function () { eval("var a = 1; switch(true) { case {a = 1} : break; };"); }, SyntaxError, "Object literal on case has initializer is not valid syntax", "Expected ':'");
}
},
{
name: "Object destructuring basic functionality",
body: function () {
{
var x3, x4;
let {x:x1} = {x:20};
assert.areEqual(x1, 20, "Object declaration pattern should match the pattern and initializes that variable correctly");
let {x2} = {x2:20};
assert.areEqual(x2, 20, "Object declaration pattern (shorthand) should match the pattern and initializes that variable correctly");
({x:x3} = {x:20});
assert.areEqual(x3, 20, "Object expression pattern should match the pattern and initializes that variable correctly");
({x4} = {x4:20});
assert.areEqual(x4, 20, "Object expression pattern (shorthand) should match the pattern and initializes that variable correctly even under a paren");
}
{
let {x:x1} = {};
assert.areEqual(x1, undefined, "Object declaration pattern find no match pattern on rhs and initialize to undefined");
let {x2} = {zee:20};
assert.areEqual(x2, undefined, "Object declaration pattern does not match pattern on rhs and initialize to undefined");
let x3, x4;
({x:x3} = {});
assert.areEqual(x3, undefined, "Object expression pattern find no match pattern on rhs and initialize to undefined");
({x4} = {foobar:20});
assert.areEqual(x4, undefined, "Object expression pattern does not match pattern on rhs and initialize to undefined");
}
{
let {x:x1, y: y1, z: z1} = {x:11, y:22, z:33, foo:44};
assert.areEqual(x1, 11, "Object declaration pattern with multiple members should match the first member correctly");
assert.areEqual(y1, 22, "Object declaration pattern with multiple members should match the second member correctly");
assert.areEqual(z1, 33, "Object declaration pattern with multiple members should match the third member correctly");
let x2, y2, z2;
({x:x2, y: y2, z: z2} = {x:11, bar:44, y:22, z:33});
assert.areEqual(x2, 11, "Object expression pattern with multiple members should match the first member correctly");
assert.areEqual(y2, 22, "Object expression pattern with multiple members should match the second member correctly");
assert.areEqual(z2, 33, "Object expression pattern with multiple members should match the third member correctly");
}
{
var y1, x1;
var z = {x:x1} = {y:y1} = {x:10, y:20};
assert.areEqual(x1, 10, "Object declaration pattern with chained assignments should match first member to rhs correctly");
assert.areEqual(y1, 20, "Object expression pattern with chained assignments should match second member to rhs correctly");
}
}
},
{
name: "Object destructuring functionality with initializer",
body : function () {
let {x:a = 1} = {x:undefined};
assert.areEqual(a, 1, "Object declaration pattern should match the pattern but it is evaluated to undefined so assign default correctly");
let {x:a1 = 1} = {x:null};
assert.areEqual(a1, null, "Object declaration pattern should match the pattern and assigned null correctly");
let {x:x1 = 1, y:y1 = 2, z: z1 = 3} = {};
assert.areEqual(x1, 1, "Object declaration pattern - first member initialized with default when no match found on rhs");
assert.areEqual(y1, 2, "Object declaration pattern - second member initialized with default when no match found on rhs");
assert.areEqual(z1, 3, "Object declaration pattern - third member initialized with default when no match found on rhs");
let x2, y2, z2;
({x:x2 = 1, y:y2 = 2, z:z2 = 3} = {z:11});
assert.areEqual(x2, 1, "Object expression pattern - first member initialized with default when no match found on rhs");
assert.areEqual(y2, 2, "Object expression pattern - second member initialized with default when no match found on rhs");
assert.areEqual(z2, 11, "Object expression pattern - third member has pattern match on rhs and should have assigned correctly");
let { x: { y:z } = { y:21 } } = {};
assert.areEqual(z, 21, "Object declaration pattern has default on nested");
let {
x:{
y:{
z:{
k:k2 = 31
} = { k:21 }
} = { z:{ k:20 } }
} = { y: { z:{} } }
} = { x:{ y:{ z:{} } } };
assert.areEqual(k2, 31, "Object declaration pattern has defaults on different level and got the inner most default");
({
x:{
y:{
z:{
k:k2 = 31
} = {k:21}
} = {z:{k:20}}
} = {y:{z:{}}}
} = {x:{y:{z:undefined}}});
assert.areEqual(k2, 21,"Object expression pattern has default on different level but got the rhs");
}
},
{
name: "Object destructuring functionality with non-name pattern",
body : function () {
let {1:x1, 0:y1} = [11, 22];
let {0:x2} = {"0":33};
let {function:x3} = {function:44};
assert.areEqual(x1, 22, "Object declaration pattern should match the second index on rhs array");
assert.areEqual(y1, 11, "Object declaration pattern should match the first index on rhs array");
assert.areEqual(x2, 33, "Object declaration pattern should match '0' on rhs");
assert.areEqual(x3, 44, "Object declaration pattern should match the name even though it is a keyword");
}
},
{
name: "Object destructuring functionality with computed property",
body : function () {
{
let key = 'x', x2;
let {[key]:x1} = {x:20};
assert.areEqual(x1, 20, "Object declaration pattern should match the computed property name as a pattern");
({[key]:x2} = {x:20});
assert.areEqual(x2, 20, "Object expression pattern should match the computed property name as a pattern");
({[`abc${"def"}`]:x2} = {abcdef:30});
assert.areEqual(x2, 30, "Object expression pattern should match the the complex computed property name as a pattern");
}
{
let [i,j] = [0,0];
function getName() {
if (i++ == 0) return 'x';
else return 'y'
}
function getData() {
assert.areEqual(i, 0, "RHS object should be initialized before");
if (j++ == 0) return 'this is x';
else return 'this is y';
}
let {[getName()]:x1, [getName()]:y1} = {x:getData(), y:getData()};
assert.areEqual(x1, 'this is x', "Object declaration pattern depicting initializing order should match first pattern evaluated on runtime");
assert.areEqual(y1, 'this is y', "Object declaration pattern depicting initializing order should match second pattern evaluated on runtime");
}
}
},
{
name: "Object destructuring functionality with property reference",
body : function () {
let a = {};
({x:a.x} = {x:10});
assert.areEqual(10, a.x, "Object expression pattern should assign value on property reference on object correctly");
({x:a['x']} = {x:20});
assert.areEqual(20, a["x"], "Object expression pattern should assign value on property reference as index on object correctly");
var obj = { x: 10, y: 20 };
function foo() { return obj };
({x:foo().x, y:foo().y} = {x:20, y:30});
assert.areEqual(20, obj.x, "Object expression pattern should assign value on first property reference on a call expression correctly");
assert.areEqual(30, obj.y, "Object expression pattern should assign value on second property reference on a call expression correctly");
(((((({x:foo().x, y:foo().y} = {x:201, y:301}))))));
assert.areEqual(201, obj.x, "Object expression pattern (under deep parens) should assign value on first property reference on a call expression correctly");
assert.areEqual(301, obj.y, "Object expression pattern (under deep parens) should assign value on second property reference on a call expression correctly");
}
},
{
name: "Destructing functionality - rest element as pattern",
body : function () {
let [...[a]] = [1, 2, 3];
assert.areEqual(a, 1, "Having rest element as array pattern and the identifier is initialized with first value");
let [...{1:x1}] = [1, 2, 3];
assert.areEqual(x1, 2, "Having rest element as object pattern and the identifier is initialized with second value");
let [...[,...[[x2]]]] = [[1, 2], [3, 4], 5];
assert.areEqual(x2, 3, "Rest element nesting another rest element and initialized with correct value");
}
},
{
name: "Object destructuring functionality with mixed array and object pattern",
body : function () {
let {first:f1, second : [,{y}]} = {first:'first', second:[{y:20, z:30}, {y:21, z:31}, {y:22, z:32}]};
assert.areEqual(f1, 'first', "Destructing declaration pattern should match first pattern on rhs");
assert.areEqual(y, 21, "Destructing declaration pattern should match second but nested array pattern on rhs");
let metadata = {
title: "Foobar",
copies: [
{
locale: "en",
title: "first"
},
{
locale: "de",
title: "second"
},
{
locale: "ps",
title: "third"
},
],
url: "http://foobar.com"
};
let { title: englishTitle, copies: [{locale : myLocale}] } = metadata;
assert.areEqual(englishTitle, 'Foobar', "Destructing declaration pattern should match first pattern on rhs");
assert.areEqual(myLocale, 'en', "Destructing declaration pattern should match second pattern on rhs");
({ copies: [,{locale : myLocale}] } = metadata);
assert.areEqual(myLocale, 'de', "Destructing expression pattern should skip first array item and match second item on rhs");
let [{x}, {z}] = [{x:1, z:20}, {x:2, z:30}, {x:3,z:40}];
assert.areEqual(x, 1, "Object under array declaration pattern should match the first pattern");
assert.areEqual(z, 30, "Object under array declaration pattern should match the second pattern");
[{x:x}, , {z:z}] = [{x:11, z:201}, {x:21, z:301}, {x:31,z:401}];
assert.areEqual(x, 11, "Object under array expression pattern should match the first pattern");
assert.areEqual(z, 401, "Object under array expression pattern should match the third pattern");
}
},
{
name: "Object destructuring functionality with for/while",
body : function () {
let i = 0, data = [20, 30];
for ( let {x:item} of [{x:20}, {x:30}]) {
assert.areEqual(item, data[i++], "Object declaration pattern under for..of should match pattern correctly");
}
function data2() {
return {x:[{y:[20]}, {y:[30]}]};
}
i = 0;
for ({y:[item]} of data2().x) {
assert.areEqual(item, data[i++], "Object expression pattern under for..of should match pattern correctly");
}
i = 0; data = [10, 12, 14, 16, 18];
for (let {x, y} = {x:10, y:20}; x<y; {x:x} = {x:x+2}) {
assert.areEqual(x, data[i++], "Object declaration pattern under native..for should match pattern correctly");
}
let y2 = 20;
i = 0; data = [18, 16, 14, 12, 10];
while ({y:y2} = {y:y2-2}) {
assert.areEqual(y2, data[i++], "Object expression pattern under while should match pattern correctly");
if (y2 == 10) {
break;
}
}
}
}
];
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });