From bc5265d006f63bf57745d0506089feb3c07486d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 18 Dec 2021 21:47:28 +0100 Subject: [PATCH 01/12] Upgrade React 18 to its latest RC version --- package.json | 4 ++-- yarn.lock | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 2fe2e9280..d23bf8a68 100644 --- a/package.json +++ b/package.json @@ -257,8 +257,8 @@ "react-primitives": "^0.8.1", "react-router-dom": "^4.2.2", "react-test-renderer": "16.8.6", - "react18": "npm:react@alpha", - "react18-dom": "npm:react-dom@alpha", + "react18": "npm:react@18.0.0-rc.0-next-aa8f2bdbc-20211215", + "react18-dom": "npm:react-dom@18.0.0-rc.0-next-aa8f2bdbc-20211215", "svg-tag-names": "^1.1.1", "through": "^2.3.8", "unified": "^6.1.6", diff --git a/yarn.lock b/yarn.lock index d599dca2d..91cf92d9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25589,19 +25589,19 @@ react-timer-mixin@^0.13.4: resolved "https://registry.npmjs.org/react-timer-mixin/-/react-timer-mixin-0.13.4.tgz#75a00c3c94c13abe29b43d63b4c65a88fc8264d3" integrity sha512-4+ow23tp/Tv7hBM5Az5/Be/eKKF7DIvJ09voz5LyHGQaqqz9WV8YMs31eFvcYQs7d451LSg7kDJV70XYN/Ug/Q== -"react18-dom@npm:react-dom@alpha": - version "18.0.0-alpha-327d5c484-20211106" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-alpha-327d5c484-20211106.tgz#f8855d8e73876b5dbf6545ca02e14d8644a48008" - integrity sha512-yI2Kxy4/+nAFYHtC5uVIwXPURABwBhtqbEgjgRa9cITHsmZIO7AqDee0a5nXVSr8wWmtmbN1vSh29aDicuO03A== +"react18-dom@npm:react-dom@18.0.0-rc.0-next-aa8f2bdbc-20211215": + version "18.0.0-rc.0-next-aa8f2bdbc-20211215" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0-rc.0-next-aa8f2bdbc-20211215.tgz#6ffd75da09e903b2a41a7864e5e593848161de49" + integrity sha512-Tst8hBrKMumjnAXiPf2rOhW6jH7tXJJiIK5lY4QYTEKfJfNDnVr/whkoXfH5bBW2co6/MZwdpNWTHzDCwCQ4qA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - scheduler "0.21.0-alpha-327d5c484-20211106" + scheduler "0.21.0-rc.0-next-aa8f2bdbc-20211215" -"react18@npm:react@alpha": - version "18.0.0-alpha-327d5c484-20211106" - resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-alpha-327d5c484-20211106.tgz#f0e29b20b8c371697207a9f7b73a7ab625bee4b7" - integrity sha512-CB3JnXquQ9FYkd8IpTlvdpyk+HN1fOUDB7NabXTfbycqqRxuKhtijv7W7F/mbTzPLLMrxV5LwUqrLFc25Zy+UQ== +"react18@npm:react@18.0.0-rc.0-next-aa8f2bdbc-20211215": + version "18.0.0-rc.0-next-aa8f2bdbc-20211215" + resolved "https://registry.yarnpkg.com/react/-/react-18.0.0-rc.0-next-aa8f2bdbc-20211215.tgz#83a27dd32f1f769e34c741cca75a1260c01911d0" + integrity sha512-9D3VLGHusmvuZB5/fD1rFC7Uqff35Nf77B4grAWH1RIoKQkvLHgwZkegInnN9dMEEf/OtJSgUcj9iJRtWugsjg== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -26911,10 +26911,10 @@ scheduler@0.19.1, scheduler@^0.19.1: loose-envify "^1.1.0" object-assign "^4.1.1" -scheduler@0.21.0-alpha-327d5c484-20211106: - version "0.21.0-alpha-327d5c484-20211106" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0-alpha-327d5c484-20211106.tgz#16340fd4c7387ff58ad897b64715c0e3098e9489" - integrity sha512-VzlBG9d8m/2GwzXMjh7FoV6lpv/vOKdUYFCw3FCVY2aP/lN4oJkKwOlf4on2vEk855ckx+s3bR4eJLrlD7kZSw== +scheduler@0.21.0-rc.0-next-aa8f2bdbc-20211215: + version "0.21.0-rc.0-next-aa8f2bdbc-20211215" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0-rc.0-next-aa8f2bdbc-20211215.tgz#89e316e4865788a9c0e4efea98d79cc34f28151e" + integrity sha512-vpZzI3C5Jqy6lPikaLxQI5WxCvR699SBnlyRHCv9YHFSsrGgkhMTARPsfRdjBkMlsqzrpiaxSbc7JDZiWQIKDw== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" From 502ebbd8dadb43bdfbb8f8b2eea0cd543a1013ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 19 Dec 2021 17:15:03 +0100 Subject: [PATCH 02/12] Refactored tests to RTL to run tests easier against different React version, also run test suite with React 18 --- jest.config.js | 6 +- package.json | 2 +- .../no-babel/__snapshots__/index.test.js.snap | 2 +- packages/css/test/no-babel/index.test.js | 39 +++-- packages/css/test/sheet.dom.test.js | 14 +- packages/jest/test/matchers.test.js | 138 ++++++++-------- packages/jest/test/printer.test.js | 12 +- packages/jest/test/react-enzyme.test.js | 4 +- .../test/emotion-primitives.test.js | 25 ++- .../__snapshots__/global-with-theme.js.snap | 16 +- .../__tests__/__snapshots__/global.js.snap | 8 +- .../globals-are-the-worst.js.snap | 8 +- .../__snapshots__/theme-provider.dom.js.snap | 8 +- .../compat/__snapshots__/browser.js.snap | 4 +- packages/react/__tests__/compat/browser.js | 13 +- packages/react/__tests__/element.js | 9 +- packages/react/__tests__/global-with-theme.js | 19 +-- packages/react/__tests__/global.js | 35 ++-- .../react/__tests__/globals-are-the-worst.js | 9 +- packages/react/__tests__/rehydration.js | 152 ++++++++++-------- .../react/__tests__/theme-provider.dom.js | 27 ++-- yarn.lock | 12 +- 22 files changed, 278 insertions(+), 284 deletions(-) diff --git a/jest.config.js b/jest.config.js index 79dda87bf..e87575b1c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -18,5 +18,9 @@ module.exports = { coveragePathIgnorePatterns: [ '/node_modules/', '/packages/babel-plugin/test/util.js' - ] + ], + moduleNameMapper: { + '^react($|\\/.+)': 'react18$1', + '^react-dom($|\\/.+)': 'react18-dom$1' + } } diff --git a/package.json b/package.json index d23bf8a68..0465342ad 100644 --- a/package.json +++ b/package.json @@ -193,7 +193,7 @@ "@mdx-js/mdx": "^1.6.22", "@mdx-js/react": "^1.6.22", "@preconstruct/cli": "1.1.34", - "@testing-library/react": "^12.1.2", + "@testing-library/react": "13.0.0-alpha.5", "@types/jest": "^27.0.3", "@types/node": "^10.11.4", "@types/react": "^16.9.11", diff --git a/packages/css/test/no-babel/__snapshots__/index.test.js.snap b/packages/css/test/no-babel/__snapshots__/index.test.js.snap index 59f6fe483..b20f2bafd 100644 --- a/packages/css/test/no-babel/__snapshots__/index.test.js.snap +++ b/packages/css/test/no-babel/__snapshots__/index.test.js.snap @@ -12,7 +12,7 @@ exports[`css @supports 1`] = ` /> `; -exports[`css component as selectors (object syntax) 1`] = `"Component selectors can only be used in conjunction with @emotion/babel-plugin."`; +exports[`css component as selectors (object syntax) 1`] = `[Error: Component selectors can only be used in conjunction with @emotion/babel-plugin.]`; exports[`css component selectors without target 1`] = `"Component selectors can only be used in conjunction with @emotion/babel-plugin."`; diff --git a/packages/css/test/no-babel/index.test.js b/packages/css/test/no-babel/index.test.js index 217a0b786..961f28ca0 100644 --- a/packages/css/test/no-babel/index.test.js +++ b/packages/css/test/no-babel/index.test.js @@ -130,21 +130,38 @@ describe('css', () => { expect(tree).toMatchSnapshot() }) test('component as selectors (object syntax)', () => { - expect(() => { - const fontSize = '20px' - const H1 = styled('h1')({ fontSize }) - const Thing = styled('div')({ - display: 'flex', - [String(H1)]: { - color: 'green' + let errored = false + class ErrorBoundary extends React.Component { + static getDerivedStateFromError(error) { + errored = true + expect(error).toMatchSnapshot() + return { hasError: true } + } + + render() { + if (this.state && this.state.hasError) { + return null } - }) - renderer.create( + + return this.props.children + } + } + const fontSize = '20px' + const H1 = styled('h1')({ fontSize }) + const Thing = styled('div')({ + display: 'flex', + [String(H1)]: { + color: 'green' + } + }) + renderer.create( + hello

