|
1 | 1 | import { type DependencyList, useEffect } from 'react';
|
2 |
| -import { useSource, usePureSource } from '../../src/withContract/useSource'; |
| 2 | +import { |
| 3 | + useSource, |
| 4 | + usePureSource, |
| 5 | + withContract, |
| 6 | +} from '../../src/withContract/useSource'; |
3 | 7 | import {
|
4 | 8 | useSource as useSourceServer,
|
5 | 9 | usePureSource as usePureSourceServer,
|
| 10 | + withContract as withContractServer, |
6 | 11 | } from '../../src/withContract/useSource/server';
|
7 | 12 | import { Source } from '../utils/source';
|
8 | 13 | import { act, create } from '../utils/renderer';
|
@@ -645,3 +650,178 @@ describe('how usePureSource works', () => {
|
645 | 650 | ]);
|
646 | 651 | });
|
647 | 652 | });
|
| 653 | + |
| 654 | +describe('how withContract works', () => { |
| 655 | + const [useSnapshot, source] = withContract( |
| 656 | + // Generate the source. |
| 657 | + new Source(0), |
| 658 | + // Subscribe to changes. |
| 659 | + (source, onChange) => source.addChangeListener(onChange) |
| 660 | + ); |
| 661 | + |
| 662 | + // App component. |
| 663 | + function App({ |
| 664 | + getSnapshotDeps = undefined as undefined | DependencyList, |
| 665 | + getSnapshotOffset = 0, |
| 666 | + }) { |
| 667 | + // Consume the snapshot. |
| 668 | + const value = useSnapshot( |
| 669 | + (source) => source.getValue() + getSnapshotOffset, |
| 670 | + getSnapshotDeps |
| 671 | + ); |
| 672 | + |
| 673 | + // Yield render value. |
| 674 | + yieldValue(`render`, `snapshot(${value})`); |
| 675 | + |
| 676 | + useEffect(() => { |
| 677 | + // Value 2 triggers a new update with value 3. |
| 678 | + if (value === 2) { |
| 679 | + source.setValue(3); |
| 680 | + } |
| 681 | + |
| 682 | + // Yield effect values. |
| 683 | + yieldValue(`effect`, `source(${source.getValue()}) snapshot(${value})`); |
| 684 | + }); |
| 685 | + |
| 686 | + return null; |
| 687 | + } |
| 688 | + |
| 689 | + beforeEach(() => { |
| 690 | + source.setValue(0); |
| 691 | + }); |
| 692 | + |
| 693 | + it('getSnapshot changes every time a dependency changes', () => { |
| 694 | + const root = create({ strictMode: true }); |
| 695 | + |
| 696 | + // Mounts the App with no dependencies. |
| 697 | + act(() => root.update(<App getSnapshotOffset={0} getSnapshotDeps={[0]} />)); |
| 698 | + |
| 699 | + expect(getValues()).toEqual([ |
| 700 | + 'render: snapshot(0)', |
| 701 | + 'render: snapshot(0)', |
| 702 | + // First lifecycle. |
| 703 | + 'effect: source(0) snapshot(0)', |
| 704 | + // Second lifecycle. |
| 705 | + 'effect: source(0) snapshot(0)', |
| 706 | + ]); |
| 707 | + |
| 708 | + // Triggers an update. |
| 709 | + act(() => root.update(<App getSnapshotOffset={1} getSnapshotDeps={[1]} />)); |
| 710 | + |
| 711 | + expect(getValues()).toEqual([ |
| 712 | + 'render: snapshot(1)', |
| 713 | + 'render: snapshot(1)', |
| 714 | + 'effect: source(0) snapshot(1)', |
| 715 | + ]); |
| 716 | + |
| 717 | + act(() => root.unmount()); |
| 718 | + }); |
| 719 | + |
| 720 | + it('getSnapshot is stable if no getSnapshot dependencies are provided', () => { |
| 721 | + const root = create({ strictMode: true }); |
| 722 | + |
| 723 | + // Mounts the App with no dependencies. |
| 724 | + act(() => root.update(<App getSnapshotOffset={0} />)); |
| 725 | + |
| 726 | + expect(getValues()).toEqual([ |
| 727 | + 'render: snapshot(0)', |
| 728 | + 'render: snapshot(0)', |
| 729 | + // First lifecycle. |
| 730 | + 'effect: source(0) snapshot(0)', |
| 731 | + // Second lifecycle. |
| 732 | + 'effect: source(0) snapshot(0)', |
| 733 | + ]); |
| 734 | + |
| 735 | + // Triggers an update. |
| 736 | + act(() => root.update(<App getSnapshotOffset={1} />)); |
| 737 | + |
| 738 | + expect(getValues()).toEqual([ |
| 739 | + 'render: snapshot(0)', |
| 740 | + 'render: snapshot(0)', |
| 741 | + 'effect: source(0) snapshot(0)', |
| 742 | + ]); |
| 743 | + |
| 744 | + act(() => root.unmount()); |
| 745 | + }); |
| 746 | + |
| 747 | + it('correctly dispatches snapshot updates', () => { |
| 748 | + const root = create({ strictMode: true }); |
| 749 | + |
| 750 | + // Mount the App. |
| 751 | + act(() => root.update(<App getSnapshotOffset={0} />)); |
| 752 | + |
| 753 | + expect(getValues()).toEqual([ |
| 754 | + 'render: snapshot(0)', |
| 755 | + 'render: snapshot(0)', |
| 756 | + // First lifecycle. |
| 757 | + 'effect: source(0) snapshot(0)', |
| 758 | + // Second lifecycle |
| 759 | + 'effect: source(0) snapshot(0)', |
| 760 | + ]); |
| 761 | + |
| 762 | + // Dispatch an update with a new value. |
| 763 | + act(() => source.setValue(1)); |
| 764 | + |
| 765 | + expect(getValues()).toEqual([ |
| 766 | + 'render: snapshot(1)', |
| 767 | + 'render: snapshot(1)', |
| 768 | + 'effect: source(1) snapshot(1)', |
| 769 | + ]); |
| 770 | + |
| 771 | + // Dispatch an update with the current value. |
| 772 | + act(() => source.setValue(1)); |
| 773 | + |
| 774 | + expect(getValues()).toEqual([]); |
| 775 | + |
| 776 | + // Re-render with no changes. |
| 777 | + act(() => root.update(<App />)); |
| 778 | + |
| 779 | + expect(getValues()).toEqual([ |
| 780 | + 'render: snapshot(1)', |
| 781 | + 'render: snapshot(1)', |
| 782 | + 'effect: source(1) snapshot(1)', |
| 783 | + ]); |
| 784 | + |
| 785 | + // Update with the special value 2, The component will trigger a new update |
| 786 | + // with the value 3 inside an effect. |
| 787 | + act(() => source.setValue(2)); |
| 788 | + |
| 789 | + expect(getValues()).toEqual([ |
| 790 | + 'render: snapshot(2)', |
| 791 | + 'render: snapshot(2)', |
| 792 | + 'effect: source(3) snapshot(2)', |
| 793 | + 'render: snapshot(3)', |
| 794 | + 'render: snapshot(3)', |
| 795 | + 'effect: source(3) snapshot(3)', |
| 796 | + ]); |
| 797 | + |
| 798 | + act(() => root.unmount()); |
| 799 | + }); |
| 800 | + |
| 801 | + it('acts correctly during ssr', () => { |
| 802 | + const [useSnapshot] = withContractServer( |
| 803 | + // Generate the source. |
| 804 | + new Source(0), |
| 805 | + // Subscribe to changes. |
| 806 | + (source, onChange) => { |
| 807 | + yieldValue(`never`, `this is never called`); |
| 808 | + source.addChangeListener(onChange); |
| 809 | + } |
| 810 | + ); |
| 811 | + |
| 812 | + const App = () => { |
| 813 | + const snapshot = useSnapshot(() => null); |
| 814 | + |
| 815 | + yieldValue(`render`, `snapshot(${snapshot})`); |
| 816 | + return null; |
| 817 | + }; |
| 818 | + |
| 819 | + const root = create(); |
| 820 | + // Mounts the App. |
| 821 | + act(() => root.update(<App />)); |
| 822 | + |
| 823 | + expect(getValues()).toEqual(['render: snapshot(null)']); |
| 824 | + |
| 825 | + act(() => root.unmount()); |
| 826 | + }); |
| 827 | +}); |
0 commit comments