|
|
@@ -1,4 +1,5 @@
|
|
|
-import { isReactive, reactive, toRaw } from '../src/reactive'
|
|
|
+import { type ComputedRef, computed } from '../src/computed'
|
|
|
+import { isReactive, reactive, shallowReactive, toRaw } from '../src/reactive'
|
|
|
import { isRef, ref } from '../src/ref'
|
|
|
import { effect } from '../src/effect'
|
|
|
|
|
|
@@ -252,4 +253,359 @@ describe('reactivity/reactive/Array', () => {
|
|
|
expect(observed.lastSearched).toBe(6)
|
|
|
})
|
|
|
})
|
|
|
+
|
|
|
+ describe('Optimized array methods:', () => {
|
|
|
+ test('iterator', () => {
|
|
|
+ const shallow = shallowReactive([1, 2, 3, 4])
|
|
|
+ let result = computed(() => {
|
|
|
+ let sum = 0
|
|
|
+ for (let x of shallow) {
|
|
|
+ sum += x ** 2
|
|
|
+ }
|
|
|
+ return sum
|
|
|
+ })
|
|
|
+ expect(result.value).toBe(30)
|
|
|
+
|
|
|
+ shallow[2] = 0
|
|
|
+ expect(result.value).toBe(21)
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 2 }])
|
|
|
+ result = computed(() => {
|
|
|
+ let sum = 0
|
|
|
+ for (let x of deep) {
|
|
|
+ sum += x.val ** 2
|
|
|
+ }
|
|
|
+ return sum
|
|
|
+ })
|
|
|
+ expect(result.value).toBe(5)
|
|
|
+
|
|
|
+ deep[1].val = 3
|
|
|
+ expect(result.value).toBe(10)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('concat', () => {
|
|
|
+ const a1 = shallowReactive([1, { val: 2 }])
|
|
|
+ const a2 = reactive([{ val: 3 }])
|
|
|
+ const a3 = [4, 5]
|
|
|
+
|
|
|
+ let result = computed(() => a1.concat(a2, a3))
|
|
|
+ expect(result.value).toStrictEqual([1, { val: 2 }, { val: 3 }, 4, 5])
|
|
|
+ expect(isReactive(result.value[1])).toBe(false)
|
|
|
+ expect(isReactive(result.value[2])).toBe(true)
|
|
|
+
|
|
|
+ a1.shift()
|
|
|
+ expect(result.value).toStrictEqual([{ val: 2 }, { val: 3 }, 4, 5])
|
|
|
+
|
|
|
+ a2.pop()
|
|
|
+ expect(result.value).toStrictEqual([{ val: 2 }, 4, 5])
|
|
|
+
|
|
|
+ a3.pop()
|
|
|
+ expect(result.value).toStrictEqual([{ val: 2 }, 4, 5])
|
|
|
+ })
|
|
|
+
|
|
|
+ test('entries', () => {
|
|
|
+ const shallow = shallowReactive([0, 1])
|
|
|
+ const result1 = computed(() => Array.from(shallow.entries()))
|
|
|
+ expect(result1.value).toStrictEqual([
|
|
|
+ [0, 0],
|
|
|
+ [1, 1],
|
|
|
+ ])
|
|
|
+
|
|
|
+ shallow[1] = 10
|
|
|
+ expect(result1.value).toStrictEqual([
|
|
|
+ [0, 0],
|
|
|
+ [1, 10],
|
|
|
+ ])
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 0 }, { val: 1 }])
|
|
|
+ const result2 = computed(() => Array.from(deep.entries()))
|
|
|
+ expect(result2.value).toStrictEqual([
|
|
|
+ [0, { val: 0 }],
|
|
|
+ [1, { val: 1 }],
|
|
|
+ ])
|
|
|
+ expect(isReactive(result2.value[0][1])).toBe(true)
|
|
|
+
|
|
|
+ deep.pop()
|
|
|
+ expect(Array.from(result2.value)).toStrictEqual([[0, { val: 0 }]])
|
|
|
+ })
|
|
|
+
|
|
|
+ test('every', () => {
|
|
|
+ const shallow = shallowReactive([1, 2, 5])
|
|
|
+ let result = computed(() => shallow.every(x => x < 5))
|
|
|
+ expect(result.value).toBe(false)
|
|
|
+
|
|
|
+ shallow.pop()
|
|
|
+ expect(result.value).toBe(true)
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 5 }])
|
|
|
+ result = computed(() => deep.every(x => x.val < 5))
|
|
|
+ expect(result.value).toBe(false)
|
|
|
+
|
|
|
+ deep[1].val = 2
|
|
|
+ expect(result.value).toBe(true)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('filter', () => {
|
|
|
+ const shallow = shallowReactive([1, 2, 3, 4])
|
|
|
+ const result1 = computed(() => shallow.filter(x => x < 3))
|
|
|
+ expect(result1.value).toStrictEqual([1, 2])
|
|
|
+
|
|
|
+ shallow[2] = 0
|
|
|
+ expect(result1.value).toStrictEqual([1, 2, 0])
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 2 }])
|
|
|
+ const result2 = computed(() => deep.filter(x => x.val < 2))
|
|
|
+ expect(result2.value).toStrictEqual([{ val: 1 }])
|
|
|
+ expect(isReactive(result2.value[0])).toBe(true)
|
|
|
+
|
|
|
+ deep[1].val = 0
|
|
|
+ expect(result2.value).toStrictEqual([{ val: 1 }, { val: 0 }])
|
|
|
+ })
|
|
|
+
|
|
|
+ test('find and co.', () => {
|
|
|
+ const shallow = shallowReactive([{ val: 1 }, { val: 2 }])
|
|
|
+ let find = computed(() => shallow.find(x => x.val === 2))
|
|
|
+ // @ts-expect-error tests are not limited to es2016
|
|
|
+ let findLast = computed(() => shallow.findLast(x => x.val === 2))
|
|
|
+ let findIndex = computed(() => shallow.findIndex(x => x.val === 2))
|
|
|
+ let findLastIndex = computed(() =>
|
|
|
+ // @ts-expect-error tests are not limited to es2016
|
|
|
+ shallow.findLastIndex(x => x.val === 2),
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(find.value).toBe(shallow[1])
|
|
|
+ expect(isReactive(find.value)).toBe(false)
|
|
|
+ expect(findLast.value).toBe(shallow[1])
|
|
|
+ expect(isReactive(findLast.value)).toBe(false)
|
|
|
+ expect(findIndex.value).toBe(1)
|
|
|
+ expect(findLastIndex.value).toBe(1)
|
|
|
+
|
|
|
+ shallow[1].val = 0
|
|
|
+
|
|
|
+ expect(find.value).toBe(shallow[1])
|
|
|
+ expect(findLast.value).toBe(shallow[1])
|
|
|
+ expect(findIndex.value).toBe(1)
|
|
|
+ expect(findLastIndex.value).toBe(1)
|
|
|
+
|
|
|
+ shallow.pop()
|
|
|
+
|
|
|
+ expect(find.value).toBe(undefined)
|
|
|
+ expect(findLast.value).toBe(undefined)
|
|
|
+ expect(findIndex.value).toBe(-1)
|
|
|
+ expect(findLastIndex.value).toBe(-1)
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 2 }])
|
|
|
+ find = computed(() => deep.find(x => x.val === 2))
|
|
|
+ // @ts-expect-error tests are not limited to es2016
|
|
|
+ findLast = computed(() => deep.findLast(x => x.val === 2))
|
|
|
+ findIndex = computed(() => deep.findIndex(x => x.val === 2))
|
|
|
+ // @ts-expect-error tests are not limited to es2016
|
|
|
+ findLastIndex = computed(() => deep.findLastIndex(x => x.val === 2))
|
|
|
+
|
|
|
+ expect(find.value).toBe(deep[1])
|
|
|
+ expect(isReactive(find.value)).toBe(true)
|
|
|
+ expect(findLast.value).toBe(deep[1])
|
|
|
+ expect(isReactive(findLast.value)).toBe(true)
|
|
|
+ expect(findIndex.value).toBe(1)
|
|
|
+ expect(findLastIndex.value).toBe(1)
|
|
|
+
|
|
|
+ deep[1].val = 0
|
|
|
+
|
|
|
+ expect(find.value).toBe(undefined)
|
|
|
+ expect(findLast.value).toBe(undefined)
|
|
|
+ expect(findIndex.value).toBe(-1)
|
|
|
+ expect(findLastIndex.value).toBe(-1)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('forEach', () => {
|
|
|
+ const shallow = shallowReactive([1, 2, 3, 4])
|
|
|
+ let result = computed(() => {
|
|
|
+ let sum = 0
|
|
|
+ shallow.forEach(x => (sum += x ** 2))
|
|
|
+ return sum
|
|
|
+ })
|
|
|
+ expect(result.value).toBe(30)
|
|
|
+
|
|
|
+ shallow[2] = 0
|
|
|
+ expect(result.value).toBe(21)
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 2 }])
|
|
|
+ result = computed(() => {
|
|
|
+ let sum = 0
|
|
|
+ deep.forEach(x => (sum += x.val ** 2))
|
|
|
+ return sum
|
|
|
+ })
|
|
|
+ expect(result.value).toBe(5)
|
|
|
+
|
|
|
+ deep[1].val = 3
|
|
|
+ expect(result.value).toBe(10)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('join', () => {
|
|
|
+ function toString(this: { val: number }) {
|
|
|
+ return this.val
|
|
|
+ }
|
|
|
+ const shallow = shallowReactive([
|
|
|
+ { val: 1, toString },
|
|
|
+ { val: 2, toString },
|
|
|
+ ])
|
|
|
+ let result = computed(() => shallow.join('+'))
|
|
|
+ expect(result.value).toBe('1+2')
|
|
|
+
|
|
|
+ shallow[1].val = 23
|
|
|
+ expect(result.value).toBe('1+2')
|
|
|
+
|
|
|
+ shallow.pop()
|
|
|
+ expect(result.value).toBe('1')
|
|
|
+
|
|
|
+ const deep = reactive([
|
|
|
+ { val: 1, toString },
|
|
|
+ { val: 2, toString },
|
|
|
+ ])
|
|
|
+ result = computed(() => deep.join())
|
|
|
+ expect(result.value).toBe('1,2')
|
|
|
+
|
|
|
+ deep[1].val = 23
|
|
|
+ expect(result.value).toBe('1,23')
|
|
|
+ })
|
|
|
+
|
|
|
+ test('map', () => {
|
|
|
+ const shallow = shallowReactive([1, 2, 3, 4])
|
|
|
+ let result = computed(() => shallow.map(x => x ** 2))
|
|
|
+ expect(result.value).toStrictEqual([1, 4, 9, 16])
|
|
|
+
|
|
|
+ shallow[2] = 0
|
|
|
+ expect(result.value).toStrictEqual([1, 4, 0, 16])
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 2 }])
|
|
|
+ result = computed(() => deep.map(x => x.val ** 2))
|
|
|
+ expect(result.value).toStrictEqual([1, 4])
|
|
|
+
|
|
|
+ deep[1].val = 3
|
|
|
+ expect(result.value).toStrictEqual([1, 9])
|
|
|
+ })
|
|
|
+
|
|
|
+ test('reduce left and right', () => {
|
|
|
+ function toString(this: any) {
|
|
|
+ return this.val + '-'
|
|
|
+ }
|
|
|
+ const shallow = shallowReactive([
|
|
|
+ { val: 1, toString },
|
|
|
+ { val: 2, toString },
|
|
|
+ ] as any[])
|
|
|
+
|
|
|
+ expect(shallow.reduce((acc, x) => acc + '' + x.val, undefined)).toBe(
|
|
|
+ 'undefined12',
|
|
|
+ )
|
|
|
+
|
|
|
+ let left = computed(() => shallow.reduce((acc, x) => acc + '' + x.val))
|
|
|
+ let right = computed(() =>
|
|
|
+ shallow.reduceRight((acc, x) => acc + '' + x.val),
|
|
|
+ )
|
|
|
+ expect(left.value).toBe('1-2')
|
|
|
+ expect(right.value).toBe('2-1')
|
|
|
+
|
|
|
+ shallow[1].val = 23
|
|
|
+ expect(left.value).toBe('1-2')
|
|
|
+ expect(right.value).toBe('2-1')
|
|
|
+
|
|
|
+ shallow.pop()
|
|
|
+ expect(left.value).toBe(shallow[0])
|
|
|
+ expect(right.value).toBe(shallow[0])
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 2 }])
|
|
|
+ left = computed(() => deep.reduce((acc, x) => acc + x.val, '0'))
|
|
|
+ right = computed(() => deep.reduceRight((acc, x) => acc + x.val, '3'))
|
|
|
+ expect(left.value).toBe('012')
|
|
|
+ expect(right.value).toBe('321')
|
|
|
+
|
|
|
+ deep[1].val = 23
|
|
|
+ expect(left.value).toBe('0123')
|
|
|
+ expect(right.value).toBe('3231')
|
|
|
+ })
|
|
|
+
|
|
|
+ test('some', () => {
|
|
|
+ const shallow = shallowReactive([1, 2, 5])
|
|
|
+ let result = computed(() => shallow.some(x => x > 4))
|
|
|
+ expect(result.value).toBe(true)
|
|
|
+
|
|
|
+ shallow.pop()
|
|
|
+ expect(result.value).toBe(false)
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 5 }])
|
|
|
+ result = computed(() => deep.some(x => x.val > 4))
|
|
|
+ expect(result.value).toBe(true)
|
|
|
+
|
|
|
+ deep[1].val = 2
|
|
|
+ expect(result.value).toBe(false)
|
|
|
+ })
|
|
|
+
|
|
|
+ // Node 20+
|
|
|
+ // @ts-expect-error tests are not limited to es2016
|
|
|
+ test.skipIf(!Array.prototype.toReversed)('toReversed', () => {
|
|
|
+ const array = reactive([1, { val: 2 }])
|
|
|
+ const result = computed(() => (array as any).toReversed())
|
|
|
+ expect(result.value).toStrictEqual([{ val: 2 }, 1])
|
|
|
+ expect(isReactive(result.value[0])).toBe(true)
|
|
|
+
|
|
|
+ array.splice(1, 1, 2)
|
|
|
+ expect(result.value).toStrictEqual([2, 1])
|
|
|
+ })
|
|
|
+
|
|
|
+ // Node 20+
|
|
|
+ // @ts-expect-error tests are not limited to es2016
|
|
|
+ test.skipIf(!Array.prototype.toSorted)('toSorted', () => {
|
|
|
+ // No comparer
|
|
|
+ // @ts-expect-error
|
|
|
+ expect(shallowReactive([2, 1, 3]).toSorted()).toStrictEqual([1, 2, 3])
|
|
|
+
|
|
|
+ const shallow = shallowReactive([{ val: 2 }, { val: 1 }, { val: 3 }])
|
|
|
+ let result: ComputedRef<{ val: number }[]>
|
|
|
+ // @ts-expect-error
|
|
|
+ result = computed(() => shallow.toSorted((a, b) => a.val - b.val))
|
|
|
+ expect(result.value.map(x => x.val)).toStrictEqual([1, 2, 3])
|
|
|
+ expect(isReactive(result.value[0])).toBe(false)
|
|
|
+
|
|
|
+ shallow[0].val = 4
|
|
|
+ expect(result.value.map(x => x.val)).toStrictEqual([1, 4, 3])
|
|
|
+
|
|
|
+ shallow.pop()
|
|
|
+ expect(result.value.map(x => x.val)).toStrictEqual([1, 4])
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 2 }, { val: 1 }, { val: 3 }])
|
|
|
+ // @ts-expect-error
|
|
|
+ result = computed(() => deep.toSorted((a, b) => a.val - b.val))
|
|
|
+ expect(result.value.map(x => x.val)).toStrictEqual([1, 2, 3])
|
|
|
+ expect(isReactive(result.value[0])).toBe(true)
|
|
|
+
|
|
|
+ deep[0].val = 4
|
|
|
+ expect(result.value.map(x => x.val)).toStrictEqual([1, 3, 4])
|
|
|
+ })
|
|
|
+
|
|
|
+ // Node 20+
|
|
|
+ // @ts-expect-error tests are not limited to es2016
|
|
|
+ test.skipIf(!Array.prototype.toSpliced)('toSpliced', () => {
|
|
|
+ const array = reactive([1, 2, 3])
|
|
|
+ // @ts-expect-error
|
|
|
+ const result = computed(() => array.toSpliced(1, 1, -2))
|
|
|
+ expect(result.value).toStrictEqual([1, -2, 3])
|
|
|
+
|
|
|
+ array[0] = 0
|
|
|
+ expect(result.value).toStrictEqual([0, -2, 3])
|
|
|
+ })
|
|
|
+
|
|
|
+ test('values', () => {
|
|
|
+ const shallow = shallowReactive([{ val: 1 }, { val: 2 }])
|
|
|
+ const result = computed(() => Array.from(shallow.values()))
|
|
|
+ expect(result.value).toStrictEqual([{ val: 1 }, { val: 2 }])
|
|
|
+ expect(isReactive(result.value[0])).toBe(false)
|
|
|
+
|
|
|
+ shallow.pop()
|
|
|
+ expect(result.value).toStrictEqual([{ val: 1 }])
|
|
|
+
|
|
|
+ const deep = reactive([{ val: 1 }, { val: 2 }])
|
|
|
+ const firstItem = Array.from(deep.values())[0]
|
|
|
+ expect(isReactive(firstItem)).toBe(true)
|
|
|
+ })
|
|
|
+ })
|
|
|
})
|