From 23274d5c0542404f6414de3549b76476811e971f Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Mon, 6 May 2024 15:27:05 -0700 Subject: [PATCH 01/30] unit test --- .../__tests__/unit/LexicalComposer.test.tsx | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/lexical-react/src/__tests__/unit/LexicalComposer.test.tsx b/packages/lexical-react/src/__tests__/unit/LexicalComposer.test.tsx index 2a79c9bc636..145192b1287 100644 --- a/packages/lexical-react/src/__tests__/unit/LexicalComposer.test.tsx +++ b/packages/lexical-react/src/__tests__/unit/LexicalComposer.test.tsx @@ -7,13 +7,19 @@ */ import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; +import { + $createParagraphNode, + $createTextNode, + $getRoot, + LexicalEditor, +} from 'lexical'; import * as React from 'react'; import {createRoot, Root} from 'react-dom/client'; import * as ReactTestUtils from 'react-dom/test-utils'; import {LexicalComposer} from '../../LexicalComposer'; -describe('LexicalNodeHelpers tests', () => { +describe('LexicalComposer tests', () => { let container: HTMLDivElement | null = null; let reactRoot: Root; @@ -59,4 +65,53 @@ describe('LexicalNodeHelpers tests', () => { reactRoot.render(); }); }); + + describe('LexicalComposerContext editor identity', () => { + ( + [ + {name: 'StrictMode', size: 2}, + {name: 'Fragment', size: 1}, + ] as const + ).forEach(({name, size}) => { + const Wrapper = React[name]; + const editors = new Set(); + function App() { + return ( + { + const p = $createParagraphNode(); + p.append($createTextNode('initial state')); + $getRoot().append(p); + }); + }, + namespace: '', + nodes: [], + onError: () => { + throw Error(); + }, + }} + /> + ); + } + it(`renders ${size} editors under ${name}`, async () => { + await ReactTestUtils.act(async () => { + reactRoot.render( + + + , + ); + }); + expect(editors.size).toBe(size); + [...editors].forEach((editor, i) => { + expect([ + i, + editor.getEditorState().read(() => $getRoot().getTextContent()), + ]).toEqual([i, 'initial state']); + }); + }); + }); + }); }); From e5e470db50cb18989ac3e70f01a69b93916f4874 Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Mon, 13 May 2024 09:18:50 -0700 Subject: [PATCH 02/30] try the unit tests with react beta --- .github/workflows/call-core-tests.yml | 5 + .github/workflows/call-e2e-all-tests.yml | 121 +++++++++++++++++++---- 2 files changed, 108 insertions(+), 18 deletions(-) diff --git a/.github/workflows/call-core-tests.yml b/.github/workflows/call-core-tests.yml index e6f1d5c2bd5..586dcca2323 100644 --- a/.github/workflows/call-core-tests.yml +++ b/.github/workflows/call-core-tests.yml @@ -30,6 +30,7 @@ jobs: strategy: matrix: node-version: [18.18.0] + react-override: ['', 'beta'] env: CI: true steps: @@ -41,6 +42,10 @@ jobs: cache: npm - name: Install dependencies run: npm ci + - name: Override React ${{ matrix.react-override }} + if: matrix.react-override != '' + # This should be safe since we are caching ~/.npm and not node_modules + run: npm i --no-save react@${{ matrix.react-override }} react-dom@${{ matrix.react-override }} - run: npm run test-unit integration: diff --git a/.github/workflows/call-e2e-all-tests.yml b/.github/workflows/call-e2e-all-tests.yml index 2b5a9475df0..7c740b61d9d 100644 --- a/.github/workflows/call-e2e-all-tests.yml +++ b/.github/workflows/call-e2e-all-tests.yml @@ -1,17 +1,95 @@ -name: Lexical e2e tests +name: Lexical Tests on: - workflow_call: + push: + branches: + - main + paths-ignore: + - 'packages/lexical-website/**' + pull_request: + types: [opened, synchronize, reopened] + paths-ignore: + - 'packages/lexical-website/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - mac: + integrity: + if: github.repository_owner == 'facebook' + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.11.0] + env: + CI: true + GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Install dependencies + run: npm ci + - run: npm run ci-check + - run: npm run build + - run: npm run build-www + + unit: + if: github.repository_owner == 'facebook' + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.18.0] + react-override: ['', 'beta'] + env: + CI: true + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Install dependencies + run: npm ci + - name: Override React ${{ matrix.react-override }} + if: matrix.react-override != '' + # This should be safe since we are caching ~/.npm and not node_modules + run: npm i --no-save react@${{ matrix.react-override }} react-dom@${{ matrix.react-override }} + - run: npm run test-unit + + integration: + if: github.repository_owner == 'facebook' + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.18.0] + env: + CI: true + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Install dependencies + run: npm ci + - run: npm run test-integration + + e2e-mac: + if: github.repository_owner == 'facebook' strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox', 'webkit'] editor-mode: ['rich-text', 'plain-text'] events-mode: ['legacy-events', 'modern-events'] - uses: ./.github/workflows/call-e2e-test.yml + uses: ./.github/workflows/e2e-test.yml with: os: 'macos-latest' node-version: ${{ matrix.node-version }} @@ -19,14 +97,15 @@ jobs: editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} - linux: + e2e-linux: + if: github.repository_owner == 'facebook' strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox'] editor-mode: ['rich-text', 'plain-text'] events-mode: ['legacy-events', 'modern-events'] - uses: ./.github/workflows/call-e2e-test.yml + uses: ./.github/workflows/e2e-test.yml with: os: 'ubuntu-latest' node-version: ${{ matrix.node-version }} @@ -34,14 +113,15 @@ jobs: editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} - windows: + e2e-windows: + if: github.repository_owner == 'facebook' strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox'] editor-mode: ['rich-text', 'plain-text'] events-mode: ['legacy-events', 'modern-events'] - uses: ./.github/workflows/call-e2e-test.yml + uses: ./.github/workflows/e2e-test.yml with: os: 'windows-latest' node-version: ${{ matrix.node-version }} @@ -49,12 +129,13 @@ jobs: editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} - collab-mac: + e2e-collab-mac: + if: github.repository_owner == 'facebook' strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox', 'webkit'] - uses: ./.github/workflows/call-e2e-test.yml + uses: ./.github/workflows/e2e-test.yml with: os: 'macos-latest' node-version: ${{ matrix.node-version }} @@ -62,12 +143,13 @@ jobs: editor-mode: 'rich-text-with-collab' events-mode: 'modern-events' - collab-linux: + e2e-collab-linux: + if: github.repository_owner == 'facebook' strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox'] - uses: ./.github/workflows/call-e2e-test.yml + uses: ./.github/workflows/e2e-test.yml with: os: 'ubuntu-latest' node-version: ${{ matrix.node-version }} @@ -75,12 +157,13 @@ jobs: editor-mode: 'rich-text-with-collab' events-mode: 'modern-events' - collab-windows: + e2e-collab-windows: + if: github.repository_owner == 'facebook' strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox'] - uses: ./.github/workflows/call-e2e-test.yml + uses: ./.github/workflows/e2e-test.yml with: os: 'windows-latest' node-version: ${{ matrix.node-version }} @@ -88,7 +171,8 @@ jobs: editor-mode: 'rich-text-with-collab' events-mode: 'modern-events' - prod: + e2e-prod: + if: github.repository_owner == 'facebook' strategy: matrix: os: ['macos-latest'] @@ -96,7 +180,7 @@ jobs: browser: ['chromium'] editor-mode: ['rich-text'] events-mode: ['modern-events'] - uses: ./.github/workflows/call-e2e-test.yml + uses: ./.github/workflows/e2e-test.yml with: prod: true os: ${{ matrix.os }} @@ -105,7 +189,8 @@ jobs: editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} - collab-prod: + e2e-collab-prod: + if: github.repository_owner == 'facebook' strategy: matrix: os: ['macos-latest'] @@ -113,7 +198,7 @@ jobs: browser: ['chromium'] editor-mode: ['rich-text-with-collab'] events-mode: ['modern-events'] - uses: ./.github/workflows/call-e2e-test.yml + uses: ./.github/workflows/e2e-test.yml with: prod: true os: ${{ matrix.os }} From 8cd0664de7613d7a9cf6b0ed86cac1d56f2fd48e Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Tue, 7 May 2024 07:57:02 -0700 Subject: [PATCH 03/30] Silence __DEV__ ArtificialNode__DO_NOT_USE warnings --- packages/lexical/src/LexicalEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lexical/src/LexicalEditor.ts b/packages/lexical/src/LexicalEditor.ts index 7c03d00c790..6b1d1c7e8d3 100644 --- a/packages/lexical/src/LexicalEditor.ts +++ b/packages/lexical/src/LexicalEditor.ts @@ -447,7 +447,7 @@ export function createEditor(editorConfig?: CreateEditorArgs): LexicalEditor { // Ensure custom nodes implement required methods. if (__DEV__) { const name = klass.name; - if (name !== 'RootNode') { + if (name !== 'RootNode' && name !== 'ArtificialNode__DO_NOT_USE') { const proto = klass.prototype; ['getType', 'clone'].forEach((method) => { // eslint-disable-next-line no-prototype-builtins From 7f470c01aa508f73c8d3bb31b19ca909012e8ac0 Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Tue, 7 May 2024 08:04:19 -0700 Subject: [PATCH 04/30] handle react-dom/test-utils deprecation --- packages/lexical-devtools/tsconfig.json | 1 + .../src/__tests__/unit/LexicalHistory.test.tsx | 2 +- .../__tests__/unit/LexicalComposer.test.tsx | 2 +- .../unit/PlainRichTextPlugin.test.tsx | 2 +- .../unit/useLexicalIsTextContentEmpty.test.tsx | 2 +- .../lexical-react/src/__tests__/unit/utils.tsx | 2 +- .../__tests__/unit/LexicalSelection.test.tsx | 2 +- .../unit/LexicalTableSelection.test.tsx | 2 +- .../unit/LexicalEventHelpers.test.tsx | 2 +- .../src/__tests__/unit/LexicalEditor.test.tsx | 2 +- .../__tests__/unit/LexicalListPlugin.test.tsx | 2 +- packages/lexical/src/__tests__/utils/index.tsx | 2 +- .../__tests__/unit/LexicalElementNode.test.tsx | 2 +- .../__tests__/unit/LexicalTextNode.test.tsx | 2 +- packages/shared/src/react-test-utils.ts | 18 ++++++++++++++++++ tsconfig.build.json | 1 + tsconfig.json | 1 + 17 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 packages/shared/src/react-test-utils.ts diff --git a/packages/lexical-devtools/tsconfig.json b/packages/lexical-devtools/tsconfig.json index 8978b961e03..ddfcd95c055 100644 --- a/packages/lexical-devtools/tsconfig.json +++ b/packages/lexical-devtools/tsconfig.json @@ -158,6 +158,7 @@ "shared/environment": ["../shared/src/environment.ts"], "shared/invariant": ["../shared/src/invariant.ts"], "shared/normalizeClassNames": ["../shared/src/normalizeClassNames.ts"], + "shared/react-test-utils": ["../shared/src/react-test-utils.ts"], "shared/simpleDiffWithCursor": ["../shared/src/simpleDiffWithCursor.ts"], "shared/useLayoutEffect": ["../shared/src/useLayoutEffect.ts"], "shared/warnOnlyOnce": ["../shared/src/warnOnlyOnce.ts"] diff --git a/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx b/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx index 804defbd8b2..057f6b75240 100644 --- a/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx +++ b/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx @@ -35,7 +35,7 @@ import { import {createTestEditor, TestComposer} from 'lexical/src/__tests__/utils'; import React from 'react'; import {createRoot, Root} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; describe('LexicalHistory tests', () => { let container: HTMLDivElement | null = null; diff --git a/packages/lexical-react/src/__tests__/unit/LexicalComposer.test.tsx b/packages/lexical-react/src/__tests__/unit/LexicalComposer.test.tsx index 145192b1287..ae9da26b1e8 100644 --- a/packages/lexical-react/src/__tests__/unit/LexicalComposer.test.tsx +++ b/packages/lexical-react/src/__tests__/unit/LexicalComposer.test.tsx @@ -15,7 +15,7 @@ import { } from 'lexical'; import * as React from 'react'; import {createRoot, Root} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import {LexicalComposer} from '../../LexicalComposer'; diff --git a/packages/lexical-react/src/__tests__/unit/PlainRichTextPlugin.test.tsx b/packages/lexical-react/src/__tests__/unit/PlainRichTextPlugin.test.tsx index 42bfea40230..60f5c8b269d 100644 --- a/packages/lexical-react/src/__tests__/unit/PlainRichTextPlugin.test.tsx +++ b/packages/lexical-react/src/__tests__/unit/PlainRichTextPlugin.test.tsx @@ -26,7 +26,7 @@ import { } from 'lexical'; import * as React from 'react'; import {createRoot, Root} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import {LexicalComposer} from '../../LexicalComposer'; import {ContentEditable} from '../../LexicalContentEditable'; diff --git a/packages/lexical-react/src/__tests__/unit/useLexicalIsTextContentEmpty.test.tsx b/packages/lexical-react/src/__tests__/unit/useLexicalIsTextContentEmpty.test.tsx index 652946f168b..9d1c30f7bdf 100644 --- a/packages/lexical-react/src/__tests__/unit/useLexicalIsTextContentEmpty.test.tsx +++ b/packages/lexical-react/src/__tests__/unit/useLexicalIsTextContentEmpty.test.tsx @@ -17,7 +17,7 @@ import { import * as React from 'react'; import {createRef} from 'react'; import {createRoot, Root} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import {useLexicalIsTextContentEmpty} from '../../useLexicalIsTextContentEmpty'; diff --git a/packages/lexical-react/src/__tests__/unit/utils.tsx b/packages/lexical-react/src/__tests__/unit/utils.tsx index c8c4beeba72..32c75551785 100644 --- a/packages/lexical-react/src/__tests__/unit/utils.tsx +++ b/packages/lexical-react/src/__tests__/unit/utils.tsx @@ -11,7 +11,7 @@ import {LexicalEditor} from 'lexical'; import * as React from 'react'; import {Container} from 'react-dom'; import {createRoot, Root} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import * as Y from 'yjs'; import {useCollaborationContext} from '../../LexicalCollaborationContext'; diff --git a/packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx b/packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx index 07b63a7f519..d2acde40cfa 100644 --- a/packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx +++ b/packages/lexical-selection/src/__tests__/unit/LexicalSelection.test.tsx @@ -48,7 +48,7 @@ import { TestComposer, } from 'lexical/src/__tests__/utils'; import {createRoot} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import { $setAnchorPoint, diff --git a/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx b/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx index 7112c101222..a3dab04aef0 100644 --- a/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx +++ b/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx @@ -21,7 +21,7 @@ import { import {createTestEditor} from 'lexical/src/__tests__/utils'; import {createRef, useEffect, useMemo} from 'react'; import {createRoot, Root} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; describe('table selection', () => { let originalText: TextNode; diff --git a/packages/lexical-utils/src/__tests__/unit/LexicalEventHelpers.test.tsx b/packages/lexical-utils/src/__tests__/unit/LexicalEventHelpers.test.tsx index 089dd086ad1..162ffcfd281 100644 --- a/packages/lexical-utils/src/__tests__/unit/LexicalEventHelpers.test.tsx +++ b/packages/lexical-utils/src/__tests__/unit/LexicalEventHelpers.test.tsx @@ -25,7 +25,7 @@ import {TableCellNode, TableNode, TableRowNode} from '@lexical/table'; import {LexicalEditor} from 'lexical'; import {initializeClipboard, TestComposer} from 'lexical/src/__tests__/utils'; import {createRoot} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; jest.mock('shared/environment', () => { const originalModule = jest.requireActual('shared/environment'); diff --git a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx index 2efc5c7309e..94197ff270e 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx +++ b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx @@ -50,7 +50,7 @@ import { } from 'react'; import {createPortal} from 'react-dom'; import {createRoot, Root} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import { $createTestDecoratorNode, diff --git a/packages/lexical/src/__tests__/unit/LexicalListPlugin.test.tsx b/packages/lexical/src/__tests__/unit/LexicalListPlugin.test.tsx index f9e6544fe95..dcd9c3b6bba 100644 --- a/packages/lexical/src/__tests__/unit/LexicalListPlugin.test.tsx +++ b/packages/lexical/src/__tests__/unit/LexicalListPlugin.test.tsx @@ -22,7 +22,7 @@ import { TestComposer, } from 'lexical/src/__tests__/utils'; import {createRoot, Root} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import { INSERT_UNORDERED_LIST_COMMAND, diff --git a/packages/lexical/src/__tests__/utils/index.tsx b/packages/lexical/src/__tests__/utils/index.tsx index c09e062d8f0..3861e8c7f6e 100644 --- a/packages/lexical/src/__tests__/utils/index.tsx +++ b/packages/lexical/src/__tests__/utils/index.tsx @@ -43,7 +43,7 @@ import {format} from 'prettier'; import * as React from 'react'; import {createRef} from 'react'; import {createRoot} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import {CreateEditorArgs, LexicalNodeReplacement} from '../../LexicalEditor'; import {resetRandomKey} from '../../LexicalUtils'; diff --git a/packages/lexical/src/nodes/__tests__/unit/LexicalElementNode.test.tsx b/packages/lexical/src/nodes/__tests__/unit/LexicalElementNode.test.tsx index 94090d32746..21e9ed3c899 100644 --- a/packages/lexical/src/nodes/__tests__/unit/LexicalElementNode.test.tsx +++ b/packages/lexical/src/nodes/__tests__/unit/LexicalElementNode.test.tsx @@ -19,7 +19,7 @@ import { import * as React from 'react'; import {createRef, useEffect} from 'react'; import {createRoot} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import { $createTestElementNode, diff --git a/packages/lexical/src/nodes/__tests__/unit/LexicalTextNode.test.tsx b/packages/lexical/src/nodes/__tests__/unit/LexicalTextNode.test.tsx index a90e2de3300..b034c96814a 100644 --- a/packages/lexical/src/nodes/__tests__/unit/LexicalTextNode.test.tsx +++ b/packages/lexical/src/nodes/__tests__/unit/LexicalTextNode.test.tsx @@ -24,7 +24,7 @@ import { import * as React from 'react'; import {createRef, useEffect, useMemo} from 'react'; import {createRoot} from 'react-dom/client'; -import * as ReactTestUtils from 'react-dom/test-utils'; +import * as ReactTestUtils from 'shared/react-test-utils'; import { $createTestSegmentedNode, diff --git a/packages/shared/src/react-test-utils.ts b/packages/shared/src/react-test-utils.ts new file mode 100644 index 00000000000..8e086744d5e --- /dev/null +++ b/packages/shared/src/react-test-utils.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ +import * as React from 'react'; +import * as ReactTestUtils from 'react-dom/test-utils'; + +/** + * React 19 moved act from react-dom/test-utils to react + * https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-react-dom-test-utils + */ +export const act = + 'act' in React + ? (React.act as typeof ReactTestUtils.act) + : ReactTestUtils.act; diff --git a/tsconfig.build.json b/tsconfig.build.json index 6b35fbf19ed..0de1e087418 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -161,6 +161,7 @@ "shared/normalizeClassNames": [ "./packages/shared/src/normalizeClassNames.ts" ], + "shared/react-test-utils": ["./packages/shared/src/react-test-utils.ts"], "shared/simpleDiffWithCursor": [ "./packages/shared/src/simpleDiffWithCursor.ts" ], diff --git a/tsconfig.json b/tsconfig.json index e106a0d58b1..2e1958aa7f8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -169,6 +169,7 @@ "shared/normalizeClassNames": [ "./packages/shared/src/normalizeClassNames.ts" ], + "shared/react-test-utils": ["./packages/shared/src/react-test-utils.ts"], "shared/simpleDiffWithCursor": [ "./packages/shared/src/simpleDiffWithCursor.ts" ], From e275d04a80a25c404745d6a0187d2b69680343ac Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Tue, 7 May 2024 09:17:55 -0700 Subject: [PATCH 05/30] e2e with beta --- .github/workflows/call-e2e-all-tests.yml | 136 ++++++----------------- .github/workflows/call-e2e-test.yml | 10 +- 2 files changed, 42 insertions(+), 104 deletions(-) diff --git a/.github/workflows/call-e2e-all-tests.yml b/.github/workflows/call-e2e-all-tests.yml index 7c740b61d9d..cdf48c23605 100644 --- a/.github/workflows/call-e2e-all-tests.yml +++ b/.github/workflows/call-e2e-all-tests.yml @@ -1,95 +1,17 @@ -name: Lexical Tests +name: Lexical e2e tests on: - push: - branches: - - main - paths-ignore: - - 'packages/lexical-website/**' - pull_request: - types: [opened, synchronize, reopened] - paths-ignore: - - 'packages/lexical-website/**' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + workflow_call: jobs: - integrity: - if: github.repository_owner == 'facebook' - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [20.11.0] - env: - CI: true - GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - name: Install dependencies - run: npm ci - - run: npm run ci-check - - run: npm run build - - run: npm run build-www - - unit: - if: github.repository_owner == 'facebook' - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.18.0] - react-override: ['', 'beta'] - env: - CI: true - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - name: Install dependencies - run: npm ci - - name: Override React ${{ matrix.react-override }} - if: matrix.react-override != '' - # This should be safe since we are caching ~/.npm and not node_modules - run: npm i --no-save react@${{ matrix.react-override }} react-dom@${{ matrix.react-override }} - - run: npm run test-unit - - integration: - if: github.repository_owner == 'facebook' - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.18.0] - env: - CI: true - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - name: Install dependencies - run: npm ci - - run: npm run test-integration - - e2e-mac: - if: github.repository_owner == 'facebook' + mac: strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox', 'webkit'] editor-mode: ['rich-text', 'plain-text'] events-mode: ['legacy-events', 'modern-events'] - uses: ./.github/workflows/e2e-test.yml + uses: ./.github/workflows/call-e2e-test.yml with: os: 'macos-latest' node-version: ${{ matrix.node-version }} @@ -97,15 +19,14 @@ jobs: editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} - e2e-linux: - if: github.repository_owner == 'facebook' + linux: strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox'] editor-mode: ['rich-text', 'plain-text'] events-mode: ['legacy-events', 'modern-events'] - uses: ./.github/workflows/e2e-test.yml + uses: ./.github/workflows/call-e2e-test.yml with: os: 'ubuntu-latest' node-version: ${{ matrix.node-version }} @@ -113,15 +34,14 @@ jobs: editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} - e2e-windows: - if: github.repository_owner == 'facebook' + windows: strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox'] editor-mode: ['rich-text', 'plain-text'] events-mode: ['legacy-events', 'modern-events'] - uses: ./.github/workflows/e2e-test.yml + uses: ./.github/workflows/call-e2e-test.yml with: os: 'windows-latest' node-version: ${{ matrix.node-version }} @@ -129,13 +49,12 @@ jobs: editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} - e2e-collab-mac: - if: github.repository_owner == 'facebook' + collab-mac: strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox', 'webkit'] - uses: ./.github/workflows/e2e-test.yml + uses: ./.github/workflows/call-e2e-test.yml with: os: 'macos-latest' node-version: ${{ matrix.node-version }} @@ -143,13 +62,12 @@ jobs: editor-mode: 'rich-text-with-collab' events-mode: 'modern-events' - e2e-collab-linux: - if: github.repository_owner == 'facebook' + collab-linux: strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox'] - uses: ./.github/workflows/e2e-test.yml + uses: ./.github/workflows/call-e2e-test.yml with: os: 'ubuntu-latest' node-version: ${{ matrix.node-version }} @@ -157,13 +75,12 @@ jobs: editor-mode: 'rich-text-with-collab' events-mode: 'modern-events' - e2e-collab-windows: - if: github.repository_owner == 'facebook' + collab-windows: strategy: matrix: node-version: [18.18.0] browser: ['chromium', 'firefox'] - uses: ./.github/workflows/e2e-test.yml + uses: ./.github/workflows/call-e2e-test.yml with: os: 'windows-latest' node-version: ${{ matrix.node-version }} @@ -171,8 +88,7 @@ jobs: editor-mode: 'rich-text-with-collab' events-mode: 'modern-events' - e2e-prod: - if: github.repository_owner == 'facebook' + prod: strategy: matrix: os: ['macos-latest'] @@ -180,7 +96,7 @@ jobs: browser: ['chromium'] editor-mode: ['rich-text'] events-mode: ['modern-events'] - uses: ./.github/workflows/e2e-test.yml + uses: ./.github/workflows/call-e2e-test.yml with: prod: true os: ${{ matrix.os }} @@ -189,8 +105,7 @@ jobs: editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} - e2e-collab-prod: - if: github.repository_owner == 'facebook' + collab-prod: strategy: matrix: os: ['macos-latest'] @@ -198,7 +113,7 @@ jobs: browser: ['chromium'] editor-mode: ['rich-text-with-collab'] events-mode: ['modern-events'] - uses: ./.github/workflows/e2e-test.yml + uses: ./.github/workflows/call-e2e-test.yml with: prod: true os: ${{ matrix.os }} @@ -206,3 +121,18 @@ jobs: browser: ${{ matrix.browser }} editor-mode: ${{ matrix.editor-mode }} events-mode: ${{ matrix.events-mode }} + + react-beta: + strategy: + matrix: + editor-mode: ['rich-text', 'rich-text-with-collab'] + prod: [false, true] + uses: ./.github/workflows/call-e2e-test.yml + with: + os: 'macos-latest' + browser: 'chromium' + node-version: 18.18.0 + events-mode: 'modern-events' + editor-mode: ${{ matrix.editor-mode }} + prod: ${{ matrix.prod }} + react-override: beta diff --git a/.github/workflows/call-e2e-test.yml b/.github/workflows/call-e2e-test.yml index 48e14617237..84873a376cf 100644 --- a/.github/workflows/call-e2e-test.yml +++ b/.github/workflows/call-e2e-test.yml @@ -9,6 +9,7 @@ on: editor-mode: {required: true, type: string} events-mode: {required: true, type: string} prod: {required: false, type: boolean} + react-override: {required: false, type: string} jobs: e2e-test: @@ -18,6 +19,7 @@ jobs: CI: true E2E_EDITOR_MODE: ${{ inputs.editor-mode }} E2E_EVENTS_MODE: ${{ inputs.events-mode }} + REACT_OVERRIDE: ${{ inputs.react-override }} cache_playwright_path: ${{ inputs.os == 'macos-latest' && '~/Library/Caches/ms-playwright' || inputs.os == 'windows-latest' && 'C:\Users\runneradmin\AppData\Local\ms-playwright' || '~/.cache/ms-playwright' }} test_results_path: ${{ inputs.os == 'windows-latest' && '~/.npm/_logs/' || 'test-results/' }} test_script: test-e2e-${{ inputs.editor-mode == 'rich-text-with-collab' && 'collab-' || '' }}${{ inputs.prod && 'prod-' || '' }}ci-${{ inputs.browser }} @@ -35,6 +37,12 @@ jobs: sudo apt-get install xvfb - name: Install dependencies run: npm ci + - name: Override React ${{ inputs.react-override }} + if: inputs.react-override != '' + # This should be safe since we are caching ~/.npm and not node_modules + run: | + npm i --no-save react@${{ inputs.react-override }} react-dom@${{ inputs.react-override }} + grep version node_modules/{react,react-dom}/package.json - name: Restore playwright from cache uses: actions/cache/restore@v4 id: playwright-cache @@ -55,6 +63,6 @@ jobs: if: failure() uses: actions/upload-artifact@v4 with: - name: Test Results ${{ inputs.os }}-${{ inputs.browser }}-${{ inputs.editor-mode }}-${{ inputs.events-mode }}-${{ inputs.prod && 'prod' || 'dev' }}-${{ inputs.node-version }} + name: Test Results ${{ inputs.os }}-${{ inputs.browser }}-${{ inputs.editor-mode }}-${{ inputs.events-mode }}-${{ inputs.prod && 'prod' || 'dev' }}-${{ inputs.node-version }}-${{ inputs.react-override }} path: ${{ env.test_results_path }} retention-days: 7 From 853dd2eca30a57d83faf0386c1d4dde9ef716754 Mon Sep 17 00:00:00 2001 From: Bob Ippolito Date: Tue, 7 May 2024 09:38:04 -0700 Subject: [PATCH 06/30] Slight changes to docs for React 19 conventions --- packages/lexical-website/docs/concepts/editor-state.md | 8 +++++--- packages/shared/src/useLayoutEffect.ts | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/lexical-website/docs/concepts/editor-state.md b/packages/lexical-website/docs/concepts/editor-state.md index 915eaf9783e..8ddd92bf098 100644 --- a/packages/lexical-website/docs/concepts/editor-state.md +++ b/packages/lexical-website/docs/concepts/editor-state.md @@ -87,17 +87,19 @@ const onSubmit = () => { } ``` -For React it could be something following: +For React it could be something like the following: ```jsx const initialEditorState = await loadContent(); -const editorStateRef = useRef(); +const editorStateRef = useRef(undefined); - editorStateRef.current = editorState} /> + { + editorStateRef.current = editorState; + }} />