Skip to content

Commit ba32362

Browse files
Basic tests
1 parent 9369845 commit ba32362

File tree

3 files changed

+237
-0
lines changed

3 files changed

+237
-0
lines changed

test/es12/optional-chaining.js

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
4+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
5+
//-------------------------------------------------------------------------------------------------------
6+
7+
// @ts-check
8+
/// <reference path="../UnitTestFramework/UnitTestFramework.js" />
9+
10+
WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
11+
12+
const simpleObj = { "null": null, "undefined": undefined };
13+
Object.freeze(simpleObj);
14+
15+
const tests = [
16+
{
17+
name: "Simple properties",
18+
body() {
19+
// Verify normal behavior
20+
assert.throws(() => simpleObj.nothing.something, TypeError);
21+
assert.throws(() => simpleObj.null.something, TypeError);
22+
assert.throws(() => simpleObj.undefined.something, TypeError);
23+
24+
// With optional-chains
25+
assert.isUndefined(simpleObj.nothing?.something, "OptChain should evaluated to 'undefined'");
26+
assert.isUndefined(simpleObj.null?.something, "OptChain should evaluated to 'undefined'");
27+
assert.isUndefined(simpleObj.undefined?.something, "OptChain should evaluated to 'undefined'");
28+
}
29+
},
30+
{
31+
name: "Simple indexers",
32+
body() {
33+
// Verify normal behavior
34+
assert.throws(() => simpleObj.nothing["something"], TypeError);
35+
assert.throws(() => simpleObj.null["something"], TypeError);
36+
assert.throws(() => simpleObj.undefined["something"], TypeError);
37+
38+
// With optional-chains
39+
assert.isUndefined(simpleObj.nothing?.["something"], "OptChain should evaluated to 'undefined'");
40+
assert.isUndefined(simpleObj.null?.["something"], "OptChain should evaluated to 'undefined'");
41+
assert.isUndefined(simpleObj.undefined?.["something"], "OptChain should evaluated to 'undefined'");
42+
}
43+
},
44+
{
45+
name: "Simple method calls",
46+
body() {
47+
// Verify normal behavior
48+
assert.throws(() => simpleObj.nothing(), TypeError);
49+
assert.throws(() => simpleObj.null(), TypeError);
50+
assert.throws(() => simpleObj.undefined(), TypeError);
51+
52+
// With optional-chains
53+
assert.isUndefined(simpleObj.nothing?.(), "OptChain should evaluated to 'undefined'");
54+
assert.isUndefined(simpleObj.null?.(), "OptChain should evaluated to 'undefined'");
55+
assert.isUndefined(simpleObj.undefined?.(), "OptChain should evaluated to 'undefined'");
56+
}
57+
},
58+
{
59+
name: "Simple properties before call",
60+
body() {
61+
// Verify normal behavior
62+
assert.throws(() => simpleObj.nothing.something(), TypeError);
63+
assert.throws(() => simpleObj.null.something(), TypeError);
64+
assert.throws(() => simpleObj.undefined.something(), TypeError);
65+
66+
// With optional-chains
67+
assert.isUndefined(simpleObj.nothing?.something(), "OptChain should evaluated to 'undefined'");
68+
assert.isUndefined(simpleObj.null?.something(), "OptChain should evaluated to 'undefined'");
69+
assert.isUndefined(simpleObj.undefined?.something(), "OptChain should evaluated to 'undefined'");
70+
}
71+
},
72+
{
73+
name: "Simple indexers before call",
74+
body() {
75+
// Verify normal behavior
76+
assert.throws(() => simpleObj.nothing["something"], TypeError);
77+
assert.throws(() => simpleObj.null["something"], TypeError);
78+
assert.throws(() => simpleObj.undefined["something"], TypeError);
79+
80+
// With optional-chains
81+
assert.isUndefined(simpleObj.nothing?.["something"](), "OptChain should evaluated to 'undefined'");
82+
assert.isUndefined(simpleObj.null?.["something"](), "OptChain should evaluated to 'undefined'");
83+
assert.isUndefined(simpleObj.undefined?.["something"](), "OptChain should evaluated to 'undefined'");
84+
}
85+
},
86+
{
87+
name: "Short-circuiting ignores indexer expression and method args",
88+
body() {
89+
let i = 0;
90+
91+
assert.isUndefined(simpleObj.nothing?.[i++]);
92+
assert.isUndefined(simpleObj.null?.[i++]);
93+
assert.isUndefined(simpleObj.undefined?.[i++]);
94+
95+
assert.isUndefined(simpleObj.nothing?.[i++]());
96+
assert.isUndefined(simpleObj.null?.[i++]());
97+
assert.isUndefined(simpleObj.undefined?.[i++]());
98+
99+
assert.isUndefined(simpleObj.nothing?.something(i++));
100+
assert.isUndefined(simpleObj.null?.something(i++));
101+
assert.isUndefined(simpleObj.undefined?.something(i++));
102+
103+
assert.strictEqual(0, i, "Indexer may never be evaluated");
104+
105+
// ToDo: How can I run async tests?
106+
// simpleObj.nothing?.[await Promise.reject()];
107+
// simpleObj.null?.[await Promise.reject()];
108+
// simpleObj.undefined?.[await Promise.reject()];
109+
}
110+
},
111+
{
112+
name: "Short-circuiting ignores nested properties",
113+
body() {
114+
assert.isUndefined(simpleObj.nothing?.a.b.c.d.e.f.g.h);
115+
assert.isUndefined(simpleObj.null?.a.b.c.d.e.f.g.h);
116+
assert.isUndefined(simpleObj.undefined?.a.b.c.d.e.f.g.h);
117+
}
118+
},
119+
{
120+
name: "Short-circuiting multiple levels",
121+
body() {
122+
let i = 0;
123+
const specialObj = {
124+
get null() {
125+
i++;
126+
return null;
127+
},
128+
get undefined() {
129+
i++;
130+
return undefined;
131+
}
132+
};
133+
134+
assert.isUndefined(specialObj?.null?.a.b.c.d?.e.f.g.h);
135+
assert.isUndefined(specialObj?.undefined?.a.b.c.d?.e.f.g.h);
136+
137+
assert.areEqual(2, i, "Properties should be called")
138+
}
139+
},
140+
{
141+
name: "Propagate 'this' correctly",
142+
body() {
143+
const specialObj = {
144+
b() { return this._b; },
145+
_b: { c: 42 }
146+
};
147+
148+
assert.areEqual(42, specialObj.b().c);
149+
assert.areEqual(42, specialObj?.b().c);
150+
assert.areEqual(42, specialObj.b?.().c);
151+
assert.areEqual(42, specialObj?.b?.().c);
152+
assert.areEqual(42, (specialObj?.b)().c);
153+
assert.areEqual(42, (specialObj.b)?.().c);
154+
assert.areEqual(42, (specialObj?.b)?.().c);
155+
}
156+
},
157+
// Null check
158+
{
159+
name: "Only check for 'null' and 'undefined'",
160+
body() {
161+
assert.areEqual(0, ""?.length, "Expected empty string length");
162+
}
163+
},
164+
// Parsing
165+
{
166+
name: "Parse ternary correctly",
167+
body() {
168+
assert.areEqual(0.42, eval(`"this is not falsy"?.42 : 0`));
169+
}
170+
},
171+
{
172+
name: "Tagged Template in OptChain is illegal",
173+
body() {
174+
assert.throws(() => eval("simpleObj.undefined?.`template`"), SyntaxError, "No TaggedTemplate here", "Invalid tagged template in optional chain.");
175+
assert.throws(() => eval(`simpleObj.undefined?.
176+
\`template\``), SyntaxError, "No TaggedTemplate here", "Invalid tagged template in optional chain.");
177+
}
178+
},
179+
{
180+
name: "No new in OptChain",
181+
body() {
182+
assert.throws(() => eval(`
183+
class Test { }
184+
new Test?.();
185+
`), SyntaxError, "'new' in OptChain is illegal", "Invalid optional chain in new expression.");
186+
}
187+
},
188+
{
189+
name: "No super in OptChain",
190+
body() {
191+
assert.throws(() => eval(`
192+
class Base { }
193+
class Test extends Base {
194+
constructor(){
195+
super?.();
196+
}
197+
}
198+
`), SyntaxError, "Super in OptChain is illegal", "Invalid use of the 'super' keyword");
199+
200+
assert.throws(() => eval(`
201+
class Base { }
202+
class Test extends Base {
203+
constructor(){
204+
super();
205+
206+
super?.abc;
207+
}
208+
}
209+
`), SyntaxError, "Super in OptChain is illegal", "Invalid use of the 'super' keyword");
210+
}
211+
},
212+
{
213+
name: "No assignment",
214+
body() {
215+
const a = {};
216+
assert.throws(() => eval(`a?.b++`), SyntaxError, "Assignment is illegal", "Invalid left-hand side in assignment.");
217+
assert.throws(() => eval(`a?.b += 1`), SyntaxError, "Assignment is illegal", "Invalid left-hand side in assignment.");
218+
assert.throws(() => eval(`a?.b = 5`), SyntaxError, "Assignment is illegal", "Invalid left-hand side in assignment.");
219+
}
220+
}
221+
];
222+
223+
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

test/es12/rlexe.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<regress-exe>
3+
<test>
4+
<default>
5+
<files>optional-chaining.js</files>
6+
<compile-flags>-args summary -endargs</compile-flags>
7+
</default>
8+
</test>
9+
</regress-exe>

test/rlexedirs.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,11 @@
272272
<files>es7</files>
273273
</default>
274274
</dir>
275+
<dir>
276+
<default>
277+
<files>es12</files>
278+
</default>
279+
</dir>
275280
<dir>
276281
<default>
277282
<files>switchStatement</files>

0 commit comments

Comments
 (0)