]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test(vIf): add tests and refactor comment node check to use `isCommentOrWhitespace...
authoredison <daiwei521@126.com>
Wed, 26 Nov 2025 01:59:31 +0000 (09:59 +0800)
committerGitHub <noreply@github.com>
Wed, 26 Nov 2025 01:59:31 +0000 (09:59 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vIf.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vIf.spec.ts
packages/compiler-vapor/src/transforms/transformComment.ts

index 608e4bac51053923a8fa752e47762031c3615ba9..232aba02a6494e651b775a30ddcbee0be1209d73 100644 (file)
@@ -308,3 +308,17 @@ export function render(_ctx) {
   return n0
 }"
 `;
+
+exports[`compiler: v-if > v-on with v-if 1`] = `
+"import { setDynamicEvents as _setDynamicEvents, renderEffect as _renderEffect, createIf as _createIf, template as _template } from 'vue';
+const t0 = _template("<button>w/ v-if</button>", true)
+
+export function render(_ctx) {
+  const n0 = _createIf(() => (true), () => {
+    const n2 = t0()
+    _renderEffect(() => _setDynamicEvents(n2, { click: _ctx.clickEvent }))
+    return n2
+  }, null, true)
+  return n0
+}"
+`;
index 728b3f9c41fdf2b352cc9c9b710138fbe7077bba..482794356ed466ee6ac32bce404d35ac6af935c3 100644 (file)
@@ -11,7 +11,7 @@ import {
   transformVOnce,
   transformVText,
 } from '../../src'
-import { NodeTypes } from '@vue/compiler-dom'
+import { ErrorCodes, NodeTypes, type RootNode } from '@vue/compiler-dom'
 
 const compileWithVIf = makeCompile({
   nodeTransforms: [
@@ -380,7 +380,181 @@ describe('compiler: v-if', () => {
     ])
   })
 
-  describe.todo('errors')
-  describe.todo('codegen')
-  test.todo('v-on with v-if')
+  test('v-on with v-if', () => {
+    const { code, ir } = compileWithVIf(
+      `<button v-on="{ click: clickEvent }" v-if="true">w/ v-if</button>`,
+    )
+    expect(code).toMatchSnapshot()
+    expect([...ir.template.keys()]).toEqual(['<button>w/ v-if</button>'])
+
+    expect(ir.block.returns).toEqual([0])
+    expect(ir.block.dynamic.children[0].operation).toMatchObject({
+      type: IRNodeTypes.IF,
+      condition: {
+        type: NodeTypes.SIMPLE_EXPRESSION,
+        content: 'true',
+        isStatic: false,
+      },
+      positive: {
+        type: IRNodeTypes.BLOCK,
+        dynamic: {
+          children: [{ template: 0 }],
+        },
+      },
+    })
+  })
+
+  describe('errors', () => {
+    test('error on v-else missing adjacent v-if', () => {
+      const onError = vi.fn()
+
+      {
+        const { ir } = compileWithVIf(`<div v-else/>`, { onError })
+        expect(onError.mock.calls[0]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: ir.node.loc,
+          },
+        ])
+      }
+
+      {
+        const { ir } = compileWithVIf(`<div/><div v-else/>`, {
+          onError,
+        })
+        expect(onError.mock.calls[1]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[1].loc,
+          },
+        ])
+      }
+
+      {
+        const { ir } = compileWithVIf(`<div/>foo<div v-else/>`, { onError })
+        expect(onError.mock.calls[2]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[2].loc,
+          },
+        ])
+      }
+
+      {
+        const { ir } = compileWithVIf(`<div v-if="bar"/>foo<div v-else/>`, {
+          onError,
+        })
+        expect(onError.mock.calls[3]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[2].loc,
+          },
+        ])
+      }
+
+      // Non-breaking space
+      {
+        const { ir } = compileWithVIf(`<div v-if="bar"/>\u00a0<div v-else/>`, {
+          onError,
+        })
+        expect(onError.mock.calls[4]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[2].loc,
+          },
+        ])
+      }
+    })
+
+    test('error on v-else-if missing adjacent v-if or v-else-if', () => {
+      const onError = vi.fn()
+      {
+        const { ir } = compileWithVIf(`<div v-else-if="foo"/>`, {
+          onError,
+        })
+        expect(onError.mock.calls[0]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: ir.node.loc,
+          },
+        ])
+      }
+      {
+        const { ir } = compileWithVIf(`<div/><div v-else-if="foo"/>`, {
+          onError,
+        })
+        expect(onError.mock.calls[1]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[1].loc,
+          },
+        ])
+      }
+      {
+        const { ir } = compileWithVIf(`<div/>foo<div v-else-if="foo"/>`, {
+          onError,
+        })
+        expect(onError.mock.calls[2]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[2].loc,
+          },
+        ])
+      }
+      {
+        const { ir } = compileWithVIf(
+          `<div v-if="bar"/>foo<div v-else-if="foo"/>`,
+          { onError },
+        )
+        expect(onError.mock.calls[3]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[2].loc,
+          },
+        ])
+      }
+      {
+        // Non-breaking space
+        const { ir } = compileWithVIf(
+          `<div v-if="bar"/>\u00a0<div v-else-if="foo"/>`,
+          { onError },
+        )
+        expect(onError.mock.calls[4]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[2].loc,
+          },
+        ])
+      }
+
+      {
+        const { ir } = compileWithVIf(
+          `<div v-if="notOk"/><div v-else/><div v-else-if="ok"/>`,
+          { onError },
+        )
+        expect(onError.mock.calls[5]).toMatchObject([
+          {
+            code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+            loc: (ir.block.node as RootNode).children[2].loc,
+          },
+        ])
+      }
+    })
+
+    test('error on adjacent v-else', () => {
+      const onError = vi.fn()
+
+      const { ir } = compileWithVIf(
+        `<div v-if="false"/><div v-else/><div v-else/>`,
+        { onError },
+      )
+
+      expect(onError.mock.calls[0]).toMatchObject([
+        {
+          code: ErrorCodes.X_V_ELSE_NO_ADJACENT_IF,
+          loc: (ir.block.node as RootNode).children[2].loc,
+        },
+      ])
+    })
+  })
 })
index f85498febce3747c67167f7e6997948846e6b36c..3850320bf2a52f28a1c990a84b96fa68ca8a03e7 100644 (file)
@@ -3,6 +3,7 @@ import {
   type ElementNode,
   NodeTypes,
   type TemplateChildNode,
+  isCommentOrWhitespace,
 } from '@vue/compiler-dom'
 import type { NodeTransform, TransformContext } from '../transform'
 import { DynamicFlag } from '../ir'
@@ -31,7 +32,7 @@ export function getSiblingIf(
   let i = siblings.indexOf(context.node)
   while (reverse ? --i >= 0 : ++i < siblings.length) {
     sibling = siblings[i]
-    if (!isCommentLike(sibling)) {
+    if (!isCommentOrWhitespace(sibling)) {
       break
     }
   }
@@ -48,10 +49,3 @@ export function getSiblingIf(
     return sibling
   }
 }
-
-function isCommentLike(node: TemplateChildNode) {
-  return (
-    node.type === NodeTypes.COMMENT ||
-    (node.type === NodeTypes.TEXT && !node.content.trim().length)
-  )
-}