]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: jest warning assert utils
authorEvan You <yyx990803@gmail.com>
Mon, 26 Aug 2019 20:08:23 +0000 (16:08 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 26 Aug 2019 20:08:23 +0000 (16:08 -0400)
packages/reactivity/__tests__/reactive.spec.ts
packages/reactivity/__tests__/readonly.spec.ts
packages/reactivity/src/collectionHandlers.ts
packages/runtime-test/src/index.ts
packages/runtime-test/src/jestUtils.ts [new file with mode: 0644]

index 8888aaed10b215ac8b6cadf8b3650e34b2dcc994..681a960992fdd5f809d98806822e5ed3a1dc6906 100644 (file)
@@ -1,6 +1,9 @@
 import { reactive, isReactive, toRaw, markNonReactive } from '../src/reactive'
+import { mockWarn } from '@vue/runtime-test'
 
 describe('reactivity/reactive', () => {
+  mockWarn()
+
   test('Object', () => {
     const original = { foo: 1 }
     const observed = reactive(original)
@@ -124,17 +127,11 @@ describe('reactivity/reactive', () => {
   })
 
   test('non-observable values', () => {
-    const warn = jest.spyOn(console, 'warn')
-    let lastMsg: string
-    warn.mockImplementation(msg => {
-      lastMsg = msg
-    })
-
-    const getMsg = (value: any) =>
-      `value cannot be made reactive: ${String(value)}`
     const assertValue = (value: any) => {
       reactive(value)
-      expect(lastMsg).toMatch(getMsg(value))
+      expect(
+        `value cannot be made reactive: ${String(value)}`
+      ).toHaveBeenWarnedLast()
     }
 
     // number
@@ -151,8 +148,6 @@ describe('reactivity/reactive', () => {
     const s = Symbol()
     assertValue(s)
 
-    warn.mockRestore()
-
     // built-ins should work and return same value
     const p = Promise.resolve()
     expect(reactive(p)).toBe(p)
index 49209857a7fe532b703b0ba486730c43df502f6c..0c4ee1530ca19deba8459f4de98caeb2559d54e4 100644 (file)
@@ -11,18 +11,10 @@ import {
   effect,
   ref
 } from '../src'
+import { mockWarn } from '@vue/runtime-test'
 
 describe('reactivity/readonly', () => {
-  let warn: any
-
-  beforeEach(() => {
-    warn = jest.spyOn(console, 'warn')
-    warn.mockImplementation(() => {})
-  })
-
-  afterEach(() => {
-    warn.mockRestore()
-  })
+  mockWarn()
 
   describe('Object', () => {
     it('should make nested values readonly', () => {
@@ -49,16 +41,24 @@ describe('reactivity/readonly', () => {
       const observed: any = readonly({ foo: 1, bar: { baz: 2 } })
       observed.foo = 2
       expect(observed.foo).toBe(1)
-      expect(warn).toHaveBeenCalledTimes(1)
+      expect(
+        `Set operation on key "foo" failed: target is readonly.`
+      ).toHaveBeenWarnedLast()
       observed.bar.baz = 3
       expect(observed.bar.baz).toBe(2)
-      expect(warn).toHaveBeenCalledTimes(2)
+      expect(
+        `Set operation on key "baz" failed: target is readonly.`
+      ).toHaveBeenWarnedLast()
       delete observed.foo
       expect(observed.foo).toBe(1)
-      expect(warn).toHaveBeenCalledTimes(3)
+      expect(
+        `Delete operation on key "foo" failed: target is readonly.`
+      ).toHaveBeenWarnedLast()
       delete observed.bar.baz
       expect(observed.bar.baz).toBe(2)
-      expect(warn).toHaveBeenCalledTimes(4)
+      expect(
+        `Delete operation on key "baz" failed: target is readonly.`
+      ).toHaveBeenWarnedLast()
     })
 
     it('should allow mutation when unlocked', () => {
@@ -73,7 +73,7 @@ describe('reactivity/readonly', () => {
       expect(observed.foo).toBeUndefined()
       expect(observed.bar.qux).toBe(3)
       expect('baz' in observed.bar).toBe(false)
-      expect(warn).not.toHaveBeenCalled()
+      expect(`target is readonly`).not.toHaveBeenWarned()
     })
 
     it('should not trigger effects when locked', () => {
@@ -128,22 +128,28 @@ describe('reactivity/readonly', () => {
       const observed: any = readonly([{ foo: 1 }])
       observed[0] = 1
       expect(observed[0]).not.toBe(1)
-      expect(warn).toHaveBeenCalledTimes(1)
+      expect(
+        `Set operation on key "0" failed: target is readonly.`
+      ).toHaveBeenWarned()
       observed[0].foo = 2
       expect(observed[0].foo).toBe(1)
-      expect(warn).toHaveBeenCalledTimes(2)
+      expect(
+        `Set operation on key "foo" failed: target is readonly.`
+      ).toHaveBeenWarned()
 
       // should block length mutation
       observed.length = 0
       expect(observed.length).toBe(1)
       expect(observed[0].foo).toBe(1)
-      expect(warn).toHaveBeenCalledTimes(3)
+      expect(
+        `Set operation on key "length" failed: target is readonly.`
+      ).toHaveBeenWarned()
 
       // mutation methods invoke set/length internally and thus are blocked as well
       observed.push(2)
       expect(observed.length).toBe(1)
       // push triggers two warnings on [1] and .length
-      expect(warn).toHaveBeenCalledTimes(5)
+      expect(`target is readonly.`).toHaveBeenWarnedTimes(5)
     })
 
     it('should allow mutation when unlocked', () => {
@@ -159,7 +165,7 @@ describe('reactivity/readonly', () => {
       expect(observed[2]).toBe(3)
       expect(observed[0].foo).toBe(2)
       expect(observed[0].bar.baz).toBe(3)
-      expect(warn).not.toHaveBeenCalled()
+      expect(`target is readonly`).not.toHaveBeenWarned()
     })
 
     it('should not trigger effects when locked', () => {
@@ -232,7 +238,9 @@ describe('reactivity/readonly', () => {
         map.set(key, 1)
         expect(dummy).toBeUndefined()
         expect(map.has(key)).toBe(false)
-        expect(warn).toHaveBeenCalledTimes(1)
+        expect(
+          `Set operation on key "${key}" failed: target is readonly.`
+        ).toHaveBeenWarned()
       })
 
       test('should allow mutation & trigger effect when unlocked', () => {
@@ -249,7 +257,7 @@ describe('reactivity/readonly', () => {
         lock()
         expect(dummy).toBe(isWeak ? 1 : 2)
         expect(map.get(key)).toBe(1)
-        expect(warn).not.toHaveBeenCalled()
+        expect(`target is readonly`).not.toHaveBeenWarned()
       })
 
       if (Collection === Map) {
@@ -301,7 +309,9 @@ describe('reactivity/readonly', () => {
         set.add(key)
         expect(dummy).toBe(false)
         expect(set.has(key)).toBe(false)
-        expect(warn).toHaveBeenCalledTimes(1)
+        expect(
+          `Add operation on key "${key}" failed: target is readonly.`
+        ).toHaveBeenWarned()
       })
 
       test('should allow mutation & trigger effect when unlocked', () => {
@@ -317,7 +327,7 @@ describe('reactivity/readonly', () => {
         lock()
         expect(dummy).toBe(true)
         expect(set.has(key)).toBe(true)
-        expect(warn).not.toHaveBeenCalled()
+        expect(`target is readonly`).not.toHaveBeenWarned()
       })
 
       if (Collection === Set) {
@@ -396,6 +406,8 @@ describe('reactivity/readonly', () => {
     const n: any = readonly(ref(1))
     n.value = 2
     expect(n.value).toBe(1)
-    expect(warn).toHaveBeenCalledTimes(1)
+    expect(
+      `Set operation on key "value" failed: target is readonly.`
+    ).toHaveBeenWarned()
   })
 })
index 11b194b7e52b55c467bec9e4c88a5b23435cb681..34dc28e773587367e0c33e975da118c549d1e4dc 100644 (file)
@@ -2,7 +2,7 @@ import { toRaw, reactive, readonly } from './reactive'
 import { track, trigger } from './effect'
 import { OperationTypes } from './operations'
 import { LOCKED } from './lock'
-import { isObject } from '@vue/shared'
+import { isObject, capitalize } from '@vue/shared'
 
 const toReactive = (value: any) => (isObject(value) ? reactive(value) : value)
 const toReadonly = (value: any) => (isObject(value) ? readonly(value) : value)
@@ -166,9 +166,9 @@ function createReadonlyMethod(
   return function(...args: any[]) {
     if (LOCKED) {
       if (__DEV__) {
-        const key = args[0] ? `on key "${args[0]}"` : ``
+        const key = args[0] ? `on key "${args[0]}" ` : ``
         console.warn(
-          `${type} operation ${key}failed: target is readonly.`,
+          `${capitalize(type)} operation ${key}failed: target is readonly.`,
           toRaw(this)
         )
       }
index db8d0cad6a6f6c5bd84391bf81ad45232f41fa66..4c211fd9f85cf56afdc40d214af44327d11a185a 100644 (file)
@@ -10,4 +10,5 @@ export const render = createRenderer({
 export { serialize } from './serialize'
 export { triggerEvent } from './triggerEvent'
 export * from './nodeOps'
+export * from './jestUtils'
 export * from '@vue/runtime-core'
diff --git a/packages/runtime-test/src/jestUtils.ts b/packages/runtime-test/src/jestUtils.ts
new file mode 100644 (file)
index 0000000..e899710
--- /dev/null
@@ -0,0 +1,83 @@
+declare global {
+  namespace jest {
+    interface Matchers<R> {
+      toHaveBeenWarned(): R
+      toHaveBeenWarnedLast(): R
+      toHaveBeenWarnedTimes(n: number): R
+    }
+  }
+}
+
+export function mockWarn() {
+  expect.extend({
+    toHaveBeenWarned(received: string) {
+      const passed = warn.mock.calls.some(
+        args => args[0].indexOf(received) > -1
+      )
+      if (passed) {
+        return {
+          pass: true,
+          message: () => `expected "${received}" not to have been warned.`
+        }
+      } else {
+        const msgs = warn.mock.calls.map(args => args[0]).join('\n - ')
+        return {
+          pass: false,
+          message: () =>
+            `expected "${received}" to have been warned.\n\nActual messages:\n\n - ${msgs}`
+        }
+      }
+    },
+
+    toHaveBeenWarnedLast(received: string) {
+      const passed =
+        warn.mock.calls[warn.mock.calls.length - 1][0].indexOf(received) > -1
+      if (passed) {
+        return {
+          pass: true,
+          message: () => `expected "${received}" not to have been warned last.`
+        }
+      } else {
+        const msgs = warn.mock.calls.map(args => args[0]).join('\n - ')
+        return {
+          pass: false,
+          message: () =>
+            `expected "${received}" to have been warned last.\n\nActual messages:\n\n - ${msgs}`
+        }
+      }
+    },
+
+    toHaveBeenWarnedTimes(received: string, n: number) {
+      let found = 0
+      warn.mock.calls.forEach(args => {
+        if (args[0].indexOf(received) > -1) {
+          found++
+        }
+      })
+      if (found > 0) {
+        return {
+          pass: true,
+          message: () =>
+            `expected "${received}" not to have been warned ${n} times.`
+        }
+      } else {
+        return {
+          pass: false,
+          message: () =>
+            `expected "${received}" to have been warned ${n} times but got ${found}.`
+        }
+      }
+    }
+  })
+
+  let warn: jest.SpyInstance
+
+  beforeEach(() => {
+    warn = jest.spyOn(console, 'warn')
+    warn.mockImplementation(() => {})
+  })
+
+  afterEach(() => {
+    warn.mockRestore()
+  })
+}