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

feat: adding tests for optional chaining proposal #2212

Merged
merged 9 commits into from
Aug 5, 2019

Conversation

bcoe
Copy link
Contributor

@bcoe bcoe commented Jun 24, 2019

starting to work on a few tests for optional chaining as I read and review the proposal:

Punctuators

  • ?.[lookahead ∉ DecimalDigit] link.

Left-Hand-Side Expressions

OptionalExpression:

  • MemberExpression OptionalChain
  • CallExpression OptionalChain
  • OptionalExpression OptionalChain

OptionalChain:

  • ?. [ expression ]
  • ?. IdentifierName
  • ?. Arguments
  • ?. TemplateLiteral (this production is an early error). link
  • OptionalChain [ expression ]
  • OptionalChain IdentifierName
  • OptionalChain Arguments
  • OptionalChain TemplateLiteral (this production is an early error).

Static Semantics: IsValidSimpleAssignmentTarget

  • LeftHandSideExpression: OptionalExpression link.

description: >
Static Semantics: IsDestructuring
LeftHandSideExpression:
CallExpression
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jridgewell @DanielRosenwasser @rkirsling, I read this rule as stating that destructuring is not supported in an optional chain, I also gathered that this was the outcome of:

tc39/proposal-optional-chaining#74

This test is failing because the current babel implementation supports destructuring.

Am I correct in my reading of this part of the proposal, if so I think we'll want to update the babel implementation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it seems that IsDestructuring is only checked from ForIn/OfBodyEvaluation, and I think we're just saying that if you see an OptionalExpression as an LHS, then (just like a CallExpression) that's not an example of destructuring.

So I don't know that there's anything that needs to be tested here—note that this test doesn't actually involve an optional chain at present, and the linked idea about optional destructuring is something that would require additional syntax.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rkirsling I understand, it's the concept of "optional destructuring" that's out of scope, and the proposal was something along the lines of foo?.bar?; my bad misreading that section of the spec.

@leobalter
Copy link
Member

I recommend you create a checklist of all the new productions possible by the new syntax rather than having just generic tests. Perhaps, one test here and there might work nice for feature check but there is still a big chunk of missing coverage here.

@bcoe
Copy link
Contributor Author

bcoe commented Jun 27, 2019

@leobalter I fleshed out the issue body, based on your recommendations. Is that looking like what you were picturing, if so, any recommendations for naming conventions of tests?

@bcoe bcoe force-pushed the optional-chaining-tests branch from 28cfd4f to c53665b Compare July 1, 2019 01:08
Copy link
Member

@leobalter leobalter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of missing parts here even if the checklist seems like a good start.

The tests need to expand the syntactical productions rather than just picking one for each. This also miss other cases with the await and yield positions flagged in here.

Also: chaining the OptionalChain:

OptionalChain: OptionalChain [Expression]
OptionalChain . IdentifierName
OptionalChain Arguments
OptionalChain TemplateLiteral

and mixing these together too.

There is also a need to verify the grammar of the OptionalExpression into parts receiving a LeftHandSideExpression, like e.g. LeftHandSideExpression AssignmentOperator AssignmentExpression.

It also needs expansion for cases like

MemberExpression OptionalChain
CallExpression OptionalChain
OptionalExpression OptionalChain

expanding MemberExpression and CallExpression until a fair amount of cases.


I believe this will be a much longer work as it usually is for new syntax features. I'm not sure if we should start so much effort before Stage 3 for this feature as well. I'd rather wait a bit until the proposal finds a better stability.

};

// OptionalChain: ?.[Expression]
assert.sameValue(11, arr?.[i + 1]);

This comment was marked as outdated.

assert.sameValue(11, arr?.[i + 1]);

// OptionalChain: ?.IdentifierName
assert.sameValue('hello', obj?.a);

This comment was marked as outdated.

assert.sameValue('hello', obj?.a);

// OptionalChain: ?.Arguments
assert.sameValue(30, fn?.(10, 20));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And Arguments need to be expanded to more productions too. There are some cases and templates from the test generation parts that could be reused for these.

assert.sameValue(30, fn?.(10, 20));

