]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: 100% coverage for observer
authorEvan You <yyx990803@gmail.com>
Fri, 21 Sep 2018 13:52:46 +0000 (09:52 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 21 Sep 2018 13:52:46 +0000 (09:52 -0400)
.gitignore
package.json
packages/observer/__tests__/autorun.spec.ts
packages/observer/__tests__/immutable.spec.ts
packages/observer/src/baseHandlers.ts
packages/observer/src/collectionHandlers.ts

index 20fa3c8083962785b8a909ad6f9f4cab85f902b7..f026311f184156cdb2aa2d3149ab42c536947371 100644 (file)
@@ -1,5 +1,6 @@
 dist
 .DS_Store
 node_modules
+coverage
 explorations
 TODOs.md
index ba43dde5491085c11cdebbca6b4b65e96037f97d..65db7d0ea78b0ec0f363177732fc5434da00d973 100644 (file)
@@ -6,7 +6,8 @@
   "scripts": {
     "dev": "node scripts/dev.js",
     "build": "node scripts/build.js",
-    "lint": "prettier --write --parser typescript 'packages/**/*.ts'"
+    "lint": "prettier --write --parser typescript 'packages/**/*.ts'",
+    "test": "jest"
   },
   "gitHooks": {
     "pre-commit": "lint-staged",
index f8b2e1a50a14305f91c8b9ce23519fd72fe09382..e652c96db91945090fd07f8299fd3376975f7402 100644 (file)
@@ -621,6 +621,10 @@ describe('observer/autorun', () => {
     stop(runner)
     obj.prop = 3
     expect(dummy).toBe(2)
+
+    // stopped runner should still be manually callable
+    runner()
+    expect(dummy).toBe(3)
   })
 
   it('markNonReactive', () => {
index 4ce9dbf1bd3856a6b146738c081a6a2f69b6077c..a30677d697a710984425f5e85088634b1c9a5cd2 100644 (file)
@@ -52,16 +52,26 @@ describe('observer/immutable', () => {
       observed.bar.baz = 3
       expect(observed.bar.baz).toBe(2)
       expect(warn).toHaveBeenCalledTimes(2)
+      delete observed.foo
+      expect(observed.foo).toBe(1)
+      expect(warn).toHaveBeenCalledTimes(3)
+      delete observed.bar.baz
+      expect(observed.bar.baz).toBe(2)
+      expect(warn).toHaveBeenCalledTimes(4)
     })
 
     it('should allow mutation when unlocked', () => {
-      const observed = immutable({ foo: 1, bar: { baz: 2 } })
+      const observed: any = immutable({ foo: 1, bar: { baz: 2 } })
       unlock()
-      observed.foo = 2
-      observed.bar.baz = 3
+      observed.prop = 2
+      observed.bar.qux = 3
+      delete observed.bar.baz
+      delete observed.foo
       lock()
-      expect(observed.foo).toBe(2)
-      expect(observed.bar.baz).toBe(3)
+      expect(observed.prop).toBe(2)
+      expect(observed.foo).toBeUndefined()
+      expect(observed.bar.qux).toBe(3)
+      expect('baz' in observed.bar).toBe(false)
       expect(warn).not.toHaveBeenCalled()
     })
 
@@ -190,7 +200,9 @@ describe('observer/immutable', () => {
       lock()
     })
   })
-  ;[Map, WeakMap].forEach((Collection: any) => {
+
+  const maps = [Map, WeakMap]
+  maps.forEach((Collection: any) => {
     describe(Collection.name, () => {
       test('should make nested values immutable', () => {
         const key1 = {}
@@ -224,22 +236,25 @@ describe('observer/immutable', () => {
 
       test('should allow mutation & trigger autorun when unlocked', () => {
         const map = immutable(new Collection())
+        const isWeak = Collection === WeakMap
         const key = {}
         let dummy
         autorun(() => {
-          dummy = map.get(key)
+          dummy = map.get(key) + (isWeak ? 0 : map.size)
         })
-        expect(dummy).toBeUndefined()
+        expect(dummy).toBeNaN()
         unlock()
         map.set(key, 1)
         lock()
-        expect(dummy).toBe(1)
+        expect(dummy).toBe(isWeak ? 1 : 2)
         expect(map.get(key)).toBe(1)
         expect(warn).not.toHaveBeenCalled()
       })
     })
   })
-  ;[Set, WeakSet].forEach((Collection: any) => {
+
+  const sets = [Set, WeakSet]
+  sets.forEach((Collection: any) => {
     describe(Collection.name, () => {
       test('should make nested values immutable', () => {
         const key1 = {}
index dc0010c0920e6f783f2ca8a0d12dfad1de5ae55e..20c938973ebf1bb7c9ac712ed5ad5d3016b7e50c 100644 (file)
@@ -11,18 +11,21 @@ const builtInSymbols = new Set(
     .filter(value => typeof value === 'symbol')
 )
 
-function get(
-  target: any,
-  key: string | symbol,
-  receiver: any,
-  toObservable: (t: any) => any
-) {
-  const res = Reflect.get(target, key, receiver)
-  if (typeof key === 'symbol' && builtInSymbols.has(key)) {
-    return res
+function makeGetter(isImmutable: boolean) {
+  return function get(target: any, key: string | symbol, receiver: any) {
+    const res = Reflect.get(target, key, receiver)
+    if (typeof key === 'symbol' && builtInSymbols.has(key)) {
+      return res
+    }
+    track(target, OperationTypes.GET, key)
+    return res !== null && typeof res === 'object'
+      ? isImmutable
+        ? // need to lazy access immutable and observable here to avoid
+          // circular dependency
+          immutable(res)
+        : observable(res)
+      : res
   }
-  track(target, OperationTypes.GET, key)
-  return res !== null && typeof res === 'object' ? toObservable(res) : res
 }
 
 function set(
@@ -37,6 +40,7 @@ function set(
   const result = Reflect.set(target, key, value, receiver)
   // don't trigger if target is something up in the prototype chain of original
   if (target === unwrap(receiver)) {
+    /* istanbul ignore else */
     if (__DEV__) {
       const extraInfo = { oldValue, newValue: value }
       if (!hadKey) {
@@ -60,6 +64,7 @@ function deleteProperty(target: any, key: string | symbol): boolean {
   const oldValue = target[key]
   const result = Reflect.deleteProperty(target, key)
   if (hadKey) {
+    /* istanbul ignore else */
     if (__DEV__) {
       trigger(target, OperationTypes.DELETE, key, { oldValue })
     } else {
@@ -81,8 +86,7 @@ function ownKeys(target: any): (string | number | symbol)[] {
 }
 
 export const mutableHandlers: ProxyHandler<any> = {
-  get: (target: any, key: string | symbol, receiver: any) =>
-    get(target, key, receiver, observable),
+  get: makeGetter(false),
   set,
   deleteProperty,
   has,
@@ -90,8 +94,7 @@ export const mutableHandlers: ProxyHandler<any> = {
 }
 
 export const immutableHandlers: ProxyHandler<any> = {
-  get: (target: any, key: string | symbol, receiver: any) =>
-    get(target, key, receiver, LOCKED ? immutable : observable),
+  get: makeGetter(true),
 
   set(target: any, key: string | symbol, value: any, receiver: any): boolean {
     if (LOCKED) {
index bf5452661d6158624942b6a67024c3db5a2bc468..3946faf67166a6b363bb8e3ecd80dd5cd9e45595 100644 (file)
@@ -34,6 +34,7 @@ function add(value: any) {
   const hadKey = proto.has.call(target, value)
   const result = proto.add.call(target, value)
   if (!hadKey) {
+    /* istanbul ignore else */
     if (__DEV__) {
       trigger(target, OperationTypes.ADD, value, { value })
     } else {
@@ -51,6 +52,7 @@ function set(key: any, value: any) {
   const oldValue = proto.get.call(target, key)
   const result = proto.set.call(target, key, value)
   if (value !== oldValue) {
+    /* istanbul ignore else */
     if (__DEV__) {
       const extraInfo = { oldValue, newValue: value }
       if (!hadKey) {
@@ -77,6 +79,7 @@ function deleteEntry(key: any) {
   // forward the operation before queueing reactions
   const result = proto.delete.call(target, key)
   if (hadKey) {
+    /* istanbul ignore else */
     if (__DEV__) {
       trigger(target, OperationTypes.DELETE, key, { oldValue })
     } else {
@@ -94,6 +97,7 @@ function clear() {
   // forward the operation before queueing reactions
   const result = proto.clear.call(target)
   if (hadItems) {
+    /* istanbul ignore else */
     if (__DEV__) {
       trigger(target, OperationTypes.CLEAR, void 0, { oldTarget })
     } else {
@@ -158,22 +162,21 @@ const immutableInstrumentations: any = {
   }
 })
 
-function getInstrumented(
-  target: any,
-  key: string | symbol,
-  receiver: any,
-  instrumentations: any
-) {
-  target = instrumentations.hasOwnProperty(key) ? instrumentations : target
-  return Reflect.get(target, key, receiver)
+function makeInstrumentationGetter(instrumentations: any) {
+  return function getInstrumented(
+    target: any,
+    key: string | symbol,
+    receiver: any
+  ) {
+    target = instrumentations.hasOwnProperty(key) ? instrumentations : target
+    return Reflect.get(target, key, receiver)
+  }
 }
 
 export const mutableCollectionHandlers: ProxyHandler<any> = {
-  get: (target: any, key: string | symbol, receiver: any) =>
-    getInstrumented(target, key, receiver, mutableInstrumentations)
+  get: makeInstrumentationGetter(mutableInstrumentations)
 }
 
 export const immutableCollectionHandlers: ProxyHandler<any> = {
-  get: (target: any, key: string | symbol, receiver: any) =>
-    getInstrumented(target, key, receiver, immutableInstrumentations)
+  get: makeInstrumentationGetter(immutableInstrumentations)
 }