Skip to content

Commit

Permalink
useInsertionEffect when it's available (#2600)
Browse files Browse the repository at this point in the history
* Upgrade React 18 to its latest RC version

* Refactored tests to RTL to run tests easier against different React version, also run test suite with React 18

* Add separate Jest config to run tests with React 18

* Move rule insertion to the inner `<Insertion/>` for the css prop

* Fixed Enzyme's shallow tests

* Make test pass with real `useInsertionEffect`

* Use `<Insertion/> and `useInsertionEffect` for all injection points in `@emotion/react` and `@emotion/styled``

* Fixed import-prod test problem with production React 18 throwing when used with RTL cause it's using act

* Refactor one last test that was using JSDOM explicitly

* Fixed CI

* Update packages/css/test/no-babel/index.test.js

* add changesets

Co-authored-by: Mitchell Hamilton <mitchell@hamil.town>
  • Loading branch information
Andarist and emmatown committed Feb 19, 2022
1 parent d253163 commit 2f27156
Show file tree
Hide file tree
Showing 50 changed files with 865 additions and 983 deletions.
6 changes: 6 additions & 0 deletions .changeset/silver-foxes-double.md
@@ -0,0 +1,6 @@
---
'@emotion/react': minor
'@emotion/styled': minor
---

Refactored code to use the upcoming `React.useInsertionEffect` when it's available (this is a new hook that is going to be introduced in React 18). This shouldn't have any effect on existing codebases and the change should be transparent.
5 changes: 5 additions & 0 deletions .changeset/tricky-cameras-fold.md
@@ -0,0 +1,5 @@
---
'@emotion/utils': minor
---

Introduced `registerStyles` helper that is shared across between other packages. This is just an internal util that shouldn't be used by packages other than `@emotion/*` packages.
5 changes: 5 additions & 0 deletions .changeset/wet-bikes-explain.md
@@ -0,0 +1,5 @@
---
'@emotion/jest': patch
---

Adjusted Enzyme-related code path to accomodate for changes related to the refactor around using `React.useInsertionEffect`.
33 changes: 32 additions & 1 deletion .github/workflows/main.yml
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions jest-react18.config.js
@@ -0,0 +1,9 @@
const baseConfig = require('./jest.config.js')

module.exports = Object.assign({}, baseConfig, {
moduleNameMapper: {
'^react($|\\/.+)': 'react18$1',
'^react-dom($|\\/.+)': 'react18-dom$1',
'^react-test-renderer($|\\/.+)': 'react18-test-renderer$1'
}
})
1 change: 0 additions & 1 deletion jest.config.js
@@ -1,7 +1,6 @@
module.exports = {
testEnvironment: 'jsdom',
transform: {
'\\.css$': '<rootDir>/test/styleTransform.js',
'^.+\\.js?$': 'babel-jest'
},
watchPlugins: [
Expand Down
2 changes: 0 additions & 2 deletions jest.dist.js
Expand Up @@ -3,5 +3,3 @@ const baseConfig = require('./jest.config.js')
module.exports = Object.assign({}, baseConfig, {
transformIgnorePatterns: ['dist', 'node_modules']
})

delete module.exports.moduleNameMapper
12 changes: 7 additions & 5 deletions package.json
Expand Up @@ -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",
Expand Down Expand Up @@ -193,7 +195,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",
Expand Down Expand Up @@ -237,7 +239,6 @@
"jest-junit": "^13.0.0",
"jest-serializer-html": "^7.1.0",
"jest-watch-typeahead": "^1.0.0",
"jsdom": "^16.6.0",
"lint-staged": "^7.2.0",
"module-alias": "^2.0.1",
"multipipe": "^1.0.2",
Expand All @@ -257,8 +258,9 @@
"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",
"react18-test-renderer": "npm:react-test-renderer@18.0.0-rc.0-next-aa8f2bdbc-20211215",
"svg-tag-names": "^1.1.1",
"through": "^2.3.8",
"unified": "^6.1.6",
Expand Down
50 changes: 1 addition & 49 deletions packages/css/test/instance/__snapshots__/inline.test.js.snap
Expand Up @@ -91,52 +91,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;
}

@keyframes animation-i9f7qw-bounce {
from, 20%, 53%, 80%, to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translate3d(0, 0, 0);
}

40%, 43% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -30px, 0);
}

70% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -15px, 0);
}

90% {
transform: translate3d(0, -4px, 0);
}
}

.no-prefix {
display: flex;
justify-content: center;
}

.some-key-14e1j2p-hoverStyles-Something_Main {
color: hotpink;
display: flex;
}

.some-key-14e1j2p-hoverStyles-Something_Main:hover {
color: hotpink;
background-color: lightgray;
border-color: aqua;
box-shadow: -15px -15px 0 0 aqua,-30px -30px 0 0 cornflowerblue;
}

