]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(watch): support traversing symbol properties in deep watcher (#10969)
authorskirtle <65301168+skirtles-code@users.noreply.github.com>
Thu, 30 May 2024 03:03:44 +0000 (04:03 +0100)
committerGitHub <noreply@github.com>
Thu, 30 May 2024 03:03:44 +0000 (11:03 +0800)
close #402

packages/runtime-core/__tests__/apiWatch.spec.ts
packages/runtime-core/src/apiWatch.ts

index 8229dce36db192915290356246241e7d3e99fb12..265bc0a0d46f045bada0d0fc29b8ac2bce2c4a9b 100644 (file)
@@ -932,6 +932,52 @@ describe('api: watch', () => {
     expect(dummy).toEqual([1, 2])
   })
 
+  it('deep with symbols', async () => {
+    const symbol1 = Symbol()
+    const symbol2 = Symbol()
+    const symbol3 = Symbol()
+    const symbol4 = Symbol()
+
+    const raw: any = {
+      [symbol1]: {
+        [symbol2]: 1,
+      },
+    }
+
+    Object.defineProperty(raw, symbol3, {
+      writable: true,
+      enumerable: false,
+      value: 1,
+    })
+
+    const state = reactive(raw)
+    const spy = vi.fn()
+
+    watch(() => state, spy, { deep: true })
+
+    await nextTick()
+    expect(spy).toHaveBeenCalledTimes(0)
+
+    state[symbol1][symbol2] = 2
+    await nextTick()
+    expect(spy).toHaveBeenCalledTimes(1)
+
+    // Non-enumerable properties don't trigger deep watchers
+    state[symbol3] = 3
+    await nextTick()
+    expect(spy).toHaveBeenCalledTimes(1)
+
+    // Adding a new symbol property
+    state[symbol4] = 1
+    await nextTick()
+    expect(spy).toHaveBeenCalledTimes(2)
+
+    // Removing a symbol property
+    delete state[symbol4]
+    await nextTick()
+    expect(spy).toHaveBeenCalledTimes(3)
+  })
+
   it('immediate', async () => {
     const count = ref(0)
     const cb = vi.fn()
index ffad8ad549583e5c60aea4caba48b2c7266339f1..bab9e0764f5b05f939d1f372c18b33adde11c8bf 100644 (file)
@@ -493,6 +493,11 @@ export function traverse(
     for (const key in value) {
       traverse(value[key], depth, seen)
     }
+    for (const key of Object.getOwnPropertySymbols(value)) {
+      if (Object.prototype.propertyIsEnumerable.call(value, key)) {
+        traverse(value[key as any], depth, seen)
+      }
+    }
   }
   return value
 }