Repository: unexpectedjs/unexpected
Pull request #412 (2017-08-04 09:57:45)

implicit return multiline arrow function inspection
Before the fix, the added test would fail with the following error:

```js
expect(
  a =>
    a + 1,
  'to inspect as',
  'a => \n     a + 1'
);
```

```

  1) function type should render an implicit return multiline arrow function:
     TypeError: Cannot read property 'length' of undefined
      at Object.inspect (lib/types.js:790:70)
      at Object.extendedType.inspect (lib/Unexpected.js:738:36)
      at printOutput (lib/Unexpected.js:314:24)
      at Function.Unexpected.inspect (lib/Unexpected.js:328:12)
      at Function.<anonymous> (test/common.js:10:19)
      at executeExpect (lib/Unexpected.js:1205:50)
      at Unexpected.expect (lib/Unexpected.js:1209:22)
      at expect (lib/Unexpected.js:849:27)
      at Context.<anonymous> (test/types/function-type.spec.js:172:13)
```

gustavnikolaj: I found a fix by deferring the checking for the implicitly returning arrow functions w/o braces, until after we have checked for the ones with braces. I can squash down the commits, if we want them to be more tidy, or we can just squash it all down to one using the interface here on GitHub.

Would like to have a review first though :-)

Patch:
diff --git a/documentation/assertions/any/to-be.md b/documentation/assertions/any/to-be.md
index c4fcc2bb..0793eabb 100644
--- a/documentation/assertions/any/to-be.md
+++ b/documentation/assertions/any/to-be.md
@@ -1,4 +1,4 @@
-Asserts equality using `Object.is`/the [SameValue](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevalue) algorithm.
+Asserts equality using `Object.is`/the [SameValue](http://ecma-international.org/ecma-262/5.1/#sec-9.12) algorithm.
 
 ```javascript
 var obj = {};
diff --git a/documentation/index.md b/documentation/index.md
index 466a9f5a..42cce8a4 100644
--- a/documentation/index.md
+++ b/documentation/index.md
@@ -221,7 +221,7 @@ The source for Unexpected can be found on
 ### 6.0.0
 
 * New documentation and [corresponding site](https://unexpectedjs.github.io/).
-* Use `Object.is`/the [SameValue algorithm](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevalue) when checking equality of primitive values (the `to be` and `to equal` assertions).
+* Use `Object.is`/the [SameValue algorithm](http://ecma-international.org/ecma-262/5.1/#sec-9.12) when checking equality of primitive values (the `to be` and `to equal` assertions).
 * Tweaked the output of numerous assertions.
 * Constrained `to be empty` and `to have length` to only work with strings and array-like objects.
 * Renamed the `arrayLike` type to `array-like`.
diff --git a/lib/types.js b/lib/types.js
index 442abd5d..5314025d 100644
--- a/lib/types.js
+++ b/lib/types.js
@@ -775,6 +775,7 @@ module.exports = function (expect) {
                 body = matchSource[2];
                 var matchBodyAndIndent = body.match(/^(\s*\{)([\s\S]*?)([ ]*)\}\s*$/);
                 var openingBrace;
+                var isWrappedInBraces = true;
                 var closingBrace = '}';
                 if (matchBodyAndIndent) {
                     openingBrace = matchBodyAndIndent[1];
@@ -783,6 +784,17 @@ module.exports = function (expect) {
                     if (bodyIndent.length === 1) {
                         closingBrace = ' }';
                     }
+                } else {
+                    // Attempt to match an arrow function with an implicit return body.
+                    matchBodyAndIndent = body.match(/^(\s*)([\s\S]*?)([ ]*)\s*$/);
+
+                    if (matchBodyAndIndent) {
+                        openingBrace = matchBodyAndIndent[1];
+                        isWrappedInBraces = false;
+                        body = matchBodyAndIndent[2];
+                        bodyIndent = matchBodyAndIndent[3] || '';
+                        closingBrace = '';
+                    }
                 }
 
                 // Remove leading indentation unless the function is a one-liner or it uses multiline string literals
@@ -801,7 +813,7 @@ module.exports = function (expect) {
                     closingBrace = '}';
                 } else if (/^\s*$/.test(body)) {
                     body = '';
-                } else if (/^\s*[^\r\n]{1,30}\s*$/.test(body) && body.indexOf('//') === -1) {
+                } else if (/^\s*[^\r\n]{1,30}\s*$/.test(body) && body.indexOf('//') === -1 && isWrappedInBraces) {
                     body = ' ' + body.trim() + ' ';
                     closingBrace = '}';
                 } else {


Test patch:
diff --git a/test/types/function-type.spec.js b/test/types/function-type.spec.js
index a2566c88..0ef77e0d 100644
--- a/test/types/function-type.spec.js
+++ b/test/types/function-type.spec.js
@@ -160,6 +160,34 @@ describe('function type', function () {
         });
     }
 
+    // We can't complete this test if the runtime doesn't support arrow functions:
+    var implicitReturnMultilineArrowFunction;
+    try {
+        implicitReturnMultilineArrowFunction = new Function(
+            'return a => \n    a + 1;'
+        )();
+    } catch (e) {}
+
+    if (implicitReturnMultilineArrowFunction) {
+        it('should render an implicit return multiline arrow function', function () {
+            expect(implicitReturnMultilineArrowFunction, 'to inspect as', 'a => \n    a + 1');
+        });
+    }
+
+    // We can't complete this test if the runtime doesn't support arrow functions:
+    var evilImplicitReturnMultilineArrowFunction;
+    try {
+        evilImplicitReturnMultilineArrowFunction = new Function(
+            'return a => \n    a || {};'
+        )();
+    } catch (e) {}
+
+    if (evilImplicitReturnMultilineArrowFunction) {
+        it('should render an implicit return multiline arrow function with an evil alternation', function () {
+            expect(evilImplicitReturnMultilineArrowFunction, 'to inspect as', 'a => \n    a || {}');
+        });
+    }
+
     // We can't complete this test if the runtime doesn't support arrow functions:
     var multiParamArrowFunction;
     try {