.some-key-1h1w8ez-Image {
animation: animation-i9f7qw-bounce;
border-radius: 50%;
Expand All @@ -157,9 +111,7 @@ exports[`renderStylesToString renders large recursive component 1`] = `
>
.some-key-127stik{color:hotpink;}
</style>
<div class="some-key-127stik"
data-reactroot
>
<div class="some-key-127stik">
woah there
<span>
hello world
Expand Down
50 changes: 1 addition & 49 deletions packages/css/test/instance/__snapshots__/stream.test.js.snap
Expand Up @@ -86,52 +86,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;
}

@keyframes animation-i9f7qw-bounce {
from, 20%, 53%, 80%, to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translate3d(0, 0, 0);
}

40%, 43% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -30px, 0);
}

70% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -15px, 0);
}

90% {
transform: translate3d(0, -4px, 0);
}
}

.no-prefix {
display: flex;
justify-content: center;
}

.some-key-14e1j2p-hoverStyles-Something_Main {
color: hotpink;
display: flex;
}

.some-key-14e1j2p-hoverStyles-Something_Main:hover {
color: hotpink;
background-color: lightgray;
border-color: aqua;
box-shadow: -15px -15px 0 0 aqua,-30px -30px 0 0 cornflowerblue;
}

.some-key-1h1w8ez-Image {
animation: animation-i9f7qw-bounce;
border-radius: 50%;
Expand All @@ -147,9 +101,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;}
</style>
<div class="some-key-127stik"
data-reactroot
>
<div class="some-key-127stik">
woah there
<span>
hello world
Expand Down
78 changes: 40 additions & 38 deletions packages/css/test/instance/inline.test.js
@@ -1,14 +1,15 @@
/**
* @jest-environment node
*/
import {
stripDataReactRoot,
disableBrowserEnvTemporarily,
safeQuerySelector
} from 'test-utils'
import {
getComponents,
getInjectedRules,
createBigComponent,
getCssFromChunks,
setHtml
} from '../../../server/test/util'
import { JSDOM } from 'jsdom'

let React
let renderToString
Expand All @@ -28,52 +29,53 @@ const resetAllModules = () => {
}

describe('renderStylesToString', () => {
beforeEach(resetAllModules)

test('renders styles with ids', () => {
const { Page1, Page2 } = getComponents(emotion, reactEmotion)
expect(
emotionServer.renderStylesToString(renderToString(<Page1 />))
).toMatchSnapshot()
expect(
emotionServer.renderStylesToString(renderToString(<Page2 />))
).toMatchSnapshot()
test('renders styles with ids', async () => {
await disableBrowserEnvTemporarily(() => {
resetAllModules()
const { Page1, Page2 } = getComponents(emotion, reactEmotion)
expect(
emotionServer.renderStylesToString(renderToString(<Page1 />))
).toMatchSnapshot()
expect(
emotionServer.renderStylesToString(renderToString(<Page2 />))
).toMatchSnapshot()
})
})
test('renders large recursive component', () => {
const BigComponent = createBigComponent(emotion)
expect(
emotionServer.renderStylesToString(
renderToString(<BigComponent count={200} />)
)
).toMatchSnapshot()
test('renders large recursive component', async () => {
await disableBrowserEnvTemporarily(() => {
resetAllModules()
const BigComponent = createBigComponent(emotion)
expect(
stripDataReactRoot(
emotionServer.renderStylesToString(
renderToString(<BigComponent count={200} />)
)
)
).toMatchSnapshot()
})
})
})
describe('hydration', () => {
beforeEach(resetAllModules)
test('only inserts rules that are not in the critical css', async () => {
const appHtml = await disableBrowserEnvTemporarily(() => {
resetAllModules()

afterEach(() => {
global.document = undefined
global.window = undefined
global.navigator = undefined
})
const { Page1 } = getComponents(emotion, reactEmotion)
return emotionServer.renderStylesToString(renderToString(<Page1 />))
})

test('only inserts rules that are not in the critical css', () => {
const { Page1 } = getComponents(emotion, reactEmotion)
const html = emotionServer.renderStylesToString(renderToString(<Page1 />))
expect(html).toMatchSnapshot()
const { window } = new JSDOM(html)
global.document = window.document
global.window = window
global.navigator = window.navigator
setHtml(html, document)
expect(appHtml).toMatchSnapshot()
document.body.innerHTML = `<div id="root">${appHtml}</div>`

resetAllModules()

expect(emotion.cache.registered).toEqual({})

const { Page1: NewPage1 } = getComponents(emotion, reactEmotion)
render(<NewPage1 />)
expect(getInjectedRules(document)).toMatchSnapshot()
render(<NewPage1 />, {
container: safeQuerySelector('#root')
})
expect(getInjectedRules()).toMatchSnapshot()
expect(getCssFromChunks(emotion, document)).toMatchSnapshot()
})
})

0 comments on commit 2f27156

Please sign in to comment.