|
1 | 1 | /*eslint-disable react/prop-types*/
|
2 | 2 |
|
3 |
| -import React, { Component, MouseEvent, useEffect } from 'react' |
| 3 | +import React, { |
| 4 | + Component, |
| 5 | + MouseEvent, |
| 6 | + useEffect, |
| 7 | + ComponentClass, |
| 8 | + ComponentType, |
| 9 | +} from 'react' |
4 | 10 | // import createClass from 'create-react-class'
|
5 | 11 | import PropTypes from 'prop-types'
|
6 | 12 | import ReactDOM from 'react-dom'
|
@@ -75,18 +81,22 @@ describe('React', () => {
|
75 | 81 | return action.type === 'APPEND' ? prev + action.body : prev
|
76 | 82 | }
|
77 | 83 |
|
78 |
| - // function imitateHotReloading(TargetClass, SourceClass, container) { |
79 |
| - // // Crude imitation of hot reloading that does the job |
80 |
| - // Object.getOwnPropertyNames(SourceClass.prototype) |
81 |
| - // .filter((key) => typeof SourceClass.prototype[key] === 'function') |
82 |
| - // .forEach((key) => { |
83 |
| - // if (key !== 'render' && key !== 'constructor') { |
84 |
| - // TargetClass.prototype[key] = SourceClass.prototype[key] |
85 |
| - // } |
86 |
| - // }) |
| 84 | + function imitateHotReloading( |
| 85 | + TargetClass: ComponentType, |
| 86 | + SourceClass: ComponentType, |
| 87 | + container: Component |
| 88 | + ) { |
| 89 | + // Crude imitation of hot reloading that does the job |
| 90 | + Object.getOwnPropertyNames(SourceClass.prototype) |
| 91 | + .filter((key) => typeof SourceClass.prototype[key] === 'function') |
| 92 | + .forEach((key) => { |
| 93 | + if (key !== 'render' && key !== 'constructor') { |
| 94 | + TargetClass.prototype[key] = SourceClass.prototype[key] |
| 95 | + } |
| 96 | + }) |
87 | 97 |
|
88 |
| - // container.forceUpdate() |
89 |
| - // } |
| 98 | + container.forceUpdate() |
| 99 | + } |
90 | 100 |
|
91 | 101 | afterEach(() => rtl.cleanup())
|
92 | 102 |
|
@@ -1751,94 +1761,140 @@ describe('React', () => {
|
1751 | 1761 | })
|
1752 | 1762 | })
|
1753 | 1763 |
|
1754 |
| - // describe('HMR handling', () => { |
1755 |
| - // it.skip('should recalculate the state and rebind the actions on hot update', () => { |
1756 |
| - // const store = createStore(() => {}) |
1757 |
| - // @connect(null, () => ({ scooby: 'doo' })) |
1758 |
| - // class ContainerBefore extends Component { |
1759 |
| - // render() { |
1760 |
| - // return <Passthrough {...this.props} /> |
1761 |
| - // } |
1762 |
| - // } |
1763 |
| - // @connect(() => ({ foo: 'baz' }), () => ({ scooby: 'foo' })) |
1764 |
| - // class ContainerAfter extends Component { |
1765 |
| - // render() { |
1766 |
| - // return <Passthrough {...this.props} /> |
1767 |
| - // } |
1768 |
| - // } |
1769 |
| - // @connect(() => ({ foo: 'bar' }), () => ({ scooby: 'boo' })) |
1770 |
| - // class ContainerNext extends Component { |
1771 |
| - // render() { |
1772 |
| - // return <Passthrough {...this.props} /> |
1773 |
| - // } |
1774 |
| - // } |
1775 |
| - // let container |
1776 |
| - // const tester = rtl.render( |
1777 |
| - // <ProviderMock store={store}> |
1778 |
| - // <ContainerBefore ref={(instance) => (container = instance)} /> |
1779 |
| - // </ProviderMock> |
1780 |
| - // ) |
1781 |
| - // expect(tester.queryByTestId('foo')).toBe(null) |
1782 |
| - // expect(tester.getByTestId('scooby')).toHaveTextContent('doo') |
1783 |
| - // imitateHotReloading(ContainerBefore, ContainerAfter, container) |
1784 |
| - // expect(tester.getByTestId('foo')).toHaveTextContent('baz') |
1785 |
| - // expect(tester.getByTestId('scooby')).toHaveTextContent('foo') |
1786 |
| - // imitateHotReloading(ContainerBefore, ContainerNext, container) |
1787 |
| - // expect(tester.getByTestId('foo')).toHaveTextContent('bar') |
1788 |
| - // expect(tester.getByTestId('scooby')).toHaveTextContent('boo') |
1789 |
| - // }) |
| 1764 | + describe('HMR handling', () => { |
| 1765 | + it.skip('should recalculate the state and rebind the actions on hot update', () => { |
| 1766 | + const store = createStore(() => {}) |
| 1767 | + class ContainerBefore extends Component { |
| 1768 | + render() { |
| 1769 | + return <Passthrough {...this.props} /> |
| 1770 | + } |
| 1771 | + } |
| 1772 | + const ConnectedContainerBefore = connect(null, () => ({ |
| 1773 | + scooby: 'doo', |
| 1774 | + }))(ContainerBefore) |
| 1775 | + class ContainerAfter extends Component { |
| 1776 | + render() { |
| 1777 | + return <Passthrough {...this.props} /> |
| 1778 | + } |
| 1779 | + } |
| 1780 | + const ConnectedContainerAfter = connect( |
| 1781 | + () => ({ foo: 'baz' }), |
| 1782 | + () => ({ scooby: 'foo' }) |
| 1783 | + )(ContainerAfter) |
| 1784 | + class ContainerNext extends Component { |
| 1785 | + render() { |
| 1786 | + return <Passthrough {...this.props} /> |
| 1787 | + } |
| 1788 | + } |
| 1789 | + const ConnectedContainerNext = connect( |
| 1790 | + () => ({ foo: 'bar' }), |
| 1791 | + () => ({ scooby: 'boo' }) |
| 1792 | + )(ContainerNext) |
1790 | 1793 |
|
1791 |
| - // it.skip('should persist listeners through hot update', () => { |
1792 |
| - // const ACTION_TYPE = 'ACTION' |
1793 |
| - // const store = createStore((state = { actions: 0 }, action) => { |
1794 |
| - // switch (action.type) { |
1795 |
| - // case ACTION_TYPE: { |
1796 |
| - // return { |
1797 |
| - // actions: state.actions + 1, |
1798 |
| - // } |
1799 |
| - // } |
1800 |
| - // default: |
1801 |
| - // return state |
1802 |
| - // } |
1803 |
| - // }) |
| 1794 | + let container = React.createRef<ContainerBefore>() |
| 1795 | + const tester = rtl.render( |
| 1796 | + <ProviderMock store={store}> |
| 1797 | + <ConnectedContainerBefore ref={container} /> |
| 1798 | + </ProviderMock> |
| 1799 | + ) |
| 1800 | + expect(tester.queryByTestId('foo')).toBe(null) |
| 1801 | + expect(tester.getByTestId('scooby')).toHaveTextContent('doo') |
| 1802 | + imitateHotReloading( |
| 1803 | + ConnectedContainerBefore, |
| 1804 | + ConnectedContainerAfter, |
| 1805 | + container.current! |
| 1806 | + ) |
| 1807 | + expect(tester.getByTestId('foo')).toHaveTextContent('baz') |
| 1808 | + expect(tester.getByTestId('scooby')).toHaveTextContent('foo') |
| 1809 | + imitateHotReloading( |
| 1810 | + ConnectedContainerBefore, |
| 1811 | + ConnectedContainerNext, |
| 1812 | + container.current! |
| 1813 | + ) |
| 1814 | + expect(tester.getByTestId('foo')).toHaveTextContent('bar') |
| 1815 | + expect(tester.getByTestId('scooby')).toHaveTextContent('boo') |
| 1816 | + }) |
1804 | 1817 |
|
1805 |
| - // @connect((state) => ({ actions: state.actions })) |
1806 |
| - // class Child extends Component { |
1807 |
| - // render() { |
1808 |
| - // return <Passthrough {...this.props} /> |
1809 |
| - // } |
1810 |
| - // } |
| 1818 | + it.skip('should persist listeners through hot update', () => { |
| 1819 | + const ACTION_TYPE = 'ACTION' |
| 1820 | + interface RootStateType { |
| 1821 | + actions: number |
| 1822 | + } |
| 1823 | + interface ActionType { |
| 1824 | + type: string |
| 1825 | + } |
| 1826 | + const store = createStore( |
| 1827 | + (state: RootStateType = { actions: 0 }, action: ActionType) => { |
| 1828 | + switch (action.type) { |
| 1829 | + case ACTION_TYPE: { |
| 1830 | + return { |
| 1831 | + actions: state.actions + 1, |
| 1832 | + } |
| 1833 | + } |
| 1834 | + default: |
| 1835 | + return state |
| 1836 | + } |
| 1837 | + } |
| 1838 | + ) |
1811 | 1839 |
|
1812 |
| - // @connect(() => ({ scooby: 'doo' })) |
1813 |
| - // class ParentBefore extends Component { |
1814 |
| - // render() { |
1815 |
| - // return <Child /> |
1816 |
| - // } |
1817 |
| - // } |
| 1840 | + class Child extends Component { |
| 1841 | + render() { |
| 1842 | + return <Passthrough {...this.props} /> |
| 1843 | + } |
| 1844 | + } |
| 1845 | + interface ChildrenTStateProps { |
| 1846 | + actions: number |
| 1847 | + } |
| 1848 | + type ChildrenNoDispatch = {} |
| 1849 | + type ChildrenTOwnProps = {} |
| 1850 | + type ChildrenRootState = RootStateType |
| 1851 | + const ConnectedChild = connect< |
| 1852 | + ChildrenTStateProps, |
| 1853 | + ChildrenNoDispatch, |
| 1854 | + ChildrenTOwnProps, |
| 1855 | + ChildrenRootState |
| 1856 | + >((state) => ({ |
| 1857 | + actions: state.actions, |
| 1858 | + }))(Child) |
1818 | 1859 |
|
1819 |
| - // @connect(() => ({ scooby: 'boo' })) |
1820 |
| - // class ParentAfter extends Component { |
1821 |
| - // render() { |
1822 |
| - // return <Child /> |
1823 |
| - // } |
1824 |
| - // } |
| 1860 | + class ParentBefore extends Component { |
| 1861 | + render() { |
| 1862 | + return <ConnectedChild /> |
| 1863 | + } |
| 1864 | + } |
| 1865 | + const ConnectedParentBefore = connect(() => ({ scooby: 'doo' }))( |
| 1866 | + ParentBefore |
| 1867 | + ) |
1825 | 1868 |
|
1826 |
| - // let container |
1827 |
| - // const tester = rtl.render( |
1828 |
| - // <ProviderMock store={store}> |
1829 |
| - // <ParentBefore ref={(instance) => (container = instance)} /> |
1830 |
| - // </ProviderMock> |
1831 |
| - // ) |
| 1869 | + class ParentAfter extends Component { |
| 1870 | + render() { |
| 1871 | + return <Child /> |
| 1872 | + } |
| 1873 | + } |
| 1874 | + const ConnectedParentAfter = connect(() => ({ scooby: 'boo' }))( |
| 1875 | + ParentAfter |
| 1876 | + ) |
1832 | 1877 |
|
1833 |
| - // imitateHotReloading(ParentBefore, ParentAfter, container) |
| 1878 | + let container = React.createRef<ParentBefore>() |
| 1879 | + const tester = rtl.render( |
| 1880 | + <ProviderMock store={store}> |
| 1881 | + <ConnectedParentBefore ref={container} /> |
| 1882 | + </ProviderMock> |
| 1883 | + ) |
1834 | 1884 |
|
1835 |
| - // rtl.act(() => { |
1836 |
| - // store.dispatch({ type: ACTION_TYPE }) |
1837 |
| - // }) |
| 1885 | + imitateHotReloading( |
| 1886 | + ConnectedParentBefore, |
| 1887 | + ConnectedParentAfter, |
| 1888 | + container.current! |
| 1889 | + ) |
1838 | 1890 |
|
1839 |
| - // expect(tester.getByTestId('actions')).toHaveTextContent('1') |
1840 |
| - // }) |
1841 |
| - // }) |
| 1891 | + rtl.act(() => { |
| 1892 | + store.dispatch({ type: ACTION_TYPE }) |
| 1893 | + }) |
| 1894 | + |
| 1895 | + expect(tester.getByTestId('actions')).toHaveTextContent('1') |
| 1896 | + }) |
| 1897 | + }) |
1842 | 1898 |
|
1843 | 1899 | // describe('Wrapped component and HOC handling', () => {
|
1844 | 1900 | // it('should throw an error if a component is not passed to the function returned by connect', () => {
|
|
0 commit comments