|
1 |
| -import { isReactive, reactive, toRaw } from '../src/reactive' |
| 1 | +import { type ComputedRef, computed } from '../src/computed' |
| 2 | +import { isReactive, reactive, shallowReactive, toRaw } from '../src/reactive' |
2 | 3 | import { isRef, ref } from '../src/ref'
|
3 | 4 | import { effect } from '../src/effect'
|
4 | 5 |
|
@@ -252,4 +253,359 @@ describe('reactivity/reactive/Array', () => {
|
252 | 253 | expect(observed.lastSearched).toBe(6)
|
253 | 254 | })
|
254 | 255 | })
|
| 256 | + |
| 257 | + describe('Optimized array methods:', () => { |
| 258 | + test('iterator', () => { |
| 259 | + const shallow = shallowReactive([1, 2, 3, 4]) |
| 260 | + let result = computed(() => { |
| 261 | + let sum = 0 |
| 262 | + for (let x of shallow) { |
| 263 | + sum += x ** 2 |
| 264 | + } |
| 265 | + return sum |
| 266 | + }) |
| 267 | + expect(result.value).toBe(30) |
| 268 | + |
| 269 | + shallow[2] = 0 |
| 270 | + expect(result.value).toBe(21) |
| 271 | + |
| 272 | + const deep = reactive([{ val: 1 }, { val: 2 }]) |
| 273 | + result = computed(() => { |
| 274 | + let sum = 0 |
| 275 | + for (let x of deep) { |
| 276 | + sum += x.val ** 2 |
| 277 | + } |
| 278 | + return sum |
| 279 | + }) |
| 280 | + expect(result.value).toBe(5) |
| 281 | + |
| 282 | + deep[1].val = 3 |
| 283 | + expect(result.value).toBe(10) |
| 284 | + }) |
| 285 | + |
| 286 | + test('concat', () => { |
| 287 | + const a1 = shallowReactive([1, { val: 2 }]) |
| 288 | + const a2 = reactive([{ val: 3 }]) |
| 289 | + const a3 = [4, 5] |
| 290 | + |
| 291 | + let result = computed(() => a1.concat(a2, a3)) |
| 292 | + expect(result.value).toStrictEqual([1, { val: 2 }, { val: 3 }, 4, 5]) |
| 293 | + expect(isReactive(result.value[1])).toBe(false) |
| 294 | + expect(isReactive(result.value[2])).toBe(true) |
| 295 | + |
| 296 | + a1.shift() |
| 297 | + expect(result.value).toStrictEqual([{ val: 2 }, { val: 3 }, 4, 5]) |
| 298 | + |
| 299 | + a2.pop() |
| 300 | + expect(result.value).toStrictEqual([{ val: 2 }, 4, 5]) |
| 301 | + |
| 302 | + a3.pop() |
| 303 | + expect(result.value).toStrictEqual([{ val: 2 }, 4, 5]) |
| 304 | + }) |
| 305 | + |
| 306 | + test('entries', () => { |
| 307 | + const shallow = shallowReactive([0, 1]) |
| 308 | + const result1 = computed(() => Array.from(shallow.entries())) |
| 309 | + expect(result1.value).toStrictEqual([ |
| 310 | + [0, 0], |
| 311 | + [1, 1], |
| 312 | + ]) |
| 313 | + |
| 314 | + shallow[1] = 10 |
| 315 | + expect(result1.value).toStrictEqual([ |
| 316 | + [0, 0], |
| 317 | + [1, 10], |
| 318 | + ]) |
| 319 | + |
| 320 | + const deep = reactive([{ val: 0 }, { val: 1 }]) |
| 321 | + const result2 = computed(() => Array.from(deep.entries())) |
| 322 | + expect(result2.value).toStrictEqual([ |
| 323 | + [0, { val: 0 }], |
| 324 | + [1, { val: 1 }], |
| 325 | + ]) |
| 326 | + expect(isReactive(result2.value[0][1])).toBe(true) |
| 327 | + |
| 328 | + deep.pop() |
| 329 | + expect(Array.from(result2.value)).toStrictEqual([[0, { val: 0 }]]) |
| 330 | + }) |
| 331 | + |
| 332 | + test('every', () => { |
| 333 | + const shallow = shallowReactive([1, 2, 5]) |
| 334 | + let result = computed(() => shallow.every(x => x < 5)) |
| 335 | + expect(result.value).toBe(false) |
| 336 | + |
| 337 | + shallow.pop() |
| 338 | + expect(result.value).toBe(true) |
| 339 | + |
| 340 | + const deep = reactive([{ val: 1 }, { val: 5 }]) |
| 341 | + result = computed(() => deep.every(x => x.val < 5)) |
| 342 | + expect(result.value).toBe(false) |
| 343 | + |
| 344 | + deep[1].val = 2 |
| 345 | + expect(result.value).toBe(true) |
| 346 | + }) |
| 347 | + |
| 348 | + test('filter', () => { |
| 349 | + const shallow = shallowReactive([1, 2, 3, 4]) |
| 350 | + const result1 = computed(() => shallow.filter(x => x < 3)) |
| 351 | + expect(result1.value).toStrictEqual([1, 2]) |
| 352 | + |
| 353 | + shallow[2] = 0 |
| 354 | + expect(result1.value).toStrictEqual([1, 2, 0]) |
| 355 | + |
| 356 | + const deep = reactive([{ val: 1 }, { val: 2 }]) |
| 357 | + const result2 = computed(() => deep.filter(x => x.val < 2)) |
| 358 | + expect(result2.value).toStrictEqual([{ val: 1 }]) |
| 359 | + expect(isReactive(result2.value[0])).toBe(true) |
| 360 | + |
| 361 | + deep[1].val = 0 |
| 362 | + expect(result2.value).toStrictEqual([{ val: 1 }, { val: 0 }]) |
| 363 | + }) |
| 364 | + |
| 365 | + test('find and co.', () => { |
| 366 | + const shallow = shallowReactive([{ val: 1 }, { val: 2 }]) |
| 367 | + let find = computed(() => shallow.find(x => x.val === 2)) |
| 368 | + // @ts-expect-error tests are not limited to es2016 |
| 369 | + let findLast = computed(() => shallow.findLast(x => x.val === 2)) |
| 370 | + let findIndex = computed(() => shallow.findIndex(x => x.val === 2)) |
| 371 | + let findLastIndex = computed(() => |
| 372 | + // @ts-expect-error tests are not limited to es2016 |
| 373 | + shallow.findLastIndex(x => x.val === 2), |
| 374 | + ) |
| 375 | + |
| 376 | + expect(find.value).toBe(shallow[1]) |
| 377 | + expect(isReactive(find.value)).toBe(false) |
| 378 | + expect(findLast.value).toBe(shallow[1]) |
| 379 | + expect(isReactive(findLast.value)).toBe(false) |
| 380 | + expect(findIndex.value).toBe(1) |
| 381 | + expect(findLastIndex.value).toBe(1) |
| 382 | + |
| 383 | + shallow[1].val = 0 |
| 384 | + |
| 385 | + expect(find.value).toBe(shallow[1]) |
| 386 | + expect(findLast.value).toBe(shallow[1]) |
| 387 | + expect(findIndex.value).toBe(1) |
| 388 | + expect(findLastIndex.value).toBe(1) |
| 389 | + |
| 390 | + shallow.pop() |
| 391 | + |
| 392 | + expect(find.value).toBe(undefined) |
| 393 | + expect(findLast.value).toBe(undefined) |
| 394 | + expect(findIndex.value).toBe(-1) |
| 395 | + expect(findLastIndex.value).toBe(-1) |
| 396 | + |
| 397 | + const deep = reactive([{ val: 1 }, { val: 2 }]) |
| 398 | + find = computed(() => deep.find(x => x.val === 2)) |
| 399 | + // @ts-expect-error tests are not limited to es2016 |
| 400 | + findLast = computed(() => deep.findLast(x => x.val === 2)) |
| 401 | + findIndex = computed(() => deep.findIndex(x => x.val === 2)) |
| 402 | + // @ts-expect-error tests are not limited to es2016 |
| 403 | + findLastIndex = computed(() => deep.findLastIndex(x => x.val === 2)) |
| 404 | + |
| 405 | + expect(find.value).toBe(deep[1]) |
| 406 | + expect(isReactive(find.value)).toBe(true) |
| 407 | + expect(findLast.value).toBe(deep[1]) |
| 408 | + expect(isReactive(findLast.value)).toBe(true) |
| 409 | + expect(findIndex.value).toBe(1) |
| 410 | + expect(findLastIndex.value).toBe(1) |
| 411 | + |
| 412 | + deep[1].val = 0 |
| 413 | + |
| 414 | + expect(find.value).toBe(undefined) |
| 415 | + expect(findLast.value).toBe(undefined) |
| 416 | + expect(findIndex.value).toBe(-1) |
| 417 | + expect(findLastIndex.value).toBe(-1) |
| 418 | + }) |
| 419 | + |
| 420 | + test('forEach', () => { |
| 421 | + const shallow = shallowReactive([1, 2, 3, 4]) |
| 422 | + let result = computed(() => { |
| 423 | + let sum = 0 |
| 424 | + shallow.forEach(x => (sum += x ** 2)) |
| 425 | + return sum |
| 426 | + }) |
| 427 | + expect(result.value).toBe(30) |
| 428 | + |
| 429 | + shallow[2] = 0 |
| 430 | + expect(result.value).toBe(21) |
| 431 | + |
| 432 | + const deep = reactive([{ val: 1 }, { val: 2 }]) |
| 433 | + result = computed(() => { |
| 434 | + let sum = 0 |
| 435 | + deep.forEach(x => (sum += x.val ** 2)) |
| 436 | + return sum |
| 437 | + }) |
| 438 | + expect(result.value).toBe(5) |
| 439 | + |
| 440 | + deep[1].val = 3 |
| 441 | + expect(result.value).toBe(10) |
| 442 | + }) |
| 443 | + |
| 444 | + test('join', () => { |
| 445 | + function toString(this: { val: number }) { |
| 446 | + return this.val |
| 447 | + } |
| 448 | + const shallow = shallowReactive([ |
| 449 | + { val: 1, toString }, |
| 450 | + { val: 2, toString }, |
| 451 | + ]) |
| 452 | + let result = computed(() => shallow.join('+')) |
| 453 | + expect(result.value).toBe('1+2') |
| 454 | + |
| 455 | + shallow[1].val = 23 |
| 456 | + expect(result.value).toBe('1+2') |
| 457 | + |
| 458 | + shallow.pop() |
| 459 | + expect(result.value).toBe('1') |
| 460 | + |
| 461 | + const deep = reactive([ |
| 462 | + { val: 1, toString }, |
| 463 | + { val: 2, toString }, |
| 464 | + ]) |
| 465 | + result = computed(() => deep.join()) |
| 466 | + expect(result.value).toBe('1,2') |
| 467 | + |
| 468 | + deep[1].val = 23 |
| 469 | + expect(result.value).toBe('1,23') |
| 470 | + }) |
| 471 | + |
| 472 | + test('map', () => { |
| 473 | + const shallow = shallowReactive([1, 2, 3, 4]) |
| 474 | + let result = computed(() => shallow.map(x => x ** 2)) |
| 475 | + expect(result.value).toStrictEqual([1, 4, 9, 16]) |
| 476 | + |
| 477 | + shallow[2] = 0 |
| 478 | + expect(result.value).toStrictEqual([1, 4, 0, 16]) |
| 479 | + |
| 480 | + const deep = reactive([{ val: 1 }, { val: 2 }]) |
| 481 | + result = computed(() => deep.map(x => x.val ** 2)) |
| 482 | + expect(result.value).toStrictEqual([1, 4]) |
| 483 | + |
| 484 | + deep[1].val = 3 |
| 485 | + expect(result.value).toStrictEqual([1, 9]) |
| 486 | + }) |
| 487 | + |
| 488 | + test('reduce left and right', () => { |
| 489 | + function toString(this: any) { |
| 490 | + return this.val + '-' |
| 491 | + } |
| 492 | + const shallow = shallowReactive([ |
| 493 | + { val: 1, toString }, |
| 494 | + { val: 2, toString }, |
| 495 | + ] as any[]) |
| 496 | + |
| 497 | + expect(shallow.reduce((acc, x) => acc + '' + x.val, undefined)).toBe( |
| 498 | + 'undefined12', |
| 499 | + ) |
| 500 | + |
| 501 | + let left = computed(() => shallow.reduce((acc, x) => acc + '' + x.val)) |
| 502 | + let right = computed(() => |
| 503 | + shallow.reduceRight((acc, x) => acc + '' + x.val), |
| 504 | + ) |
| 505 | + expect(left.value).toBe('1-2') |
| 506 | + expect(right.value).toBe('2-1') |
| 507 | + |
| 508 | + shallow[1].val = 23 |
| 509 | + expect(left.value).toBe('1-2') |
| 510 | + expect(right.value).toBe('2-1') |
| 511 | + |
| 512 | + shallow.pop() |
| 513 | + expect(left.value).toBe(shallow[0]) |
| 514 | + expect(right.value).toBe(shallow[0]) |
| 515 | + |
| 516 | + const deep = reactive([{ val: 1 }, { val: 2 }]) |
| 517 | + left = computed(() => deep.reduce((acc, x) => acc + x.val, '0')) |
| 518 | + right = computed(() => deep.reduceRight((acc, x) => acc + x.val, '3')) |
| 519 | + expect(left.value).toBe('012') |
| 520 | + expect(right.value).toBe('321') |
| 521 | + |
| 522 | + deep[1].val = 23 |
| 523 | + expect(left.value).toBe('0123') |
| 524 | + expect(right.value).toBe('3231') |
| 525 | + }) |
| 526 | + |
| 527 | + test('some', () => { |
| 528 | + const shallow = shallowReactive([1, 2, 5]) |
| 529 | + let result = computed(() => shallow.some(x => x > 4)) |
| 530 | + expect(result.value).toBe(true) |
| 531 | + |
| 532 | + shallow.pop() |
| 533 | + expect(result.value).toBe(false) |
| 534 | + |
| 535 | + const deep = reactive([{ val: 1 }, { val: 5 }]) |
| 536 | + result = computed(() => deep.some(x => x.val > 4)) |
| 537 | + expect(result.value).toBe(true) |
| 538 | + |
| 539 | + deep[1].val = 2 |
| 540 | + expect(result.value).toBe(false) |
| 541 | + }) |
| 542 | + |
| 543 | + // Node 20+ |
| 544 | + // @ts-expect-error tests are not limited to es2016 |
| 545 | + test.skipIf(!Array.prototype.toReversed)('toReversed', () => { |
| 546 | + const array = reactive([1, { val: 2 }]) |
| 547 | + const result = computed(() => (array as any).toReversed()) |
| 548 | + expect(result.value).toStrictEqual([{ val: 2 }, 1]) |
| 549 | + expect(isReactive(result.value[0])).toBe(true) |
| 550 | + |
| 551 | + array.splice(1, 1, 2) |
| 552 | + expect(result.value).toStrictEqual([2, 1]) |
| 553 | + }) |
| 554 | + |
| 555 | + // Node 20+ |
| 556 | + // @ts-expect-error tests are not limited to es2016 |
| 557 | + test.skipIf(!Array.prototype.toSorted)('toSorted', () => { |
| 558 | + // No comparer |
| 559 | + // @ts-expect-error |
| 560 | + expect(shallowReactive([2, 1, 3]).toSorted()).toStrictEqual([1, 2, 3]) |
| 561 | + |
| 562 | + const shallow = shallowReactive([{ val: 2 }, { val: 1 }, { val: 3 }]) |
| 563 | + let result: ComputedRef<{ val: number }[]> |
| 564 | + // @ts-expect-error |
| 565 | + result = computed(() => shallow.toSorted((a, b) => a.val - b.val)) |
| 566 | + expect(result.value.map(x => x.val)).toStrictEqual([1, 2, 3]) |
| 567 | + expect(isReactive(result.value[0])).toBe(false) |
| 568 | + |
| 569 | + shallow[0].val = 4 |
| 570 | + expect(result.value.map(x => x.val)).toStrictEqual([1, 4, 3]) |
| 571 | + |
| 572 | + shallow.pop() |
| 573 | + expect(result.value.map(x => x.val)).toStrictEqual([1, 4]) |
| 574 | + |
| 575 | + const deep = reactive([{ val: 2 }, { val: 1 }, { val: 3 }]) |
| 576 | + // @ts-expect-error |
| 577 | + result = computed(() => deep.toSorted((a, b) => a.val - b.val)) |
| 578 | + expect(result.value.map(x => x.val)).toStrictEqual([1, 2, 3]) |
| 579 | + expect(isReactive(result.value[0])).toBe(true) |
| 580 | + |
| 581 | + deep[0].val = 4 |
| 582 | + expect(result.value.map(x => x.val)).toStrictEqual([1, 3, 4]) |
| 583 | + }) |
| 584 | + |
| 585 | + // Node 20+ |
| 586 | + // @ts-expect-error tests are not limited to es2016 |
| 587 | + test.skipIf(!Array.prototype.toSpliced)('toSpliced', () => { |
| 588 | + const array = reactive([1, 2, 3]) |
| 589 | + // @ts-expect-error |
| 590 | + const result = computed(() => array.toSpliced(1, 1, -2)) |
| 591 | + expect(result.value).toStrictEqual([1, -2, 3]) |
| 592 | + |
| 593 | + array[0] = 0 |
| 594 | + expect(result.value).toStrictEqual([0, -2, 3]) |
| 595 | + }) |
| 596 | + |
| 597 | + test('values', () => { |
| 598 | + const shallow = shallowReactive([{ val: 1 }, { val: 2 }]) |
| 599 | + const result = computed(() => Array.from(shallow.values())) |
| 600 | + expect(result.value).toStrictEqual([{ val: 1 }, { val: 2 }]) |
| 601 | + expect(isReactive(result.value[0])).toBe(false) |
| 602 | + |
| 603 | + shallow.pop() |
| 604 | + expect(result.value).toStrictEqual([{ val: 1 }]) |
| 605 | + |
| 606 | + const deep = reactive([{ val: 1 }, { val: 2 }]) |
| 607 | + const firstItem = Array.from(deep.values())[0] |
| 608 | + expect(isReactive(firstItem)).toBe(true) |
| 609 | + }) |
| 610 | + }) |
255 | 611 | })
|
0 commit comments