@samitouri / QOS-React-1 / commits / 99471c02dd

[assert helpers] ReactFlight (#31860)

Ricky committed Dec 20, 2024 at 12:41 UTC 99471c02dd6631df1892bf76d932afd22fffa5e3
1 file changed +474 -166
packages/react-client/src/__tests__/ReactFlight-test.js
+474 -166
@@ -1467,13 +1467,12 @@ describe('ReactFlight', () => {
1467
1468 const transport = ReactNoopFlightServer.render(<App />);
1469
1470 - await expect(async () => {
1471 - await act(() => {
1472 - startTransition(() => {
1473 - ReactNoop.render(ReactNoopFlightClient.read(transport));
1474 - });
1470 + await act(() => {
1471 + startTransition(() => {
1472 + ReactNoop.render(ReactNoopFlightClient.read(transport));
1473 });
1476 - }).toErrorDev(
1474 + });
1475 + assertConsoleErrorDev([
1476 'Each child in a list should have a unique "key" prop.\n' +
1477 '\n' +
1478 'Check the render method of `Component`. See https://react.dev/link/warning-keys for more information.\n' +
@@ -1483,7 +1482,7 @@ describe('ReactFlight', () => {
1482 ? ''
1483 : ' in Indirection (at **)\n') +
1484 ' in App (at **)',
1486 - );
1485 + ]);
1486 });
1487
1488 it('should trigger the inner most error boundary inside a Client Component', async () => {
@@ -1541,17 +1540,47 @@ describe('ReactFlight', () => {
1540 return 123;
1541 },
1542 };
1544 - expect(() => {
1545 - const transport = ReactNoopFlightServer.render(<input value={obj} />);
1546 - ReactNoopFlightClient.read(transport);
1547 - }).toErrorDev(
1548 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1549 - 'Objects with toJSON methods are not supported. ' +
1550 - 'Convert it manually to a simple value before passing it to props.\n' +
1551 - ' <input value={{toJSON: ...}}>\n' +
1552 - ' ^^^^^^^^^^^^^^^',
1553 - {withoutStack: true},
1554 - );
1543 + const transport = ReactNoopFlightServer.render(<input value={obj} />);
1544 + if (gate(flags => flags.enableOwnerStacks)) {
1545 + assertConsoleErrorDev(
1546 + [
1547 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1548 + 'Objects with toJSON methods are not supported. ' +
1549 + 'Convert it manually to a simple value before passing it to props.\n' +
1550 + ' <input value={{toJSON: ...}}>\n' +
1551 + ' ^^^^^^^^^^^^^^^',
1552 + ],
1553 + {withoutStack: true},
1554 + );
1555 + }
1556 +
1557 + ReactNoopFlightClient.read(transport);
1558 + if (gate(flags => flags.enableOwnerStacks)) {
1559 + assertConsoleErrorDev([
1560 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1561 + 'Objects with toJSON methods are not supported. ' +
1562 + 'Convert it manually to a simple value before passing it to props.\n' +
1563 + ' <input value={{toJSON: ...}}>\n' +
1564 + ' ^^^^^^^^^^^^^^^\n' +
1565 + ' at (<anonymous>)',
1566 + ]);
1567 + } else {
1568 + assertConsoleErrorDev(
1569 + [
1570 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1571 + 'Objects with toJSON methods are not supported. ' +
1572 + 'Convert it manually to a simple value before passing it to props.\n' +
1573 + ' <input value={{toJSON: ...}}>\n' +
1574 + ' ^^^^^^^^^^^^^^^',
1575 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1576 + 'Objects with toJSON methods are not supported. ' +
1577 + 'Convert it manually to a simple value before passing it to props.\n' +
1578 + ' <input value={{toJSON: ...}}>\n' +
1579 + ' ^^^^^^^^^^^^^^^',
1580 + ],
1581 + {withoutStack: true},
1582 + );
1583 + }
1584 });
1585
1586 it('should warn in DEV if a toJSON instance is passed to a host component child', () => {
@@ -1560,43 +1589,123 @@ describe('ReactFlight', () => {
1589 return 123;
1590 }
1591 }
1563 - expect(() => {
1564 - const transport = ReactNoopFlightServer.render(
1565 - <div>Womp womp: {new MyError('spaghetti')}</div>,
1592 + const transport = ReactNoopFlightServer.render(
1593 + <div>Womp womp: {new MyError('spaghetti')}</div>,
1594 + );
1595 + if (gate(flags => flags.enableOwnerStacks)) {
1596 + assertConsoleErrorDev(
1597 + [
1598 + 'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
1599 + ' <div>Womp womp: {Error}</div>\n' +
1600 + ' ^^^^^^^',
1601 + ],
1602 + {withoutStack: true},
1603 );
1567 - ReactNoopFlightClient.read(transport);
1568 - }).toErrorDev(
1569 - 'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
1570 - ' <div>Womp womp: {Error}</div>\n' +
1571 - ' ^^^^^^^',
1572 - {withoutStack: true},
1573 - );
1604 + }
1605 +
1606 + ReactNoopFlightClient.read(transport);
1607 + if (gate(flags => flags.enableOwnerStacks)) {
1608 + assertConsoleErrorDev([
1609 + 'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
1610 + ' <div>Womp womp: {Error}</div>\n' +
1611 + ' ^^^^^^^\n' +
1612 + ' at (<anonymous>)',
1613 + ]);
1614 + } else {
1615 + assertConsoleErrorDev(
1616 + [
1617 + 'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
1618 + ' <div>Womp womp: {Error}</div>\n' +
1619 + ' ^^^^^^^',
1620 + 'Error objects cannot be rendered as text children. Try formatting it using toString().\n' +
1621 + ' <div>Womp womp: {Error}</div>\n' +
1622 + ' ^^^^^^^',
1623 + ],
1624 + {withoutStack: true},
1625 + );
1626 + }
1627 });
1628
1629 it('should warn in DEV if a special object is passed to a host component', () => {
1577 - expect(() => {
1578 - const transport = ReactNoopFlightServer.render(<input value={Math} />);
1579 - ReactNoopFlightClient.read(transport);
1580 - }).toErrorDev(
1581 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1582 - 'Math objects are not supported.\n' +
1583 - ' <input value={Math}>\n' +
1584 - ' ^^^^^^',
1585 - {withoutStack: true},
1586 - );
1630 + const transport = ReactNoopFlightServer.render(<input value={Math} />);
1631 + if (gate(flags => flags.enableOwnerStacks)) {
1632 + assertConsoleErrorDev(
1633 + [
1634 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1635 + 'Math objects are not supported.\n' +
1636 + ' <input value={Math}>\n' +
1637 + ' ^^^^^^',
1638 + ],
1639 + {withoutStack: true},
1640 + );
1641 + }
1642 +
1643 + ReactNoopFlightClient.read(transport);
1644 + if (gate(flags => flags.enableOwnerStacks)) {
1645 + assertConsoleErrorDev([
1646 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1647 + 'Math objects are not supported.\n' +
1648 + ' <input value={Math}>\n' +
1649 + ' ^^^^^^\n' +
1650 + ' at (<anonymous>)',
1651 + ]);
1652 + } else {
1653 + assertConsoleErrorDev(
1654 + [
1655 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1656 + 'Math objects are not supported.\n' +
1657 + ' <input value={Math}>\n' +
1658 + ' ^^^^^^',
1659 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1660 + 'Math objects are not supported.\n' +
1661 + ' <input value={Math}>\n' +
1662 + ' ^^^^^^',
1663 + ],
1664 + {withoutStack: true},
1665 + );
1666 + }
1667 });
1668
1669 it('should warn in DEV if an object with symbols is passed to a host component', () => {
1590 - expect(() => {
1591 - const transport = ReactNoopFlightServer.render(
1592 - <input value={{[Symbol.iterator]: {}}} />,
1670 + const transport = ReactNoopFlightServer.render(
1671 + <input value={{[Symbol.iterator]: {}}} />,
1672 + );
1673 + if (gate(flags => flags.enableOwnerStacks)) {
1674 + assertConsoleErrorDev(
1675 + [
1676 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1677 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1678 + ' <input value={{}}>\n' +
1679 + ' ^^^^',
1680 + ],
1681 + {withoutStack: true},
1682 );
1594 - ReactNoopFlightClient.read(transport);
1595 - }).toErrorDev(
1596 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1597 - 'Objects with symbol properties like Symbol.iterator are not supported.',
1598 - {withoutStack: true},
1599 - );
1683 + }
1684 +
1685 + ReactNoopFlightClient.read(transport);
1686 + if (gate(flags => flags.enableOwnerStacks)) {
1687 + assertConsoleErrorDev([
1688 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1689 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1690 + ' <input value={{}}>\n' +
1691 + ' ^^^^\n' +
1692 + ' at (<anonymous>)',
1693 + ]);
1694 + } else {
1695 + assertConsoleErrorDev(
1696 + [
1697 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1698 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1699 + ' <input value={{}}>\n' +
1700 + ' ^^^^',
1701 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1702 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1703 + ' <input value={{}}>\n' +
1704 + ' ^^^^',
1705 + ],
1706 + {withoutStack: true},
1707 + );
1708 + }
1709 });
1710
1711 it('should warn in DEV if a toJSON instance is passed to a Client Component', () => {
@@ -1609,14 +1718,47 @@ describe('ReactFlight', () => {
1718 return <div>{value}</div>;
1719 }
1720 const Client = clientReference(ClientImpl);
1612 - expect(() => {
1613 - const transport = ReactNoopFlightServer.render(<Client value={obj} />);
1614 - ReactNoopFlightClient.read(transport);
1615 - }).toErrorDev(
1616 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1617 - 'Objects with toJSON methods are not supported.',
1618 - {withoutStack: true},
1619 - );
1721 + const transport = ReactNoopFlightServer.render(<Client value={obj} />);
1722 + if (gate(flags => flags.enableOwnerStacks)) {
1723 + assertConsoleErrorDev(
1724 + [
1725 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1726 + 'Objects with toJSON methods are not supported. ' +
1727 + 'Convert it manually to a simple value before passing it to props.\n' +
1728 + ' <... value={{toJSON: ...}}>\n' +
1729 + ' ^^^^^^^^^^^^^^^',
1730 + ],
1731 + {withoutStack: true},
1732 + );
1733 + }
1734 +
1735 + ReactNoopFlightClient.read(transport);
1736 + if (gate(flags => flags.enableOwnerStacks)) {
1737 + assertConsoleErrorDev([
1738 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1739 + 'Objects with toJSON methods are not supported. ' +
1740 + 'Convert it manually to a simple value before passing it to props.\n' +
1741 + ' <... value={{toJSON: ...}}>\n' +
1742 + ' ^^^^^^^^^^^^^^^\n' +
1743 + ' at (<anonymous>)',
1744 + ]);
1745 + } else {
1746 + assertConsoleErrorDev(
1747 + [
1748 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1749 + 'Objects with toJSON methods are not supported. ' +
1750 + 'Convert it manually to a simple value before passing it to props.\n' +
1751 + ' <... value={{toJSON: ...}}>\n' +
1752 + ' ^^^^^^^^^^^^^^^',
1753 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1754 + 'Objects with toJSON methods are not supported. ' +
1755 + 'Convert it manually to a simple value before passing it to props.\n' +
1756 + ' <... value={{toJSON: ...}}>\n' +
1757 + ' ^^^^^^^^^^^^^^^',
1758 + ],
1759 + {withoutStack: true},
1760 + );
1761 + }
1762 });
1763
1764 it('should warn in DEV if a toJSON instance is passed to a Client Component child', () => {
@@ -1629,19 +1771,49 @@ describe('ReactFlight', () => {
1771 return <div>{children}</div>;
1772 }
1773 const Client = clientReference(ClientImpl);
1632 - expect(() => {
1633 - const transport = ReactNoopFlightServer.render(
1634 - <Client>Current date: {obj}</Client>,
1774 + const transport = ReactNoopFlightServer.render(
1775 + <Client>Current date: {obj}</Client>,
1776 + );
1777 + if (gate(flags => flags.enableOwnerStacks)) {
1778 + assertConsoleErrorDev(
1779 + [
1780 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1781 + 'Objects with toJSON methods are not supported. ' +
1782 + 'Convert it manually to a simple value before passing it to props.\n' +
1783 + ' <>Current date: {{toJSON: ...}}</>\n' +
1784 + ' ^^^^^^^^^^^^^^^',
1785 + ],
1786 + {withoutStack: true},
1787 );
1636 - ReactNoopFlightClient.read(transport);
1637 - }).toErrorDev(
1638 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1639 - 'Objects with toJSON methods are not supported. ' +
1640 - 'Convert it manually to a simple value before passing it to props.\n' +
1641 - ' <>Current date: {{toJSON: ...}}</>\n' +
1642 - ' ^^^^^^^^^^^^^^^',
1643 - {withoutStack: true},
1644 - );
1788 + }
1789 +
1790 + ReactNoopFlightClient.read(transport);
1791 + if (gate(flags => flags.enableOwnerStacks)) {
1792 + assertConsoleErrorDev([
1793 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1794 + 'Objects with toJSON methods are not supported. ' +
1795 + 'Convert it manually to a simple value before passing it to props.\n' +
1796 + ' <>Current date: {{toJSON: ...}}</>\n' +
1797 + ' ^^^^^^^^^^^^^^^\n' +
1798 + ' at (<anonymous>)',
1799 + ]);
1800 + } else {
1801 + assertConsoleErrorDev(
1802 + [
1803 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1804 + 'Objects with toJSON methods are not supported. ' +
1805 + 'Convert it manually to a simple value before passing it to props.\n' +
1806 + ' <>Current date: {{toJSON: ...}}</>\n' +
1807 + ' ^^^^^^^^^^^^^^^',
1808 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1809 + 'Objects with toJSON methods are not supported. ' +
1810 + 'Convert it manually to a simple value before passing it to props.\n' +
1811 + ' <>Current date: {{toJSON: ...}}</>\n' +
1812 + ' ^^^^^^^^^^^^^^^',
1813 + ],
1814 + {withoutStack: true},
1815 + );
1816 + }
1817 });
1818
1819 it('should warn in DEV if a special object is passed to a Client Component', () => {
@@ -1649,16 +1821,44 @@ describe('ReactFlight', () => {
1821 return <div>{value}</div>;
1822 }
1823 const Client = clientReference(ClientImpl);
1652 - expect(() => {
1653 - const transport = ReactNoopFlightServer.render(<Client value={Math} />);
1654 - ReactNoopFlightClient.read(transport);
1655 - }).toErrorDev(
1656 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1657 - 'Math objects are not supported.\n' +
1658 - ' <... value={Math}>\n' +
1659 - ' ^^^^^^',
1660 - {withoutStack: true},
1661 - );
1824 + const transport = ReactNoopFlightServer.render(<Client value={Math} />);
1825 +
1826 + if (gate(flags => flags.enableOwnerStacks)) {
1827 + assertConsoleErrorDev(
1828 + [
1829 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1830 + 'Math objects are not supported.\n' +
1831 + ' <... value={Math}>\n' +
1832 + ' ^^^^^^',
1833 + ],
1834 + {withoutStack: true},
1835 + );
1836 + }
1837 +
1838 + ReactNoopFlightClient.read(transport);
1839 + if (gate(flags => flags.enableOwnerStacks)) {
1840 + assertConsoleErrorDev([
1841 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1842 + 'Math objects are not supported.\n' +
1843 + ' <... value={Math}>\n' +
1844 + ' ^^^^^^\n' +
1845 + ' at (<anonymous>)',
1846 + ]);
1847 + } else {
1848 + assertConsoleErrorDev(
1849 + [
1850 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1851 + 'Math objects are not supported.\n' +
1852 + ' <... value={Math}>\n' +
1853 + ' ^^^^^^',
1854 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1855 + 'Math objects are not supported.\n' +
1856 + ' <... value={Math}>\n' +
1857 + ' ^^^^^^',
1858 + ],
1859 + {withoutStack: true},
1860 + );
1861 + }
1862 });
1863
1864 it('should warn in DEV if an object with symbols is passed to a Client Component', () => {
@@ -1666,16 +1866,46 @@ describe('ReactFlight', () => {
1866 return <div>{value}</div>;
1867 }
1868 const Client = clientReference(ClientImpl);
1669 - expect(() => {
1670 - const transport = ReactNoopFlightServer.render(
1671 - <Client value={{[Symbol.iterator]: {}}} />,
1869 + assertConsoleErrorDev([]);
1870 + const transport = ReactNoopFlightServer.render(
1871 + <Client value={{[Symbol.iterator]: {}}} />,
1872 + );
1873 + if (gate(flags => flags.enableOwnerStacks)) {
1874 + assertConsoleErrorDev(
1875 + [
1876 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1877 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1878 + ' <... value={{}}>\n' +
1879 + ' ^^^^',
1880 + ],
1881 + {withoutStack: true},
1882 );
1673 - ReactNoopFlightClient.read(transport);
1674 - }).toErrorDev(
1675 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1676 - 'Objects with symbol properties like Symbol.iterator are not supported.',
1677 - {withoutStack: true},
1678 - );
1883 + }
1884 +
1885 + ReactNoopFlightClient.read(transport);
1886 +
1887 + if (gate(flags => flags.enableOwnerStacks)) {
1888 + assertConsoleErrorDev([
1889 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1890 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1891 + ' <... value={{}}>\n' +
1892 + ' ^^^^\n',
1893 + ]);
1894 + } else {
1895 + assertConsoleErrorDev(
1896 + [
1897 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1898 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1899 + ' <... value={{}}>\n' +
1900 + ' ^^^^',
1901 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1902 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1903 + ' <... value={{}}>\n' +
1904 + ' ^^^^',
1905 + ],
1906 + {withoutStack: true},
1907 + );
1908 + }
1909 });
1910
1911 it('should warn in DEV if a special object is passed to a nested object in Client Component', () => {
@@ -1683,18 +1913,41 @@ describe('ReactFlight', () => {
1913 return <div>{value}</div>;
1914 }
1915 const Client = clientReference(ClientImpl);
1686 - expect(() => {
1687 - const transport = ReactNoopFlightServer.render(
1688 - <Client value={{hello: Math, title: <h1>hi</h1>}} />,
1689 - );
1690 - ReactNoopFlightClient.read(transport);
1691 - }).toErrorDev(
1692 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1693 - 'Math objects are not supported.\n' +
1694 - ' {hello: Math, title: <h1/>}\n' +
1695 - ' ^^^^',
1696 - {withoutStack: true},
1916 + const transport = ReactNoopFlightServer.render(
1917 + <Client value={{[Symbol.iterator]: {}}} />,
1918 );
1919 + ReactNoopFlightClient.read(transport);
1920 +
1921 + if (gate(flags => flags.enableOwnerStacks)) {
1922 + assertConsoleErrorDev([
1923 + [
1924 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1925 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1926 + ' <... value={{}}>\n' +
1927 + ' ^^^^',
1928 + {withoutStack: true},
1929 + ],
1930 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1931 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1932 + ' <... value={{}}>\n' +
1933 + ' ^^^^\n' +
1934 + ' at (<anonymous>)',
1935 + ]);
1936 + } else {
1937 + assertConsoleErrorDev(
1938 + [
1939 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1940 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1941 + ' <... value={{}}>\n' +
1942 + ' ^^^^',
1943 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1944 + 'Objects with symbol properties like Symbol.iterator are not supported.\n' +
1945 + ' <... value={{}}>\n' +
1946 + ' ^^^^',
1947 + ],
1948 + {withoutStack: true},
1949 + );
1950 + }
1951 });
1952
1953 it('should warn in DEV if a special object is passed to a nested array in Client Component', () => {
@@ -1702,20 +1955,40 @@ describe('ReactFlight', () => {
1955 return <div>{value}</div>;
1956 }
1957 const Client = clientReference(ClientImpl);
1705 - expect(() => {
1706 - const transport = ReactNoopFlightServer.render(
1707 - <Client
1708 - value={['looooong string takes up noise', Math, <h1>hi</h1>]}
1709 - />,
1710 - );
1711 - ReactNoopFlightClient.read(transport);
1712 - }).toErrorDev(
1713 - 'Only plain objects can be passed to Client Components from Server Components. ' +
1714 - 'Math objects are not supported.\n' +
1715 - ' [..., Math, <h1/>]\n' +
1716 - ' ^^^^',
1717 - {withoutStack: true},
1958 + const transport = ReactNoopFlightServer.render(
1959 + <Client value={['looooong string takes up noise', Math, <h1>hi</h1>]} />,
1960 );
1961 + ReactNoopFlightClient.read(transport);
1962 + if (gate(flags => flags.enableOwnerStacks)) {
1963 + assertConsoleErrorDev([
1964 + [
1965 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1966 + 'Math objects are not supported.\n' +
1967 + ' [..., Math, <h1/>]\n' +
1968 + ' ^^^^',
1969 + {withoutStack: true},
1970 + ],
1971 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1972 + 'Math objects are not supported.\n' +
1973 + ' [..., Math, <h1/>]\n' +
1974 + ' ^^^^\n' +
1975 + ' at (<anonymous>)',
1976 + ]);
1977 + } else {
1978 + assertConsoleErrorDev(
1979 + [
1980 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1981 + 'Math objects are not supported.\n' +
1982 + ' [..., Math, <h1/>]\n' +
1983 + ' ^^^^',
1984 + 'Only plain objects can be passed to Client Components from Server Components. ' +
1985 + 'Math objects are not supported.\n' +
1986 + ' [..., Math, <h1/>]\n' +
1987 + ' ^^^^',
1988 + ],
1989 + {withoutStack: true},
1990 + );
1991 + }
1992 });
1993
1994 it('should NOT warn in DEV for key getters', () => {
@@ -1729,63 +2002,100 @@ describe('ReactFlight', () => {
2002 key: "this has a key but parent doesn't",
2003 });
2004 }
1732 - expect(() => {
1733 - // While we're on the server we need to have the Server version active to track component stacks.
1734 - jest.resetModules();
1735 - jest.mock('react', () => ReactServer);
1736 - const transport = ReactNoopFlightServer.render(
1737 - ReactServer.createElement(
1738 - 'div',
1739 - null,
1740 - Array(6).fill(ReactServer.createElement(NoKey)),
1741 - ),
1742 - );
1743 - jest.resetModules();
1744 - jest.mock('react', () => React);
1745 - ReactNoopFlightClient.read(transport);
1746 - }).toErrorDev('Each child in a list should have a unique "key" prop.');
2005 + // While we're on the server we need to have the Server version active to track component stacks.
2006 + jest.resetModules();
2007 + jest.mock('react', () => ReactServer);
2008 + const transport = ReactNoopFlightServer.render(
2009 + ReactServer.createElement(
2010 + 'div',
2011 + null,
2012 + Array(6).fill(ReactServer.createElement(NoKey)),
2013 + ),
2014 + );
2015 + jest.resetModules();
2016 + jest.mock('react', () => React);
2017 + ReactNoopFlightClient.read(transport);
2018 + if (gate(flags => flags.enableOwnerStacks)) {
2019 + assertConsoleErrorDev([
2020 + 'Each child in a list should have a unique "key" prop. ' +
2021 + 'See https://react.dev/link/warning-keys for more information.\n' +
2022 + ' in NoKey (at **)',
2023 + 'Each child in a list should have a unique "key" prop. ' +
2024 + 'See https://react.dev/link/warning-keys for more information.\n' +
2025 + ' in NoKey (at **)',
2026 + ]);
2027 + } else {
2028 + assertConsoleErrorDev([
2029 + 'Each child in a list should have a unique "key" prop.\n\n' +
2030 + 'Check the top-level render call using <div>. ' +
2031 + 'See https://react.dev/link/warning-keys for more information.\n' +
2032 + ' in NoKey (at **)',
2033 + ]);
2034 + }
2035 });
2036
2037 // @gate !__DEV__ || enableOwnerStacks
2038 it('should warn in DEV a child is missing keys on a fragment', () => {
1751 - expect(() => {
1752 - // While we're on the server we need to have the Server version active to track component stacks.
1753 - jest.resetModules();
1754 - jest.mock('react', () => ReactServer);
1755 - const transport = ReactNoopFlightServer.render(
1756 - ReactServer.createElement(
1757 - 'div',
1758 - null,
1759 - Array(6).fill(ReactServer.createElement(ReactServer.Fragment)),
1760 - ),
1761 - );
1762 - jest.resetModules();
1763 - jest.mock('react', () => React);
1764 - ReactNoopFlightClient.read(transport);
1765 - }).toErrorDev('Each child in a list should have a unique "key" prop.');
2039 + // While we're on the server we need to have the Server version active to track component stacks.
2040 + jest.resetModules();
2041 + jest.mock('react', () => ReactServer);
2042 + const transport = ReactNoopFlightServer.render(
2043 + ReactServer.createElement(
2044 + 'div',
2045 + null,
2046 + Array(6).fill(ReactServer.createElement(ReactServer.Fragment)),
2047 + ),
2048 + );
2049 + jest.resetModules();
2050 + jest.mock('react', () => React);
2051 + ReactNoopFlightClient.read(transport);
2052 + if (gate(flags => flags.enableOwnerStacks)) {
2053 + assertConsoleErrorDev([
2054 + 'Each child in a list should have a unique "key" prop. ' +
2055 + 'See https://react.dev/link/warning-keys for more information.\n' +
2056 + ' in Fragment (at **)',
2057 + 'Each child in a list should have a unique "key" prop. ' +
2058 + 'See https://react.dev/link/warning-keys for more information.\n' +
2059 + ' in Fragment (at **)',
2060 + ]);
2061 + } else {
2062 + assertConsoleErrorDev([
2063 + 'Each child in a list should have a unique "key" prop.\n\n' +
2064 + 'Check the top-level render call using <div>. ' +
2065 + 'See https://react.dev/link/warning-keys for more information.\n' +
2066 + ' in Fragment (at **)',
2067 + ]);
2068 + }
2069 });
2070
2071 it('should warn in DEV a child is missing keys in client component', async () => {
2072 function ParentClient({children}) {
2073 return children;
2074 }
1772 - const Parent = clientReference(ParentClient);
1773 - await expect(async () => {
2075 +
2076 + await act(async () => {
2077 + const Parent = clientReference(ParentClient);
2078 const transport = ReactNoopFlightServer.render(
2079 <Parent>{Array(6).fill(<div>no key</div>)}</Parent>,
2080 );
2081 ReactNoopFlightClient.read(transport);
1778 - await act(async () => {
1779 - ReactNoop.render(await ReactNoopFlightClient.read(transport));
1780 - });
1781 - }).toErrorDev(
1782 - gate(flags => flags.enableOwnerStacks)
1783 - ? 'Each child in a list should have a unique "key" prop.' +
1784 - '\n\nCheck the top-level render call using <ParentClient>. ' +
1785 - 'See https://react.dev/link/warning-keys for more information.'
1786 - : 'Each child in a list should have a unique "key" prop. ' +
1787 - 'See https://react.dev/link/warning-keys for more information.',
1788 - );
2082 +
2083 + ReactNoop.render(await ReactNoopFlightClient.read(transport));
2084 + });
2085 + if (gate(flags => flags.enableOwnerStacks)) {
2086 + assertConsoleErrorDev([
2087 + 'Each child in a list should have a unique "key" prop.\n\n' +
2088 + 'Check the top-level render call using <ParentClient>. ' +
2089 + 'See https://react.dev/link/warning-keys for more information.\n' +
2090 + ' in div (at **)',
2091 + ]);
2092 + } else {
2093 + assertConsoleErrorDev([
2094 + 'Each child in a list should have a unique "key" prop. ' +
2095 + 'See https://react.dev/link/warning-keys for more information.\n' +
2096 + ' in div (at **)',
2097 + ]);
2098 + }
2099 });
2100
2101 it('should error if a class instance is passed to a host component', () => {
@@ -3135,19 +3445,17 @@ describe('ReactFlight', () => {
3445 },
3446 );
3447
3138 - let transport;
3139 - expect(() => {
3140 - // Reset the modules so that we get a new overridden console on top of the
3141 - // one installed by expect. This ensures that we still emit console.error
3142 - // calls.
3143 - jest.resetModules();
3144 - jest.mock('react', () => require('react/react.react-server'));
3145 - ReactServer = require('react');
3146 - ReactNoopFlightServer = require('react-noop-renderer/flight-server');
3147 - transport = ReactNoopFlightServer.render({
3148 - root: ReactServer.createElement(App),
3149 - });
3150 - }).toErrorDev('err');
3448 + // Reset the modules so that we get a new overridden console on top of the
3449 + // one installed by expect. This ensures that we still emit console.error
3450 + // calls.
3451 + jest.resetModules();
3452 + jest.mock('react', () => require('react/react.react-server'));
3453 + ReactServer = require('react');
3454 + ReactNoopFlightServer = require('react-noop-renderer/flight-server');
3455 + const transport = ReactNoopFlightServer.render({
3456 + root: ReactServer.createElement(App),
3457 + });
3458 + assertConsoleErrorDev(['Error: err']);
3459
3460 expect(mockConsoleLog).toHaveBeenCalledTimes(1);
3461 expect(mockConsoleLog.mock.calls[0][0]).toBe('hi');