observe.test.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /**
  2. * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
  3. * SPDX-License-Identifier: MIT
  4. */
  5. import * as React from 'react';
  6. import { describe, it, expect, afterEach } from 'vitest';
  7. import { render, cleanup } from '@testing-library/react';
  8. import { observe, Tracker, ReactiveBaseState } from '../src';
  9. function nextTick(v = 0): Promise<void> {
  10. return new Promise(res => setTimeout(res, v));
  11. }
  12. function createComp(name: string): {
  13. Comp: any;
  14. renderTimes: number;
  15. name: string;
  16. fireRender: () => void;
  17. } {
  18. let renderTimes = 0;
  19. let state = new ReactiveBaseState(0);
  20. // let refresh: any;
  21. const Comp = observe((props: any) => {
  22. // refresh = useRefresh()
  23. renderTimes++;
  24. return (
  25. <span>
  26. {state.value}
  27. {typeof props.children === 'function' ? props.children() : props.children}
  28. </span>
  29. );
  30. });
  31. return {
  32. Comp,
  33. name,
  34. get renderTimes(): number {
  35. return renderTimes;
  36. },
  37. fireRender(): void {
  38. state.value += 1;
  39. // refresh()
  40. },
  41. };
  42. }
  43. describe('observe', () => {
  44. afterEach(() => cleanup());
  45. it('base', async () => {
  46. const comp = createComp('comp1');
  47. const result = render(<comp.Comp />);
  48. expect(comp.renderTimes).toEqual(1);
  49. expect(result.asFragment().textContent).toEqual('0');
  50. comp.fireRender();
  51. Tracker.flush();
  52. expect(comp.renderTimes).toEqual(2);
  53. expect(result.asFragment().textContent).toEqual('1');
  54. comp.fireRender();
  55. Tracker.flush();
  56. expect(comp.renderTimes).toEqual(3);
  57. expect(result.asFragment().textContent).toEqual('2');
  58. comp.fireRender();
  59. // use next tick to wait update
  60. await nextTick();
  61. expect(comp.renderTimes).toEqual(4);
  62. expect(result.asFragment().textContent).toEqual('3');
  63. });
  64. it('render nested', () => {
  65. const comp1 = createComp('comp1');
  66. const comp2 = createComp('comp2');
  67. const checkTimes = (v1: number, v2: number) => {
  68. // console.log(comp1.renderTimes, comp2.renderTimes)
  69. expect(comp1.renderTimes).toEqual(v1);
  70. expect(comp2.renderTimes).toEqual(v2);
  71. };
  72. render(
  73. <comp1.Comp>
  74. <comp2.Comp />
  75. </comp1.Comp>,
  76. );
  77. checkTimes(1, 1);
  78. comp1.fireRender();
  79. Tracker.flush();
  80. checkTimes(2, 1);
  81. comp2.fireRender();
  82. Tracker.flush();
  83. checkTimes(2, 2);
  84. comp1.fireRender();
  85. comp2.fireRender();
  86. Tracker.flush();
  87. checkTimes(3, 3);
  88. });
  89. it('render nested with renderProps', () => {
  90. const comp1 = createComp('comp1');
  91. const comp2 = createComp('comp2');
  92. const checkTimes = (v1: number, v2: number) => {
  93. // console.log(comp1.renderTimes, comp2.renderTimes)
  94. expect(comp1.renderTimes).toEqual(v1);
  95. expect(comp2.renderTimes).toEqual(v2);
  96. };
  97. render(<comp1.Comp>{() => <comp2.Comp />}</comp1.Comp>);
  98. checkTimes(1, 1);
  99. comp1.fireRender();
  100. Tracker.flush();
  101. checkTimes(2, 2);
  102. comp2.fireRender();
  103. Tracker.flush();
  104. checkTimes(2, 3);
  105. comp1.fireRender();
  106. comp2.fireRender();
  107. Tracker.flush();
  108. checkTimes(3, 4);
  109. });
  110. });