diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index e6b4989a24..7f3e04d035 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -11,7 +11,7 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} @@ -32,7 +32,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -42,7 +42,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -95,11 +95,11 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -114,7 +114,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -124,7 +124,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -177,11 +177,11 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -196,7 +196,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -206,7 +206,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -259,11 +259,11 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -278,7 +278,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -288,7 +288,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -341,11 +341,11 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -360,7 +360,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -370,7 +370,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -423,11 +423,11 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -442,7 +442,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -452,7 +452,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -504,11 +504,11 @@ jobs: matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -523,7 +523,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -533,7 +533,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -586,11 +586,11 @@ jobs: matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -605,7 +605,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -615,7 +615,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -668,11 +668,11 @@ jobs: # matrix: # node-version: [18.x] # steps: - # - uses: actions/checkout@v3 + # - uses: actions/checkout@v4 # # node setup # - name: Use Node.js ${{ matrix.node-version }} - # uses: actions/setup-node@v3 + # uses: actions/setup-node@v4 # with: # node-version: ${{ matrix.node-version }} @@ -687,7 +687,7 @@ jobs: # run: | # echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - # - uses: actions/cache@v3 + # - uses: actions/cache@v4 # name: Setup pnpm cache # with: # path: ${{ env.STORE_PATH }} @@ -739,11 +739,11 @@ jobs: matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -758,7 +758,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -768,7 +768,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -822,11 +822,11 @@ jobs: node-version: [18.x] # python-version: [3.7] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -841,7 +841,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -851,7 +851,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -932,11 +932,11 @@ jobs: project-directory: ./my-volto-app steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -951,7 +951,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -961,7 +961,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -1069,11 +1069,11 @@ jobs: matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -1088,7 +1088,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -1098,7 +1098,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} @@ -1140,7 +1140,7 @@ jobs: - uses: actions/upload-artifact@v1 if: failure() with: - name: cypress-videos + name: cypress-videos-seamless path: packages/volto/cypress/videos multilingualseamless: @@ -1153,11 +1153,11 @@ jobs: matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -1172,7 +1172,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -1182,7 +1182,7 @@ jobs: - name: Cache Cypress Binary id: cache-cypress-binary - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/Cypress key: binary-${{ matrix.node-version }}-${{ hashFiles('package-lock.json') }} diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index c6a16acd47..04b8739752 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -12,7 +12,7 @@ jobs: towncrier: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # Fetch all history fetch-depth: '0' diff --git a/.github/workflows/code-analysis.yml b/.github/workflows/code-analysis.yml index cdba0307d1..592bd0cb3e 100644 --- a/.github/workflows/code-analysis.yml +++ b/.github/workflows/code-analysis.yml @@ -10,11 +10,11 @@ jobs: name: Prettier runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ env.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.node-version }} @@ -29,7 +29,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -47,11 +47,11 @@ jobs: name: ESlint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ env.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.node-version }} @@ -66,7 +66,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -87,11 +87,11 @@ jobs: name: Stylelint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ env.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.node-version }} @@ -106,7 +106,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -127,11 +127,11 @@ jobs: name: i18n runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ env.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.node-version }} @@ -146,7 +146,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 08763d2f3a..987ac42c7c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -19,7 +19,7 @@ jobs: matrix: python-version: ['3.10'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 9f2ec8ec26..a9cb936cdc 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -14,11 +14,11 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -33,7 +33,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -64,11 +64,11 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -83,7 +83,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -105,11 +105,11 @@ jobs: matrix: node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} @@ -124,7 +124,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} @@ -141,10 +141,10 @@ jobs: name: '@plone/client' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ env.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.node-version }} @@ -159,7 +159,7 @@ jobs: run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 + - uses: actions/cache@v4 name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} diff --git a/docs/source/upgrade-guide/index.md b/docs/source/upgrade-guide/index.md index a89577132b..06427363f5 100644 --- a/docs/source/upgrade-guide/index.md +++ b/docs/source/upgrade-guide/index.md @@ -28,6 +28,27 @@ Thus it is safe to run it on top of your project and answer the prompts. ## Upgrading to Volto 18.x.x +### Volto runs now on React 18.2.0 + +We have updated Volto to use React 18. +This has been the latest published stable version since June 2022. +This aligns Volto with the latests developments in the React ecosystem and opens the door to up to date software and React features, like client side `Suspense` and others: + +- Concurrent rendering in client (Suspense) +- Automatic batching updates +- Transitions +- New hooks `useId`, `useTransition`, `useDeferredValue`, `useSyncExternalStore`, and other hooks + +### `react-portal` dependency removed + +`react-portal` is deprecated and it was removed from Volto. +The Volto code that relied on it was mainly CMS UI components. +If your project relies on it, either in your code or the shadowed components you may have, you should update to use the standard React API, `createPortal`. +You can update your shadows taking the modified components as templates. +As a last resort, you can install `react-portal` as a dependency of your project. +However, this is discouraged, because the React 18 rendering could have unexpected side effects. +It is recommended that you use the React API instead. + ### ESlint project configuration update `@plone/registry` and [other packages on which Volto depends](https://github.com/plone/volto/tree/main/packages) are now stand-alone releases in the monorepo structure released in 18.0.0-alpha.4. diff --git a/packages/coresandbox/package.json b/packages/coresandbox/package.json index e90e2e480c..aaf007882e 100644 --- a/packages/coresandbox/package.json +++ b/packages/coresandbox/package.json @@ -26,17 +26,17 @@ "react" ], "peerDependencies": { - "react": "17.0.2", - "react-dom": "17.0.2", + "react": "18.2.0", + "react-dom": "18.2.0", "react-intl": "3.8.0", "react-redux": "7.2.4", "semantic-ui-react": "2.0.3" }, "devDependencies": { "@plone/types": "workspace:*", + "@types/react": "^18", + "@types/react-dom": "^18", "@plone/registry": "workspace:*", - "@types/react": "^17.0.52", - "@types/react-dom": "^17", "@types/react-redux": "^7.1.33" } } diff --git a/packages/registry/news/3221.feature b/packages/registry/news/3221.feature new file mode 100644 index 0000000000..3260496e2f --- /dev/null +++ b/packages/registry/news/3221.feature @@ -0,0 +1 @@ +Upgrade Volto core to use React 18.2.0 @sneridagh diff --git a/packages/registry/package.json b/packages/registry/package.json index f25299a8aa..d728d06749 100644 --- a/packages/registry/package.json +++ b/packages/registry/package.json @@ -76,9 +76,11 @@ "@parcel/packager-ts": "2.10.2", "@parcel/transformer-typescript-types": "2.10.2", "@plone/types": "workspace:*", - "@types/react": "^17.0.52", - "@types/react-dom": "^17", + "@types/react": "^18", + "@types/react-dom": "^18", "parcel": "2.10.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", "release-it": "16.2.1", "tsconfig": "workspace:*", "typescript": "5.2.2", diff --git a/packages/types/news/3221.feature b/packages/types/news/3221.feature new file mode 100644 index 0000000000..3260496e2f --- /dev/null +++ b/packages/types/news/3221.feature @@ -0,0 +1 @@ +Upgrade Volto core to use React 18.2.0 @sneridagh diff --git a/packages/types/package.json b/packages/types/package.json index 7520438490..7f0eb8bcec 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -50,10 +50,12 @@ "devDependencies": { "@parcel/packager-ts": "2.10.2", "@parcel/transformer-typescript-types": "2.10.2", - "@types/react": "^17.0.52", - "@types/react-dom": "^17", + "@types/react": "^18", + "@types/react-dom": "^18", "history": "^5.3.0", "parcel": "2.10.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-intl": "3.8.0", "release-it": "16.2.1", "tsconfig": "workspace:*", diff --git a/packages/volto-slate/news/3221.feature b/packages/volto-slate/news/3221.feature new file mode 100644 index 0000000000..3260496e2f --- /dev/null +++ b/packages/volto-slate/news/3221.feature @@ -0,0 +1 @@ +Upgrade Volto core to use React 18.2.0 @sneridagh diff --git a/packages/volto-slate/package.json b/packages/volto-slate/package.json index 8eadc11fee..512bc8818b 100644 --- a/packages/volto-slate/package.json +++ b/packages/volto-slate/package.json @@ -21,9 +21,9 @@ "image-extensions": "1.1.0", "is-url": "1.2.4", "jsdom": "^16.6.0", - "react": "17.0.2", + "react": "18.2.0", "react-intersection-observer": "9.1.0", - "react-dom": "17.0.2", + "react-dom": "18.2.0", "slate": "0.100.0", "slate-history": "0.100.0", "slate-hyperscript": "0.100.0", diff --git a/packages/volto-slate/src/blocks/Text/PluginSidebar.jsx b/packages/volto-slate/src/blocks/Text/PluginSidebar.jsx index 3858e9448f..a5a3185a05 100644 --- a/packages/volto-slate/src/blocks/Text/PluginSidebar.jsx +++ b/packages/volto-slate/src/blocks/Text/PluginSidebar.jsx @@ -1,16 +1,15 @@ import React from 'react'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; const PluginSidebar = ({ children, selected }) => { return ( <> - {selected && ( - - {children} - - )} + {selected && + __CLIENT__ && + createPortal( + <>{children}, + document.getElementById('slate-plugin-sidebar'), + )} ); }; diff --git a/packages/volto-slate/src/blocks/Text/extensions/breakList.js b/packages/volto-slate/src/blocks/Text/extensions/breakList.js index c02e74ec13..b4117a0d8b 100644 --- a/packages/volto-slate/src/blocks/Text/extensions/breakList.js +++ b/packages/volto-slate/src/blocks/Text/extensions/breakList.js @@ -77,8 +77,8 @@ export const breakList = (editor) => { Editor.deleteBackward(editor, { unit: 'line' }); // also account for empty nodes [{text: ''}] if (Editor.isEmpty(editor, parent)) { - Transforms.removeNodes(editor, { at: ref.current }); createAndSelectNewBlockAfter(editor, [createEmptyParagraph()]); + Transforms.removeNodes(editor, { at: ref.current }); return true; } diff --git a/packages/volto-slate/src/blocks/Text/extensions/insertBreak.js b/packages/volto-slate/src/blocks/Text/extensions/insertBreak.js index 258aa7d382..d767c30ab6 100644 --- a/packages/volto-slate/src/blocks/Text/extensions/insertBreak.js +++ b/packages/volto-slate/src/blocks/Text/extensions/insertBreak.js @@ -42,9 +42,9 @@ export const withSplitBlocksOnBreak = (editor) => { // deconstructToVoltoBlocks ReactDOM.unstable_batchedUpdates(() => { const [top, bottom] = splitEditorInTwoFragments(editor); - setEditorContent(editor, top); // ReactEditor.blur(editor); createAndSelectNewBlockAfter(editor, bottom); + setEditorContent(editor, top); }); } return; diff --git a/packages/volto-slate/src/editor/SlateEditor.jsx b/packages/volto-slate/src/editor/SlateEditor.jsx index d59e8b3f4a..fe8457b191 100644 --- a/packages/volto-slate/src/editor/SlateEditor.jsx +++ b/packages/volto-slate/src/editor/SlateEditor.jsx @@ -166,7 +166,14 @@ class SlateEditor extends Component { ReactEditor.focus(editor); Transforms.select(editor, selection); } else { - Transforms.select(editor, Editor.end(editor, [])); + try { + Transforms.select(editor, Editor.end(editor, [])); + } catch (error) { + // Weird error only happening in Cypress + // Adding a try/catch + // eslint-disable-next-line no-console + console.log(error); + } } this.setState({ diff --git a/packages/volto-slate/src/editor/ui/PositionedToolbar.jsx b/packages/volto-slate/src/editor/ui/PositionedToolbar.jsx index 93ab6d27d2..1ea7ab68ce 100644 --- a/packages/volto-slate/src/editor/ui/PositionedToolbar.jsx +++ b/packages/volto-slate/src/editor/ui/PositionedToolbar.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import BasicToolbar from './BasicToolbar'; @@ -20,12 +20,11 @@ const PositionedToolbar = ({ toggleButton, className, children, position }) => { el.style.left = left; }); - return ( - - - {children} - - + return createPortal( + + {children} + , + document.body, ); }; diff --git a/packages/volto-slate/src/editor/ui/Toolbar.jsx b/packages/volto-slate/src/editor/ui/Toolbar.jsx index 2d7406e12f..4e7afc51de 100644 --- a/packages/volto-slate/src/editor/ui/Toolbar.jsx +++ b/packages/volto-slate/src/editor/ui/Toolbar.jsx @@ -1,11 +1,11 @@ import cx from 'classnames'; import React, { useRef, useEffect } from 'react'; -import { Portal } from 'react-portal'; import { useSlate } from 'slate-react'; import Separator from './Separator'; import BasicToolbar from './BasicToolbar'; import { Editor, Node } from 'slate'; import { ReactEditor } from 'slate-react'; +import { createPortal } from 'react-dom'; const Toolbar = ({ elementType, @@ -82,21 +82,20 @@ const Toolbar = ({ )}px`; }); - return ( - - - {children} - {enableExpando && toggleButton && ( - <> - - {toggleButton} - - )} - - + return createPortal( + + {children} + {enableExpando && toggleButton && ( + <> + + {toggleButton} + + )} + , + document.body, ); }; diff --git a/packages/volto/cypress/tests/core/basic/folder-contents.js b/packages/volto/cypress/tests/core/basic/folder-contents.js index 71dcaf9306..6efb50fe7e 100644 --- a/packages/volto/cypress/tests/core/basic/folder-contents.js +++ b/packages/volto/cypress/tests/core/basic/folder-contents.js @@ -130,25 +130,23 @@ describe('Folder Contents Tests', () => { }); it('Move items to top of folder and bottom of folder', () => { + cy.intercept('GET', `/**/@search*`).as('search'); + cy.intercept('PATCH', `/**/my-folder`).as('reorder'); // creating a Document - cy.createContent({ - contentType: 'Document', - contentId: 'child', - contentTitle: 'My Child', - path: 'my-folder', - }); - - // doing copy paste for dummy data - cy.get('svg[class="icon unchecked"]').click(); - cy.get('svg[class="icon copy"]').click(); var genArr = Array.from({ length: 56 }, (v, k) => k + 1); - cy.wrap(genArr).each((index) => { - cy.get('svg[class="icon paste"]').click({ force: true }); + genArr.forEach((item) => { + cy.createContent({ + contentType: 'Document', + contentTitle: 'My Child', + path: 'my-folder', + }); }); - cy.wait(2000); // just for clearing of toast // after adding 56 page I need to add a final page to move around. // when I add a page + cy.visit('/my-folder'); + cy.wait('@content'); + cy.get('#toolbar-add').click(); cy.get('#toolbar-add-document').click(); cy.getSlateTitle() @@ -159,6 +157,7 @@ describe('Folder Contents Tests', () => { // then a new page has been created cy.get('#toolbar-save').click(); + cy.wait('@content'); cy.url().should( 'eq', Cypress.config().baseUrl + '/my-folder/last-and-first-page', @@ -171,7 +170,7 @@ describe('Folder Contents Tests', () => { ).click(); cy.findByText('Move to top of folder').click(); cy.url().should('eq', Cypress.config().baseUrl + '/my-folder/contents'); - cy.wait(1000); // waiting for settling of odering or search return + cy.wait('@reorder'); // Checking if move to top of folder works or not. cy.get('table tbody tr:first-child a span').findByText( @@ -181,6 +180,7 @@ describe('Folder Contents Tests', () => { 'tr[aria-label="/my-folder/last-and-first-page"] svg[class="icon dropdown-popup-trigger"]', ).click(); cy.findByText('Move to bottom of folder').click(); + cy.wait('@reorder'); // Checking whether moving to bottom of folder works or not. cy.get('.contents-pagination .menu').findByText('2').click(); @@ -195,7 +195,8 @@ describe('Folder Contents Tests', () => { cy.get( 'tr[aria-label="/my-folder/last-and-first-page"] svg[class="icon dropdown-popup-trigger"]', ).click(); - // cy.intercept('GET', '/plone/++api++/my-folder/@search').as('getSearch'); // I don't know proper way to wait + cy.wait('@search'); + cy.findByText('Move to top of folder').click(); cy.get('.search.item button').click(); @@ -207,6 +208,8 @@ describe('Folder Contents Tests', () => { 'tr[aria-label="/my-folder/last-and-first-page"] svg[class="icon dropdown-popup-trigger"]', ).click(); cy.findByText('Move to bottom of folder').click(); + cy.wait('@reorder'); + cy.get('.contents-pagination .menu').findByText('2').click(); // Checking whether moving to bottom of folder works or not. diff --git a/packages/volto/cypress/tests/core/blocks/blocks-autofocus.js b/packages/volto/cypress/tests/core/blocks/blocks-autofocus.js index fed851ad51..ef48d8f8bb 100644 --- a/packages/volto/cypress/tests/core/blocks/blocks-autofocus.js +++ b/packages/volto/cypress/tests/core/blocks/blocks-autofocus.js @@ -1,7 +1,7 @@ describe('New Block Auto Focus Tests', () => { beforeEach(() => { - cy.intercept('GET', `/**/*?expand*`).as('content'); cy.intercept('GET', '/**/my-page').as('content'); + cy.intercept('GET', '/**/Document').as('schema'); cy.intercept('PATCH', '*').as('save'); // given a logged in editor and a page in edit mode @@ -15,12 +15,17 @@ describe('New Block Auto Focus Tests', () => { cy.visit('/my-page'); cy.wait('@content'); + cy.wait(500); + cy.navigate('/my-page/edit'); + cy.wait('@schema'); }); it('Press Enter on a description block adds new autofocused default block', () => { cy.addNewBlock('description'); cy.get('.documentDescription').first().click().type('{enter}'); + cy.get('.block-editor-description + .block-editor-slate'); + cy.wait(500); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { @@ -34,6 +39,8 @@ describe('New Block Auto Focus Tests', () => { cy.get('.blocks-chooser .title').contains('Text').click({ force: true }); cy.get('.blocks-chooser .text').contains('Text').click({ force: true }); cy.get('.text-slate-editor-inner').first().click().type('{enter}'); + cy.wait(500); + cy.get('.block-editor-slate + .block-editor-slate'); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { @@ -43,7 +50,15 @@ describe('New Block Auto Focus Tests', () => { it('Press Enter on a image block adds new autofocused default block', () => { cy.addNewBlock('image'); - cy.get('.block-editor-image').first().click().type('{enter}'); + // Timing issues ahead :( + cy.get('.block-editor-image .no-image-wrapper img') + .should('be.visible') + .and(($img) => { + // "naturalWidth" and "naturalHeight" are set when the image loads + expect($img[0].naturalWidth).to.be.greaterThan(0); + }); + cy.get('.block-editor-image').wait(500).click('topLeft').type('{enter}'); + cy.wait(500); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { @@ -53,7 +68,15 @@ describe('New Block Auto Focus Tests', () => { it('Press Enter on a video block adds new autofocused default block', () => { cy.addNewBlock('video'); + cy.get('.block-editor-video .message img') + .should('be.visible') + .and(($img) => { + // "naturalWidth" and "naturalHeight" are set when the image loads + expect($img[0].naturalWidth).to.be.greaterThan(0); + }); cy.get('.block-editor-video').first().click().type('{enter}'); + cy.get('.block-editor-slate + .block-editor-slate'); + cy.wait(500); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { @@ -64,6 +87,7 @@ describe('New Block Auto Focus Tests', () => { it('Press Enter on a listing block adds new autofocused default block', () => { cy.addNewBlock('listing'); cy.get('.block-editor-listing').first().click().type('{enter}'); + cy.wait(500); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { @@ -74,6 +98,7 @@ describe('New Block Auto Focus Tests', () => { it('Press Enter on a table of contents block adds new autofocused default block', () => { cy.addNewBlock('contents'); cy.get('.block-editor-toc').first().click().type('{enter}'); + cy.wait(500); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { @@ -83,7 +108,14 @@ describe('New Block Auto Focus Tests', () => { it('Press Enter on a maps block adds new autofocused default block', () => { cy.addNewBlock('maps'); + cy.get('.block-editor-maps .message img') + .should('be.visible') + .and(($img) => { + // "naturalWidth" and "naturalHeight" are set when the image loads + expect($img[0].naturalWidth).to.be.greaterThan(0); + }); cy.get('.block-editor-maps').first().click().type('{enter}'); + cy.wait(500); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { @@ -94,6 +126,7 @@ describe('New Block Auto Focus Tests', () => { it('Press Enter on a html block adds new autofocused default block', () => { cy.addNewBlock('html'); cy.get('.block-editor-html').first().click().type('{enter}'); + cy.wait(500); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { @@ -104,6 +137,7 @@ describe('New Block Auto Focus Tests', () => { it('Press Enter on a search block adds new autofocused default block', () => { cy.addNewBlock('search'); cy.get('.block-editor-search').first().click().type('{enter}'); + cy.wait(500); cy.get('*[class^="block-editor"]') .eq(2) .within(() => { diff --git a/packages/volto/cypress/tests/core/blocks/blocks-image.js b/packages/volto/cypress/tests/core/blocks/blocks-image.js index e96bb1dd21..9b76682372 100644 --- a/packages/volto/cypress/tests/core/blocks/blocks-image.js +++ b/packages/volto/cypress/tests/core/blocks/blocks-image.js @@ -15,6 +15,8 @@ describe('Blocks Tests', () => { cy.visit('/my-page'); cy.wait('@content'); + cy.wait(500); + cy.navigate('/my-page/edit'); cy.wait('@schema'); }); @@ -156,7 +158,7 @@ describe('Blocks Tests', () => { }); }); - it('Create an image block and initially alt attr is empty', () => { + it.only('Create an image block and initially alt attr is empty', () => { // when I add an image block via upload cy.get('.content-area .slate-editor [contenteditable=true]', { timeout: 10000, diff --git a/packages/volto/cypress/tests/core/blocks/listing/blocks-listing.js b/packages/volto/cypress/tests/core/blocks/listing/blocks-listing.js index cc4f5e13d8..ab7c82bfcf 100644 --- a/packages/volto/cypress/tests/core/blocks/listing/blocks-listing.js +++ b/packages/volto/cypress/tests/core/blocks/listing/blocks-listing.js @@ -445,7 +445,9 @@ describe('Listing Block Tests', () => { //add listing block cy.scrollTo('bottom'); - cy.addNewBlock('listing', true); + cy.getSlate().click(); + cy.get('.ui.basic.icon.button.block-add-button').click(); + cy.get('.ui.basic.icon.button.listing').contains('Listing').click(); //******** add Page Type criteria filter cy.configureListingWith('Page'); diff --git a/packages/volto/cypress/tests/core/controlpanels/dexterity-controlpanel-layout.js b/packages/volto/cypress/tests/core/controlpanels/dexterity-controlpanel-layout.js index 35a24d1b65..20b1a097e6 100644 --- a/packages/volto/cypress/tests/core/controlpanels/dexterity-controlpanel-layout.js +++ b/packages/volto/cypress/tests/core/controlpanels/dexterity-controlpanel-layout.js @@ -21,7 +21,7 @@ describe('ControlPanel: Dexterity Content-Types Layout', () => { 'Book', ); - cy.visit('/controlpanel/dexterity-types/book/layout'); + cy.navigate('/controlpanel/dexterity-types/book/layout'); cy.get('#page-controlpanel-layout').contains( 'Can not edit Layout for Book', ); diff --git a/packages/volto/jest-setup-afterenv.js b/packages/volto/jest-setup-afterenv.js new file mode 100644 index 0000000000..8c79262657 --- /dev/null +++ b/packages/volto/jest-setup-afterenv.js @@ -0,0 +1,2 @@ +// Jest-crap setup after env T_T +import '@testing-library/jest-dom'; diff --git a/packages/volto/news/3221.breaking b/packages/volto/news/3221.breaking new file mode 100644 index 0000000000..3260496e2f --- /dev/null +++ b/packages/volto/news/3221.breaking @@ -0,0 +1 @@ +Upgrade Volto core to use React 18.2.0 @sneridagh diff --git a/packages/volto/package.json b/packages/volto/package.json index 582e195212..8529184635 100644 --- a/packages/volto/package.json +++ b/packages/volto/package.json @@ -110,6 +110,9 @@ "./test-setup-config.js" ], "globalSetup": "./global-test-setup.js", + "setupFilesAfterEnv": [ + "/jest-setup-afterenv.js" + ], "globals": { "__DEV__": true }, @@ -276,7 +279,7 @@ "razzle-dev-utils": "4.2.18", "razzle-plugin-scss": "4.2.18", "rc-time-picker": "3.7.3", - "react": "17.0.2", + "react": "18.2.0", "react-anchor-link-smooth-scroll": "1.0.12", "react-animate-height": "2.0.17", "react-beautiful-dnd": "13.0.0", @@ -285,17 +288,16 @@ "react-detect-click-outside": "1.1.1", "react-dnd": "5.0.0", "react-dnd-html5-backend": "5.0.1", - "react-dom": "17.0.2", + "react-dom": "18.2.0", "react-dropzone": "11.1.0", "react-fast-compare": "2.0.4", "react-image-gallery": "1.2.7", "react-intersection-observer": "9.1.0", "react-intl": "3.8.0", - "react-intl-redux": "2.2.0", + "react-intl-redux": "2.3.0", "react-medium-image-zoom": "3.0.15", "react-popper": "^2.3.0", - "react-portal": "4.2.1", - "react-redux": "7.2.4", + "react-redux": "8.1.2", "react-router": "5.2.0", "react-router-config": "5.1.1", "react-router-dom": "5.2.0", @@ -303,21 +305,21 @@ "react-select": "4.3.1", "react-select-async-paginate": "0.5.3", "react-share": "2.3.1", - "react-side-effect": "2.1.0", + "react-side-effect": "2.1.2", "react-simple-code-editor": "0.7.1", "react-sortable-hoc": "2.0.0", - "react-test-renderer": "17.0.2", + "react-test-renderer": "18.2.0", "react-toastify": "5.4.1", "react-transition-group": "4.4.5", "react-virtualized": "9.22.3", "redraft": "0.10.2", - "redux": "4.1.0", - "redux-actions": "2.6.5", + "redux": "4.2.1", + "redux-actions": "3.0.0", "redux-connect": "10.0.0", - "redux-devtools-extension": "2.13.8", - "redux-localstorage-simple": "2.3.1", + "redux-devtools-extension": "2.13.9", + "redux-localstorage-simple": "2.5.1", "redux-mock-store": "1.5.4", - "redux-thunk": "2.3.0", + "redux-thunk": "2.4.2", "rrule": "2.7.1", "semantic-ui-less": "2.4.1", "semantic-ui-react": "2.1.5", @@ -362,13 +364,15 @@ "@storybook/manager-webpack5": "^6.5.15", "@storybook/react": "^6.5.15", "@testing-library/cypress": "9.0.0", - "@testing-library/jest-dom": "5.16.4", - "@testing-library/react": "12.1.5", + "@testing-library/jest-dom": "6.4.1", + "@testing-library/react": "14.2.0", "@testing-library/react-hooks": "8.0.1", "@types/jest": "^29.5.8", "@types/lodash": "^4.14.201", + "@types/react": "^18", + "@types/react-dom": "^18", "@types/react-router-dom": "^5.3.3", - "@types/react-test-renderer": "18.0.1", + "@types/react-test-renderer": "18.0.7", "@types/uuid": "^9.0.2", "@typescript-eslint/eslint-plugin": "6.7.0", "@typescript-eslint/parser": "6.7.0", @@ -385,7 +389,7 @@ "jsonwebtoken": "9.0.0", "react-docgen-typescript-plugin": "^1.0.5", "react-error-overlay": "6.0.9", - "react-is": "^16.13.1", + "react-is": "^18.2.0", "release-it": "^16.2.1", "semver": "^7.5.4", "tmp": "0.2.1", diff --git a/packages/volto/src/components/manage/Add/Add.jsx b/packages/volto/src/components/manage/Add/Add.jsx index d1c14bee17..c16b41e2d7 100644 --- a/packages/volto/src/components/manage/Add/Add.jsx +++ b/packages/volto/src/components/manage/Add/Add.jsx @@ -11,7 +11,7 @@ import { compose } from 'redux'; import { keys, isEmpty } from 'lodash'; import { defineMessages, injectIntl } from 'react-intl'; import { Button, Grid, Menu } from 'semantic-ui-react'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { v4 as uuid } from 'uuid'; import qs from 'query-string'; import { toast } from 'react-toastify'; @@ -366,8 +366,8 @@ class Add extends Component { }} global /> - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} - {visual && this.state.isClient && ( - - - - )} + />, + document.getElementById('toolbar'), + )} + {visual && + this.state.isClient && + createPortal(, document.getElementById('sidebar'))} ); diff --git a/packages/volto/src/components/manage/Add/Add.test.jsx b/packages/volto/src/components/manage/Add/Add.test.jsx index 2a1ee56192..4d6500e885 100644 --- a/packages/volto/src/components/manage/Add/Add.test.jsx +++ b/packages/volto/src/components/manage/Add/Add.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; import config from '@plone/volto/registry'; @@ -16,9 +16,8 @@ beforeAll(() => { config.settings.loadables = {}; }); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); + jest.mock('../Form/Form', () => jest.fn(() =>
)); describe('Add', () => { @@ -39,13 +38,12 @@ describe('Add', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( , ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + expect(container).toMatchSnapshot(); }); it('renders an add component', () => { @@ -67,13 +65,13 @@ describe('Add', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( , ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); it('renders an add component with schema', () => { @@ -106,12 +104,12 @@ describe('Add', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( , ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Add/__snapshots__/Add.test.jsx.snap b/packages/volto/src/components/manage/Add/__snapshots__/Add.test.jsx.snap index 00ad89f369..e0b4e6d306 100644 --- a/packages/volto/src/components/manage/Add/__snapshots__/Add.test.jsx.snap +++ b/packages/volto/src/components/manage/Add/__snapshots__/Add.test.jsx.snap @@ -1,7 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Add renders an add component 1`] = `
`; +exports[`Add renders an add component 1`] = ` +
+
+
+`; -exports[`Add renders an add component with schema 1`] = `
`; +exports[`Add renders an add component with schema 1`] = ` +
+
+
+`; -exports[`Add renders an empty add component 1`] = `
`; +exports[`Add renders an empty add component 1`] = ` +
+
+
+`; diff --git a/packages/volto/src/components/manage/Aliases/Aliases.jsx b/packages/volto/src/components/manage/Aliases/Aliases.jsx index 7554a9f20f..15af7a0326 100644 --- a/packages/volto/src/components/manage/Aliases/Aliases.jsx +++ b/packages/volto/src/components/manage/Aliases/Aliases.jsx @@ -8,7 +8,7 @@ import { Helmet } from '@plone/volto/helpers'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { Link } from 'react-router-dom'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { Button, Checkbox, @@ -317,8 +317,8 @@ class Aliases extends Component { - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )} ); } diff --git a/packages/volto/src/components/manage/Aliases/Aliases.test.jsx b/packages/volto/src/components/manage/Aliases/Aliases.test.jsx index 31350c8d94..3ded78f739 100644 --- a/packages/volto/src/components/manage/Aliases/Aliases.test.jsx +++ b/packages/volto/src/components/manage/Aliases/Aliases.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import { Provider } from 'react-intl-redux'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; @@ -9,9 +9,8 @@ import Aliases from './Aliases'; const middlewares = [thunk]; const mockStore = configureMockStore(middlewares); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); + jest.mock('../Toolbar/More', () => jest.fn(() =>
)); describe('Aliases', () => { @@ -45,12 +44,13 @@ describe('Aliases', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Aliases/__snapshots__/Aliases.test.jsx.snap b/packages/volto/src/components/manage/Aliases/__snapshots__/Aliases.test.jsx.snap index 85b8d5c307..5bfa3e94a7 100644 --- a/packages/volto/src/components/manage/Aliases/__snapshots__/Aliases.test.jsx.snap +++ b/packages/volto/src/components/manage/Aliases/__snapshots__/Aliases.test.jsx.snap @@ -1,96 +1,97 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Aliases renders aliases object control 1`] = ` -
+
- URL Management for - - Blog - -
-
- Using this form, you can manage alternative urls for an item. This is an easy way to make an item available under two different URLs. -
-
+ URL Management for + + Blog + +
+
+ Using this form, you can manage alternative urls for an item. This is an easy way to make an item available under two different URLs. +
+
- Add a new alternative url -
-

- Enter the absolute path where the alternative url should exist. The path must start with '/'. Only urls that result in a 404 not found page will result in a redirect occurring. -

-
- + Add a new alternative url
+

+ Enter the absolute path where the alternative url should exist. The path must start with '/'. Only urls that result in a 404 not found page will result in a redirect occurring. +

+
+
+ +
+
+
- -
- -
-
+
- Existing alternative urls for this item +
+ Existing alternative urls for this item +
+
- -
-
+ +
+ id="toolbar" + > +
+
`; diff --git a/packages/volto/src/components/manage/BlockChooser/BlockChooser.test.jsx b/packages/volto/src/components/manage/BlockChooser/BlockChooser.test.jsx index 22fd5b5f48..447c20f61d 100644 --- a/packages/volto/src/components/manage/BlockChooser/BlockChooser.test.jsx +++ b/packages/volto/src/components/manage/BlockChooser/BlockChooser.test.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import '@testing-library/jest-dom/extend-expect'; import { render, screen } from '@testing-library/react'; import { Provider } from 'react-intl-redux'; import configureStore from 'redux-mock-store'; diff --git a/packages/volto/src/components/manage/BlockChooser/BlockChooserButton.jsx b/packages/volto/src/components/manage/BlockChooser/BlockChooserButton.jsx index d52389492d..136b413b70 100644 --- a/packages/volto/src/components/manage/BlockChooser/BlockChooserButton.jsx +++ b/packages/volto/src/components/manage/BlockChooser/BlockChooserButton.jsx @@ -7,7 +7,7 @@ import config from '@plone/volto/registry'; import { Button, Ref } from 'semantic-ui-react'; import { defineMessages, useIntl } from 'react-intl'; import { usePopper } from 'react-popper'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; const messages = defineMessages({ addBlock: { @@ -115,8 +115,8 @@ const BlockChooserButton = (props) => { /> )} - {addNewBlockOpened && ( - + {addNewBlockOpened && + createPortal(
{ navRoot={navRoot} contentType={contentType} /> -
-
- )} +
, + document.body, + )} ); }; diff --git a/packages/volto/src/components/manage/BlockChooser/BlockChooserSearch.test.jsx b/packages/volto/src/components/manage/BlockChooser/BlockChooserSearch.test.jsx index 7176bdda06..2bc70ced70 100644 --- a/packages/volto/src/components/manage/BlockChooser/BlockChooserSearch.test.jsx +++ b/packages/volto/src/components/manage/BlockChooser/BlockChooserSearch.test.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import '@testing-library/jest-dom/extend-expect'; import { render } from '@testing-library/react'; import BlockChooserSearch from './BlockChooserSearch'; import { Provider } from 'react-intl-redux'; diff --git a/packages/volto/src/components/manage/BlockChooser/__snapshots__/BlockChooser.test.jsx.snap b/packages/volto/src/components/manage/BlockChooser/__snapshots__/BlockChooser.test.jsx.snap index d61323c068..b0f6bc9a54 100644 --- a/packages/volto/src/components/manage/BlockChooser/__snapshots__/BlockChooser.test.jsx.snap +++ b/packages/volto/src/components/manage/BlockChooser/__snapshots__/BlockChooser.test.jsx.snap @@ -26,7 +26,6 @@ exports[`BlocksChooser Fallback BlockChooser component onMutateBlock 1`] = ` value="" />
-
Image -
Listing -
Video -
@@ -142,7 +138,6 @@ exports[`BlocksChooser Fallback BlockChooser component onMutateBlock 1`] = ` style="height: 36px; width: auto; fill: currentColor;" /> Text -
@@ -186,7 +181,6 @@ exports[`BlocksChooser Fallback BlockChooser component onMutateBlock 1`] = ` style="height: 36px; width: auto; fill: currentColor;" /> Image -
Lead Image Field -
Video -
@@ -258,7 +250,6 @@ exports[`BlocksChooser Fallback BlockChooser component onMutateBlock 1`] = ` style="height: 36px; width: auto; fill: currentColor;" /> Listing -
Table of Contents -
Hero -
Maps -
HTML -
Table -
@@ -365,7 +351,6 @@ exports[`BlocksChooser renders a BlockChooser component 1`] = ` value="" />
-
Image -
Listing -
Video -
@@ -481,7 +463,6 @@ exports[`BlocksChooser renders a BlockChooser component 1`] = ` style="height: 36px; width: auto; fill: currentColor;" /> Text - @@ -525,7 +506,6 @@ exports[`BlocksChooser renders a BlockChooser component 1`] = ` style="height: 36px; width: auto; fill: currentColor;" /> Image -
Lead Image Field -
Video -
@@ -597,7 +575,6 @@ exports[`BlocksChooser renders a BlockChooser component 1`] = ` style="height: 36px; width: auto; fill: currentColor;" /> Listing -
Table of Contents -
Hero -
Maps -
HTML -
Table -
diff --git a/packages/volto/src/components/manage/Blocks/Block/Settings.test.jsx b/packages/volto/src/components/manage/Blocks/Block/Settings.test.jsx index 57b7ea90ca..8cc2a7f301 100644 --- a/packages/volto/src/components/manage/Blocks/Block/Settings.test.jsx +++ b/packages/volto/src/components/manage/Blocks/Block/Settings.test.jsx @@ -1,7 +1,6 @@ import React from 'react'; import Settings from './Settings'; import { render } from '@testing-library/react'; -import '@testing-library/jest-dom/extend-expect'; import configureStore from 'redux-mock-store'; import config from '@plone/volto/registry'; import { Provider } from 'react-intl-redux'; diff --git a/packages/volto/src/components/manage/Blocks/Container/NewBlockAddButton.jsx b/packages/volto/src/components/manage/Blocks/Container/NewBlockAddButton.jsx index 89076a0560..713f518e22 100644 --- a/packages/volto/src/components/manage/Blocks/Container/NewBlockAddButton.jsx +++ b/packages/volto/src/components/manage/Blocks/Container/NewBlockAddButton.jsx @@ -5,7 +5,7 @@ import { BlockChooser, Icon } from '@plone/volto/components'; import { useDetectClickOutside } from '@plone/volto/helpers'; import addSVG from '@plone/volto/icons/add.svg'; import { usePopper } from 'react-popper'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; const messages = defineMessages({ addBlock: { @@ -59,24 +59,25 @@ const NewBlockAddButton = (props) => { - {isOpenMenu ? ( - -
- -
-
- ) : null} + {isOpenMenu + ? createPortal( +
+ +
, + document.body, + ) + : null} ); }; diff --git a/packages/volto/src/components/manage/Blocks/Image/View.test.jsx b/packages/volto/src/components/manage/Blocks/Image/View.test.jsx index fb073c2f21..81aac59bfd 100644 --- a/packages/volto/src/components/manage/Blocks/Image/View.test.jsx +++ b/packages/volto/src/components/manage/Blocks/Image/View.test.jsx @@ -1,5 +1,4 @@ import React from 'react'; -import '@testing-library/jest-dom/extend-expect'; import { render } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; import { Provider } from 'react-intl-redux'; diff --git a/packages/volto/src/components/manage/Blocks/Table/Edit.jsx b/packages/volto/src/components/manage/Blocks/Table/Edit.jsx index dee0234118..2f00b4ba77 100644 --- a/packages/volto/src/components/manage/Blocks/Table/Edit.jsx +++ b/packages/volto/src/components/manage/Blocks/Table/Edit.jsx @@ -8,7 +8,7 @@ import PropTypes from 'prop-types'; import { compose } from 'redux'; import { map, remove } from 'lodash'; import { Button, Segment, Table, Form } from 'semantic-ui-react'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import cx from 'classnames'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; @@ -670,8 +670,9 @@ class Edit extends Component { )} - {this.props.selected && this.state.isClient && ( - + {this.props.selected && + this.state.isClient && + createPortal(
{ @@ -736,9 +737,9 @@ class Edit extends Component { onChange={this.toggleCellType} /> -
-
- )} + , + document.getElementById('sidebar-properties'), + )} ); } diff --git a/packages/volto/src/components/manage/Blocks/ToC/variations/__snapshots__/DefaultTocRenderer.test.jsx.snap b/packages/volto/src/components/manage/Blocks/ToC/variations/__snapshots__/DefaultTocRenderer.test.jsx.snap index 59f2bde9df..b1037d169f 100644 --- a/packages/volto/src/components/manage/Blocks/ToC/variations/__snapshots__/DefaultTocRenderer.test.jsx.snap +++ b/packages/volto/src/components/manage/Blocks/ToC/variations/__snapshots__/DefaultTocRenderer.test.jsx.snap @@ -1,47 +1,44 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders a default toc renderer component 1`] = ` -Array [ - "", - + + `; diff --git a/packages/volto/src/components/manage/Contents/Contents.jsx b/packages/volto/src/components/manage/Contents/Contents.jsx index c462592977..66805cabdb 100644 --- a/packages/volto/src/components/manage/Contents/Contents.jsx +++ b/packages/volto/src/components/manage/Contents/Contents.jsx @@ -7,7 +7,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { compose } from 'redux'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { Link } from 'react-router-dom'; import { Button, @@ -2159,8 +2159,8 @@ class Contents extends Component { - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )} ) : ( diff --git a/packages/volto/src/components/manage/Contents/Contents.test.jsx b/packages/volto/src/components/manage/Contents/Contents.test.jsx index 48f01c1562..87982d36d4 100644 --- a/packages/volto/src/components/manage/Contents/Contents.test.jsx +++ b/packages/volto/src/components/manage/Contents/Contents.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; import { MemoryRouter } from 'react-router-dom'; @@ -14,9 +14,8 @@ beforeAll( await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(), ); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); + jest.mock('../../theme/Pagination/Pagination', () => jest.fn(() =>
), ); @@ -91,14 +90,15 @@ describe('Contents', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Contents/ContentsPropertiesModal.test.jsx b/packages/volto/src/components/manage/Contents/ContentsPropertiesModal.test.jsx index dd4a2b65bf..126e695026 100644 --- a/packages/volto/src/components/manage/Contents/ContentsPropertiesModal.test.jsx +++ b/packages/volto/src/components/manage/Contents/ContentsPropertiesModal.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; @@ -23,7 +23,7 @@ describe('ContentsPropertiesModal', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( { /> , ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Contents/__snapshots__/Contents.test.jsx.snap b/packages/volto/src/components/manage/Contents/__snapshots__/Contents.test.jsx.snap index a348d4c3db..2c6dd5c65f 100644 --- a/packages/volto/src/components/manage/Contents/__snapshots__/Contents.test.jsx.snap +++ b/packages/volto/src/components/manage/Contents/__snapshots__/Contents.test.jsx.snap @@ -1,1067 +1,600 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Contents renders a folder contents view component 1`] = ` -
+
- Loading +
+ Loading +
-
-
-
-
-
+
- -
-
- - - - -
-
- - - - -
- -
-
- - Home - + + + + +
- +
-
-
- - - - - - - - - - -
- - - - - Title - - Actions -
-
-
+ + + + + + + + Title + + + Actions + + + + + +
+ class="contents-pagination" + > +
-
-
-
+ + +
+
+
diff --git a/packages/volto/src/components/manage/Contents/__snapshots__/ContentsPropertiesModal.test.jsx.snap b/packages/volto/src/components/manage/Contents/__snapshots__/ContentsPropertiesModal.test.jsx.snap index 3c382ace86..c460a95329 100644 --- a/packages/volto/src/components/manage/Contents/__snapshots__/ContentsPropertiesModal.test.jsx.snap +++ b/packages/volto/src/components/manage/Contents/__snapshots__/ContentsPropertiesModal.test.jsx.snap @@ -1,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ContentsPropertiesModal renders a contents properties modal component 1`] = ` -
+
+
+
`; diff --git a/packages/volto/src/components/manage/Controlpanels/AddonsControlpanel.jsx b/packages/volto/src/components/manage/Controlpanels/AddonsControlpanel.jsx index 1248c90cbf..66e1bc7a06 100644 --- a/packages/volto/src/components/manage/Controlpanels/AddonsControlpanel.jsx +++ b/packages/volto/src/components/manage/Controlpanels/AddonsControlpanel.jsx @@ -7,7 +7,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { Link } from 'react-router-dom'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { Accordion, Button, @@ -550,8 +550,8 @@ class AddonsControlpanel extends Component { )} - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )} ); } diff --git a/packages/volto/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx b/packages/volto/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx index 460b69f85e..67ce84f2ac 100644 --- a/packages/volto/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/AddonsControlpanel.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; @@ -7,9 +7,7 @@ import AddonsControlpanel from './AddonsControlpanel'; const mockStore = configureStore(); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); describe('AddonsControlpanel', () => { it('renders an addon control component', () => { @@ -57,12 +55,13 @@ describe('AddonsControlpanel', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Controlpanels/Aliases.jsx b/packages/volto/src/components/manage/Controlpanels/Aliases.jsx index 6a927d7ae5..6b985ea3d3 100644 --- a/packages/volto/src/components/manage/Controlpanels/Aliases.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Aliases.jsx @@ -10,7 +10,7 @@ import { compose } from 'redux'; import { Link } from 'react-router-dom'; import { getBaseUrl, getParentUrl, Helmet } from '@plone/volto/helpers'; import { removeAliases, addAliases, getAliases } from '@plone/volto/actions'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { Container, Button, @@ -652,8 +652,8 @@ class Aliases extends Component { - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )}
); } diff --git a/packages/volto/src/components/manage/Controlpanels/Aliases.test.jsx b/packages/volto/src/components/manage/Controlpanels/Aliases.test.jsx index 661611753f..c6a9a18010 100644 --- a/packages/volto/src/components/manage/Controlpanels/Aliases.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Aliases.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import { Provider } from 'react-intl-redux'; @@ -10,9 +10,7 @@ import { MemoryRouter } from 'react-router'; const middlewares = [thunk]; const mockStore = configureMockStore(middlewares); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); describe('Aliases', () => { it('renders an aliases control component', () => { @@ -59,14 +57,15 @@ describe('Aliases', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Controlpanels/ContentType.jsx b/packages/volto/src/components/manage/Controlpanels/ContentType.jsx index 097dd488ff..6b8edbb9e6 100644 --- a/packages/volto/src/components/manage/Controlpanels/ContentType.jsx +++ b/packages/volto/src/components/manage/Controlpanels/ContentType.jsx @@ -8,7 +8,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { getParentUrl } from '@plone/volto/helpers'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { Button, Header } from 'semantic-ui-react'; import { defineMessages, injectIntl } from 'react-intl'; import { toast } from 'react-toastify'; @@ -210,8 +210,8 @@ class ContentType extends Component { hideActions loading={this.props.cpanelRequest.update.loading} /> - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )}
); } diff --git a/packages/volto/src/components/manage/Controlpanels/ContentType.test.jsx b/packages/volto/src/components/manage/Controlpanels/ContentType.test.jsx index 63aa9fcd68..159c303936 100644 --- a/packages/volto/src/components/manage/Controlpanels/ContentType.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/ContentType.test.jsx @@ -1,16 +1,14 @@ import React from 'react'; -import renderer from 'react-test-renderer'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; import { MemoryRouter, Route } from 'react-router-dom'; +import { render } from '@testing-library/react'; import ContentType from './ContentType'; const mockStore = configureStore(); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); jest.mock('../Form/Form', () => jest.fn(() =>
)); describe('ContentType', () => { @@ -35,7 +33,8 @@ describe('ContentType', () => { messages: {}, }, }); - const component = renderer.create( + + const { container } = render( { path={'/controlpanel/dexterity-types/:id'} component={ContentType} /> +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Controlpanels/ContentTypeLayout.jsx b/packages/volto/src/components/manage/Controlpanels/ContentTypeLayout.jsx index b2754d90ba..3e5cd1a388 100644 --- a/packages/volto/src/components/manage/Controlpanels/ContentTypeLayout.jsx +++ b/packages/volto/src/components/manage/Controlpanels/ContentTypeLayout.jsx @@ -14,7 +14,7 @@ import { getBlocksFieldname, getBlocksLayoutFieldname, } from '@plone/volto/helpers'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { Button, Segment } from 'semantic-ui-react'; import { toast } from 'react-toastify'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; @@ -343,26 +343,30 @@ class ContentTypeLayout extends Component { content={this.props.intl.formatMessage(messages.enable)} /> - - - this.onCancel()}> - - - - } - /> - + {this.state.isClient && + createPortal( + + this.onCancel()} + > + + + + } + />, + document.getElementById('toolbar'), + )} ); } @@ -392,26 +396,30 @@ class ContentTypeLayout extends Component { content={this.props.intl.formatMessage(messages.enable)} /> - - - this.onCancel()}> - - - - } - /> - + {this.state.isClient && + createPortal( + + this.onCancel()} + > + + + + } + />, + document.getElementById('toolbar'), + )} ); } @@ -449,50 +457,50 @@ class ContentTypeLayout extends Component { visual={this.state.visual} hideActions /> - - - - - - - - - } - /> - + {this.state.isClient && + createPortal( + , + document.getElementById('sidebar'), + )} + {this.state.isClient && + createPortal( + + + + + } + />, + document.getElementById('toolbar'), + )}
); } diff --git a/packages/volto/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx b/packages/volto/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx index 70127b8477..aee7d78ec6 100644 --- a/packages/volto/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/ContentTypeLayout.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; import { MemoryRouter, Route } from 'react-router-dom'; @@ -8,9 +8,8 @@ import ContentTypeLayout from './ContentTypeLayout'; const mockStore = configureStore(); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); + jest.mock('../Form/Form', () => jest.fn(() =>
)); describe('ContentTypeLayout', () => { @@ -38,7 +37,7 @@ describe('ContentTypeLayout', () => { schema: null, }, }); - const component = renderer.create( + const { container } = render( { path={'/controlpanel/dexterity-types/:id/layout'} component={ContentTypeLayout} /> +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Controlpanels/ContentTypeSchema.jsx b/packages/volto/src/components/manage/Controlpanels/ContentTypeSchema.jsx index b8ebf1dea0..ab6888140b 100644 --- a/packages/volto/src/components/manage/Controlpanels/ContentTypeSchema.jsx +++ b/packages/volto/src/components/manage/Controlpanels/ContentTypeSchema.jsx @@ -12,7 +12,7 @@ import saveSVG from '@plone/volto/icons/save.svg'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { defineMessages, injectIntl } from 'react-intl'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { connect } from 'react-redux'; import { toast } from 'react-toastify'; import { compose } from 'redux'; @@ -283,8 +283,8 @@ class ContentTypeSchema extends Component { onCancel={this.onCancel} hideActions /> - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )}
); } diff --git a/packages/volto/src/components/manage/Controlpanels/ContentTypes.jsx b/packages/volto/src/components/manage/Controlpanels/ContentTypes.jsx index 4c386c4bce..4759ed6fb2 100644 --- a/packages/volto/src/components/manage/Controlpanels/ContentTypes.jsx +++ b/packages/volto/src/components/manage/Controlpanels/ContentTypes.jsx @@ -9,7 +9,7 @@ import { connect } from 'react-redux'; import { compose } from 'redux'; import { Link } from 'react-router-dom'; import { getParentUrl } from '@plone/volto/helpers'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { last } from 'lodash'; import { Confirm, Container, Table, Button, Header } from 'semantic-ui-react'; import { toast } from 'react-toastify'; @@ -457,8 +457,8 @@ class ContentTypes extends Component { - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )} ); } diff --git a/packages/volto/src/components/manage/Controlpanels/ContentTypes.test.jsx b/packages/volto/src/components/manage/Controlpanels/ContentTypes.test.jsx index 876aed77df..5289835b93 100644 --- a/packages/volto/src/components/manage/Controlpanels/ContentTypes.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/ContentTypes.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; import { MemoryRouter, Route } from 'react-router-dom'; @@ -8,9 +8,8 @@ import ContentTypes from './ContentTypes'; const mockStore = configureStore(); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); + jest.mock('../Form/Form', () => jest.fn(() =>
)); describe('ContentTypes', () => { @@ -60,14 +59,15 @@ describe('ContentTypes', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Controlpanels/Controlpanel.jsx b/packages/volto/src/components/manage/Controlpanels/Controlpanel.jsx index a6fc83740f..a55477d787 100644 --- a/packages/volto/src/components/manage/Controlpanels/Controlpanel.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Controlpanel.jsx @@ -9,7 +9,7 @@ import { connect } from 'react-redux'; import { compose } from 'redux'; import { withRouter } from 'react-router-dom'; import { Helmet } from '@plone/volto/helpers'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { Button, Container } from 'semantic-ui-react'; import { defineMessages, injectIntl } from 'react-intl'; import { toast } from 'react-toastify'; @@ -167,8 +167,8 @@ class Controlpanel extends Component { loading={this.props.updateRequest.loading} /> - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )}
); } diff --git a/packages/volto/src/components/manage/Controlpanels/Controlpanel.test.jsx b/packages/volto/src/components/manage/Controlpanels/Controlpanel.test.jsx index d03d87e2d6..1ee6a98c11 100644 --- a/packages/volto/src/components/manage/Controlpanels/Controlpanel.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Controlpanel.test.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; import { MemoryRouter, Route } from 'react-router-dom'; @@ -8,9 +8,8 @@ import Controlpanel from './Controlpanel'; const mockStore = configureStore(); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); + jest.mock('../Form/Form', () => jest.fn(() =>
)); describe('Controlpanel', () => { @@ -36,14 +35,15 @@ describe('Controlpanel', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Controlpanels/Controlpanels.jsx b/packages/volto/src/components/manage/Controlpanels/Controlpanels.jsx index 263be3b02f..d2751c0142 100644 --- a/packages/volto/src/components/manage/Controlpanels/Controlpanels.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Controlpanels.jsx @@ -8,7 +8,7 @@ import { concat, filter, last, map, sortBy, uniqBy } from 'lodash'; import PropTypes from 'prop-types'; import { useEffect, useState } from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; import { compose } from 'redux'; @@ -260,8 +260,8 @@ function Controlpanels({ - {isClient && ( - + {isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )}
); } diff --git a/packages/volto/src/components/manage/Controlpanels/Controlpanels.test.jsx b/packages/volto/src/components/manage/Controlpanels/Controlpanels.test.jsx index 23c9d83392..10ce403043 100644 --- a/packages/volto/src/components/manage/Controlpanels/Controlpanels.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Controlpanels.test.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { Provider } from 'react-intl-redux'; import { MemoryRouter } from 'react-router-dom'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import config from '@plone/volto/registry'; @@ -9,9 +9,7 @@ import Controlpanels from './Controlpanels'; const mockStore = configureStore(); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../Toolbar/Toolbar', () => jest.fn(() =>
)); jest.mock('./VersionOverview', () => jest.fn(() =>
), @@ -73,15 +71,16 @@ describe('Controlpanels', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); it('renders an additional control panel', () => { @@ -127,14 +126,15 @@ describe('Controlpanels', () => { component: FooComponent, }, ]; - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Controlpanels/DatabaseInformation.jsx b/packages/volto/src/components/manage/Controlpanels/DatabaseInformation.jsx index ec17c9b8ce..04b29655ad 100644 --- a/packages/volto/src/components/manage/Controlpanels/DatabaseInformation.jsx +++ b/packages/volto/src/components/manage/Controlpanels/DatabaseInformation.jsx @@ -7,7 +7,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { Link } from 'react-router-dom'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { Container, Divider, Message, Segment, Table } from 'semantic-ui-react'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; @@ -216,8 +216,8 @@ class DatabaseInformation extends Component { - {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )} ) : null; } diff --git a/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx b/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx index 95505c9030..42bffa4768 100644 --- a/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx @@ -30,7 +30,7 @@ import { find, map, pull } from 'lodash'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { FormattedMessage, injectIntl } from 'react-intl'; -import { Portal } from 'react-portal'; +import { createPortal } from 'react-dom'; import { connect } from 'react-redux'; import { toast } from 'react-toastify'; @@ -575,8 +575,8 @@ class GroupsControlpanel extends Component {
- {this.state.isClient && ( - + {this.state.isClient && + createPortal( } - /> - - )} + />, + document.getElementById('toolbar'), + )} ); } diff --git a/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx b/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx index f6bf548d90..561aab0507 100644 --- a/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Groups/GroupsControlpanel.test.jsx @@ -1,14 +1,13 @@ import React from 'react'; -import renderer from 'react-test-renderer'; +import { render } from '@testing-library/react'; import configureStore from 'redux-mock-store'; import { Provider } from 'react-intl-redux'; import GroupsControlpanel from './GroupsControlpanel'; const mockStore = configureStore(); -jest.mock('react-portal', () => ({ - Portal: jest.fn(() =>
), -})); +jest.mock('../../Toolbar/Toolbar', () => jest.fn(() =>
)); + describe('UsersControlpanel', () => { it('renders a user control component', () => { const store = mockStore({ @@ -25,12 +24,13 @@ describe('UsersControlpanel', () => { messages: {}, }, }); - const component = renderer.create( + const { container } = render( +
, ); - const json = component.toJSON(); - expect(json).toMatchSnapshot(); + + expect(container).toMatchSnapshot(); }); }); diff --git a/packages/volto/src/components/manage/Controlpanels/Groups/__snapshots__/GroupsControlpanel.test.jsx.snap b/packages/volto/src/components/manage/Controlpanels/Groups/__snapshots__/GroupsControlpanel.test.jsx.snap index 6a7e41b64b..36ba594690 100644 --- a/packages/volto/src/components/manage/Controlpanels/Groups/__snapshots__/GroupsControlpanel.test.jsx.snap +++ b/packages/volto/src/components/manage/Controlpanels/Groups/__snapshots__/GroupsControlpanel.test.jsx.snap @@ -1,128 +1,121 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`UsersControlpanel renders a user control component 1`] = ` -
+
-
- Groups -
-
- Groups are logical collections of users, such as departments and business units. Groups are not directly related to permissions on a global level, you normally use Roles for that - and let certain Groups have a particular role. The symbol - plone-svgundefined", - } - } - onClick={null} - style={ - Object { - "fill": "#007EB1", - "height": "20px", - "width": "auto", - } - } - viewBox="" - xmlns="" - /> - indicates a role inherited from membership in another group. -
+ class="container" + />
-
-
+
+ Groups are logical collections of users, such as departments and business units. Groups are not directly related to permissions on a global level, you normally use Roles for that - and let certain Groups have a particular role. The symbol + + + plone-svg + + undefined + + indicates a role inherited from membership in another group. +
+
+
- -