This will be green

world
- ) - }).toThrowErrorMatchingSnapshot() +
+ ) + expect(errored).toBe(true) }) test('component selectors without target', () => { const SomeComponent = styled('div')` diff --git a/packages/css/test/sheet.dom.test.js b/packages/css/test/sheet.dom.test.js index 98c75a680..1f857ad9f 100644 --- a/packages/css/test/sheet.dom.test.js +++ b/packages/css/test/sheet.dom.test.js @@ -1,6 +1,12 @@ // @flow import { sheet } from '@emotion/css' +const consoleError = console.error + +afterEach(() => { + console.error = consoleError +}) + describe('sheet', () => { beforeEach(() => { sheet.flush() @@ -31,9 +37,13 @@ describe('sheet', () => { test('throws', () => { sheet.speedy(true) - const spy = jest.spyOn(global.console, 'error') + const spy = jest.fn() + console.error = spy sheet.insert('.asdfasdf4###112121211{') - expect(spy).toHaveBeenCalled() + expect(spy.mock.calls.length).toBe(1) + expect(spy.mock.calls[0][0]).toMatchInlineSnapshot( + `"There was a problem inserting the following rule: \\".asdfasdf4###112121211{\\""` + ) }) test('.speedy throws when a rule has already been inserted', () => { diff --git a/packages/jest/test/matchers.test.js b/packages/jest/test/matchers.test.js index 3e3665e30..4f4f17769 100644 --- a/packages/jest/test/matchers.test.js +++ b/packages/jest/test/matchers.test.js @@ -1,11 +1,14 @@ import 'test-utils/legacy-env' import renderer from 'react-test-renderer' /** @jsx jsx */ +import * as React from 'react' import * as enzyme from 'enzyme' import { css, jsx } from '@emotion/react' import styled from '@emotion/styled' import { matchers } from '@emotion/jest' +const isReact16 = React.version.split('.')[0] === '16' + const { toHaveStyleRule } = matchers expect.extend(matchers) @@ -54,73 +57,6 @@ describe('toHaveStyleRule', () => { expect(svgNode).toHaveStyleRule('width', expect.stringMatching(/.*%$/)) }) - it('supports enzyme `mount` method', () => { - const Component = () => ( -
- -
- ) - - const wrapper = enzyme.mount() - expect(wrapper).toHaveStyleRule('color', 'red') - expect(wrapper).not.toHaveStyleRule('width', '100%') - const svgNode = wrapper.find('svg') - expect(svgNode).toHaveStyleRule('width', '100%') - expect(svgNode).not.toHaveStyleRule('color', 'red') - }) - - it('supports enzyme `render` method', () => { - const Component = () => ( -
- -
- ) - - const wrapper = enzyme.render() - expect(wrapper).toHaveStyleRule('color', 'red') - expect(wrapper).not.toHaveStyleRule('width', '100%') - const svgNode = wrapper.find('svg') - expect(svgNode).toHaveStyleRule('width', '100%') - expect(svgNode).not.toHaveStyleRule('color', 'red') - }) - - it('supports enzyme `shallow` method', () => { - const Component = () => ( -
- -
- ) - - const wrapper = enzyme.shallow() - expect(wrapper).toHaveStyleRule('color', 'red') - expect(wrapper).not.toHaveStyleRule('width', '100%') - const svgNode = wrapper.childAt(0) - expect(svgNode).toHaveStyleRule('width', '100%') - expect(svgNode).not.toHaveStyleRule('color', 'red') - }) - - it('supports styled components', () => { - const Div = styled('div')` - color: red; - ` - const Svg = styled('svg')` - width: 100%; - ` - ;['mount', 'render', 'shallow'].forEach(method => { - const wrapper = enzyme[method]( -
- -
- ) - expect(wrapper).toHaveStyleRule('color', 'red') - expect(wrapper).not.toHaveStyleRule('width', '100%') - const svgNode = - method === 'render' ? wrapper.find('svg') : wrapper.find(Svg) - expect(svgNode).toHaveStyleRule('width', '100%') - expect(svgNode).not.toHaveStyleRule('color', 'red') - }) - }) - it('fails if no styles are found', () => { const tree = renderer.create(
).toJSON() const result = toHaveStyleRule(tree, 'color', 'red') @@ -365,4 +301,72 @@ describe('toHaveStyleRule', () => { expect(tree.children[0]).toHaveStyleRule('color', 'hotpink') }) + ;(isReact16 ? describe : describe.skip)('enzyme', () => { + it('supports enzyme `mount` method', () => { + const Component = () => ( +
+ +
+ ) + + const wrapper = enzyme.mount() + expect(wrapper).toHaveStyleRule('color', 'red') + expect(wrapper).not.toHaveStyleRule('width', '100%') + const svgNode = wrapper.find('svg') + expect(svgNode).toHaveStyleRule('width', '100%') + expect(svgNode).not.toHaveStyleRule('color', 'red') + }) + + it('supports enzyme `render` method', () => { + const Component = () => ( +
+ +
+ ) + + const wrapper = enzyme.render() + expect(wrapper).toHaveStyleRule('color', 'red') + expect(wrapper).not.toHaveStyleRule('width', '100%') + const svgNode = wrapper.find('svg') + expect(svgNode).toHaveStyleRule('width', '100%') + expect(svgNode).not.toHaveStyleRule('color', 'red') + }) + + it('supports enzyme `shallow` method', () => { + const Component = () => ( +
+ +
+ ) + + const wrapper = enzyme.shallow() + expect(wrapper).toHaveStyleRule('color', 'red') + expect(wrapper).not.toHaveStyleRule('width', '100%') + const svgNode = wrapper.childAt(0) + expect(svgNode).toHaveStyleRule('width', '100%') + expect(svgNode).not.toHaveStyleRule('color', 'red') + }) + + it('supports styled components', () => { + const Div = styled('div')` + color: red; + ` + const Svg = styled('svg')` + width: 100%; + ` + ;['mount', 'render', 'shallow'].forEach(method => { + const wrapper = enzyme[method]( +
+ +
+ ) + expect(wrapper).toHaveStyleRule('color', 'red') + expect(wrapper).not.toHaveStyleRule('width', '100%') + const svgNode = + method === 'render' ? wrapper.find('svg') : wrapper.find(Svg) + expect(svgNode).toHaveStyleRule('width', '100%') + expect(svgNode).not.toHaveStyleRule('color', 'red') + }) + }) + }) }) diff --git a/packages/jest/test/printer.test.js b/packages/jest/test/printer.test.js index 645737a40..6152b35c9 100644 --- a/packages/jest/test/printer.test.js +++ b/packages/jest/test/printer.test.js @@ -1,6 +1,5 @@ // @flow import React from 'react' -import ReactDOM from 'react-dom' import 'test-utils/legacy-env' import renderer from 'react-test-renderer' import prettyFormat from 'pretty-format' @@ -8,6 +7,7 @@ import prettyFormat from 'pretty-format' import { css, jsx, CacheProvider } from '@emotion/react' import createCache from '@emotion/cache' import { createSerializer } from '@emotion/jest' +import { render } from '@testing-library/react' import { ignoreConsoleErrors } from 'test-utils' let emotionPlugin = createSerializer() @@ -41,11 +41,10 @@ describe('jest-emotion with dom elements', () => { it('replaces class names and inserts styles into DOM element snapshots', () => { const divRef = React.createRef() - ReactDOM.render( + render(
-
, - document.createElement('div') +
) const output = prettyFormat(divRef.current, { @@ -85,11 +84,10 @@ describe('jest-emotion with DOM elements disabled', () => { it('does not replace class names or insert styles into DOM element snapshots', () => { const divRef = React.createRef() - ReactDOM.render( + render(
-
, - document.createElement('div') + ) const output = prettyFormat(divRef.current, { diff --git a/packages/jest/test/react-enzyme.test.js b/packages/jest/test/react-enzyme.test.js index 76888ddad..e91e2e9f8 100644 --- a/packages/jest/test/react-enzyme.test.js +++ b/packages/jest/test/react-enzyme.test.js @@ -11,6 +11,8 @@ import toJson from 'enzyme-to-json' import { matchers } from '@emotion/jest' import * as serializer from '@emotion/jest/enzyme-serializer' +const isReact16 = React.version.split('.')[0] === '16' + expect.extend(matchers) expect.addSnapshotSerializer(serializer) @@ -349,7 +351,7 @@ const cases = { } } -describe('enzyme', () => { +;(isReact16 ? describe : describe.skip)('enzyme', () => { jestInCase( 'shallow', ({ render, selector = identity }) => { diff --git a/packages/primitives/test/emotion-primitives.test.js b/packages/primitives/test/emotion-primitives.test.js index 70d277b45..035b08c12 100644 --- a/packages/primitives/test/emotion-primitives.test.js +++ b/packages/primitives/test/emotion-primitives.test.js @@ -3,7 +3,7 @@ import * as React from 'react' import renderer from 'react-test-renderer' import { Text, StyleSheet } from 'react-primitives' import { ThemeProvider } from '@emotion/react' -import { render, unmountComponentAtNode } from 'react-dom' +import { render } from '@testing-library/react' import styled from '@emotion/primitives' @@ -60,20 +60,17 @@ describe('Emotion primitives', () => { display: ${props => props.theme.display}; ` - let mountNode = document.createElement('div') - - render( + const { container, unmount } = render( {/* $FlowFixMe */} Hello World - , - mountNode + ) - expect(mountNode).toMatchSnapshot() - unmountComponentAtNode(mountNode) - expect(mountNode.querySelector('#something')).toBe(null) + expect(container).toMatchSnapshot() + unmount() + expect(container.querySelector('#something')).toBe(null) }) test('should render the primitive on changing the props', () => { @@ -143,11 +140,11 @@ describe('Emotion primitives', () => { color: hotpink; ` let ref = React.createRef() - const rootNode = document.createElement('div') - // $FlowFixMe - render(, rootNode) - expect(ref.current).toBe(rootNode.firstElementChild) - unmountComponentAtNode(rootNode) + const { container, unmount } = render( + + ) + expect(ref.current).toBe(container.firstElementChild) + unmount() }) it('should pass props in withComponent', () => { diff --git a/packages/react/__tests__/__snapshots__/global-with-theme.js.snap b/packages/react/__tests__/__snapshots__/global-with-theme.js.snap index bf694978c..1e07f2ec6 100644 --- a/packages/react/__tests__/__snapshots__/global-with-theme.js.snap +++ b/packages/react/__tests__/__snapshots__/global-with-theme.js.snap @@ -19,9 +19,7 @@ exports[`array 1`] = ` -
+
`; @@ -30,9 +28,7 @@ exports[`array 2`] = ` -
+
`; @@ -49,9 +45,7 @@ exports[`basic 1`] = ` -
+
`; @@ -60,9 +54,7 @@ exports[`basic 2`] = ` -
+
`; diff --git a/packages/react/__tests__/__snapshots__/global.js.snap b/packages/react/__tests__/__snapshots__/global.js.snap index 74367e1b9..8f4a98b80 100644 --- a/packages/react/__tests__/__snapshots__/global.js.snap +++ b/packages/react/__tests__/__snapshots__/global.js.snap @@ -56,9 +56,7 @@ exports[`basic 1`] = ` exports[`basic 2`] = ` -
+
`; @@ -90,9 +88,7 @@ exports[`basic 3`] = ` exports[`basic 4`] = ` -
+
`; diff --git a/packages/react/__tests__/__snapshots__/globals-are-the-worst.js.snap b/packages/react/__tests__/__snapshots__/globals-are-the-worst.js.snap index 1a4bc2121..00a9d8daa 100644 --- a/packages/react/__tests__/__snapshots__/globals-are-the-worst.js.snap +++ b/packages/react/__tests__/__snapshots__/globals-are-the-worst.js.snap @@ -19,9 +19,7 @@ exports[`specificity with globals 1`] = ` -
+
@@ -56,9 +54,7 @@ exports[`specificity with globals 2`] = ` -
+
diff --git a/packages/react/__tests__/__snapshots__/theme-provider.dom.js.snap b/packages/react/__tests__/__snapshots__/theme-provider.dom.js.snap index 2667c5dd1..9d3a243eb 100644 --- a/packages/react/__tests__/__snapshots__/theme-provider.dom.js.snap +++ b/packages/react/__tests__/__snapshots__/theme-provider.dom.js.snap @@ -6,9 +6,7 @@ exports[`provider with theme value that changes 1`] = ` padding: 4px; } -
+
+
-
+
diff --git a/packages/react/__tests__/compat/browser.js b/packages/react/__tests__/compat/browser.js index a6c8c02d4..450a1d267 100644 --- a/packages/react/__tests__/compat/browser.js +++ b/packages/react/__tests__/compat/browser.js @@ -3,22 +3,17 @@ import 'test-utils/dev-mode' import { throwIfFalsy } from 'test-utils' import { jsx, CacheProvider } from '@emotion/react' -import { render } from 'react-dom' +import { render } from '@testing-library/react' import { css, cache } from '@emotion/css' -test('composition works from old emotion css calls', cb => { +test('composition works from old emotion css calls', () => { const cls = css` color: green; ` - throwIfFalsy(document.body).innerHTML = '
' render(
- , - throwIfFalsy(document.getElementById('root')), - () => { - expect(document.documentElement).toMatchSnapshot() - cb() - } + ) + expect(document.documentElement).toMatchSnapshot() }) diff --git a/packages/react/__tests__/element.js b/packages/react/__tests__/element.js index 38a99d1d5..f4a89dc89 100644 --- a/packages/react/__tests__/element.js +++ b/packages/react/__tests__/element.js @@ -1,7 +1,7 @@ // @flow /** @jsx jsx */ import 'test-utils/dev-mode' -import { render } from 'react-dom' +import { render } from '@testing-library/react' import { jsx, css, CacheProvider, ThemeProvider } from '@emotion/react' import createCache from '@emotion/cache' @@ -11,9 +11,6 @@ console.error = jest.fn() beforeEach(() => { // $FlowFixMe document.head.innerHTML = '' - // $FlowFixMe - document.body.innerHTML = `
` - jest.clearAllMocks() }) @@ -38,9 +35,9 @@ describe('EmotionElement', () => { ) - render(, document.getElementById('root')) + render() expect(console.error).not.toHaveBeenCalled() - render(, document.getElementById('root')) + render() expect(console.error).not.toHaveBeenCalled() }) }) diff --git a/packages/react/__tests__/global-with-theme.js b/packages/react/__tests__/global-with-theme.js index f8b66b430..32b0d46c7 100644 --- a/packages/react/__tests__/global-with-theme.js +++ b/packages/react/__tests__/global-with-theme.js @@ -1,18 +1,16 @@ // @flow import 'test-utils/dev-mode' import * as React from 'react' -import { render, unmountComponentAtNode } from 'react-dom' +import { render } from '@testing-library/react' import { Global, ThemeProvider } from '@emotion/react' beforeEach(() => { // $FlowFixMe document.head.innerHTML = '' - // $FlowFixMe - document.body.innerHTML = `
` }) test('basic', () => { - render( + const { unmount } = render( ({ @@ -21,17 +19,15 @@ test('basic', () => { } })} /> - , - // $FlowFixMe - document.getElementById('root') + ) expect(document.documentElement).toMatchSnapshot() - unmountComponentAtNode(document.getElementById('root')) + unmount() expect(document.documentElement).toMatchSnapshot() }) test('array', () => { - render( + const { unmount } = render( { theme => ({ html: { fontSize: theme.fontSize } }) ]} /> - , // $FlowFixMe - document.getElementById('root') + ) expect(document.documentElement).toMatchSnapshot() - unmountComponentAtNode(document.getElementById('root')) + unmount() expect(document.documentElement).toMatchSnapshot() }) diff --git a/packages/react/__tests__/global.js b/packages/react/__tests__/global.js index a624da805..2ecc07540 100644 --- a/packages/react/__tests__/global.js +++ b/packages/react/__tests__/global.js @@ -1,7 +1,7 @@ // @flow import 'test-utils/dev-mode' import * as React from 'react' -import { render, unmountComponentAtNode } from 'react-dom' +import { render } from '@testing-library/react' import { Global, keyframes, @@ -17,14 +17,11 @@ console.error = jest.fn() beforeEach(() => { // $FlowFixMe document.head.innerHTML = '' - // $FlowFixMe - document.body.innerHTML = `
` - jest.resetAllMocks() }) test('basic', () => { - render( + const { unmount } = render( { } ]} /> - , - // $FlowFixMe - document.getElementById('root') + ) expect(document.head).toMatchSnapshot() expect(document.body).toMatchSnapshot() - unmountComponentAtNode(document.getElementById('root')) + unmount() expect(document.head).toMatchSnapshot() expect(document.body).toMatchSnapshot() }) test('updating more than 1 global rule', () => { const cache = createCache({ key: 'global-multiple-rules' }) - const renderComponent = ({ background, color }) => - render( - - - , - // $FlowFixMe - document.getElementById('root') - ) - renderComponent({ background: 'white', color: 'black' }) + const Comp = ({ background, color }) => ( + + + + ) + + const { rerender } = render() expect(document.head).toMatchSnapshot() - renderComponent({ background: 'gray', color: 'white' }) + rerender() expect(document.head).toMatchSnapshot() }) @@ -99,8 +92,8 @@ test('no React hook order violations', () => { ) - render(, document.getElementById('root')) + render() expect(console.error).not.toHaveBeenCalled() - render(, document.getElementById('root')) + render() expect(console.error).not.toHaveBeenCalled() }) diff --git a/packages/react/__tests__/globals-are-the-worst.js b/packages/react/__tests__/globals-are-the-worst.js index 2d40fa367..33d7dd1bd 100644 --- a/packages/react/__tests__/globals-are-the-worst.js +++ b/packages/react/__tests__/globals-are-the-worst.js @@ -1,8 +1,7 @@ // @flow import 'test-utils/dev-mode' -import { throwIfFalsy } from 'test-utils' +import { render } from '@testing-library/react' import * as React from 'react' -import { render } from 'react-dom' import { Global } from '@emotion/react' import styled from '@emotion/styled' @@ -25,11 +24,9 @@ test('specificity with globals', () => {
) - throwIfFalsy(document.body).innerHTML = `
` - let root = throwIfFalsy(document.getElementById('root')) - render(, root) + const { rerender } = render() expect(document.documentElement).toMatchSnapshot() - render(, root) + rerender() expect(document.documentElement).toMatchSnapshot() }) diff --git a/packages/react/__tests__/rehydration.js b/packages/react/__tests__/rehydration.js index 32d300afc..d754aad8f 100644 --- a/packages/react/__tests__/rehydration.js +++ b/packages/react/__tests__/rehydration.js @@ -14,6 +14,8 @@ afterEach(() => { let React let ReactDOM let ReactDOMServer +let render + let createCache let css let jsx @@ -30,6 +32,11 @@ const resetAllModules = () => { React = require('react') ReactDOM = require('react-dom') ReactDOMServer = require('react-dom/server') + // we can't use regular entrypoint here as it registers afterEach + // this means that we don't get auto-cleanup from RTL + // but it shouldn't be needed in this file + // we are resetting JSDOM's state on our own, and we don't depend on React's unmounting anyhow here + render = require('@testing-library/react/pure').render const emotionReact = require('@emotion/react') css = emotionReact.css @@ -99,7 +106,10 @@ test("cache created in render doesn't cause a hydration mismatch", () => { ) } - ReactDOM.hydrate(, safeQuerySelector('#root')) + render(, { + hydrate: true, + container: safeQuerySelector('#root') + }) expect((console.error: any).mock.calls).toMatchInlineSnapshot(`Array []`) expect((console.warn: any).mock.calls).toMatchInlineSnapshot(`Array []`) @@ -135,7 +145,10 @@ test('initializing another Emotion instance should not move already moved styles ) } - ReactDOM.hydrate(, safeQuerySelector('#root')) + render(, { + hydrate: true, + container: safeQuerySelector('#root') + }) resetAllModules() @@ -187,7 +200,9 @@ test('initializing another Emotion instance should not move already moved styles ) } - ReactDOM.render(, safeQuerySelector('#root')) + render(, { + container: safeQuerySelector('#root') + }) resetAllModules() @@ -272,7 +287,7 @@ test('global styles can be removed individually after rehydrating HTML SSRed wit resetAllModules() const cache = createCache({ key: 'mui', speedy: true }) - ReactDOM.render( + render( @@ -280,7 +295,9 @@ test('global styles can be removed individually after rehydrating HTML SSRed wit
, - safeQuerySelector('#root') + { + container: safeQuerySelector('#root') + } ) expect(safeQuerySelector('head')).toMatchInlineSnapshot(` @@ -306,14 +323,16 @@ test('global styles can be removed individually after rehydrating HTML SSRed wit `) - ReactDOM.render( + render(
, - safeQuerySelector('#root') + { + container: safeQuerySelector('#root') + } ) expect(safeQuerySelector('head')).toMatchInlineSnapshot(` @@ -387,13 +406,15 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe resetAllModules() const cache = createCache({ key: 'muii', speedy: true }) - ReactDOM.render( + render(
, - safeQuerySelector('#root') + { + container: safeQuerySelector('#root') + } ) // it's expected that this contains 2 copies of the same global style @@ -422,12 +443,14 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe `) - ReactDOM.render( + render(
, - safeQuerySelector('#root') + { + container: safeQuerySelector('#root') + } ) // this should still have a global style @@ -448,11 +471,13 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe `) - ReactDOM.render( + render(
, - safeQuerySelector('#root') + { + container: safeQuerySelector('#root') + } ) // this should render without a crash @@ -521,13 +546,15 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe resetAllModules() const cache = createCache({ key: 'globcop', speedy: true }) - ReactDOM.render( + render(
, - safeQuerySelector('#root') + { + container: safeQuerySelector('#root') + } ) // it's expected that this contains 2 copies of the same global style @@ -555,12 +582,14 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe `) - ReactDOM.render( + render(
, - safeQuerySelector('#root') + { + container: safeQuerySelector('#root') + } ) // this should still have a global style @@ -581,11 +610,13 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe `) - ReactDOM.render( + render(
, - safeQuerySelector('#root') + { + container: safeQuerySelector('#root') + } ) // this should render without a crash @@ -601,29 +632,7 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe `) }) -describe('react18', () => { - let previousIsReactActEnvironment - beforeAll(() => { - jest - .mock('react', () => { - return jest.requireActual('react18') - }) - .mock('react-dom', () => { - return jest.requireActual('react18-dom') - }) - .mock('react-dom/server', () => { - return jest.requireActual('react18-dom/server') - }) - - previousIsReactActEnvironment = global.IS_REACT_ACT_ENVIRONMENT - global.IS_REACT_ACT_ENVIRONMENT = true - }) - - afterAll(() => { - jest.clearAllMocks() - global.IS_REACT_ACT_ENVIRONMENT = previousIsReactActEnvironment - }) - +describe('useId', () => { test('no hydration mismatch for styled when using useId', () => { const finalHTML = disableBrowserEnvTemporarily(() => { resetAllModules() @@ -649,8 +658,9 @@ describe('react18', () => { border: '1px solid black' }) - ;(React: any).unstable_act(() => { - ReactDOM.hydrateRoot(safeQuerySelector('#root'), ) + render(, { + hydrate: true, + container: safeQuerySelector('#root') }) expect((console.error: any).mock.calls).toMatchInlineSnapshot(`Array []`) @@ -684,16 +694,17 @@ describe('react18', () => { return
} - ;(React: any).unstable_act(() => { - ReactDOM.hydrateRoot( - safeQuerySelector('#root'), - - ) - }) + render( + , + { + hydrate: true, + container: safeQuerySelector('#root') + } + ) expect((console.error: any).mock.calls).toMatchInlineSnapshot(`Array []`) expect((console.warn: any).mock.calls).toMatchInlineSnapshot(`Array []`) @@ -732,22 +743,23 @@ describe('react18', () => { return
} - ;(React: any).unstable_act(() => { - ReactDOM.hydrateRoot( - safeQuerySelector('#root'), - - {({ css }) => { - return ( - - ) - }} - - ) - }) + render( + + {({ css }) => { + return ( + + ) + }} + , + { + hydrate: true, + container: safeQuerySelector('#root') + } + ) expect((console.error: any).mock.calls).toMatchInlineSnapshot(`Array []`) expect((console.warn: any).mock.calls).toMatchInlineSnapshot(`Array []`) diff --git a/packages/react/__tests__/theme-provider.dom.js b/packages/react/__tests__/theme-provider.dom.js index ef0a6deda..412539c75 100644 --- a/packages/react/__tests__/theme-provider.dom.js +++ b/packages/react/__tests__/theme-provider.dom.js @@ -2,10 +2,15 @@ /** @jsx jsx */ import 'test-utils/next-env' import 'test-utils/dev-mode' -import { throwIfFalsy, safeQuerySelector } from 'test-utils' +import { render, fireEvent } from '@testing-library/react' +import { safeQuerySelector } from 'test-utils' import * as React from 'react' import { jsx, ThemeProvider } from '@emotion/react' -import { render } from 'react-dom' + +beforeEach(() => { + // $FlowFixMe + document.head.innerHTML = '' +}) test('provider with theme value that changes', () => { class ThemeTest extends React.Component<*, *> { @@ -27,19 +32,9 @@ test('provider with theme value that changes', () => { ) } } - let head = throwIfFalsy(document.head) - let body = throwIfFalsy(document.body) - - head.innerHTML = '' - body.innerHTML = '
' - - let root = safeQuerySelector('#root') - - render(, root) - expect(root).toMatchSnapshot() - throwIfFalsy(safeQuerySelector('#the-thing')).click() - expect(root).toMatchSnapshot() - head.innerHTML = '' - body.innerHTML = '
' + const { container } = render() + expect(container).toMatchSnapshot() + fireEvent.click(safeQuerySelector('#the-thing')) + expect(container).toMatchSnapshot() }) diff --git a/yarn.lock b/yarn.lock index 91cf92d9b..41ab201ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5598,7 +5598,7 @@ dependencies: defer-to-connect "^2.0.0" -"@testing-library/dom@^8.0.0": +"@testing-library/dom@^8.5.0": version "8.11.1" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.11.1.tgz#03fa2684aa09ade589b460db46b4c7be9fc69753" integrity sha512-3KQDyx9r0RKYailW2MiYrSSKEfH0GTkI51UGEvJenvcoDoeRYs0PZpi2SXqtnMClQvCqdtTTpOfFETDTVADpAg== @@ -5612,13 +5612,13 @@ lz-string "^1.4.4" pretty-format "^27.0.2" -"@testing-library/react@^12.1.2": - version "12.1.2" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.2.tgz#f1bc9a45943461fa2a598bb4597df1ae044cfc76" - integrity sha512-ihQiEOklNyHIpo2Y8FREkyD1QAea054U0MVbwH1m8N9TxeFz+KoJ9LkqoKqJlzx2JDm56DVwaJ1r36JYxZM05g== +"@testing-library/react@13.0.0-alpha.5": + version "13.0.0-alpha.5" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-13.0.0-alpha.5.tgz#29bfc36b550e2a1025cbebf7254d5a0a46cb58c5" + integrity sha512-QrxKC/7pTE0ze3wLZNaenGJqsLcbAJL71XqU/ryJTL2pqZBjiJHuxZavl2ZQAxnBQkDQF9oh9my3bKPstWfnhA== dependencies: "@babel/runtime" "^7.12.5" - "@testing-library/dom" "^8.0.0" + "@testing-library/dom" "^8.5.0" "@theme-ui/color-modes@0.12.0": version "0.12.0" From f88d21c2e18301faaa06644c3e2aca5460bd1249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sun, 19 Dec 2021 21:51:41 +0100 Subject: [PATCH 03/12] Add separate Jest config to run tests with React 18 --- .github/workflows/main.yml | 33 ++++++++++++++++++- jest-react18.config.js | 8 +++++ jest.config.js | 7 +--- jest.dist.js | 2 -- package.json | 4 ++- .../__snapshots__/inline.test.js.snap | 4 +-- .../__snapshots__/stream.test.js.snap | 4 +-- packages/css/test/instance/inline.test.js | 7 ++-- packages/css/test/instance/stream.test.js | 9 +++-- packages/react/__tests__/rehydration.js | 5 ++- .../test/__snapshots__/inline.test.js.snap | 5 +-- .../test/__snapshots__/stream.test.js.snap | 4 +-- packages/server/test/inline.test.js | 9 +++-- packages/server/test/stream.test.js | 9 +++-- scripts/test-utils/src/index.js | 5 +++ test/styleTransform.js | 13 -------- 16 files changed, 78 insertions(+), 50 deletions(-) create mode 100644 jest-react18.config.js delete mode 100644 test/styleTransform.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index da30222c6..27fd0a735 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,7 +44,7 @@ jobs: run: yarn - name: Run Tests - run: yarn coverage --color + run: yarn test:ci --color - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 @@ -81,6 +81,37 @@ jobs: - name: Check Types run: yarn flow:check + test_react18: + name: Test React 18 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + + - name: Set Node.js 12.x + uses: actions/setup-node@main + with: + node-version: 12.x + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v2 + id: yarn-cache + with: + path: | + ${{ steps.yarn-cache-dir-path.outputs.dir }} + node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install Dependencies + run: yarn + + - name: Run Tests with React 18 + run: yarn test:react18:ci + test_dist: name: Test Dist runs-on: ubuntu-latest diff --git a/jest-react18.config.js b/jest-react18.config.js new file mode 100644 index 000000000..ebe8cd167 --- /dev/null +++ b/jest-react18.config.js @@ -0,0 +1,8 @@ +const baseConfig = require('./jest.config.js') + +module.exports = Object.assign({}, baseConfig, { + moduleNameMapper: { + '^react($|\\/.+)': 'react18$1', + '^react-dom($|\\/.+)': 'react18-dom$1' + } +}) diff --git a/jest.config.js b/jest.config.js index e87575b1c..e07058c11 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,6 @@ module.exports = { testEnvironment: 'jsdom', transform: { - '\\.css$': '/test/styleTransform.js', '^.+\\.js?$': 'babel-jest' }, watchPlugins: [ @@ -18,9 +17,5 @@ module.exports = { coveragePathIgnorePatterns: [ '/node_modules/', '/packages/babel-plugin/test/util.js' - ], - moduleNameMapper: { - '^react($|\\/.+)': 'react18$1', - '^react-dom($|\\/.+)': 'react18-dom$1' - } + ] } diff --git a/jest.dist.js b/jest.dist.js index a34e1460e..29c7b1017 100644 --- a/jest.dist.js +++ b/jest.dist.js @@ -3,5 +3,3 @@ const baseConfig = require('./jest.config.js') module.exports = Object.assign({}, baseConfig, { transformIgnorePatterns: ['dist', 'node_modules'] }) - -delete module.exports.moduleNameMapper diff --git a/package.json b/package.json index 0465342ad..2ebb3f1d8 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,10 @@ "test:size": "npm-run-all build size", "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand --watch", "test": "jest", + "test:react18": "jest -c jest-react18.config.js", "test:typescript": "yarn workspaces run test:typescript", - "coverage": "jest --coverage --no-cache --ci --runInBand", + "test:ci": "jest --coverage --no-cache --ci --runInBand", + "test:react18:ci": "yarn test:react18 --coverage --no-cache --ci --runInBand", "test:prod": "yarn build && jest -c jest.dist.js --no-cache --ci --runInBand", "lint:check": "eslint .", "test:watch": "jest --watch", diff --git a/packages/css/test/instance/__snapshots__/inline.test.js.snap b/packages/css/test/instance/__snapshots__/inline.test.js.snap index 886284570..a45cf6e73 100644 --- a/packages/css/test/instance/__snapshots__/inline.test.js.snap +++ b/packages/css/test/instance/__snapshots__/inline.test.js.snap @@ -157,9 +157,7 @@ exports[`renderStylesToString renders large recursive component 1`] = ` > .some-key-127stik{color:hotpink;} -
+
woah there hello world diff --git a/packages/css/test/instance/__snapshots__/stream.test.js.snap b/packages/css/test/instance/__snapshots__/stream.test.js.snap index 3eb787809..49f592814 100644 --- a/packages/css/test/instance/__snapshots__/stream.test.js.snap +++ b/packages/css/test/instance/__snapshots__/stream.test.js.snap @@ -147,9 +147,7 @@ exports[`renderStylesToNodeStream renders large recursive component 1`] = ` > .some-global-200{padding:0;margin:200;}.some-key-127stik{color:hotpink;}.some-global-199{padding:0;margin:199;}.some-global-198{padding:0;margin:198;}.some-global-197{padding:0;margin:197;}.some-global-196{padding:0;margin:196;}.some-global-195{padding:0;margin:195;}.some-global-194{padding:0;margin:194;}.some-global-193{padding:0;margin:193;}.some-global-192{padding:0;margin:192;}.some-global-191{padding:0;margin:191;}.some-global-190{padding:0;margin:190;}.some-global-189{padding:0;margin:189;}.some-global-188{padding:0;margin:188;}.some-global-187{padding:0;margin:187;}.some-global-186{padding:0;margin:186;}.some-global-185{padding:0;margin:185;}.some-global-184{padding:0;margin:184;}.some-global-183{padding:0;margin:183;}.some-global-182{padding:0;margin:182;}.some-global-181{padding:0;margin:181;}.some-global-180{padding:0;margin:180;}.some-global-179{padding:0;margin:179;}.some-global-178{padding:0;margin:178;}.some-global-177{padding:0;margin:177;}.some-global-176{padding:0;margin:176;}.some-global-175{padding:0;margin:175;}.some-global-174{padding:0;margin:174;}.some-global-173{padding:0;margin:173;}.some-global-172{padding:0;margin:172;}.some-global-171{padding:0;margin:171;}.some-global-170{padding:0;margin:170;}.some-global-169{padding:0;margin:169;}.some-global-168{padding:0;margin:168;}.some-global-167{padding:0;margin:167;}.some-global-166{padding:0;margin:166;}.some-global-165{padding:0;margin:165;}.some-global-164{padding:0;margin:164;}.some-global-163{padding:0;margin:163;}.some-global-162{padding:0;margin:162;}.some-global-161{padding:0;margin:161;}.some-global-160{padding:0;margin:160;}.some-global-159{padding:0;margin:159;}.some-global-158{padding:0;margin:158;}.some-global-157{padding:0;margin:157;}.some-global-156{padding:0;margin:156;}.some-global-155{padding:0;margin:155;}.some-global-154{padding:0;margin:154;}.some-global-153{padding:0;margin:153;}.some-global-152{padding:0;margin:152;}.some-global-151{padding:0;margin:151;}.some-global-150{padding:0;margin:150;}.some-global-149{padding:0;margin:149;}.some-global-148{padding:0;margin:148;}.some-global-147{padding:0;margin:147;}.some-global-146{padding:0;margin:146;}.some-global-145{padding:0;margin:145;}.some-global-144{padding:0;margin:144;}.some-global-143{padding:0;margin:143;}.some-global-142{padding:0;margin:142;}.some-global-141{padding:0;margin:141;}.some-global-140{padding:0;margin:140;}.some-global-139{padding:0;margin:139;}.some-global-138{padding:0;margin:138;}.some-global-137{padding:0;margin:137;}.some-global-136{padding:0;margin:136;}.some-global-135{padding:0;margin:135;}.some-global-134{padding:0;margin:134;}.some-global-133{padding:0;margin:133;}.some-global-132{padding:0;margin:132;}.some-global-131{padding:0;margin:131;}.some-global-130{padding:0;margin:130;}.some-global-129{padding:0;margin:129;}.some-global-128{padding:0;margin:128;}.some-global-127{padding:0;margin:127;}.some-global-126{padding:0;margin:126;}.some-global-125{padding:0;margin:125;}.some-global-124{padding:0;margin:124;}.some-global-123{padding:0;margin:123;}.some-global-122{padding:0;margin:122;}.some-global-121{padding:0;margin:121;}.some-global-120{padding:0;margin:120;}.some-global-119{padding:0;margin:119;}.some-global-118{padding:0;margin:118;}.some-global-117{padding:0;margin:117;}.some-global-116{padding:0;margin:116;}.some-global-115{padding:0;margin:115;}.some-global-114{padding:0;margin:114;}.some-global-113{padding:0;margin:113;}.some-global-112{padding:0;margin:112;}.some-global-111{padding:0;margin:111;}.some-global-110{padding:0;margin:110;}.some-global-109{padding:0;margin:109;}.some-global-108{padding:0;margin:108;}.some-global-107{padding:0;margin:107;}.some-global-106{padding:0;margin:106;}.some-global-105{padding:0;margin:105;}.some-global-104{padding:0;margin:104;}.some-global-103{padding:0;margin:103;}.some-global-102{padding:0;margin:102;}.some-global-101{padding:0;margin:101;}.some-global-100{padding:0;margin:100;}.some-global-99{padding:0;margin:99;}.some-global-98{padding:0;margin:98;}.some-global-97{padding:0;margin:97;}.some-global-96{padding:0;margin:96;}.some-global-95{padding:0;margin:95;}.some-global-94{padding:0;margin:94;}.some-global-93{padding:0;margin:93;}.some-global-92{padding:0;margin:92;}.some-global-91{padding:0;margin:91;}.some-global-90{padding:0;margin:90;}.some-global-89{padding:0;margin:89;}.some-global-88{padding:0;margin:88;}.some-global-87{padding:0;margin:87;}.some-global-86{padding:0;margin:86;}.some-global-85{padding:0;margin:85;}.some-global-84{padding:0;margin:84;}.some-global-83{padding:0;margin:83;}.some-global-82{padding:0;margin:82;}.some-global-81{padding:0;margin:81;}.some-global-80{padding:0;margin:80;}.some-global-79{padding:0;margin:79;}.some-global-78{padding:0;margin:78;}.some-global-77{padding:0;margin:77;}.some-global-76{padding:0;margin:76;}.some-global-75{padding:0;margin:75;}.some-global-74{padding:0;margin:74;}.some-global-73{padding:0;margin:73;}.some-global-72{padding:0;margin:72;}.some-global-71{padding:0;margin:71;}.some-global-70{padding:0;margin:70;}.some-global-69{padding:0;margin:69;}.some-global-68{padding:0;margin:68;}.some-global-67{padding:0;margin:67;}.some-global-66{padding:0;margin:66;}.some-global-65{padding:0;margin:65;}.some-global-64{padding:0;margin:64;}.some-global-63{padding:0;margin:63;}.some-global-62{padding:0;margin:62;}.some-global-61{padding:0;margin:61;}.some-global-60{padding:0;margin:60;}.some-global-59{padding:0;margin:59;}.some-global-58{padding:0;margin:58;}.some-global-57{padding:0;margin:57;}.some-global-56{padding:0;margin:56;}.some-global-55{padding:0;margin:55;}.some-global-54{padding:0;margin:54;}.some-global-53{padding:0;margin:53;}.some-global-52{padding:0;margin:52;}.some-global-51{padding:0;margin:51;}.some-global-50{padding:0;margin:50;}.some-global-49{padding:0;margin:49;}.some-global-48{padding:0;margin:48;}.some-global-47{padding:0;margin:47;}.some-global-46{padding:0;margin:46;}.some-global-45{padding:0;margin:45;}.some-global-44{padding:0;margin:44;}.some-global-43{padding:0;margin:43;}.some-global-42{padding:0;margin:42;}.some-global-41{padding:0;margin:41;}.some-global-40{padding:0;margin:40;}.some-global-39{padding:0;margin:39;}.some-global-38{padding:0;margin:38;}.some-global-37{padding:0;margin:37;}.some-global-36{padding:0;margin:36;}.some-global-35{padding:0;margin:35;}.some-global-34{padding:0;margin:34;}.some-global-33{padding:0;margin:33;}.some-global-32{padding:0;margin:32;}.some-global-31{padding:0;margin:31;}.some-global-30{padding:0;margin:30;}.some-global-29{padding:0;margin:29;}.some-global-28{padding:0;margin:28;}.some-global-27{padding:0;margin:27;}.some-global-26{padding:0;margin:26;}.some-global-25{padding:0;margin:25;}.some-global-24{padding:0;margin:24;}.some-global-23{padding:0;margin:23;}.some-global-22{padding:0;margin:22;}.some-global-21{padding:0;margin:21;}.some-global-20{padding:0;margin:20;}.some-global-19{padding:0;margin:19;}.some-global-18{padding:0;margin:18;}.some-global-17{padding:0;margin:17;}.some-global-16{padding:0;margin:16;}.some-global-15{padding:0;margin:15;}.some-global-14{padding:0;margin:14;}.some-global-13{padding:0;margin:13;}.some-global-12{padding:0;margin:12;}.some-global-11{padding:0;margin:11;}.some-global-10{padding:0;margin:10;}.some-global-9{padding:0;margin:9;}.some-global-8{padding:0;margin:8;}.some-global-7{padding:0;margin:7;}.some-global-6{padding:0;margin:6;}.some-global-5{padding:0;margin:5;}.some-global-4{padding:0;margin:4;}.some-global-3{padding:0;margin:3;}.some-global-2{padding:0;margin:2;}.some-global-1{padding:0;margin:1;} -
+
woah there hello world diff --git a/packages/css/test/instance/inline.test.js b/packages/css/test/instance/inline.test.js index 7e1ccf2af..3dc07efd5 100644 --- a/packages/css/test/instance/inline.test.js +++ b/packages/css/test/instance/inline.test.js @@ -1,6 +1,7 @@ /** * @jest-environment node */ +import { stripDataReactRoot } from 'test-utils' import { getComponents, getInjectedRules, @@ -42,8 +43,10 @@ describe('renderStylesToString', () => { test('renders large recursive component', () => { const BigComponent = createBigComponent(emotion) expect( - emotionServer.renderStylesToString( - renderToString() + stripDataReactRoot( + emotionServer.renderStylesToString( + renderToString() + ) ) ).toMatchSnapshot() }) diff --git a/packages/css/test/instance/stream.test.js b/packages/css/test/instance/stream.test.js index fe4aa4af3..1ee62e197 100644 --- a/packages/css/test/instance/stream.test.js +++ b/packages/css/test/instance/stream.test.js @@ -3,6 +3,7 @@ * @flow */ import { JSDOM } from 'jsdom' +import { stripDataReactRoot } from 'test-utils' let React let renderToString @@ -38,9 +39,11 @@ describe('renderStylesToNodeStream', () => { test('renders large recursive component', async () => { const BigComponent = util.createBigComponent(emotion) expect( - await util.renderToStringWithStream( - , - emotionServer + stripDataReactRoot( + await util.renderToStringWithStream( + , + emotionServer + ) ) ).toMatchSnapshot() }) diff --git a/packages/react/__tests__/rehydration.js b/packages/react/__tests__/rehydration.js index d754aad8f..d2142c05d 100644 --- a/packages/react/__tests__/rehydration.js +++ b/packages/react/__tests__/rehydration.js @@ -11,7 +11,7 @@ afterEach(() => { jest.clearAllMocks() }) -let React +let React = require('react') let ReactDOM let ReactDOMServer let render @@ -631,8 +631,7 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe `) }) - -describe('useId', () => { +;((React: any).useId ? describe : describe.skip)('useId', () => { test('no hydration mismatch for styled when using useId', () => { const finalHTML = disableBrowserEnvTemporarily(() => { resetAllModules() diff --git a/packages/server/test/__snapshots__/inline.test.js.snap b/packages/server/test/__snapshots__/inline.test.js.snap index 2f2844fc5..08ba2c5da 100644 --- a/packages/server/test/__snapshots__/inline.test.js.snap +++ b/packages/server/test/__snapshots__/inline.test.js.snap @@ -268,9 +268,7 @@ exports[`renderStylesToString renders large recursive component 1`] = ` -
+
woah there hello world @@ -2110,7 +2108,6 @@ exports[`renderStylesToString skip undefined styles 1`] = ` `; diff --git a/packages/server/test/__snapshots__/stream.test.js.snap b/packages/server/test/__snapshots__/stream.test.js.snap index d7dc070ea..87e9b5fd6 100644 --- a/packages/server/test/__snapshots__/stream.test.js.snap +++ b/packages/server/test/__snapshots__/stream.test.js.snap @@ -262,9 +262,7 @@ exports[`renderStylesToNodeStream renders large recursive component 1`] = ` -
+
woah there hello world diff --git a/packages/server/test/inline.test.js b/packages/server/test/inline.test.js index 1519a4cf0..9abd6f946 100644 --- a/packages/server/test/inline.test.js +++ b/packages/server/test/inline.test.js @@ -3,6 +3,7 @@ * @flow */ import { JSDOM } from 'jsdom' +import { stripDataReactRoot } from 'test-utils' let React let renderToString @@ -44,13 +45,15 @@ describe('renderStylesToString', () => { const output = emotionServer.renderStylesToString(renderToString(component)) expect(output).toEqual(expect.not.stringContaining('undefined')) - expect(output).toMatchSnapshot() + expect(stripDataReactRoot(output)).toMatchSnapshot() }) test('renders large recursive component', () => { const BigComponent = util.createBigComponent(emotion) expect( - emotionServer.renderStylesToString( - renderToString() + stripDataReactRoot( + emotionServer.renderStylesToString( + renderToString() + ) ) ).toMatchSnapshot() }) diff --git a/packages/server/test/stream.test.js b/packages/server/test/stream.test.js index c708ceaa1..d9d98ba2b 100644 --- a/packages/server/test/stream.test.js +++ b/packages/server/test/stream.test.js @@ -3,6 +3,7 @@ * @flow */ import { JSDOM } from 'jsdom' +import { stripDataReactRoot } from 'test-utils' let React let renderToString @@ -38,9 +39,11 @@ describe('renderStylesToNodeStream', () => { test('renders large recursive component', async () => { const BigComponent = util.createBigComponent(emotion) expect( - await util.renderToStringWithStream( - , - emotionServer + stripDataReactRoot( + await util.renderToStringWithStream( + , + emotionServer + ) ) ).toMatchSnapshot() }) diff --git a/scripts/test-utils/src/index.js b/scripts/test-utils/src/index.js index 4c019d9cc..89780bc20 100644 --- a/scripts/test-utils/src/index.js +++ b/scripts/test-utils/src/index.js @@ -28,3 +28,8 @@ export let safeQuerySelector = (selector: string): HTMLElement => { } return element } + +// React 18 doesn't use this attribute anymore +// we normalize this to avoid snapshot mismatches between React versions +export let stripDataReactRoot = (html: string): string => + html.replace(' data-reactroot=""', '') diff --git a/test/styleTransform.js b/test/styleTransform.js deleted file mode 100644 index 50e0aaac7..000000000 --- a/test/styleTransform.js +++ /dev/null @@ -1,13 +0,0 @@ -// @flow -const path = require('path') - -module.exports = { - process(src /*: string */, filename /*: string */) { - return ` - if (!global.stylesMocked) global.mockedCssImports = {} - global.mockedCssImports[${JSON.stringify( - path.basename(filename) - )}] = ${JSON.stringify(src)} - ` - } -} From 0f150588716ea6d2d0ed6be314bf112a4574fdcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 18 Dec 2021 12:02:57 +0100 Subject: [PATCH 04/12] Move rule insertion to the inner `` for the css prop --- packages/react/src/emotion-element.js | 54 ++++++++++--------- packages/react/src/useInsertionEffectMaybe.js | 16 ++++++ 2 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 packages/react/src/useInsertionEffectMaybe.js diff --git a/packages/react/src/emotion-element.js b/packages/react/src/emotion-element.js index 809a05916..309d67c5c 100644 --- a/packages/react/src/emotion-element.js +++ b/packages/react/src/emotion-element.js @@ -6,6 +6,7 @@ import { getRegisteredStyles, insertStyles } from '@emotion/utils' import { hasOwnProperty, isBrowser } from './utils' import { serializeStyles } from '@emotion/serialize' import { getLabelFromStackTrace } from './get-label-from-stack-trace' +import useInsertionEffectMaybe from './useInsertionEffectMaybe' let typePropName = '__EMOTION_TYPE_PLEASE_DO_NOT_USE__' @@ -49,7 +50,30 @@ export const createEmotionProps = (type: React.ElementType, props: Object) => { return newProps } -const Noop = () => null +const Insertion = ({ cache, serialized }) => { + const rules = useInsertionEffectMaybe(() => + insertStyles(cache, serialized, typeof type === 'string') + ) + + if (!isBrowser && rules !== undefined) { + let serializedNames = serialized.name + let next = serialized.next + while (next !== undefined) { + serializedNames += ' ' + next.name + next = next.next + } + return ( + `; diff --git a/packages/server/test/__snapshots__/stream.test.js.snap b/packages/server/test/__snapshots__/stream.test.js.snap index 87e9b5fd6..eb6097b39 100644 --- a/packages/server/test/__snapshots__/stream.test.js.snap +++ b/packages/server/test/__snapshots__/stream.test.js.snap @@ -142,112 +142,6 @@ exports[`hydration only inserts rules that are not in the critical css 3`] = ` box-shadow: -15px -15px 0 0 aqua,-30px -30px 0 0 cornflowerblue; } -@font-face { - font-family: 'Patrick Hand SC'; - font-style: normal; - font-weight: 400; - src: local('Patrick Hand SC'),local('PatrickHandSC-Regular'),url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2'); - unicode-range: U+0100-024f,U+1-1eff,U+20a0-20ab,U+20ad-20cf,U+2c60-2c7f,U+A720-A7FF; -} - -@-webkit-keyframes animation-i9f7qw-bounce { - from, 20%, 53%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 40%, 43% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - -webkit-transform: translate3d(0, -30px, 0); - -moz-transform: translate3d(0, -30px, 0); - -ms-transform: translate3d(0, -30px, 0); - transform: translate3d(0, -30px, 0); - } - - 70% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - -webkit-transform: translate3d(0, -15px, 0); - -moz-transform: translate3d(0, -15px, 0); - -ms-transform: translate3d(0, -15px, 0); - transform: translate3d(0, -15px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -4px, 0); - -moz-transform: translate3d(0, -4px, 0); - -ms-transform: translate3d(0, -4px, 0); - transform: translate3d(0, -4px, 0); - } -} - -@keyframes animation-i9f7qw-bounce { - from, 20%, 53%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 40%, 43% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - -webkit-transform: translate3d(0, -30px, 0); - -moz-transform: translate3d(0, -30px, 0); - -ms-transform: translate3d(0, -30px, 0); - transform: translate3d(0, -30px, 0); - } - - 70% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); - -webkit-transform: translate3d(0, -15px, 0); - -moz-transform: translate3d(0, -15px, 0); - -ms-transform: translate3d(0, -15px, 0); - transform: translate3d(0, -15px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -4px, 0); - -moz-transform: translate3d(0, -4px, 0); - -ms-transform: translate3d(0, -4px, 0); - transform: translate3d(0, -4px, 0); - } -} - -.no-prefix { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: center; - -ms-flex-pack: center; - -webkit-justify-content: center; - justify-content: center; -} - -.css-14e1j2p-hoverStyles-Something_Main { - color: hotpink; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; -} - -.css-14e1j2p-hoverStyles-Something_Main:hover { - color: white; - background-color: lightgray; - border-color: aqua; - box-shadow: -15px -15px 0 0 aqua,-30px -30px 0 0 cornflowerblue; -} - .css-1h1w8ez-Image { -webkit-animation: animation-i9f7qw-bounce; animation: animation-i9f7qw-bounce; diff --git a/packages/server/test/inline.test.js b/packages/server/test/inline.test.js index 9abd6f946..0378b0c5a 100644 --- a/packages/server/test/inline.test.js +++ b/packages/server/test/inline.test.js @@ -1,9 +1,8 @@ -/** - * @jest-environment node - * @flow - */ -import { JSDOM } from 'jsdom' -import { stripDataReactRoot } from 'test-utils' +import { + stripDataReactRoot, + disableBrowserEnvTemporarily, + safeQuerySelector +} from 'test-utils' let React let renderToString @@ -25,58 +24,60 @@ const resetAllModules = () => { } describe('renderStylesToString', () => { - beforeEach(resetAllModules) - - test('renders styles with ids', () => { - const { Page1, Page2 } = util.getComponents(emotion, reactEmotion) - expect( - emotionServer.renderStylesToString(renderToString()) - ).toMatchSnapshot() - expect( - emotionServer.renderStylesToString(renderToString()) - ).toMatchSnapshot() + test('renders styles with ids', async () => { + await disableBrowserEnvTemporarily(() => { + resetAllModules() + const { Page1, Page2 } = util.getComponents(emotion, reactEmotion) + expect( + emotionServer.renderStylesToString(renderToString()) + ).toMatchSnapshot() + expect( + emotionServer.renderStylesToString(renderToString()) + ).toMatchSnapshot() + }) }) - test('skip undefined styles', () => { - const { css } = emotion - const style = css` - color: red; - ` - const component = - const output = emotionServer.renderStylesToString(renderToString(component)) + test('skip undefined styles', async () => { + await disableBrowserEnvTemporarily(() => { + resetAllModules() + const { css } = emotion + const style = css` + color: red; + ` + const component = ( + + ) + const output = emotionServer.renderStylesToString( + renderToString(component) + ) - expect(output).toEqual(expect.not.stringContaining('undefined')) - expect(stripDataReactRoot(output)).toMatchSnapshot() + expect(output).toEqual(expect.not.stringContaining('undefined')) + expect(stripDataReactRoot(output)).toMatchSnapshot() + }) }) - test('renders large recursive component', () => { - const BigComponent = util.createBigComponent(emotion) - expect( - stripDataReactRoot( - emotionServer.renderStylesToString( - renderToString() + test('renders large recursive component', async () => { + await disableBrowserEnvTemporarily(() => { + resetAllModules() + const BigComponent = util.createBigComponent(emotion) + expect( + stripDataReactRoot( + emotionServer.renderStylesToString( + renderToString() + ) ) - ) - ).toMatchSnapshot() + ).toMatchSnapshot() + }) }) }) describe('hydration', () => { - beforeEach(resetAllModules) - - afterEach(() => { - global.document = undefined - global.window = undefined - global.navigator = undefined - }) - - test('only inserts rules that are not in the critical css', () => { - const { Page1 } = util.getComponents(emotion, reactEmotion) - const html = emotionServer.renderStylesToString(renderToString()) - expect(html).toMatchSnapshot() + test('only inserts rules that are not in the critical css', async () => { + const appHtml = await disableBrowserEnvTemporarily(() => { + resetAllModules() + const { Page1 } = util.getComponents(emotion, reactEmotion) + return emotionServer.renderStylesToString(renderToString()) + }) - const { window } = new JSDOM(html) - global.document = window.document - global.window = window - global.navigator = window.navigator - util.setHtml(html, document) + expect(appHtml).toMatchSnapshot() + document.body.innerHTML = `
${appHtml}
` resetAllModules() @@ -84,7 +85,9 @@ describe('hydration', () => { const { Page1: NewPage1 } = util.getComponents(emotion, reactEmotion) - render() + render(, { + container: safeQuerySelector('#root') + }) expect(util.getInjectedRules(document)).toMatchSnapshot() expect(util.getCssFromChunks(emotion, document)).toMatchSnapshot() }) diff --git a/packages/server/test/stream.test.js b/packages/server/test/stream.test.js index d9d98ba2b..6c95301bb 100644 --- a/packages/server/test/stream.test.js +++ b/packages/server/test/stream.test.js @@ -1,9 +1,8 @@ -/** - * @jest-environment node - * @flow - */ -import { JSDOM } from 'jsdom' -import { stripDataReactRoot } from 'test-utils' +import { + stripDataReactRoot, + disableBrowserEnvTemporarily, + safeQuerySelector +} from 'test-utils' let React let renderToString @@ -25,54 +24,52 @@ const resetAllModules = () => { } describe('renderStylesToNodeStream', () => { - beforeEach(resetAllModules) - test('renders styles with ids', async () => { - const { Page1, Page2 } = util.getComponents(emotion, reactEmotion) - expect( - await util.renderToStringWithStream(, emotionServer) - ).toMatchSnapshot() - expect( - await util.renderToStringWithStream(, emotionServer) - ).toMatchSnapshot() + await disableBrowserEnvTemporarily(async () => { + resetAllModules() + const { Page1, Page2 } = util.getComponents(emotion, reactEmotion) + expect( + await util.renderToStringWithStream(, emotionServer) + ).toMatchSnapshot() + expect( + await util.renderToStringWithStream(, emotionServer) + ).toMatchSnapshot() + }) }) test('renders large recursive component', async () => { - const BigComponent = util.createBigComponent(emotion) - expect( - stripDataReactRoot( - await util.renderToStringWithStream( - , - emotionServer + await disableBrowserEnvTemporarily(async () => { + resetAllModules() + const BigComponent = util.createBigComponent(emotion) + expect( + stripDataReactRoot( + await util.renderToStringWithStream( + , + emotionServer + ) ) - ) - ).toMatchSnapshot() + ).toMatchSnapshot() + }) }) }) describe('hydration', () => { - beforeEach(resetAllModules) - - afterEach(() => { - global.document = undefined - global.window = undefined - global.navigator = undefined - }) - test('only inserts rules that are not in the critical css', async () => { - const { Page1 } = util.getComponents(emotion, reactEmotion) - const html = await util.renderToStringWithStream(, emotionServer) - expect(html).toMatchSnapshot() - const { window } = new JSDOM(html) - global.document = window.document - global.window = window - global.navigator = window.navigator - util.setHtml(html, document) + const appHtml = await disableBrowserEnvTemporarily(() => { + resetAllModules() + const { Page1 } = util.getComponents(emotion, reactEmotion) + return util.renderToStringWithStream(, emotionServer) + }) + + expect(appHtml).toMatchSnapshot() + document.body.innerHTML = `
${appHtml}
` resetAllModules() expect(emotion.cache.registered).toEqual({}) const { Page1: NewPage1 } = util.getComponents(emotion, reactEmotion) - render() + render(, { + container: safeQuerySelector('#root') + }) expect(util.getInjectedRules(document)).toMatchSnapshot() expect(util.getCssFromChunks(emotion, document)).toMatchSnapshot() }) diff --git a/packages/server/test/util.js b/packages/server/test/util.js index 6c1ddae23..0f5df444d 100644 --- a/packages/server/test/util.js +++ b/packages/server/test/util.js @@ -198,7 +198,7 @@ const isSSRedStyle = node => { return attrib.length > 1 } -export const getCssFromChunks = (emotion: Emotion, document: Document) => { +export const getCssFromChunks = (emotion: Emotion) => { const chunks = Array.from( // $FlowFixMe emotion.sheet.tags[0].parentNode.querySelectorAll(`[data-emotion]`) @@ -211,7 +211,7 @@ export const getCssFromChunks = (emotion: Emotion, document: Document) => { return prettify(css) } -export const getInjectedRules = (document: Document = global.document) => +export const getInjectedRules = () => prettify( Array.from(document.querySelectorAll('[data-emotion]')) .filter(node => !isSSRedStyle(node)) @@ -219,14 +219,6 @@ export const getInjectedRules = (document: Document = global.document) => .join('') ) -export const setHtml = (html: string, document: Document) => { - if (document.body !== null) { - document.body.innerHTML = html - } else { - throw new Error('body does not exist on document') - } -} - export const renderToStringWithStream = ( element: React.Element<*>, { renderStylesToNodeStream }: EmotionServer diff --git a/packages/styled/src/base.js b/packages/styled/src/base.js index d2ea17900..74ce54106 100644 --- a/packages/styled/src/base.js +++ b/packages/styled/src/base.js @@ -9,8 +9,13 @@ import { type StyledElementType } from './utils' import { withEmotionCache, ThemeContext } from '@emotion/react' -import { getRegisteredStyles, insertStyles } from '@emotion/utils' +import { + getRegisteredStyles, + insertStyles, + registerStyles +} from '@emotion/utils' import { serializeStyles } from '@emotion/serialize' +import useInsertionEffectMaybe from './useInsertionEffectMaybe' const ILLEGAL_ESCAPE_SEQUENCE_ERROR = `You have illegal escape sequence in your template literal, most likely inside content's property value. Because you write your CSS inside a JavaScript string you actually have to do double escaping, so for example "content: '\\00d7';" should become "content: '\\\\00d7';". @@ -18,7 +23,33 @@ You can read more about this here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#ES2018_revision_of_illegal_escape_sequences` let isBrowser = typeof document !== 'undefined' -const Noop = () => null + +const Insertion = ({ cache, serialized, isStringTag }) => { + registerStyles(cache, serialized, isStringTag) + + const rules = useInsertionEffectMaybe(() => + insertStyles(cache, serialized, isStringTag) + ) + + if (!isBrowser && rules !== undefined) { + let serializedNames = serialized.name + let next = serialized.next + while (next !== undefined) { + serializedNames += ' ' + next.name + next = next.next + } + return ( +