]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: improve coverage
authorEvan You <yyx990803@gmail.com>
Tue, 24 Sep 2019 20:35:01 +0000 (16:35 -0400)
committerEvan You <yyx990803@gmail.com>
Tue, 24 Sep 2019 20:35:01 +0000 (16:35 -0400)
packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap
packages/compiler-core/__tests__/codegen.spec.ts
packages/compiler-core/__tests__/transforms/transformElement.spec.ts
packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/parse.ts
packages/compiler-core/src/transform.ts
packages/compiler-core/src/utils.ts

index 1bafff968c7e35bf4e4e8303d600a6b1361abe7e..08c0b3e928b05f740be8254da42918b467e98465 100644 (file)
@@ -5,8 +5,9 @@ exports[`compiler: codegen callExpression + objectExpression + arrayExpression 1
   with (this) {
     return createVNode(\\"div\\", {
       id: \\"foo\\",
-      [prop]: bar
-    }, [
+      [prop]: bar,
+      [foo + bar]: bar
+    }, [createVNode(\\"p\\", { \\"some-key\\": \\"foo\\" })], [
       foo,
       createVNode(\\"p\\")
     ])
@@ -22,6 +23,14 @@ exports[`compiler: codegen comment 1`] = `
 }"
 `;
 
+exports[`compiler: codegen compound expression 1`] = `
+"return function render() {
+  with (this) {
+    return toString(_ctx.foo)
+  }
+}"
+`;
+
 exports[`compiler: codegen forNode 1`] = `
 "return function render() {
   with (this) {
@@ -30,6 +39,30 @@ exports[`compiler: codegen forNode 1`] = `
 }"
 `;
 
+exports[`compiler: codegen forNode w/ skipped key alias 1`] = `
+"return function render() {
+  with (this) {
+    return renderList(list, (v, __key, i) => toString(v))
+  }
+}"
+`;
+
+exports[`compiler: codegen forNode w/ skipped value alias 1`] = `
+"return function render() {
+  with (this) {
+    return renderList(list, (__value, k, i) => toString(v))
+  }
+}"
+`;
+
+exports[`compiler: codegen forNode w/ skipped value and key aliases 1`] = `
+"return function render() {
+  with (this) {
+    return renderList(list, (__value, __key, i) => toString(v))
+  }
+}"
+`;
+
 exports[`compiler: codegen function mode preamble 1`] = `
 "const { helperOne, helperTwo } = Vue
 
@@ -52,6 +85,18 @@ exports[`compiler: codegen ifNode 1`] = `
 }"
 `;
 
+exports[`compiler: codegen ifNode with no v-else 1`] = `
+"return function render() {
+  with (this) {
+    return (foo)
+      ? \\"foo\\"
+      : (bar)
+        ? toString(bye)
+        : null
+  }
+}"
+`;
+
 exports[`compiler: codegen interpolation 1`] = `
 "return function render() {
   with (this) {
index daf84568ad8f8452199dff066054b2a64851ec0a..38ef6b0675059436d8f2352e30408c97c5c931a8 100644 (file)
@@ -7,9 +7,11 @@ import {
   createExpression,
   Namespaces,
   ElementTypes,
+  CallExpression,
   createObjectExpression,
   createObjectProperty,
-  createArrayExpression
+  createArrayExpression,
+  ElementNode
 } from '../src'
 import { SourceMapConsumer, RawSourceMap } from 'source-map'
 import { CREATE_VNODE, COMMENT, TO_STRING } from '../src/runtimeConstants'
@@ -145,6 +147,25 @@ describe('compiler: codegen', () => {
     expect(code).toMatchSnapshot()
   })
 
+  test('compound expression', () => {
+    const { code } = generate(
+      createRoot({
+        children: [
+          {
+            type: NodeTypes.EXPRESSION,
+            content: 'foo',
+            isStatic: false,
+            isInterpolation: true,
+            loc: mockLoc,
+            children: [`_ctx.`, createExpression(`foo`, false, mockLoc)]
+          }
+        ]
+      })
+    )
+    expect(code).toMatch(`return toString(_ctx.foo)`)
+    expect(code).toMatchSnapshot()
+  })
+
   test('ifNode', () => {
     const { code } = generate(
       createRoot({
@@ -202,6 +223,50 @@ describe('compiler: codegen', () => {
     expect(code).toMatchSnapshot()
   })
 
+  test('ifNode with no v-else', () => {
+    const { code } = generate(
+      createRoot({
+        children: [
+          {
+            type: NodeTypes.IF,
+            loc: mockLoc,
+            isRoot: true,
+            branches: [
+              {
+                type: NodeTypes.IF_BRANCH,
+                condition: createExpression('foo', false, mockLoc),
+                loc: mockLoc,
+                isRoot: true,
+                children: [
+                  {
+                    type: NodeTypes.TEXT,
+                    content: 'foo',
+                    isEmpty: false,
+                    loc: mockLoc
+                  }
+                ]
+              },
+              {
+                type: NodeTypes.IF_BRANCH,
+                condition: createExpression('bar', false, mockLoc),
+                loc: mockLoc,
+                isRoot: true,
+                children: [createExpression(`bye`, false, mockLoc, true)]
+              }
+            ]
+          }
+        ]
+      })
+    )
+    expect(code).toMatch(`
+    return (foo)
+      ? "foo"
+      : (bar)
+        ? ${TO_STRING}(bye)
+        : null`)
+    expect(code).toMatchSnapshot()
+  })
+
   test('forNode', () => {
     const { code } = generate(
       createRoot({
@@ -222,63 +287,166 @@ describe('compiler: codegen', () => {
     expect(code).toMatchSnapshot()
   })
 
-  test('callExpression + objectExpression + arrayExpression', () => {
+  test('forNode w/ skipped value alias', () => {
+    const { code } = generate(
+      createRoot({
+        children: [
+          {
+            type: NodeTypes.FOR,
+            loc: mockLoc,
+            source: createExpression(`list`, false, mockLoc),
+            valueAlias: undefined,
+            keyAlias: createExpression(`k`, false, mockLoc),
+            objectIndexAlias: createExpression(`i`, false, mockLoc),
+            children: [createExpression(`v`, false, mockLoc, true)]
+          }
+        ]
+      })
+    )
+    expect(code).toMatch(`renderList(list, (__value, k, i) => toString(v))`)
+    expect(code).toMatchSnapshot()
+  })
+
+  test('forNode w/ skipped key alias', () => {
+    const { code } = generate(
+      createRoot({
+        children: [
+          {
+            type: NodeTypes.FOR,
+            loc: mockLoc,
+            source: createExpression(`list`, false, mockLoc),
+            valueAlias: createExpression(`v`, false, mockLoc),
+            keyAlias: undefined,
+            objectIndexAlias: createExpression(`i`, false, mockLoc),
+            children: [createExpression(`v`, false, mockLoc, true)]
+          }
+        ]
+      })
+    )
+    expect(code).toMatch(`renderList(list, (v, __key, i) => toString(v))`)
+    expect(code).toMatchSnapshot()
+  })
+
+  test('forNode w/ skipped value and key aliases', () => {
     const { code } = generate(
       createRoot({
         children: [
           {
-            type: NodeTypes.ELEMENT,
+            type: NodeTypes.FOR,
             loc: mockLoc,
-            ns: Namespaces.HTML,
-            tag: 'div',
-            tagType: ElementTypes.ELEMENT,
-            isSelfClosing: false,
-            props: [],
-            children: [],
-            codegenNode: {
-              type: NodeTypes.JS_CALL_EXPRESSION,
-              loc: mockLoc,
-              callee: CREATE_VNODE,
-              arguments: [
-                `"div"`,
+            source: createExpression(`list`, false, mockLoc),
+            valueAlias: undefined,
+            keyAlias: undefined,
+            objectIndexAlias: createExpression(`i`, false, mockLoc),
+            children: [createExpression(`v`, false, mockLoc, true)]
+          }
+        ]
+      })
+    )
+    expect(code).toMatch(`renderList(list, (__value, __key, i) => toString(v))`)
+    expect(code).toMatchSnapshot()
+  })
+
+  test('callExpression + objectExpression + arrayExpression', () => {
+    function createElementWithCodegen(
+      args: CallExpression['arguments']
+    ): ElementNode {
+      return {
+        type: NodeTypes.ELEMENT,
+        loc: mockLoc,
+        ns: Namespaces.HTML,
+        tag: 'div',
+        tagType: ElementTypes.ELEMENT,
+        isSelfClosing: false,
+        props: [],
+        children: [],
+        codegenNode: {
+          type: NodeTypes.JS_CALL_EXPRESSION,
+          loc: mockLoc,
+          callee: CREATE_VNODE,
+          arguments: args
+        }
+      }
+    }
+
+    const { code } = generate(
+      createRoot({
+        children: [
+          createElementWithCodegen([
+            // string
+            `"div"`,
+            // ObjectExpression
+            createObjectExpression(
+              [
+                createObjectProperty(
+                  createExpression(`id`, true, mockLoc),
+                  createExpression(`foo`, true, mockLoc),
+                  mockLoc
+                ),
+                createObjectProperty(
+                  createExpression(`prop`, false, mockLoc),
+                  createExpression(`bar`, false, mockLoc),
+                  mockLoc
+                ),
+                // compound expression as computed key
+                createObjectProperty(
+                  {
+                    type: NodeTypes.EXPRESSION,
+                    content: ``,
+                    loc: mockLoc,
+                    isStatic: false,
+                    isInterpolation: false,
+                    children: [
+                      `foo + `,
+                      createExpression(`bar`, false, mockLoc)
+                    ]
+                  },
+                  createExpression(`bar`, false, mockLoc),
+                  mockLoc
+                )
+              ],
+              mockLoc
+            ),
+            // ChildNode[]
+            [
+              createElementWithCodegen([
+                `"p"`,
                 createObjectExpression(
                   [
                     createObjectProperty(
-                      createExpression(`id`, true, mockLoc),
+                      // should quote the key!
+                      createExpression(`some-key`, true, mockLoc),
                       createExpression(`foo`, true, mockLoc),
                       mockLoc
-                    ),
-                    createObjectProperty(
-                      createExpression(`prop`, false, mockLoc),
-                      createExpression(`bar`, false, mockLoc),
-                      mockLoc
                     )
                   ],
                   mockLoc
-                ),
-                createArrayExpression(
-                  [
-                    'foo',
-                    {
-                      type: NodeTypes.JS_CALL_EXPRESSION,
-                      loc: mockLoc,
-                      callee: CREATE_VNODE,
-                      arguments: [`"p"`]
-                    }
-                  ],
-                  mockLoc
                 )
-              ]
-            }
-          }
+              ])
+            ],
+            // ArrayExpression
+            createArrayExpression(
+              [
+                'foo',
+                {
+                  type: NodeTypes.JS_CALL_EXPRESSION,
+                  loc: mockLoc,
+                  callee: CREATE_VNODE,
+                  arguments: [`"p"`]
+                }
+              ],
+              mockLoc
+            )
+          ])
         ]
       })
     )
     expect(code).toMatch(`
     return ${CREATE_VNODE}("div", {
       id: "foo",
-      [prop]: bar
-    }, [
+      [prop]: bar,
+      [foo + bar]: bar
+    }, [${CREATE_VNODE}("p", { "some-key": "foo" })], [
       foo,
       ${CREATE_VNODE}("p")
     ])`)
index 95a55227dabdd49a3facd998dcda7315317be7a9..af39a3b8d6b3c04cad4adeb7fb4be5f3e8f0c630 100644 (file)
@@ -80,6 +80,46 @@ describe('compiler: element transform', () => {
     ])
   })
 
+  test('props + children', () => {
+    const { node } = parseWithElementTransform(`<div id="foo"><span/></div>`)
+    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.arguments).toMatchObject([
+      `"div"`,
+      createStaticObjectMatcher({
+        id: 'foo'
+      }),
+      [
+        {
+          type: NodeTypes.ELEMENT,
+          tag: 'span',
+          codegenNode: {
+            callee: CREATE_VNODE,
+            arguments: [`"span"`]
+          }
+        }
+      ]
+    ])
+  })
+
+  test('0 placeholder for children with no props', () => {
+    const { node } = parseWithElementTransform(`<div><span/></div>`)
+    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.arguments).toMatchObject([
+      `"div"`,
+      `0`,
+      [
+        {
+          type: NodeTypes.ELEMENT,
+          tag: 'span',
+          codegenNode: {
+            callee: CREATE_VNODE,
+            arguments: [`"span"`]
+          }
+        }
+      ]
+    ])
+  })
+
   test('v-bind="obj"', () => {
     const { root, node } = parseWithElementTransform(`<div v-bind="obj" />`)
     // single v-bind doesn't need mergeProps
index ae4cba926c13f2709178b46eeaaadbf0266c8199..85089bd223d6c65753c9bc05fba5d1be2fd706f9 100644 (file)
@@ -5,16 +5,21 @@ import {
   ElementNode,
   DirectiveNode,
   NodeTypes,
-  ForNode
+  ForNode,
+  CompilerOptions
 } from '../../src'
 import { transformFor } from '../..//src/transforms/vFor'
 import { transformExpression } from '../../src/transforms/transformExpression'
 
-function parseWithExpressionTransform(template: string) {
+function parseWithExpressionTransform(
+  template: string,
+  options: CompilerOptions = {}
+) {
   const ast = parse(template)
   transform(ast, {
     prefixIdentifiers: true,
-    nodeTransforms: [transformFor, transformExpression]
+    nodeTransforms: [transformFor, transformExpression],
+    ...options
   })
   return ast.children[0]
 }
@@ -297,4 +302,10 @@ describe('compiler: expression transform', () => {
       `]`
     ])
   })
+
+  test('should handle parse error', () => {
+    const onError = jest.fn()
+    parseWithExpressionTransform(`{{ a( }}`, { onError })
+    expect(onError.mock.calls[0][0].message).toMatch(`Expected ')'`)
+  })
 })
index 0e0c085e2f972c2c165c947cb9eb6f2df9e0b9c4..559e3942c811e62cd825532c8d4639ec340ddf00 100644 (file)
@@ -277,6 +277,7 @@ function genNode(node: CodegenNode, context: CodegenContext) {
       genArrayExpression(node, context)
       break
     default:
+      /* istanbul ignore next */
       __DEV__ &&
         assert(false, `unhandled codegen node type: ${(node as any).type}`)
   }
@@ -399,7 +400,7 @@ function genFor(node: ForNode, context: CodegenContext) {
   }
   if (keyAlias) {
     if (!valueAlias) {
-      push(`_`)
+      push(`__value`)
     }
     push(`, `)
     genExpression(keyAlias, context)
@@ -407,9 +408,9 @@ function genFor(node: ForNode, context: CodegenContext) {
   if (objectIndexAlias) {
     if (!keyAlias) {
       if (!valueAlias) {
-        push(`_, __`)
+        push(`__value, __key`)
       } else {
-        push(`__`)
+        push(`, __key`)
       }
     }
     push(`, `)
@@ -447,12 +448,9 @@ function genObjectExpression(node: ObjectExpression, context: CodegenContext) {
     // value
     genExpression(value, context)
     if (i < properties.length - 1) {
-      if (multilines) {
-        push(`,`)
-        newline()
-      } else {
-        push(`, `)
-      }
+      // will only reach this if it's multilines
+      push(`,`)
+      newline()
     }
   }
   multilines && deindent()
index 0df48ed5188350ee94c5d9c093803e66ae425cc9..84677fd87377f5d2547fa6152086b28675998e3d 100644 (file)
@@ -199,6 +199,7 @@ function pushNode(
   node: ChildNode
 ): void {
   // ignore comments in production
+  /* istanbul ignore next */
   if (!__DEV__ && node.type === NodeTypes.COMMENT) {
     return
   }
index b0a1278c6722b46710969fec186f1fca6b92c79a..4dac7986ab5672b818afe767055699fc229e3a01 100644 (file)
@@ -85,6 +85,7 @@ function createTransformContext(
     childIndex: 0,
     currentNode: null,
     replaceNode(node) {
+      /* istanbul ignore if */
       if (__DEV__ && !context.currentNode) {
         throw new Error(`node being replaced is already removed.`)
       }
@@ -97,6 +98,7 @@ function createTransformContext(
         : context.currentNode
           ? context.childIndex
           : -1
+      /* istanbul ignore if */
       if (__DEV__ && removalIndex < 0) {
         throw new Error(`node being removed is not a child of current parent`)
       }
index 2a93612bd888e4ece81741e572304a1a913a49ab..59704a2d633ae1dcf31963750b1a2456a4870272 100644 (file)
@@ -60,6 +60,7 @@ export function advancePositionWithMutation(
 }
 
 export function assert(condition: boolean, msg?: string) {
+  /* istanbul ignore if */
   if (!condition) {
     throw new Error(msg || `unexpected compiler condition`)
   }