From 305ca72af764ea89010613a00872ab706948046d Mon Sep 17 00:00:00 2001 From: Adam Zielinski Date: Wed, 30 Jun 2021 16:25:57 +0200 Subject: [PATCH 01/19] Fix flaky widgets-related E2E tests (#33066) * Remove empty keys from the compared object * Revert dev artifacts * Disable the gutenberg-test-marquee-widget plugin * Wrap marquee tests in their own describe statement * Lint * Update snapshots * Replace hello with howdy * Move plugin activation to beforeEach * Move deleteAllWidgets to beforeEach * Update tests * use data-testid rather than name attribute selectors * Remove any existing marquees before running the tests, use the "save" form button * Remove dev artifact Co-authored-by: Kai Hao (cherry picked from commit 5cafe02e25f9a42d4abd7bf05857c006683ef023) --- .../plugins/marquee-function-widget.php | 20 +- .../specs/widgets/editing-widgets.test.js | 190 ++++++++++-------- 2 files changed, 115 insertions(+), 95 deletions(-) diff --git a/packages/e2e-tests/plugins/marquee-function-widget.php b/packages/e2e-tests/plugins/marquee-function-widget.php index 43b4f15661772f..dda0c3f9a6e273 100644 --- a/packages/e2e-tests/plugins/marquee-function-widget.php +++ b/packages/e2e-tests/plugins/marquee-function-widget.php @@ -34,15 +34,17 @@ function() { $greeting = get_option( 'marquee_greeting' ); ?>

- - +

{ @@ -89,6 +89,12 @@ describe( 'Widgets screen', () => { ); expect( categoryHeaders.length > 0 ).toBe( true ); + const searchBox = await find( { + role: 'searchbox', + name: 'Search for blocks and patterns', + } ); + await searchBox.type( blockName ); + const addBlock = await find( { role: 'option', @@ -394,109 +400,123 @@ describe( 'Widgets screen', () => { ` ); } ); - async function addMarquee() { - // There will be 2 matches here. - // One is the in-between inserter, - // and the other one is the button block appender. - const [ inlineInserterButton ] = await findAll( { - role: 'combobox', - name: 'Add block', - } ); - await inlineInserterButton.click(); - - // TODO: Convert to find() API from puppeteer-testing-library. - const inserterSearchBox = await page.waitForSelector( - 'aria/Search for blocks and patterns[role="searchbox"]' - ); - await expect( inserterSearchBox ).toHaveFocus(); + describe( 'Function widgets', () => { + async function addMarquee( nbExpectedMarquees ) { + const marqueeBlock = await getBlockInGlobalInserter( + 'Marquee Greeting' + ); + await marqueeBlock.click(); + await page.waitForFunction( + ( expectedMarquees ) => { + return ( + document.querySelectorAll( + '[data-testid="marquee-greeting"]' + ).length === expectedMarquees + ); + }, + {}, + nbExpectedMarquees + ); + } - await page.keyboard.type( 'Marquee' ); + async function deleteExistingMarquees() { + const widgetAreasHoldingMarqueeWidgets = await page.$x( + '//input[@data-testid="marquee-greeting"]/ancestor::div[@aria-label="Block: Widget Area"]' + ); + for ( const widgetArea of widgetAreasHoldingMarqueeWidgets ) { + const closedPanelBody = await widgetArea.$( + '.components-panel__body:not(.is-opened)' + ); + if ( closedPanelBody ) { + await closedPanelBody.focus(); + await closedPanelBody.click(); + } - const inlineQuickInserter = await find( { - role: 'listbox', - name: 'Blocks', - } ); - const marqueeBlockOption = await find( - { - role: 'option', - }, - { - root: inlineQuickInserter, + const [ existingMarqueeWidgets ] = await widgetArea.$x( + '//input[@data-testid="marquee-greeting"]/ancestor::div[@data-block][contains(@class, "wp-block-legacy-widget")]' + ); + if ( existingMarqueeWidgets ) { + await existingMarqueeWidgets.focus(); + await pressKeyWithModifier( 'access', 'z' ); + } } - ); - await marqueeBlockOption.click(); - } - - it( 'Should add and save the marquee widget', async () => { - await activatePlugin( 'gutenberg-test-marquee-widget' ); - await visitAdminPage( 'widgets.php' ); + } - await addMarquee(); + beforeAll( async () => { + await activatePlugin( 'gutenberg-test-marquee-widget' ); + } ); - await find( { - selector: '[data-block][data-type="core/legacy-widget"]', + beforeEach( async () => { + await deleteExistingMarquees(); } ); - const greetingsInput = await find( { - selector: '#marquee-greeting', + afterAll( async () => { + await deactivatePlugin( 'gutenberg-test-marquee-widget' ); } ); - await greetingsInput.click(); - await page.keyboard.type( 'Howdy' ); - await saveWidgets(); + it( 'Should add and save the marquee widget', async () => { + await addMarquee( 1 ); - let editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Hello!", - } - ` ); + const [ marqueeInput ] = await page.$x( + '//input[@data-testid="marquee-greeting"]' + ); + await marqueeInput.focus(); + await marqueeInput.type( 'Howdy' ); - await page.reload(); + // The first marquee is saved after clicking the form save button. + const [ marqueeSaveButton ] = await marqueeInput.$x( + '//input/ancestor::div[@data-block][contains(@class, "wp-block-legacy-widget")]//button[@type="submit"]' + ); + await marqueeSaveButton.click(); - editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Hello!", - } - ` ); + await saveWidgets(); - // Add another marquee, it shouldn't be saved - await addMarquee(); + let editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Howdy", + } + ` ); - // It takes a moment to load the form, let's wait for it. - await waitFor( async () => { - const marquees = await findAll( { - selector: '[id=marquee-greeting]', - } ); - if ( marquees.length === 1 ) { - throw new Error(); + await page.reload(); + + editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Howdy", } - } ); + ` ); - const marquees = await findAll( { - selector: '[id=marquee-greeting]', - } ); + await addMarquee( 2 ); - expect( marquees ).toHaveLength( 2 ); - await marquees[ 1 ].click(); - await page.keyboard.type( 'Second howdy' ); + const marqueeInputs = await page.$$( + '[data-testid="marquee-greeting"]' + ); - await saveWidgets(); - editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Hello!", - } - ` ); + expect( marqueeInputs ).toHaveLength( 2 ); + await marqueeInputs[ 0 ].focus(); + await marqueeInputs[ 0 ].type( 'first howdy' ); + + await marqueeInputs[ 1 ].focus(); + await marqueeInputs[ 1 ].type( 'Second howdy' ); + + // No marquee should be changed without clicking on their "save" button. + // The second marquee shouldn't be stored as a widget. + // See #32978 for more info. + await saveWidgets(); + editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Howdy", + } + ` ); - await page.reload(); - const marqueesAfter = await findAll( { - selector: '[id=marquee-greeting]', + await page.reload(); + const marqueesAfter = await findAll( { + selector: '[data-testid="marquee-greeting"]', + } ); + expect( marqueesAfter ).toHaveLength( 1 ); } ); - expect( marqueesAfter ).toHaveLength( 1 ); - - await deactivatePlugin( 'gutenberg-test-marquee-widget' ); } ); // Disable reason: We temporary skip this test until we can figure out why it fails sometimes. @@ -528,7 +548,6 @@ describe( 'Widgets screen', () => { "sidebar-1": "

First Paragraph

", - "wp_inactive_widgets": "", } ` ); const initialWidgets = await getWidgetAreaWidgets(); @@ -599,7 +618,6 @@ describe( 'Widgets screen', () => {

First Paragraph

", - "wp_inactive_widgets": "", } ` ); const editedWidgets = await getWidgetAreaWidgets(); From f762de687082af6ab84f34eeef2f3b15663dd5c6 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Fri, 2 Jul 2021 12:54:53 -0400 Subject: [PATCH 02/19] Revert "Fix flaky widgets-related E2E tests (#33066)" This reverts commit 305ca72af764ea89010613a00872ab706948046d. --- .../plugins/marquee-function-widget.php | 20 +- .../specs/widgets/editing-widgets.test.js | 190 ++++++++---------- 2 files changed, 95 insertions(+), 115 deletions(-) diff --git a/packages/e2e-tests/plugins/marquee-function-widget.php b/packages/e2e-tests/plugins/marquee-function-widget.php index dda0c3f9a6e273..43b4f15661772f 100644 --- a/packages/e2e-tests/plugins/marquee-function-widget.php +++ b/packages/e2e-tests/plugins/marquee-function-widget.php @@ -34,17 +34,15 @@ function() { $greeting = get_option( 'marquee_greeting' ); ?>

- + +

{ @@ -89,12 +89,6 @@ describe( 'Widgets screen', () => { ); expect( categoryHeaders.length > 0 ).toBe( true ); - const searchBox = await find( { - role: 'searchbox', - name: 'Search for blocks and patterns', - } ); - await searchBox.type( blockName ); - const addBlock = await find( { role: 'option', @@ -400,123 +394,109 @@ describe( 'Widgets screen', () => { ` ); } ); - describe( 'Function widgets', () => { - async function addMarquee( nbExpectedMarquees ) { - const marqueeBlock = await getBlockInGlobalInserter( - 'Marquee Greeting' - ); - await marqueeBlock.click(); - await page.waitForFunction( - ( expectedMarquees ) => { - return ( - document.querySelectorAll( - '[data-testid="marquee-greeting"]' - ).length === expectedMarquees - ); - }, - {}, - nbExpectedMarquees - ); - } + async function addMarquee() { + // There will be 2 matches here. + // One is the in-between inserter, + // and the other one is the button block appender. + const [ inlineInserterButton ] = await findAll( { + role: 'combobox', + name: 'Add block', + } ); + await inlineInserterButton.click(); - async function deleteExistingMarquees() { - const widgetAreasHoldingMarqueeWidgets = await page.$x( - '//input[@data-testid="marquee-greeting"]/ancestor::div[@aria-label="Block: Widget Area"]' - ); - for ( const widgetArea of widgetAreasHoldingMarqueeWidgets ) { - const closedPanelBody = await widgetArea.$( - '.components-panel__body:not(.is-opened)' - ); - if ( closedPanelBody ) { - await closedPanelBody.focus(); - await closedPanelBody.click(); - } + // TODO: Convert to find() API from puppeteer-testing-library. + const inserterSearchBox = await page.waitForSelector( + 'aria/Search for blocks and patterns[role="searchbox"]' + ); + await expect( inserterSearchBox ).toHaveFocus(); - const [ existingMarqueeWidgets ] = await widgetArea.$x( - '//input[@data-testid="marquee-greeting"]/ancestor::div[@data-block][contains(@class, "wp-block-legacy-widget")]' - ); - if ( existingMarqueeWidgets ) { - await existingMarqueeWidgets.focus(); - await pressKeyWithModifier( 'access', 'z' ); - } - } - } + await page.keyboard.type( 'Marquee' ); - beforeAll( async () => { - await activatePlugin( 'gutenberg-test-marquee-widget' ); + const inlineQuickInserter = await find( { + role: 'listbox', + name: 'Blocks', } ); + const marqueeBlockOption = await find( + { + role: 'option', + }, + { + root: inlineQuickInserter, + } + ); + await marqueeBlockOption.click(); + } - beforeEach( async () => { - await deleteExistingMarquees(); - } ); + it( 'Should add and save the marquee widget', async () => { + await activatePlugin( 'gutenberg-test-marquee-widget' ); + await visitAdminPage( 'widgets.php' ); - afterAll( async () => { - await deactivatePlugin( 'gutenberg-test-marquee-widget' ); + await addMarquee(); + + await find( { + selector: '[data-block][data-type="core/legacy-widget"]', } ); - it( 'Should add and save the marquee widget', async () => { - await addMarquee( 1 ); + const greetingsInput = await find( { + selector: '#marquee-greeting', + } ); + await greetingsInput.click(); + await page.keyboard.type( 'Howdy' ); - const [ marqueeInput ] = await page.$x( - '//input[@data-testid="marquee-greeting"]' - ); - await marqueeInput.focus(); - await marqueeInput.type( 'Howdy' ); + await saveWidgets(); - // The first marquee is saved after clicking the form save button. - const [ marqueeSaveButton ] = await marqueeInput.$x( - '//input/ancestor::div[@data-block][contains(@class, "wp-block-legacy-widget")]//button[@type="submit"]' - ); - await marqueeSaveButton.click(); + let editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Hello!", + } + ` ); - await saveWidgets(); + await page.reload(); - let editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Howdy", - } - ` ); + editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Hello!", + } + ` ); - await page.reload(); + // Add another marquee, it shouldn't be saved + await addMarquee(); - editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Howdy", + // It takes a moment to load the form, let's wait for it. + await waitFor( async () => { + const marquees = await findAll( { + selector: '[id=marquee-greeting]', + } ); + if ( marquees.length === 1 ) { + throw new Error(); } - ` ); + } ); - await addMarquee( 2 ); + const marquees = await findAll( { + selector: '[id=marquee-greeting]', + } ); - const marqueeInputs = await page.$$( - '[data-testid="marquee-greeting"]' - ); + expect( marquees ).toHaveLength( 2 ); + await marquees[ 1 ].click(); + await page.keyboard.type( 'Second howdy' ); - expect( marqueeInputs ).toHaveLength( 2 ); - await marqueeInputs[ 0 ].focus(); - await marqueeInputs[ 0 ].type( 'first howdy' ); - - await marqueeInputs[ 1 ].focus(); - await marqueeInputs[ 1 ].type( 'Second howdy' ); - - // No marquee should be changed without clicking on their "save" button. - // The second marquee shouldn't be stored as a widget. - // See #32978 for more info. - await saveWidgets(); - editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Howdy", - } - ` ); + await saveWidgets(); + editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Hello!", + } + ` ); - await page.reload(); - const marqueesAfter = await findAll( { - selector: '[data-testid="marquee-greeting"]', - } ); - expect( marqueesAfter ).toHaveLength( 1 ); + await page.reload(); + const marqueesAfter = await findAll( { + selector: '[id=marquee-greeting]', } ); + expect( marqueesAfter ).toHaveLength( 1 ); + + await deactivatePlugin( 'gutenberg-test-marquee-widget' ); } ); // Disable reason: We temporary skip this test until we can figure out why it fails sometimes. @@ -548,6 +528,7 @@ describe( 'Widgets screen', () => { "sidebar-1": "

First Paragraph

", + "wp_inactive_widgets": "", } ` ); const initialWidgets = await getWidgetAreaWidgets(); @@ -618,6 +599,7 @@ describe( 'Widgets screen', () => {

First Paragraph

", + "wp_inactive_widgets": "", } ` ); const editedWidgets = await getWidgetAreaWidgets(); From 353202822e4d872107e116212c57f0ef76d3e062 Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Mon, 5 Jul 2021 03:38:16 -0400 Subject: [PATCH 03/19] Backport several GitHub Action workflow improvements to `wp/trunk` (#33174) * Only calculate the compressed size when necessary. (#32161) This updates the compressed size workflow to run only when the files changes would have an impact on the package size. (cherry picked from commit 23d84b3ed7614196450e911da83a9a21e3f625bf) * Limit when workflows run on forks (#32114) (cherry picked from commit 435dde470f5541ba397a83126333223abe1eee41) * Improvements to NPM package caching across workflows (#32458) * Use a consistent cache key for NPM packages across all workflows. Also, include the NodeJS version in the cache key in case different package versions are required. * Update the `actions/cache` action to the latest version. * Remove the strategy matrix from jobs with a single NodeJS version. For some reason, GitHub Actions will attach matrix values to job names in parenthesis. Because required checks are configured by job name, these need to stay consistent. (cherry picked from commit 7e5416280ecb9d3197647e8eae20e0f62afc3570) * Limit when release artifacts are built on forks: pt. 2 (#32494) * Limit when release artifacts are built on forks. Previously in #32114, adjustments were made to GHA workflow files to limit when workflows ran on forked repositories. But this missed the second job in the workflow that builds the release artifact. Because it was set to always run even though the previous job is required, it has continued to run on forks. * Ensure the artifact is built always, even when the preceding job does not run. (cherry picked from commit 8fbc4d617f6d85da7f5496e8d49e869c7ecca011) * Use a different cache key for the PR automation workflow (#32588) * Use a different cache key for the PR automation workflow. * Update the `chalk` dependency to the latest version. (cherry picked from commit 05ed04a83eba9aee6e68bb3cdd99bd3a788b6311) * Fix flaky widgets-related E2E tests (#33066) * Remove empty keys from the compared object * Revert dev artifacts * Disable the gutenberg-test-marquee-widget plugin * Wrap marquee tests in their own describe statement * Lint * Update snapshots * Replace hello with howdy * Move plugin activation to beforeEach * Move deleteAllWidgets to beforeEach * Update tests * use data-testid rather than name attribute selectors * Remove any existing marquees before running the tests, use the "save" form button * Remove dev artifact Co-authored-by: Kai Hao (cherry picked from commit 5cafe02e25f9a42d4abd7bf05857c006683ef023) * Navigation: skip flakey tests (#33074) (cherry picked from commit 4d0959e2dc956a9e40a4e04db3029f26832c4d70) Co-authored-by: Adam Zielinski Co-authored-by: Kerry Liu --- .github/workflows/build-plugin-zip.yml | 18 +- .github/workflows/bundle-size.yml | 39 +++- .github/workflows/create-block.yml | 13 +- .github/workflows/end2end-test.yml | 16 +- .github/workflows/performance.yml | 14 +- .github/workflows/pull-request-automation.yml | 20 +- .github/workflows/rnmobile-android-runner.yml | 14 +- .github/workflows/rnmobile-ios-runner.yml | 17 +- .../stale-issue-add-needs-testing.yml | 1 + .github/workflows/stale-issue-mark-stale.yml | 1 + .github/workflows/stale-issue-needs-info.yml | 1 + .github/workflows/static-checks.yml | 14 +- .github/workflows/storybook-pages.yml | 17 +- .github/workflows/unit-test.yml | 42 ++-- package-lock.json | 19 +- package.json | 2 +- .../plugins/marquee-function-widget.php | 20 +- .../experiments/blocks/navigation.test.js | 6 +- .../specs/widgets/editing-widgets.test.js | 190 ++++++++++-------- 19 files changed, 266 insertions(+), 198 deletions(-) diff --git a/.github/workflows/build-plugin-zip.yml b/.github/workflows/build-plugin-zip.yml index 9d376e0ea6e2fe..613d7c6c0479cd 100644 --- a/.github/workflows/build-plugin-zip.yml +++ b/.github/workflows/build-plugin-zip.yml @@ -22,6 +22,7 @@ jobs: name: Bump version runs-on: ubuntu-latest if: | + github.repository == 'WordPress/gutenberg' && github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/trunk' && ( github.event.inputs.version == 'rc' || @@ -110,26 +111,25 @@ jobs: name: Build Release Artifact runs-on: ubuntu-latest needs: bump-version - if: always() + if: ${{ ( github.repository == 'WordPress/gutenberg' && always() ) || ( github.event_name == 'pull_request' && always() ) }} + steps: - name: Checkout code uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 with: ref: ${{ needs.bump-version.outputs.release_branch || github.ref }} - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: 14 - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-14-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: Build Gutenberg plugin ZIP file run: ./bin/build-plugin-zip.sh @@ -169,6 +169,8 @@ jobs: name: Create Release Draft and Attach Asset needs: [bump-version, build] runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' }} + steps: - name: Set Release Version id: get_release_version diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml index cd3f591a04910f..56b45f6a7e1aa0 100644 --- a/.github/workflows/bundle-size.yml +++ b/.github/workflows/bundle-size.yml @@ -1,6 +1,28 @@ name: Compressed Size -on: [pull_request] +on: + pull_request: + paths: + # Any change to a CSS, Sass, or JavaScript file should run checks. + - '**.js' + - '**.css' + - '**.scss' + # Changes to any NPM related files could affect the outcome. + - '**package*.json' + # These files configures ESLint. Changes could affect the outcome. + - '**.eslint*' + # These files configures JSHint. Changes could affect the outcome. + - '**.jshint*' + # These files configures Prettier. Changes could affect the outcome. + - '**.prettier*' + # These files configures stylelint. Changes could affect the outcome. + - '**.stylelint*' + # These files configures TypeScript. Changes could affect the outcome. + - '**.tsconfig*' + # This file configures Webpack. Changes could affect the outcome. + - 'webpack.config.js' + # Changes to this workflow file should always verify the changes are successful. + - '.github/workflows/bundle-size.yml' # Cancels all previous workflow runs for pull requests that have not completed. concurrency: @@ -13,16 +35,25 @@ jobs: build: name: Check runs-on: ubuntu-latest - + strategy: + matrix: + node: ['14'] steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 with: fetch-depth: 1 - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: ${{ matrix.node }} + + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node }}-npm-cache-${{ hashFiles('**/package-lock.json') }} - uses: preactjs/compressed-size-action@7d87f60a6b0c7d193b8183ce859ed00b356ea92f # v2.1.0 with: diff --git a/.github/workflows/create-block.yml b/.github/workflows/create-block.yml index 76a11ff6ad69b1..34f3fb65f53b71 100644 --- a/.github/workflows/create-block.yml +++ b/.github/workflows/create-block.yml @@ -16,27 +16,26 @@ jobs: checks: name: Checks runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: fail-fast: false matrix: - node: [12, 14] + node: ['12', '14'] steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js ${{ matrix.node }}.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: node-version: ${{ matrix.node }} - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules-${{ matrix.node }} + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-${{ matrix.node }}-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: npm install, build, format and lint run: | diff --git a/.github/workflows/end2end-test.yml b/.github/workflows/end2end-test.yml index a6ab7b73e85a0b..398cd76ba2367d 100644 --- a/.github/workflows/end2end-test.yml +++ b/.github/workflows/end2end-test.yml @@ -18,30 +18,28 @@ concurrency: jobs: admin: name: Admin - ${{ matrix.part }} - runs-on: ubuntu-latest - + if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: fail-fast: false matrix: part: [1, 2, 3, 4] + node: ['14'] steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: ${{ matrix.node }} - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-${{ matrix.node }}-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: Npm install and build run: | diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 649f9155ad5e87..c3fde03d6cee75 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -15,25 +15,23 @@ concurrency: jobs: performance: name: Run performance tests - runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' }} steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: 14 - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-14-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: Npm install run: | diff --git a/.github/workflows/pull-request-automation.yml b/.github/workflows/pull-request-automation.yml index 6c84669f3e3905..f8df8babb5327b 100644 --- a/.github/workflows/pull-request-automation.yml +++ b/.github/workflows/pull-request-automation.yml @@ -7,6 +7,11 @@ name: Pull request automation jobs: pull-request-automation: runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' }} + strategy: + matrix: + node: ['14'] + steps: # Checkout defaults to using the branch which triggered the event, which # isn't necessarily `trunk` (e.g. in the case of a merge). @@ -14,14 +19,23 @@ jobs: with: ref: trunk - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: ${{ matrix.node }} + + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node }}-npm-pr-automation-cache-${{ hashFiles('**/package-lock.json') }} # Changing into the action's directory and running `npm install` is much # faster than a full project-wide `npm ci`. - - run: cd packages/project-management-automation && npm install + - name: Install NPM dependencies + run: npm install + working-directory: packages/project-management-automation - uses: ./packages/project-management-automation with: diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml index 9c2de4d3355edd..e028267fe0b788 100644 --- a/.github/workflows/rnmobile-android-runner.yml +++ b/.github/workflows/rnmobile-android-runner.yml @@ -21,26 +21,28 @@ jobs: strategy: matrix: native-test-name: [gutenberg-editor-initial-html] + node: ['14'] steps: - name: checkout uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: ${{ matrix.node }} - - name: Restore npm cache - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: + # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} + key: ${{ runner.os }}-node-${{ matrix.node }}-npm-cache-${{ hashFiles('**/package-lock.json') }} - run: npm ci - name: Restore Gradle cache - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index 971ef150e01260..2a5a3d7c6bdc51 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -15,24 +15,27 @@ concurrency: jobs: test: runs-on: macos-latest + if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: matrix: xcode: [12.2] native-test-name: [gutenberg-editor-initial-html] + node: ['14'] steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: ${{ matrix.node }} - - name: Restore npm cache - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: + # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} + key: ${{ runner.os }}-node-${{ matrix.node }}-npm-cache-${{ hashFiles('**/package-lock.json') }} - run: npm ci @@ -40,7 +43,7 @@ jobs: run: find package-lock.json packages/react-native-editor/ios packages/react-native-aztec/ios packages/react-native-bridge/ios -type f -print0 | sort -z | xargs -0 shasum | tee ios-checksums.txt - name: Restore build cache - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: path: | packages/react-native-editor/ios/build/GutenbergDemo/Build/Products/Release-iphonesimulator/GutenbergDemo.app @@ -48,7 +51,7 @@ jobs: key: ${{ runner.os }}-ios-build-${{ matrix.xcode }}-${{ hashFiles('ios-checksums.txt') }} - name: Restore pods cache - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: path: | packages/react-native-editor/ios/Pods diff --git a/.github/workflows/stale-issue-add-needs-testing.yml b/.github/workflows/stale-issue-add-needs-testing.yml index e17bfa7b295670..a01f1bfcaf9ee1 100644 --- a/.github/workflows/stale-issue-add-needs-testing.yml +++ b/.github/workflows/stale-issue-add-needs-testing.yml @@ -6,6 +6,7 @@ on: jobs: stale: runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' }} steps: - uses: actions/stale@996798eb71ef485dc4c7b4d3285842d714040c4a # v3.0.17 with: diff --git a/.github/workflows/stale-issue-mark-stale.yml b/.github/workflows/stale-issue-mark-stale.yml index 983b62c1e07005..746a123df56ac5 100644 --- a/.github/workflows/stale-issue-mark-stale.yml +++ b/.github/workflows/stale-issue-mark-stale.yml @@ -6,6 +6,7 @@ on: jobs: stale: runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' }} steps: - uses: actions/stale@996798eb71ef485dc4c7b4d3285842d714040c4a # v3.0.17 with: diff --git a/.github/workflows/stale-issue-needs-info.yml b/.github/workflows/stale-issue-needs-info.yml index c0f3e4ed6bec62..3de5cb07f9d330 100644 --- a/.github/workflows/stale-issue-needs-info.yml +++ b/.github/workflows/stale-issue-needs-info.yml @@ -6,6 +6,7 @@ on: jobs: stale: runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' }} steps: - uses: actions/stale@996798eb71ef485dc4c7b4d3285842d714040c4a # v3.0.17 with: diff --git a/.github/workflows/static-checks.yml b/.github/workflows/static-checks.yml index 32508611082d69..de8a78796b6621 100644 --- a/.github/workflows/static-checks.yml +++ b/.github/workflows/static-checks.yml @@ -18,25 +18,23 @@ concurrency: jobs: check: name: All - runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: 14 - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-14-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: Npm install and build # A "full" install is executed, since `npm ci` does not always exit diff --git a/.github/workflows/storybook-pages.yml b/.github/workflows/storybook-pages.yml index 7084b8d9642302..5cdcec4866f941 100644 --- a/.github/workflows/storybook-pages.yml +++ b/.github/workflows/storybook-pages.yml @@ -8,25 +8,28 @@ on: jobs: deploy: runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' }} + strategy: + matrix: + node: ['14'] + steps: - name: Checkout uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 with: ref: trunk - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: ${{ matrix.node }} - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-${{ matrix.node }}-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: Install Dependencies run: npm ci diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index d5d4b06c6bcfd0..73507e750a2106 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -21,27 +21,27 @@ jobs: unit-js: name: JavaScript runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} + strategy: fail-fast: false matrix: - node: [12, 14] + node: ['12', '14'] steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js ${{ matrix.node }}.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: node-version: ${{ matrix.node }} - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules-${{ matrix.node }} + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-${{ matrix.node }}-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: Npm install and build # It's not necessary to run the full build, since Jest can interpret @@ -59,25 +59,23 @@ jobs: unit-php: name: PHP - runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: 14 - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-14-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: Npm install and build run: | @@ -101,25 +99,23 @@ jobs: mobile-unit-js: name: Mobile - runs-on: ubuntu-latest + if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 - - name: Use Node.js 14.x + - name: Use desired version of NodeJS uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: 14 - - name: Cache node modules - uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 - env: - cache-name: cache-node-modules + - name: Cache NPM packages + uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 # v2.1.6 with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-node-14-npm-cache-${{ hashFiles('**/package-lock.json') }} - name: Npm install and build # It's not necessary to run the full build, since Jest can interpret diff --git a/package-lock.json b/package-lock.json index 362747ddc9998a..f369c8901aeca4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25021,9 +25021,9 @@ "dev": true }, "chalk": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", - "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -25031,12 +25031,11 @@ }, "dependencies": { "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, @@ -25062,9 +25061,9 @@ "dev": true }, "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" diff --git a/package.json b/package.json index a3f1a9d769bbca..0d6fc3774c5822 100644 --- a/package.json +++ b/package.json @@ -153,7 +153,7 @@ "babel-plugin-transform-remove-console": "6.9.4", "benchmark": "2.1.4", "browserslist": "4.16.6", - "chalk": "4.0.0", + "chalk": "4.1.1", "commander": "4.1.0", "concurrently": "3.5.0", "copy-webpack-plugin": "5.1.2", diff --git a/packages/e2e-tests/plugins/marquee-function-widget.php b/packages/e2e-tests/plugins/marquee-function-widget.php index 43b4f15661772f..dda0c3f9a6e273 100644 --- a/packages/e2e-tests/plugins/marquee-function-widget.php +++ b/packages/e2e-tests/plugins/marquee-function-widget.php @@ -34,15 +34,17 @@ function() { $greeting = get_option( 'marquee_greeting' ); ?>

- - +

{ expect( await getEditedPostContent() ).toMatchSnapshot(); } ); - it( 'loads frontend code only if the block is present', async () => { + // The following tests are unstable, roughly around when https://github.com/WordPress/wordpress-develop/pull/1412 + // landed. The block manually tests well, so let's skip to unblock other PRs and immediately follow up. cc @vcanales + it.skip( 'loads frontend code only if the block is present', async () => { // Mock the response from the Pages endpoint. This is done so that the pages returned are always // consistent and to test the feature more rigorously than the single default sample page. await mockPagesResponse( [ @@ -588,7 +590,7 @@ describe( 'Navigation', () => { expect( tagCount ).toBe( 1 ); } ); - it( 'loads frontend code only if responsiveness is turned on', async () => { + it.skip( 'loads frontend code only if responsiveness is turned on', async () => { await mockPagesResponse( [ { title: 'Home', diff --git a/packages/e2e-tests/specs/widgets/editing-widgets.test.js b/packages/e2e-tests/specs/widgets/editing-widgets.test.js index e9cf7fa91c15b0..642af7ee8171b6 100644 --- a/packages/e2e-tests/specs/widgets/editing-widgets.test.js +++ b/packages/e2e-tests/specs/widgets/editing-widgets.test.js @@ -16,7 +16,7 @@ import { * External dependencies */ // eslint-disable-next-line no-restricted-imports -import { find, findAll, waitFor } from 'puppeteer-testing-library'; +import { find, findAll } from 'puppeteer-testing-library'; import { groupBy, mapValues } from 'lodash'; describe( 'Widgets screen', () => { @@ -89,6 +89,12 @@ describe( 'Widgets screen', () => { ); expect( categoryHeaders.length > 0 ).toBe( true ); + const searchBox = await find( { + role: 'searchbox', + name: 'Search for blocks and patterns', + } ); + await searchBox.type( blockName ); + const addBlock = await find( { role: 'option', @@ -394,109 +400,123 @@ describe( 'Widgets screen', () => { ` ); } ); - async function addMarquee() { - // There will be 2 matches here. - // One is the in-between inserter, - // and the other one is the button block appender. - const [ inlineInserterButton ] = await findAll( { - role: 'combobox', - name: 'Add block', - } ); - await inlineInserterButton.click(); - - // TODO: Convert to find() API from puppeteer-testing-library. - const inserterSearchBox = await page.waitForSelector( - 'aria/Search for blocks and patterns[role="searchbox"]' - ); - await expect( inserterSearchBox ).toHaveFocus(); + describe( 'Function widgets', () => { + async function addMarquee( nbExpectedMarquees ) { + const marqueeBlock = await getBlockInGlobalInserter( + 'Marquee Greeting' + ); + await marqueeBlock.click(); + await page.waitForFunction( + ( expectedMarquees ) => { + return ( + document.querySelectorAll( + '[data-testid="marquee-greeting"]' + ).length === expectedMarquees + ); + }, + {}, + nbExpectedMarquees + ); + } - await page.keyboard.type( 'Marquee' ); + async function deleteExistingMarquees() { + const widgetAreasHoldingMarqueeWidgets = await page.$x( + '//input[@data-testid="marquee-greeting"]/ancestor::div[@aria-label="Block: Widget Area"]' + ); + for ( const widgetArea of widgetAreasHoldingMarqueeWidgets ) { + const closedPanelBody = await widgetArea.$( + '.components-panel__body:not(.is-opened)' + ); + if ( closedPanelBody ) { + await closedPanelBody.focus(); + await closedPanelBody.click(); + } - const inlineQuickInserter = await find( { - role: 'listbox', - name: 'Blocks', - } ); - const marqueeBlockOption = await find( - { - role: 'option', - }, - { - root: inlineQuickInserter, + const [ existingMarqueeWidgets ] = await widgetArea.$x( + '//input[@data-testid="marquee-greeting"]/ancestor::div[@data-block][contains(@class, "wp-block-legacy-widget")]' + ); + if ( existingMarqueeWidgets ) { + await existingMarqueeWidgets.focus(); + await pressKeyWithModifier( 'access', 'z' ); + } } - ); - await marqueeBlockOption.click(); - } - - it( 'Should add and save the marquee widget', async () => { - await activatePlugin( 'gutenberg-test-marquee-widget' ); - await visitAdminPage( 'widgets.php' ); + } - await addMarquee(); + beforeAll( async () => { + await activatePlugin( 'gutenberg-test-marquee-widget' ); + } ); - await find( { - selector: '[data-block][data-type="core/legacy-widget"]', + beforeEach( async () => { + await deleteExistingMarquees(); } ); - const greetingsInput = await find( { - selector: '#marquee-greeting', + afterAll( async () => { + await deactivatePlugin( 'gutenberg-test-marquee-widget' ); } ); - await greetingsInput.click(); - await page.keyboard.type( 'Howdy' ); - await saveWidgets(); + it( 'Should add and save the marquee widget', async () => { + await addMarquee( 1 ); - let editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Hello!", - } - ` ); + const [ marqueeInput ] = await page.$x( + '//input[@data-testid="marquee-greeting"]' + ); + await marqueeInput.focus(); + await marqueeInput.type( 'Howdy' ); - await page.reload(); + // The first marquee is saved after clicking the form save button. + const [ marqueeSaveButton ] = await marqueeInput.$x( + '//input/ancestor::div[@data-block][contains(@class, "wp-block-legacy-widget")]//button[@type="submit"]' + ); + await marqueeSaveButton.click(); - editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Hello!", - } - ` ); + await saveWidgets(); - // Add another marquee, it shouldn't be saved - await addMarquee(); + let editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Howdy", + } + ` ); - // It takes a moment to load the form, let's wait for it. - await waitFor( async () => { - const marquees = await findAll( { - selector: '[id=marquee-greeting]', - } ); - if ( marquees.length === 1 ) { - throw new Error(); + await page.reload(); + + editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Howdy", } - } ); + ` ); - const marquees = await findAll( { - selector: '[id=marquee-greeting]', - } ); + await addMarquee( 2 ); - expect( marquees ).toHaveLength( 2 ); - await marquees[ 1 ].click(); - await page.keyboard.type( 'Second howdy' ); + const marqueeInputs = await page.$$( + '[data-testid="marquee-greeting"]' + ); - await saveWidgets(); - editedSerializedWidgetAreas = await getSerializedWidgetAreas(); - await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` - Object { - "sidebar-1": "Hello!", - } - ` ); + expect( marqueeInputs ).toHaveLength( 2 ); + await marqueeInputs[ 0 ].focus(); + await marqueeInputs[ 0 ].type( 'first howdy' ); + + await marqueeInputs[ 1 ].focus(); + await marqueeInputs[ 1 ].type( 'Second howdy' ); + + // No marquee should be changed without clicking on their "save" button. + // The second marquee shouldn't be stored as a widget. + // See #32978 for more info. + await saveWidgets(); + editedSerializedWidgetAreas = await getSerializedWidgetAreas(); + await expect( editedSerializedWidgetAreas ).toMatchInlineSnapshot( ` + Object { + "sidebar-1": "Howdy", + } + ` ); - await page.reload(); - const marqueesAfter = await findAll( { - selector: '[id=marquee-greeting]', + await page.reload(); + const marqueesAfter = await findAll( { + selector: '[data-testid="marquee-greeting"]', + } ); + expect( marqueesAfter ).toHaveLength( 1 ); } ); - expect( marqueesAfter ).toHaveLength( 1 ); - - await deactivatePlugin( 'gutenberg-test-marquee-widget' ); } ); // Disable reason: We temporary skip this test until we can figure out why it fails sometimes. @@ -528,7 +548,6 @@ describe( 'Widgets screen', () => { "sidebar-1": "

First Paragraph

", - "wp_inactive_widgets": "", } ` ); const initialWidgets = await getWidgetAreaWidgets(); @@ -599,7 +618,6 @@ describe( 'Widgets screen', () => {

First Paragraph

", - "wp_inactive_widgets": "", } ` ); const editedWidgets = await getWidgetAreaWidgets(); From d068d2cd8f3a8ff16a3ee1c5ece9c851b8f4f7cc Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 1 Jul 2021 12:41:36 +0300 Subject: [PATCH 04/19] [Block Library]: Less warnings when blocks try to render themselves. (#33032) * Less warnings when blocks try to render themeselves. * rename util to gutenberg_is_rest_api_request * Log only if is `is_debug` and not in admin or REST request * remove log entirely --- packages/block-library/src/block/index.php | 11 ----------- .../block-library/src/post-content/index.php | 16 ++++------------ .../block-library/src/template-part/index.php | 12 +----------- 3 files changed, 5 insertions(+), 34 deletions(-) diff --git a/packages/block-library/src/block/index.php b/packages/block-library/src/block/index.php index 3613680e9e5159..8b0227f43c45fd 100644 --- a/packages/block-library/src/block/index.php +++ b/packages/block-library/src/block/index.php @@ -25,17 +25,6 @@ function render_block_core_block( $attributes ) { } if ( isset( $seen_refs[ $attributes['ref'] ] ) ) { - if ( ! is_admin() ) { - trigger_error( - sprintf( - // translators: %s is the user-provided title of the reusable block. - __( 'Could not render Reusable Block %s. Block cannot be rendered inside itself.' ), - $reusable_block->post_title - ), - E_USER_WARNING - ); - } - // WP_DEBUG_DISPLAY must only be honored when WP_DEBUG. This precedent // is set in `wp_debug_mode()`. $is_debug = defined( 'WP_DEBUG' ) && WP_DEBUG && diff --git a/packages/block-library/src/post-content/index.php b/packages/block-library/src/post-content/index.php index 4c0c4965647f11..400e3068dfa0a9 100644 --- a/packages/block-library/src/post-content/index.php +++ b/packages/block-library/src/post-content/index.php @@ -23,19 +23,11 @@ function render_block_core_post_content( $attributes, $content, $block ) { $post_id = $block->context['postId']; if ( isset( $seen_ids[ $post_id ] ) ) { - if ( ! is_admin() ) { - trigger_error( - sprintf( - // translators: %s is a post ID (integer). - __( 'Could not render Post Content block with post ID: %s. Block cannot be rendered inside itself.' ), - $post_id - ), - E_USER_WARNING - ); - } - + // WP_DEBUG_DISPLAY must only be honored when WP_DEBUG. This precedent + // is set in `wp_debug_mode()`. $is_debug = defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY; + return $is_debug ? // translators: Visible only in the front end, this warning takes the place of a faulty block. __( '[block rendering halted]' ) : @@ -44,7 +36,7 @@ function render_block_core_post_content( $attributes, $content, $block ) { $seen_ids[ $post_id ] = true; - if ( ! in_the_loop() ) { + if ( ! in_the_loop() && have_posts() ) { the_post(); } diff --git a/packages/block-library/src/template-part/index.php b/packages/block-library/src/template-part/index.php index a30a1ca327e7ee..54271e979fd4e9 100644 --- a/packages/block-library/src/template-part/index.php +++ b/packages/block-library/src/template-part/index.php @@ -73,21 +73,11 @@ function render_block_core_template_part( $attributes ) { } if ( isset( $seen_ids[ $template_part_id ] ) ) { - if ( ! is_admin() ) { - trigger_error( - sprintf( - // translators: %s are the block attributes. - __( 'Could not render Template Part block with the attributes: %s. Block cannot be rendered inside itself.' ), - wp_json_encode( $attributes ) - ), - E_USER_WARNING - ); - } - // WP_DEBUG_DISPLAY must only be honored when WP_DEBUG. This precedent // is set in `wp_debug_mode()`. $is_debug = defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY; + return $is_debug ? // translators: Visible only in the front end, this warning takes the place of a faulty block. __( '[block rendering halted]' ) : From ec43a53697f4c1948efbab9adb729036ff002701 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Thu, 1 Jul 2021 20:06:50 +1000 Subject: [PATCH 05/19] Reset z-index on focused widget form (#33122) --- packages/widgets/src/blocks/legacy-widget/editor.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/widgets/src/blocks/legacy-widget/editor.scss b/packages/widgets/src/blocks/legacy-widget/editor.scss index 69f8f577702255..ec57f623da8575 100644 --- a/packages/widgets/src/blocks/legacy-widget/editor.scss +++ b/packages/widgets/src/blocks/legacy-widget/editor.scss @@ -74,7 +74,8 @@ } // Reset z-index set on https://github.com/WordPress/wordpress-develop/commit/f26d4d37351a55fd1fc5dad0f5fef8f0f964908c. - .widget.open { + .widget.open, + .widget.open:focus-within { z-index: 0; } } From fc348a1dbf23f7bbdca14142ce1447eb807930f1 Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Thu, 1 Jul 2021 13:40:20 +0200 Subject: [PATCH 06/19] Try: Refactor appender margin. (#33088) * Try: Refactor appender margin. * Expand comment. * Add clarifying comment. --- .../components/block-list-appender/style.scss | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/components/block-list-appender/style.scss b/packages/block-editor/src/components/block-list-appender/style.scss index ebfeb4c0b090c1..5079df7cdadbe5 100644 --- a/packages/block-editor/src/components/block-list-appender/style.scss +++ b/packages/block-editor/src/components/block-list-appender/style.scss @@ -10,26 +10,35 @@ max-width: none; } - // Add a little left margin when used horizontally. - // The right margin should be set to auto, so as to not shift layout in flex containers. - margin: 0 auto 0 $grid-unit-10; - - // ... unless it's the only child. - &:first-child { - margin-left: 0; - } - .block-editor-default-block-appender { margin: $grid-unit-10 0; } - // Animate appearance. + // Add an explicit left margin of zero and auto right margin to work in horizontal + // flex containers. Without it, a "space-between"-like effect from two auto margins + // will cause the black plus to sit in the center of what space is left. + margin: 0 auto 0 0; + + // Black square plus appender. .block-list-appender__toggle { padding: 0; + + // Animate appearance. opacity: 1; transform: scale(1); transition: all 0.1s ease; @include reduce-motion("transition"); + + // The black square button should have a little left margin in horizontal containers. + margin-left: $grid-unit-10; + } + + // Cancel any left margin if the black plus sits alone in the container. + // `first-of-type` is used instead of `first-child` as the element is not always the only + // element in the "empty" container. For example the empty navigation block state has a + // zero-width placeholder state that is meant to help correctly size the dimensions. + &:first-of-type .block-list-appender__toggle { + margin-left: 0; } } From b102fc684ce7040e8dfbfcc2bc8dfe6e0d92036e Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Fri, 2 Jul 2021 17:47:00 +0800 Subject: [PATCH 07/19] Fix slash inserter for widgets screen (#33161) * Revert "Fix insertion point displaying when there are no inserter items (#32576)" This reverts commit 80ab980c72057644ab5efc6d367559932e51a1f2. * Avoid setting insertion point within locked templates --- .../block-list/use-in-between-inserter.js | 6 ++++ packages/block-editor/src/store/selectors.js | 12 +------ .../block-editor/src/store/test/selectors.js | 31 ------------------- 3 files changed, 7 insertions(+), 42 deletions(-) diff --git a/packages/block-editor/src/components/block-list/use-in-between-inserter.js b/packages/block-editor/src/components/block-list/use-in-between-inserter.js index 618811ec91ba64..2c385e50d181dc 100644 --- a/packages/block-editor/src/components/block-list/use-in-between-inserter.js +++ b/packages/block-editor/src/components/block-list/use-in-between-inserter.js @@ -25,6 +25,7 @@ export function useInBetweenInserter() { isBlockInsertionPointVisible, isMultiSelecting, getSelectedBlockClientIds, + getTemplateLock, } = useSelect( blockEditorStore ); const { showInsertionPoint, hideInsertionPoint } = useDispatch( blockEditorStore @@ -68,6 +69,11 @@ export function useInBetweenInserter() { rootClientId = blockElement.getAttribute( 'data-block' ); } + // Don't set the insertion point if the template is locked. + if ( getTemplateLock( rootClientId ) ) { + return; + } + const orientation = getBlockListSettings( rootClientId )?.orientation || 'vertical'; diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index bb310ccfab2db5..de8dd02b2c0e4e 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -1215,17 +1215,7 @@ export function getBlockInsertionPoint( state ) { * @return {?boolean} Whether the insertion point is visible or not. */ export function isBlockInsertionPointVisible( state ) { - const insertionPoint = state.insertionPoint; - - if ( ! state.insertionPoint ) { - return false; - } - - if ( getTemplateLock( state, insertionPoint.rootClientId ) ) { - return false; - } - - return true; + return state.insertionPoint !== null; } /** diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js index 40194fad3c5c6b..0e67cc0f1d5515 100644 --- a/packages/block-editor/src/store/test/selectors.js +++ b/packages/block-editor/src/store/test/selectors.js @@ -2255,43 +2255,12 @@ describe( 'selectors', () => { expect( isBlockInsertionPointVisible( state ) ).toBe( false ); } ); - it( 'should return false if the rootClientId has a truthy template lock', () => { - const state = { - insertionPoint: { - rootClientId: 'testClientId', - index: 5, - }, - blockListSettings: { - testClientId: { - templateLock: 'all', - }, - }, - }; - - expect( isBlockInsertionPointVisible( state ) ).toBe( false ); - } ); - - it( 'should return false if the rootClientId is undefined, and the settings has a template lock', () => { - const state = { - insertionPoint: { - rootClientId: undefined, - index: 5, - }, - settings: { - templateLock: 'all', - }, - }; - - expect( isBlockInsertionPointVisible( state ) ).toBe( false ); - } ); - it( 'should return true if assigned insertion point', () => { const state = { insertionPoint: { rootClientId: undefined, index: 5, }, - settings: {}, }; expect( isBlockInsertionPointVisible( state ) ).toBe( true ); From 022c2837c90f88aa7d86036bd3eadfb6c929e981 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 2 Jul 2021 14:46:31 +0100 Subject: [PATCH 08/19] Widget screens: set html block as freeform content handler (#33164) --- packages/customize-widgets/src/index.js | 7 +++++++ packages/edit-widgets/src/index.js | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/packages/customize-widgets/src/index.js b/packages/customize-widgets/src/index.js index bf3b8eef0c8622..e578b491adbb90 100644 --- a/packages/customize-widgets/src/index.js +++ b/packages/customize-widgets/src/index.js @@ -11,6 +11,7 @@ import { registerLegacyWidgetBlock, registerLegacyWidgetVariations, } from '@wordpress/widgets'; +import { setFreeformContentHandlerName } from '@wordpress/blocks'; /** * Internal dependencies @@ -49,6 +50,12 @@ export function initialize( editorName, blockEditorSettings ) { } registerLegacyWidgetVariations( blockEditorSettings ); + // As we are unregistering `core/freeform` to avoid the Classic block, we must + // replace it with something as the default freeform content handler. Failure to + // do this will result in errors in the default block parser. + // see: https://github.com/WordPress/gutenberg/issues/33097 + setFreeformContentHandlerName( 'core/html' ); + const SidebarControl = getSidebarControl( blockEditorSettings ); wp.customize.sectionConstructor.sidebar = getSidebarSection(); diff --git a/packages/edit-widgets/src/index.js b/packages/edit-widgets/src/index.js index 7ed910113e7e8f..7527529dbb4edd 100644 --- a/packages/edit-widgets/src/index.js +++ b/packages/edit-widgets/src/index.js @@ -4,6 +4,7 @@ import { registerBlockType, unstable__bootstrapServerSideBlockDefinitions, // eslint-disable-line camelcase + setFreeformContentHandlerName, } from '@wordpress/blocks'; import { render } from '@wordpress/element'; import { @@ -63,6 +64,11 @@ export function initialize( id, settings ) { settings.__experimentalFetchLinkSuggestions = ( search, searchOptions ) => fetchLinkSuggestions( search, searchOptions, settings ); + // As we are unregistering `core/freeform` to avoid the Classic block, we must + // replace it with something as the default freeform content handler. Failure to + // do this will result in errors in the default block parser. + // see: https://github.com/WordPress/gutenberg/issues/33097 + setFreeformContentHandlerName( 'core/html' ); render( , document.getElementById( id ) From 99084b6c506fdeb1a571701d753792422f50305b Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Sun, 4 Jul 2021 23:15:50 +0100 Subject: [PATCH 09/19] Widget Block: widget_id is undefined when a widget is placed (#33152) * Fix notice error * Fix lint --- .../widgets/src/blocks/legacy-widget/index.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/widgets/src/blocks/legacy-widget/index.php b/packages/widgets/src/blocks/legacy-widget/index.php index 030aa88f56b637..8a326056816c9d 100644 --- a/packages/widgets/src/blocks/legacy-widget/index.php +++ b/packages/widgets/src/blocks/legacy-widget/index.php @@ -25,13 +25,15 @@ function render_block_core_legacy_widget( $attributes ) { } $id_base = $attributes['idBase']; - if ( method_exists( $wp_widget_factory, 'get_widget_key' ) ) { - $widget_key = $wp_widget_factory->get_widget_key( $id_base ); + if ( method_exists( $wp_widget_factory, 'get_widget_key' ) && method_exists( $wp_widget_factory, 'get_widget_object' ) ) { + $widget_key = $wp_widget_factory->get_widget_key( $id_base ); + $widget_object = $wp_widget_factory->get_widget_object( $id_base ); } else { - $widget_key = gutenberg_get_widget_key( $id_base ); + $widget_key = gutenberg_get_widget_key( $id_base ); + $widget_object = gutenberg_get_widget_object( $id_base ); } - if ( ! $widget_key ) { + if ( ! $widget_key || ! $widget_object ) { return ''; } @@ -45,8 +47,13 @@ function render_block_core_legacy_widget( $attributes ) { $instance = array(); } + $args = array( + 'widget_id' => $widget_object->id, + 'widget_name' => $widget_object->name, + ); + ob_start(); - the_widget( $widget_key, $instance ); + the_widget( $widget_key, $instance, $args ); return ob_get_clean(); } From d8dccefad9b75b4d806a98bf7115bb9a281f3e37 Mon Sep 17 00:00:00 2001 From: Adam Zielinski Date: Mon, 5 Jul 2021 03:18:38 +0200 Subject: [PATCH 10/19] Add to WidgetAreasBlockEditorProvider (#33166) --- .../components/sidebar-block-editor/index.js | 23 +++++++++++-------- .../index.js | 3 ++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/customize-widgets/src/components/sidebar-block-editor/index.js b/packages/customize-widgets/src/components/sidebar-block-editor/index.js index 3ba3fa0b1799a2..34e38c01e86c44 100644 --- a/packages/customize-widgets/src/components/sidebar-block-editor/index.js +++ b/packages/customize-widgets/src/components/sidebar-block-editor/index.js @@ -14,6 +14,7 @@ import { BlockTools, BlockSelectionClearer, BlockInspector, + CopyHandler, ObserveTyping, WritingFlow, BlockEditorKeyboardShortcuts, @@ -114,15 +115,19 @@ export default function SidebarBlockEditor( { isFixedToolbarActive={ isFixedToolbarActive } /> - - - - - - - - - + + + + + + + + + + + { createPortal( // This is a temporary hack to prevent button component inside diff --git a/packages/edit-widgets/src/components/widget-areas-block-editor-provider/index.js b/packages/edit-widgets/src/components/widget-areas-block-editor-provider/index.js index c94754ba5bf431..7e78b67adc7feb 100644 --- a/packages/edit-widgets/src/components/widget-areas-block-editor-provider/index.js +++ b/packages/edit-widgets/src/components/widget-areas-block-editor-provider/index.js @@ -13,6 +13,7 @@ import { useMemo } from '@wordpress/element'; import { BlockEditorProvider, BlockEditorKeyboardShortcuts, + CopyHandler, } from '@wordpress/block-editor'; import { ReusableBlocksMenuItems } from '@wordpress/reusable-blocks'; @@ -108,7 +109,7 @@ export default function WidgetAreasBlockEditorProvider( { useSubRegistry={ false } { ...props } > - { children } + { children } From 6b78c8c465f72031b48df166b86078f8d3e7d712 Mon Sep 17 00:00:00 2001 From: Adam Zielinski Date: Mon, 5 Jul 2021 03:19:16 +0200 Subject: [PATCH 11/19] Add width: 100% to components-base-control inside wp-block-legacy-widget (#33141) --- packages/widgets/src/blocks/legacy-widget/editor.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/widgets/src/blocks/legacy-widget/editor.scss b/packages/widgets/src/blocks/legacy-widget/editor.scss index ec57f623da8575..de88a38f889072 100644 --- a/packages/widgets/src/blocks/legacy-widget/editor.scss +++ b/packages/widgets/src/blocks/legacy-widget/editor.scss @@ -155,6 +155,9 @@ } .wp-block-legacy-widget { + .components-base-control { + width: 100%; + } .components-select-control__input { padding: 0; font-family: system-ui; From 8dfa4af4856973bc0c1cfb6055085faecf0c6de0 Mon Sep 17 00:00:00 2001 From: Adam Zielinski Date: Fri, 2 Jul 2021 17:31:02 +0200 Subject: [PATCH 12/19] Replace the technical error message with a more user-friendly one (#33165) --- .../widgets/src/blocks/legacy-widget/edit/form.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/widgets/src/blocks/legacy-widget/edit/form.js b/packages/widgets/src/blocks/legacy-widget/edit/form.js index eb8abefb6dc586..b7a3f0e3e9b98c 100644 --- a/packages/widgets/src/blocks/legacy-widget/edit/form.js +++ b/packages/widgets/src/blocks/legacy-widget/edit/form.js @@ -8,7 +8,7 @@ import classnames from 'classnames'; import { useRef, useEffect } from '@wordpress/element'; import { useDispatch } from '@wordpress/data'; import { store as noticesStore } from '@wordpress/notices'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { Popover } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; /** @@ -56,12 +56,16 @@ export default function Form( { }, onChangeHasPreview, onError( error ) { + window.console.error( error ); createNotice( 'error', - error?.message ?? + sprintf( + /* translators: %s: the name of the affected block. */ __( - 'An error occured while fetching or updating the widget.' - ) + 'The "%s" block was affected by errors and may not function properly. Check the developer tools for more details.' + ), + idBase || id + ) ); }, } ); From 2b64861f12cddfe84899007d65d4197059cd5cfa Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Mon, 5 Jul 2021 19:51:53 +0800 Subject: [PATCH 13/19] Fix legacy widget height overflow (#33191) --- .../src/blocks/legacy-widget/edit/preview.js | 82 +++++++++++++------ 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/packages/widgets/src/blocks/legacy-widget/edit/preview.js b/packages/widgets/src/blocks/legacy-widget/edit/preview.js index 39e4d65a51cb45..66109d62558ae9 100644 --- a/packages/widgets/src/blocks/legacy-widget/edit/preview.js +++ b/packages/widgets/src/blocks/legacy-widget/edit/preview.js @@ -13,36 +13,54 @@ import { Placeholder, Spinner, Disabled } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; export default function Preview( { idBase, instance, isVisible } ) { - const [ iframeHeight, setIframeHeight ] = useState(); + const [ isLoaded, setIsLoaded ] = useState( false ); // Resize the iframe on either the load event, or when the iframe becomes visible. - const ref = useRefEffect( ( iframe ) => { - function onChange() { - const boundingRect = iframe?.contentDocument?.body?.getBoundingClientRect(); - if ( boundingRect ) { - // Include `top` in the height calculation to avoid the bottom - // of widget previews being cut-off. Most widgets have a - // heading at the top that has top margin, and the `height` - // alone doesn't take that margin into account. - setIframeHeight( boundingRect.top + boundingRect.height ); - } - } + const ref = useRefEffect( + ( iframe ) => { + // Only set height if the iframe is loaded, + // or it will grow to an unexpected large height in Safari if it's hidden initially. + if ( isLoaded ) { + // If the preview frame has another origin then this won't work. + // One possible solution is to add custom script to call `postMessage` in the preview frame. + // Or, better yet, we migrate away from iframe. + function setHeight() { + // Pick the maximum of these two values to account for margin collapsing. + const height = Math.max( + iframe.contentDocument.documentElement.offsetHeight, + iframe.contentDocument.body.offsetHeight + ); + iframe.style.height = `${ height }px`; + } - const { IntersectionObserver } = iframe.ownerDocument.defaultView; + const { + IntersectionObserver, + } = iframe.ownerDocument.defaultView; - // Observe for intersections that might cause a change in the height of - // the iframe, e.g. a Widget Area becoming expanded. - const intersectionObserver = new IntersectionObserver( onChange, { - threshold: 1, - } ); - intersectionObserver.observe( iframe ); + // Observe for intersections that might cause a change in the height of + // the iframe, e.g. a Widget Area becoming expanded. + const intersectionObserver = new IntersectionObserver( + ( [ entry ] ) => { + if ( entry.isIntersecting ) { + setHeight(); + } + }, + { + threshold: 1, + } + ); + intersectionObserver.observe( iframe ); - iframe.addEventListener( 'load', onChange ); + iframe.addEventListener( 'load', setHeight ); - return () => { - iframe.removeEventListener( 'load', onChange ); - }; - }, [] ); + return () => { + intersectionObserver.disconnect(); + iframe.removeEventListener( 'load', setHeight ); + }; + } + }, + [ isLoaded ] + ); return ( <> @@ -53,7 +71,7 @@ export default function Preview( { idBase, instance, isVisible } ) { move the iframe off-screen instead of hiding it because web browsers will not trigger onLoad if the iframe is hidden. */ } - { isVisible && iframeHeight === null && ( + { isVisible && ! isLoaded && ( @@ -62,7 +80,7 @@ export default function Preview( { idBase, instance, isVisible } ) { className={ classnames( 'wp-block-legacy-widget__edit-preview', { - 'is-offscreen': ! isVisible || iframeHeight === null, + 'is-offscreen': ! isVisible || ! isLoaded, } ) } > @@ -84,7 +102,17 @@ export default function Preview( { idBase, instance, isVisible } ) { instance, }, } ) } - height={ iframeHeight || 100 } + onLoad={ ( event ) => { + // To hide the scrollbars of the preview frame for some edge cases, + // such as negative margins in the Gallery Legacy Widget. + // It can't be scrolled anyway. + // TODO: Ideally, this should be fixed in core. + event.target.contentDocument.body.style.overflow = + 'hidden'; + + setIsLoaded( true ); + } } + height={ 100 } /> From d7d583b9e2f77b6981d314084c3f31f08d7e02b0 Mon Sep 17 00:00:00 2001 From: Adam Zielinski Date: Mon, 5 Jul 2021 17:01:20 +0200 Subject: [PATCH 14/19] Fix "Select all" behavior in the editor (#33167) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make isEntirelySelected consider "deep" first and last children in case the selection does not belong to the top-level children directly * Rollback unit tests – jsdom does not support contentEditable https://github.com/jsdom/jsdom/issues/1670 * Add an e2e test for multi-block selection * Adjust e2e tests * Add a separate test for gradual select-all from within the list block * Cosmetic adjustments to the e2e test * Update the snapshot --- packages/dom/src/dom/is-entirely-selected.js | 36 +++++++++++++++---- .../multi-block-selection.test.js.snap | 10 ++++++ .../various/multi-block-selection.test.js | 21 +++++++++++ 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/packages/dom/src/dom/is-entirely-selected.js b/packages/dom/src/dom/is-entirely-selected.js index 3445f90facb31c..2a2ddc6308c162 100644 --- a/packages/dom/src/dom/is-entirely-selected.js +++ b/packages/dom/src/dom/is-entirely-selected.js @@ -48,15 +48,37 @@ export default function isEntirelySelected( element ) { const lastChild = element.lastChild; assertIsDefined( lastChild, 'lastChild' ); - const lastChildContentLength = - lastChild.nodeType === lastChild.TEXT_NODE - ? /** @type {Text} */ ( lastChild ).data.length - : lastChild.childNodes.length; + const endContainerContentLength = + endContainer.nodeType === endContainer.TEXT_NODE + ? /** @type {Text} */ ( endContainer ).data.length + : endContainer.childNodes.length; return ( - startContainer === element.firstChild && - endContainer === element.lastChild && + isDeepChild( startContainer, element, 'firstChild' ) && + isDeepChild( endContainer, element, 'lastChild' ) && startOffset === 0 && - endOffset === lastChildContentLength + endOffset === endContainerContentLength ); } + +/** + * Check whether the contents of the element have been entirely selected. + * Returns true if there is no possibility of selection. + * + * @param {HTMLElement|Node} query The element to check. + * @param {HTMLElement} container The container that we suspect "query" may be a first or last child of. + * @param {"firstChild"|"lastChild"} propName "firstChild" or "lastChild" + * + * @return {boolean} True if query is a deep first/last child of container, false otherwise. + */ +function isDeepChild( query, container, propName ) { + /** @type {HTMLElement | ChildNode | null} */ + let candidate = container; + do { + if ( query === candidate ) { + return true; + } + candidate = candidate[ propName ]; + } while ( candidate ); + return false; +} diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap index 5d4499423f1eb0..fd0466cb4b3bb8 100644 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap +++ b/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap @@ -70,6 +70,16 @@ exports[`Multi-block selection should cut and paste 2`] = ` " `; +exports[`Multi-block selection should multi-select from within the list block 1`] = ` +" +

1

+ + + +
  • 1
+" +`; + exports[`Multi-block selection should not multi select single block 1`] = ` "

diff --git a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js index f8d748eaa285ca..8eef794c3f5a8a 100644 --- a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js +++ b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js @@ -615,4 +615,25 @@ describe( 'Multi-block selection', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + + it( 'should multi-select from within the list block', async () => { + await clickBlockAppender(); + // Select a paragraph. + await page.keyboard.type( '1' ); + await page.keyboard.press( 'Enter' ); + // Add a list + await page.keyboard.type( '/list' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( '1' ); + + // Confirm correct setup: a paragraph and a list + expect( await getEditedPostContent() ).toMatchSnapshot(); + + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await page.waitForSelector( + '[data-type="core/paragraph"].is-multi-selected' + ); + } ); } ); From e593ceea347c691f82f4fbf63bba9efe40795c9a Mon Sep 17 00:00:00 2001 From: Adam Zielinski Date: Mon, 5 Jul 2021 16:41:35 +0200 Subject: [PATCH 15/19] fix the NoPreview component's styling issues (#33200) --- packages/widgets/src/blocks/legacy-widget/editor.scss | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/widgets/src/blocks/legacy-widget/editor.scss b/packages/widgets/src/blocks/legacy-widget/editor.scss index de88a38f889072..a7bbb6b92d9e9f 100644 --- a/packages/widgets/src/blocks/legacy-widget/editor.scss +++ b/packages/widgets/src/blocks/legacy-widget/editor.scss @@ -114,10 +114,15 @@ width: 100%; } -.wp-block-legacy-widget__edit-no-preview { +.wp-block-legacy-widget__edit-no-preview.wp-block-legacy-widget__edit-no-preview.wp-block-legacy-widget__edit-no-preview { + &, + & h3, + & p { + font-family: $default-font; + font-size: $default-font-size; + } + background: $gray-100; - font-family: $default-font; - font-size: $default-font-size; padding: $grid-unit-10 $grid-unit-15; h3 { From 621d558a7af8358b4fdc94ffaca1f7562db66987 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Mon, 5 Jul 2021 17:34:42 +0300 Subject: [PATCH 16/19] [Block Library - Query Loop]: Set default block variations not to inherit from global query (#33163) --- .../block-library/src/query/variations.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/block-library/src/query/variations.js b/packages/block-library/src/query/variations.js index d5790da2048105..ddcd522298f9d3 100644 --- a/packages/block-library/src/query/variations.js +++ b/packages/block-library/src/query/variations.js @@ -14,6 +14,24 @@ import { imageDateTitle, } from './icons'; +const QUERY_DEFAULT_ATTRIBUTES = { + query: { + perPage: 3, + pages: 0, + offset: 0, + postType: 'post', + categoryIds: [], + tagIds: [], + order: 'desc', + orderBy: 'date', + author: '', + search: '', + exclude: [], + sticky: '', + inherit: false, + }, +}; + const variations = [ { name: 'posts-list', @@ -44,6 +62,7 @@ const variations = [ name: 'title-date', title: __( 'Title & Date' ), icon: titleDate, + attributes: { ...QUERY_DEFAULT_ATTRIBUTES }, innerBlocks: [ [ 'core/post-template', @@ -57,6 +76,7 @@ const variations = [ name: 'title-excerpt', title: __( 'Title & Excerpt' ), icon: titleExcerpt, + attributes: { ...QUERY_DEFAULT_ATTRIBUTES }, innerBlocks: [ [ 'core/post-template', @@ -70,6 +90,7 @@ const variations = [ name: 'title-date-excerpt', title: __( 'Title, Date, & Excerpt' ), icon: titleDateExcerpt, + attributes: { ...QUERY_DEFAULT_ATTRIBUTES }, innerBlocks: [ [ 'core/post-template', @@ -87,6 +108,7 @@ const variations = [ name: 'image-date-title', title: __( 'Image, Date, & Title' ), icon: imageDateTitle, + attributes: { ...QUERY_DEFAULT_ATTRIBUTES }, innerBlocks: [ [ 'core/post-template', From 936e69fed3d416cf0ccee7b193b4b8a8af130bde Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Tue, 6 Jul 2021 14:52:37 +0800 Subject: [PATCH 17/19] Fix move to widget area checkmark (#33213) * Traverse through block parents to find widget area * Refactor to selector * Switch back to previous selector const * Add doc block --- .../src/filters/move-to-widget-area.js | 16 +++++++------ .../hooks/use-last-selected-widget-area.js | 24 +++++++++---------- packages/edit-widgets/src/store/selectors.js | 21 ++++++++++++++++ 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/packages/edit-widgets/src/filters/move-to-widget-area.js b/packages/edit-widgets/src/filters/move-to-widget-area.js index ca7a31cfd493b4..2354c74e52f003 100644 --- a/packages/edit-widgets/src/filters/move-to-widget-area.js +++ b/packages/edit-widgets/src/filters/move-to-widget-area.js @@ -6,7 +6,7 @@ import { BlockControls } from '@wordpress/block-editor'; import { createHigherOrderComponent } from '@wordpress/compose'; import { useDispatch, useSelect } from '@wordpress/data'; import { addFilter } from '@wordpress/hooks'; -import { getWidgetIdFromBlock, MoveToWidgetArea } from '@wordpress/widgets'; +import { MoveToWidgetArea } from '@wordpress/widgets'; /** * Internal dependencies @@ -15,8 +15,7 @@ import { store as editWidgetsStore } from '../store'; const withMoveToWidgetAreaToolbarItem = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { - const widgetId = getWidgetIdFromBlock( props ); - const blockName = props.name; + const { clientId, name: blockName } = props; const { widgetAreas, currentWidgetAreaId, @@ -29,17 +28,20 @@ const withMoveToWidgetAreaToolbarItem = createHigherOrderComponent( } const selectors = select( editWidgetsStore ); + + const widgetAreaBlock = selectors.getParentWidgetAreaBlock( + clientId + ); + return { widgetAreas: selectors.getWidgetAreas(), - currentWidgetAreaId: widgetId - ? selectors.getWidgetAreaForWidgetId( widgetId )?.id - : undefined, + currentWidgetAreaId: widgetAreaBlock?.attributes?.id, canInsertBlockInWidgetArea: selectors.canInsertBlockInWidgetArea( blockName ), }; }, - [ widgetId, blockName ] + [ clientId, blockName ] ); const { moveBlockToWidgetArea } = useDispatch( editWidgetsStore ); diff --git a/packages/edit-widgets/src/hooks/use-last-selected-widget-area.js b/packages/edit-widgets/src/hooks/use-last-selected-widget-area.js index 4a33e2b3d6097f..ac3e3f3269dc36 100644 --- a/packages/edit-widgets/src/hooks/use-last-selected-widget-area.js +++ b/packages/edit-widgets/src/hooks/use-last-selected-widget-area.js @@ -6,6 +6,7 @@ import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ +import { store as widgetsEditorStore } from '../store'; import { buildWidgetAreasPostId, KIND, POST_TYPE } from '../store/utils'; /** @@ -16,27 +17,24 @@ import { buildWidgetAreasPostId, KIND, POST_TYPE } from '../store/utils'; */ const useLastSelectedWidgetArea = () => useSelect( ( select ) => { - const { getBlockSelectionEnd, getBlockParents, getBlockName } = select( + const { getBlockSelectionEnd, getBlockName } = select( 'core/block-editor' ); - const blockSelectionEndClientId = getBlockSelectionEnd(); + const selectionEndClientId = getBlockSelectionEnd(); // If the selected block is a widget area, return its clientId. - if ( - getBlockName( blockSelectionEndClientId ) === 'core/widget-area' - ) { - return blockSelectionEndClientId; + if ( getBlockName( selectionEndClientId ) === 'core/widget-area' ) { + return selectionEndClientId; } - // Otherwise, find the clientId of the top-level widget area by looking - // through the selected block's parents. - const blockParents = getBlockParents( blockSelectionEndClientId ); - const rootWidgetAreaClientId = blockParents.find( - ( clientId ) => getBlockName( clientId ) === 'core/widget-area' + const { getParentWidgetAreaBlock } = select( widgetsEditorStore ); + const widgetAreaBlock = getParentWidgetAreaBlock( + selectionEndClientId ); + const widgetAreaBlockClientId = widgetAreaBlock?.clientId; - if ( rootWidgetAreaClientId ) { - return rootWidgetAreaClientId; + if ( widgetAreaBlockClientId ) { + return widgetAreaBlockClientId; } // If no widget area has been selected, return the clientId of the first diff --git a/packages/edit-widgets/src/store/selectors.js b/packages/edit-widgets/src/store/selectors.js index 7e30ed3f81f0cf..8dace5020abf52 100644 --- a/packages/edit-widgets/src/store/selectors.js +++ b/packages/edit-widgets/src/store/selectors.js @@ -77,6 +77,27 @@ export const getWidgetAreaForWidgetId = createRegistrySelector( } ); +/** + * Given a child client id, returns the parent widget area block. + * + * @param {string} clientId The client id of a block in a widget area. + * + * @return {WPBlock} The widget area block. + */ +export const getParentWidgetAreaBlock = createRegistrySelector( + ( select ) => ( state, clientId ) => { + const { getBlock, getBlockName, getBlockParents } = select( + blockEditorStore + ); + const blockParents = getBlockParents( clientId ); + const widgetAreaClientId = blockParents.find( + ( parentClientId ) => + getBlockName( parentClientId ) === 'core/widget-area' + ); + return getBlock( widgetAreaClientId ); + } +); + export const getEditedWidgetAreas = createRegistrySelector( ( select ) => ( state, ids ) => { let widgetAreas = select( editWidgetsStoreName ).getWidgetAreas(); From 6dfaa8265061390f5bf6591d9f9f0966b21f60e9 Mon Sep 17 00:00:00 2001 From: Emmanuel Hesry Date: Tue, 6 Jul 2021 12:59:27 +0200 Subject: [PATCH 18/19] Replace legacy widget icon with its new version (#33041) * Replace legacy widget icon with its new version * Fix the legacy widget with its correct version from Figma --- packages/icons/src/library/widget.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/icons/src/library/widget.js b/packages/icons/src/library/widget.js index 7fb67180ca8688..50e086c17a1783 100644 --- a/packages/icons/src/library/widget.js +++ b/packages/icons/src/library/widget.js @@ -4,8 +4,8 @@ import { Path, SVG } from '@wordpress/primitives'; const widget = ( - - + + ); From f8d65ce1b6992104e3a788ea1915d773e3b244d1 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 6 Jul 2021 12:24:33 +0100 Subject: [PATCH 19/19] Fix linting issue --- packages/edit-widgets/src/store/selectors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-widgets/src/store/selectors.js b/packages/edit-widgets/src/store/selectors.js index 8dace5020abf52..bd520ea15d7325 100644 --- a/packages/edit-widgets/src/store/selectors.js +++ b/packages/edit-widgets/src/store/selectors.js @@ -87,7 +87,7 @@ export const getWidgetAreaForWidgetId = createRegistrySelector( export const getParentWidgetAreaBlock = createRegistrySelector( ( select ) => ( state, clientId ) => { const { getBlock, getBlockName, getBlockParents } = select( - blockEditorStore + 'core/block-editor' ); const blockParents = getBlockParents( clientId ); const widgetAreaClientId = blockParents.find(