// OptionalChain: OptionalChain [Expression]
assert.sameValue(12, obj?.arr[i + 1]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once again, double exposition of Expression when you have [Expression][Expression] and all the multi combinations you can get here, same will go for the chain of possible productions.

info: |
optional chain on recursive optional expression
description: >
Left-Hand-Side Expressions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the content for info and description are inverted in the test files.

const a = {fn() {}};

a?.fn
`hello`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not having expanding this to verify

a?.fn`hello`;

in the same line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was specifically trying to address this section of the spec:

NOTE This production exists in order to prevent automatic semicolon insertion rules (11.9) to be applied to the following code.

... however, by adding a semi-colon to the end of the expression I was failing to actually exercise this behavior, I've split it into another test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the clarification


const fn = () => {
return {a: 33};
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

function fn() {
  return {a: 33};
}

};

assert.sameValue(33, fn()?.a);
assert.sameValue(undefined, fn()?.b?.c);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to go to c? Could definitely sport replacing it with a throwing function call, or even ?.a after ?.b

@bcoe
Copy link
Contributor Author

bcoe commented Jul 4, 2019

@leobalter I offered to review the spec text of optional chaining, as part of the entrance criteria for stage 3.

Writing tests has been helping me better dive into edge-cases of the proposal, and get a better feel for the specification.

I'd love to help see these tests further along, as it's a great learning experience. Would you rather that I close this draft until we've reached stage 3 approval? or is it okay if I continue putting some work into it.

@leobalter
Copy link
Member

Closing is not necessary but we won't be able to merge the tests until it reaches stage 3.

I'm ok to leave this open, including this new "Draft" option in the PR as a good flag. As I pointed out there is a good chunk of coverage to be done yet. I might wait until Stage 3 for another review, but feel free to ping me for any questions.

@bcoe
Copy link
Contributor Author

bcoe commented Jul 13, 2019

@leobalter I made an effort to enumerate more test cases today, reading through the spec. Let me know if this is looking more like it.

https://gist.github.com/bcoe/b0e6ae3f93f8c8b8f8559f4428187f25

Note, I put proposed file-names for the tests to the right of the productions.

@leobalter leobalter self-assigned this Jul 30, 2019
Copy link
Member

@leobalter leobalter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some few changes to let us land this PR. We can work on the extended coverage checklist through follow up PRs.

@@ -0,0 +1,17 @@
/*---
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the copyright headers into each file? They are required to part tests correctly in different test runners used to consume Test262.

@@ -0,0 +1,17 @@
/*---
esid: pending
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use esid: prod-OptionalExpression instead of any pending in the test files.

esid: pending
info: |
optional chain on call expression
description: >
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invert usage of info and description. Description is the small line, info is the large chunk.

You may keep the block characters info: | (pipe) and description: > (greater than)

@bcoe
Copy link
Contributor Author

bcoe commented Aug 1, 2019

@leobalter I have a fairly light weekend, I'll make an effort to put in a few hours expanding the cases outlined in the gist.

@leobalter
Copy link
Member

@leobalter I have a fairly light weekend, I'll make an effort to put in a few hours expanding the cases outlined in the gist.

Sure! If you can first address the small items in here, I can already land these tests. I've wrote some other tests (related) to #2262 and it's just a very small chunk from the complete coverage.

@bcoe bcoe marked this pull request as ready for review August 2, 2019 23:19
@bcoe bcoe force-pushed the optional-chaining-tests branch from 7081b52 to bc393df Compare August 5, 2019 05:55
Copy link
Member

@leobalter leobalter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests in this PR are correct. I have some follow ups I described in the comments.


$DONOTEVALUATE();

const a = {fn() {}};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be a simple var a;. To enable the test, all you need is to have a valid reference for a.

Static Semantics: Early Errors
OptionalChain:
?.TemplateLiteral
OptionalChain TemplateLiteral
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add the error part: It is a Syntax Error if any code matches this production.

// This production exists in order to prevent automatic semicolon
// insertion rules.
a?.fn
`hello`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a follow up PR: we are missing tests for the ?.TemplateLiteral productions:

a?.`hello`

// and

a?.
  `hello`

Also verify this is valid syntax:

`foo`?.bar

Static Semantics: Early Errors
OptionalChain:
?.TemplateLiteral
OptionalChain TemplateLiteral
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add the error part: It is a Syntax Error if any code matches this production.


// CallExpression Arguments
assert.sameValue(33, fn()?.a);
assert.sameValue(undefined, fn()?.b);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in a follow up PR, we should expand these to other types and checking property existence:

Currently the CallExpression evaluates to:

  1. An Object with the property a

Missing:

  1. The CallExpression evaluates to falsy values
    a. false
    b. 0
    c. ''
    d. undefined // different behavior
    e. null // same as undefined
  2. CallExpression evaluates to other type values.
    a. true
    b. 1
    c. NaN
    d. 'undefined'
    e. Symbol
  3. Verify [[Get]] from the returned object properties

This test itself is good enough as a syntax test, these expansions are more useful for further evaluation of the results.


$DONOTEVALUATE();

const a = {fn() {}};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name can be simplified here as well.


const nul = null;
const undf = undefined;
assert.sameValue(undefined, nul?.a);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for a follow up:

var x = 0;
var y = null?.[(function() { x += 1 }())];

// assert value of x to verify if the `[Expression]` has got evaluated
// assert y is undefined.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh! you did that in test/language/expressions/optional-chaining/short-circuiting.js, nice!


const obj = {};

obj?.a = 33;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@leobalter leobalter merged commit aae991d into tc39:master Aug 5, 2019
@bcoe
Copy link
Contributor Author

bcoe commented Aug 5, 2019

@leobalter 🎉 I have this PR open on my fork of test262, which I've been adding a more thorough set of grammar productions to.

I will make this PR official now that this has landed, and address your comments in it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants