diff --git a/.env.example b/.env.example index b279c54e7..7b919f2e8 100644 --- a/.env.example +++ b/.env.example @@ -5,8 +5,13 @@ WORDPRESS_ROOT_DIR="/Users/tim/Local Sites/convertkit-github/app/public" WORDPRESS_URL=http://kit.local # Local site DB SQL dump file +# Set to `tests/Support/Data/dump-6.2.8.sql` when testing in WordPress 6.2.8 or older i.e. to test apiVersion 2 blocks WORDPRESS_DB_SQL_DUMP_FILE="tests/Support/Data/dump.sql" +# Use apiVersion 3 of the block editor +# Set to `false` when testing in WordPress 6.2.8 or older i.e. to test apiVersion 2 blocks +WORDPRESS_V3_BLOCK_EDITOR_ENABLED=true + # Kit credentials CONVERTKIT_OAUTH_ACCESS_TOKEN= CONVERTKIT_OAUTH_REFRESH_TOKEN= diff --git a/.github/workflows/tests-backward-compat.yml b/.github/workflows/tests-backward-compat.yml index 2f73012b6..9948399c0 100644 --- a/.github/workflows/tests-backward-compat.yml +++ b/.github/workflows/tests-backward-compat.yml @@ -29,6 +29,7 @@ jobs: DB_USER: root DB_PASS: root DB_HOST: localhost + WORDPRESS_V3_BLOCK_EDITOR_ENABLED: false # Test apiVersion 2 blocks against WordPress 6.2.8 WORDPRESS_DB_SQL_DUMP_FILE: tests/Support/Data/dump-6.2.8.sql # Used to populate the test site database for WordPress 6.2.8 INSTALL_PLUGINS: "autoptimize debloat litespeed-cache rocket-lazy-load sg-cachepress" # Don't include this repository's Plugin here. INSTALL_PLUGINS_URLS: "http://cktestplugins.wpengine.com/wp-content/uploads/2024/11/disable-doing-it-wrong-notices.zip https://downloads.wordpress.org/plugin/block-visibility.3.3.0.zip https://downloads.wordpress.org/plugin/jetpack-boost.3.5.0.zip" # URLs to specific third party Plugins or versions that support WordPress 6.2.8 @@ -134,7 +135,7 @@ jobs: - name: Install Paid Third Party WordPress Plugins working-directory: ${{ env.ROOT_DIR }} run: wp-cli plugin install ${{ secrets.CONVERTKIT_PAID_PLUGIN_URLS }} - + # Move Plugin - name: Move Plugin run: mv /home/runner/work/convertkit-wordpress/convertkit-wordpress/convertkit ${{ env.PLUGIN_DIR }} @@ -244,6 +245,7 @@ jobs: with: path: ${{ env.PLUGIN_DIR }}/.env.testing contents: | + WORDPRESS_V3_BLOCK_EDITOR_ENABLED=${{ env.WORDPRESS_V3_BLOCK_EDITOR_ENABLED }} WORDPRESS_DB_SQL_DUMP_FILE=${{ env.WORDPRESS_DB_SQL_DUMP_FILE }} CONVERTKIT_API_KEY=${{ env.CONVERTKIT_API_KEY }} CONVERTKIT_API_SECRET=${{ env.CONVERTKIT_API_SECRET }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d59ffb260..704de67b6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,7 +30,8 @@ jobs: DB_USER: root DB_PASS: root DB_HOST: localhost - WORDPRESS_DB_SQL_DUMP_FILE: tests/Support/Data/dump.sql # Used to populate the test site database for WordPress 6.2.8 + WORDPRESS_V3_BLOCK_EDITOR_ENABLED: true + WORDPRESS_DB_SQL_DUMP_FILE: tests/Support/Data/dump.sql INSTALL_PLUGINS: "admin-menu-editor autoptimize beaver-builder-lite-version block-visibility contact-form-7 classic-editor custom-post-type-ui debloat elementor forminator jetpack-boost mailchimp-for-wp rocket-lazy-load woocommerce wordpress-seo wpforms-lite litespeed-cache wp-crontrol wp-super-cache w3-total-cache wp-fastest-cache wp-optimize sg-cachepress" # Don't include this repository's Plugin here. INSTALL_PLUGINS_URLS: "https://downloads.wordpress.org/plugin/convertkit-for-woocommerce.1.6.4.zip http://cktestplugins.wpengine.com/wp-content/uploads/2024/01/convertkit-action-filter-tests.zip http://cktestplugins.wpengine.com/wp-content/uploads/2024/11/disable-doing-it-wrong-notices.zip http://cktestplugins.wpengine.com/wp-content/uploads/2025/03/uncode-js_composer.7.8.zip http://cktestplugins.wpengine.com/wp-content/uploads/2025/03/uncode-core.zip" # URLs to specific third party Plugins INSTALL_THEMES_URLS: "http://cktestplugins.wpengine.com/wp-content/uploads/2025/03/uncode.zip http://cktestplugins.wpengine.com/wp-content/uploads/2025/04/Divi.zip" @@ -266,6 +267,7 @@ jobs: with: path: ${{ env.PLUGIN_DIR }}/.env.testing contents: | + WORDPRESS_V3_BLOCK_EDITOR_ENABLED=${{ env.WORDPRESS_V3_BLOCK_EDITOR_ENABLED }} WORDPRESS_DB_SQL_DUMP_FILE=${{ env.WORDPRESS_DB_SQL_DUMP_FILE }} CONVERTKIT_API_KEY=${{ env.CONVERTKIT_API_KEY }} CONVERTKIT_API_SECRET=${{ env.CONVERTKIT_API_SECRET }} diff --git a/TESTING.md b/TESTING.md index 14d732985..2577f28f0 100644 --- a/TESTING.md +++ b/TESTING.md @@ -339,6 +339,29 @@ the Helper's namespace and class under the `enabled` section. Need to change how Codeception runs? Edit the [codeception.dist.xml](codeception.dist.xml) file. +## Block Testing + +To locally test that Kit Blocks are compatible with apiVersion 2, use the following configuration in `.env.testing`: + +| Environment Variable | Value | +|----------------------|-------| +| `WORDPRESS_DB_SQL_DUMP_FILE` | `tests/Support/Data/dump-6.2.8.sql` | +| `WORDPRESS_V3_BLOCK_EDITOR_ENABLED` | `false` | + +To locally test that Kit Blocks are compatible with apiVersion 3, use the following configuration in `.env.testing`: + +| Environment Variable | Value | +|----------------------|-------| +| `WORDPRESS_DB_SQL_DUMP_FILE` | `tests/Support/Data/dump.sql` | +| `WORDPRESS_V3_BLOCK_EDITOR_ENABLED` | `true` | + +GitHub Actions are configured to automatically configure the hosted runner with the applicable SQL dump file and block editor version: + +| Workflow File | Description | +|---------------|-------------| +| `tests-backward-compat.yml` | Runs tests against WordPress 6.2.8, with apiVersion `2` for blocks | +| `tests.yml` | Runs tests against the latest WordPress version, with apiVersion `3` for blocks | + ## Writing a WordPress Unit Test WordPress Unit tests provide testing of Plugin specific functions and/or classes, typically to assert that they perform as expected diff --git a/includes/blocks/broadcasts/block.json b/includes/blocks/v2/broadcasts/block.json similarity index 100% rename from includes/blocks/broadcasts/block.json rename to includes/blocks/v2/broadcasts/block.json diff --git a/includes/blocks/form-builder-field-custom/block.json b/includes/blocks/v2/form-builder-field-custom/block.json similarity index 100% rename from includes/blocks/form-builder-field-custom/block.json rename to includes/blocks/v2/form-builder-field-custom/block.json diff --git a/includes/blocks/form-builder-field-email/block.json b/includes/blocks/v2/form-builder-field-email/block.json similarity index 100% rename from includes/blocks/form-builder-field-email/block.json rename to includes/blocks/v2/form-builder-field-email/block.json diff --git a/includes/blocks/form-builder-field-name/block.json b/includes/blocks/v2/form-builder-field-name/block.json similarity index 100% rename from includes/blocks/form-builder-field-name/block.json rename to includes/blocks/v2/form-builder-field-name/block.json diff --git a/includes/blocks/form-builder/block.json b/includes/blocks/v2/form-builder/block.json similarity index 100% rename from includes/blocks/form-builder/block.json rename to includes/blocks/v2/form-builder/block.json diff --git a/includes/blocks/form/block.json b/includes/blocks/v2/form/block.json similarity index 100% rename from includes/blocks/form/block.json rename to includes/blocks/v2/form/block.json diff --git a/includes/blocks/formtrigger/block.json b/includes/blocks/v2/formtrigger/block.json similarity index 100% rename from includes/blocks/formtrigger/block.json rename to includes/blocks/v2/formtrigger/block.json diff --git a/includes/blocks/product/block.json b/includes/blocks/v2/product/block.json similarity index 100% rename from includes/blocks/product/block.json rename to includes/blocks/v2/product/block.json diff --git a/includes/blocks/v3/broadcasts/block.json b/includes/blocks/v3/broadcasts/block.json new file mode 100644 index 000000000..650a77901 --- /dev/null +++ b/includes/blocks/v3/broadcasts/block.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "convertkit/broadcasts", + "title": "Kit Broadcasts", + "category": "kit", + "description": "Displays a list of your Kit broadcasts.", + "keywords": [ "convertkit", "kit", "broadcasts", "posts" ], + "textdomain": "convertkit", + "attributes": { + "display_grid": { + "type": "boolean" + }, + "date_format": { + "type": "string" + }, + "display_image": { + "type": "boolean" + }, + "display_description": { + "type": "boolean" + }, + "display_read_more": { + "type": "boolean" + }, + "read_more_label": { + "type": "string" + }, + "limit": { + "type": "number" + }, + "page": { + "type": "number" + }, + "paginate": { + "type": "boolean" + }, + "paginate_label_prev": { + "type": "string" + }, + "paginate_label_next": { + "type": "string" + }, + "style": { + "type": "object" + }, + "backgroundColor": { + "type": "string" + }, + "textColor": { + "type": "string" + }, + "is_gutenberg_example": { + "type": "boolean", + "default": false + } + }, + "supports": { + "className": true, + "color": { + "link": true, + "background": true, + "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "convertkit-gutenberg" +} \ No newline at end of file diff --git a/includes/blocks/v3/form-builder-field-custom/block.json b/includes/blocks/v3/form-builder-field-custom/block.json new file mode 100644 index 000000000..a5ab5b7fe --- /dev/null +++ b/includes/blocks/v3/form-builder-field-custom/block.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "convertkit/form-builder-field-custom", + "title": "Kit Form Builder: Custom Field", + "category": "kit", + "description": "Adds a text field to the Kit Form Builder, whose value is stored in a Kit custom field.", + "keywords": [ + "convertkit", + "kit", + "custom", + "field" + ], + "textdomain": "convertkit", + "parent": [ "convertkit/form-builder" ], + "attributes": { + "label": { + "type": "string" + }, + "custom_field": { + "type": "string" + }, + "fontSize": { + "type": "string" + }, + "style": { + "type": "object" + }, + "backgroundColor": { + "type": "string" + }, + "textColor": { + "type": "string" + }, + "is_gutenberg_example": { + "type": "boolean", + "default": false + } + }, + "supports": { + "align": true, + "className": true, + "color": { + "background": true, + "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "convertkit-gutenberg" +} \ No newline at end of file diff --git a/includes/blocks/v3/form-builder-field-email/block.json b/includes/blocks/v3/form-builder-field-email/block.json new file mode 100644 index 000000000..209e6e373 --- /dev/null +++ b/includes/blocks/v3/form-builder-field-email/block.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "convertkit/form-builder-field-email", + "title": "Kit Form Builder: Email Field", + "category": "kit", + "description": "Adds an email field to the Kit Form Builder.", + "keywords": [ + "convertkit", + "kit", + "email", + "field" + ], + "textdomain": "convertkit", + "parent": [ "convertkit/form-builder" ], + "attributes": { + "label": { + "type": "string" + }, + "fontSize": { + "type": "string" + }, + "style": { + "type": "object" + }, + "backgroundColor": { + "type": "string" + }, + "textColor": { + "type": "string" + }, + "is_gutenberg_example": { + "type": "boolean", + "default": false + } + }, + "supports": { + "align": true, + "className": true, + "color": { + "background": true, + "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "convertkit-gutenberg" +} \ No newline at end of file diff --git a/includes/blocks/v3/form-builder-field-name/block.json b/includes/blocks/v3/form-builder-field-name/block.json new file mode 100644 index 000000000..b8a6a1b01 --- /dev/null +++ b/includes/blocks/v3/form-builder-field-name/block.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "convertkit/form-builder-field-name", + "title": "Kit Form Builder: Name Field", + "category": "kit", + "description": "Adds a name field to the Kit Form Builder.", + "keywords": [ + "convertkit", + "kit", + "name", + "field" + ], + "textdomain": "convertkit", + "parent": [ "convertkit/form-builder" ], + "attributes": { + "label": { + "type": "string" + }, + "fontSize": { + "type": "string" + }, + "style": { + "type": "object" + }, + "backgroundColor": { + "type": "string" + }, + "textColor": { + "type": "string" + }, + "is_gutenberg_example": { + "type": "boolean", + "default": false + } + }, + "supports": { + "align": true, + "className": true, + "color": { + "background": true, + "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "convertkit-gutenberg" +} \ No newline at end of file diff --git a/includes/blocks/v3/form-builder/block.json b/includes/blocks/v3/form-builder/block.json new file mode 100644 index 000000000..edacd8a45 --- /dev/null +++ b/includes/blocks/v3/form-builder/block.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "convertkit/form-builder", + "title": "Kit Form Builder", + "category": "kit", + "description": "Build a subscription form that inherits your site's styles.", + "keywords": [ + "form", + "embed", + "subscriber", + "email", + "convertkit" + ], + "textdomain": "convertkit", + "attributes": { + "redirect": { + "type": "string" + }, + "store_entries": { + "type": "boolean" + }, + "display_form_if_subscribed": { + "type": "boolean" + }, + "text_if_subscribed": { + "type": "string" + }, + "form_id": { + "type": "string" + }, + "tag_id": { + "type": "string" + }, + "sequence_id": { + "type": "string" + }, + "fontSize": { + "type": "string" + }, + "style": { + "type": "object" + }, + "backgroundColor": { + "type": "string" + }, + "textColor": { + "type": "string" + }, + "is_gutenberg_example": { + "type": "boolean", + "default": false + } + }, + "supports": { + "align": true, + "className": true, + "color": { + "background": true, + "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "convertkit-gutenberg" +} \ No newline at end of file diff --git a/includes/blocks/v3/form/block.json b/includes/blocks/v3/form/block.json new file mode 100644 index 000000000..35c9727c9 --- /dev/null +++ b/includes/blocks/v3/form/block.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "convertkit/form", + "title": "Kit Form", + "category": "kit", + "description": "Displays a Kit Form.", + "keywords": [ + "form", + "embed", + "subscriber", + "email", + "convertkit" + ], + "textdomain": "convertkit", + "attributes": { + "form": { + "type": "string" + }, + "is_gutenberg_example": { + "type": "boolean", + "default": false + } + }, + "supports": { + "align": true, + "className": true, + "color": { + "link": false, + "background": true, + "text": false + }, + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "convertkit-gutenberg" +} \ No newline at end of file diff --git a/includes/blocks/v3/formtrigger/block.json b/includes/blocks/v3/formtrigger/block.json new file mode 100644 index 000000000..b9ea5e4a2 --- /dev/null +++ b/includes/blocks/v3/formtrigger/block.json @@ -0,0 +1,50 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "convertkit/formtrigger", + "title": "Kit Form Trigger", + "category": "kit", + "description": "Displays a modal, sticky bar or slide in form to display when the button is pressed.", + "keywords": [ "convertkit", "kit", "form" ], + "textdomain": "convertkit", + "attributes": { + "form": { + "type": "string" + }, + "text": { + "type": "string" + }, + "fontSize": { + "type": "string" + }, + "style": { + "type": "object" + }, + "backgroundColor": { + "type": "string" + }, + "textColor": { + "type": "string" + }, + "is_gutenberg_example": { + "type": "boolean", + "default": false + } + }, + "supports": { + "className": true, + "color": { + "background": true, + "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "convertkit-gutenberg" +} \ No newline at end of file diff --git a/includes/blocks/v3/product/block.json b/includes/blocks/v3/product/block.json new file mode 100644 index 000000000..27fc0d9e5 --- /dev/null +++ b/includes/blocks/v3/product/block.json @@ -0,0 +1,50 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "convertkit/product", + "title": "Kit Product", + "category": "kit", + "description": "Displays a button to purchase a Kit product.", + "keywords": [ "convertkit", "kit", "product" ], + "textdomain": "convertkit", + "attributes": { + "product": { + "type": "string" + }, + "text": { + "type": "string" + }, + "fontSize": { + "type": "string" + }, + "style": { + "type": "object" + }, + "backgroundColor": { + "type": "string" + }, + "textColor": { + "type": "string" + }, + "is_gutenberg_example": { + "type": "boolean", + "default": false + } + }, + "supports": { + "className": true, + "color": { + "background": true, + "text": true + }, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true + } + }, + "editorScript": "convertkit-gutenberg" +} \ No newline at end of file diff --git a/includes/class-convertkit-gutenberg.php b/includes/class-convertkit-gutenberg.php index 4c8fc5d4b..3d7059af5 100644 --- a/includes/class-convertkit-gutenberg.php +++ b/includes/class-convertkit-gutenberg.php @@ -147,6 +147,21 @@ public function add_blocks() { return; } + // Determine the block API version to use for registering blocks. + // WordPress supports Version 3 from WordPress 6.3: + // https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/. + $block_api_version = ( version_compare( get_bloginfo( 'version' ), '6.3', '>=' ) ? 3 : 2 ); + + /** + * Determine the block API version to use for registering blocks. + * + * @since 3.1.4 + * + * @param int $block_api_version Block API version. + * @return int Block API version. + */ + $block_api_version = apply_filters( 'convertkit_gutenberg_block_api_version', $block_api_version ); + // Get registered blocks. $registered_blocks = array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() ); @@ -160,7 +175,7 @@ public function add_blocks() { // Register block. register_block_type( - CONVERTKIT_PLUGIN_PATH . '/includes/blocks/' . $block, + CONVERTKIT_PLUGIN_PATH . '/includes/blocks/v' . (string) $block_api_version . '/' . $block, array( 'attributes' => $properties['attributes'], 'editor_script' => 'convertkit-gutenberg', diff --git a/tests/EndToEnd/forms/blocks-shortcodes/PageBlockFormBuilderCest.php b/tests/EndToEnd/forms/blocks-shortcodes/PageBlockFormBuilderCest.php index 3cccaf73f..3ba66bd14 100644 --- a/tests/EndToEnd/forms/blocks-shortcodes/PageBlockFormBuilderCest.php +++ b/tests/EndToEnd/forms/blocks-shortcodes/PageBlockFormBuilderCest.php @@ -129,7 +129,8 @@ public function testFormBuilderBlockWithDefaultConfiguration(EndToEndTester $I) fieldName: 'first_name', fieldID: 'first_name', label: 'First name', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); $this->seeFormBuilderField( $I, @@ -137,7 +138,8 @@ public function testFormBuilderBlockWithDefaultConfiguration(EndToEndTester $I) fieldName: 'email', fieldID: 'email', label: 'Email address', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); // Generate email address for this test. @@ -206,11 +208,11 @@ public function testFormBuilderBlockWithTextCustomization(EndToEndTester $I) ); // Change the labels of the form fields. These are added as inner blocks when the Form Builder block is added. - $I->click('div[data-type="convertkit/form-builder-field-name"]'); + $I->selectGutenbergBlockInEditor($I, 'convertkit/form-builder-field-name'); $I->waitForElementVisible('.interface-interface-skeleton__sidebar[aria-label="Editor settings"]'); $I->fillField('#convertkit_form_builder_field_name_label', 'Nafnið þitt'); - $I->click('div[data-type="convertkit/form-builder-field-email"]'); + $I->selectGutenbergBlockInEditor($I, 'convertkit/form-builder-field-email'); $I->waitForElementVisible('.interface-interface-skeleton__sidebar[aria-label="Editor settings"]'); $I->fillField('#convertkit_form_builder_field_email_label', 'Netfangið þitt'); @@ -247,7 +249,8 @@ public function testFormBuilderBlockWithTextCustomization(EndToEndTester $I) fieldName: 'first_name', fieldID: 'first_name', label: 'Nafnið þitt', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); $this->seeFormBuilderField( $I, @@ -255,7 +258,8 @@ public function testFormBuilderBlockWithTextCustomization(EndToEndTester $I) fieldName: 'email', fieldID: 'email', label: 'Netfangið þitt', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); // Generate email address for this test. @@ -267,9 +271,9 @@ public function testFormBuilderBlockWithTextCustomization(EndToEndTester $I) $I->click('div.wp-block-convertkit-form-builder button[type="submit"]'); // Check that the form no longer displays and the message displays. + $I->waitForText('Welcome to the newsletter!', 10, '.convertkit-form-builder.wp-block-convertkit-form-builder'); $I->dontSeeElementInDOM('input[name="convertkit[first_name]"]'); $I->dontSeeElementInDOM('input[name="convertkit[email]"]'); - $I->waitForText('Welcome to the newsletter!', 10, '.convertkit-form-builder.wp-block-convertkit-form-builder'); // Confirm that the email address was added to Kit. $I->apiCheckSubscriberExists( @@ -348,7 +352,8 @@ public function testFormBuilderBlockWithFormEnabled(EndToEndTester $I) fieldName: 'first_name', fieldID: 'first_name', label: 'First name', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); $this->seeFormBuilderField( $I, @@ -356,7 +361,8 @@ public function testFormBuilderBlockWithFormEnabled(EndToEndTester $I) fieldName: 'email', fieldID: 'email', label: 'Email address', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); // Generate email address for this test. @@ -454,7 +460,8 @@ public function testFormBuilderBlockWithTaggingEnabled(EndToEndTester $I) fieldName: 'first_name', fieldID: 'first_name', label: 'First name', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); $this->seeFormBuilderField( $I, @@ -462,7 +469,8 @@ public function testFormBuilderBlockWithTaggingEnabled(EndToEndTester $I) fieldName: 'email', fieldID: 'email', label: 'Email address', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); // Generate email address for this test. @@ -559,7 +567,8 @@ public function testFormBuilderBlockWithSequenceEnabled(EndToEndTester $I) fieldName: 'first_name', fieldID: 'first_name', label: 'First name', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); $this->seeFormBuilderField( $I, @@ -567,7 +576,8 @@ public function testFormBuilderBlockWithSequenceEnabled(EndToEndTester $I) fieldName: 'email', fieldID: 'email', label: 'Email address', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); // Generate email address for this test. @@ -656,7 +666,7 @@ public function testFormBuilderBlockWithCustomField(EndToEndTester $I) foreach ( $customFields as $field ) { // Focus on an inner block, so the Form Builder field blocks are available in the inserter. - $I->click('div[data-type="convertkit/form-builder-field-name"]'); + $I->selectGutenbergBlockInEditor($I, 'convertkit/form-builder-field-name'); // Add custom field block, mapping its data to the Last Name field in Kit. $I->addGutenbergBlock( @@ -681,7 +691,8 @@ public function testFormBuilderBlockWithCustomField(EndToEndTester $I) fieldName: 'first_name', fieldID: 'first_name', label: 'First name', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); $this->seeFormBuilderField( $I, @@ -689,7 +700,8 @@ public function testFormBuilderBlockWithCustomField(EndToEndTester $I) fieldName: 'email', fieldID: 'email', label: 'Email address', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); foreach ( $customFields as $key => $field ) { $this->seeFormBuilderField( @@ -698,7 +710,8 @@ public function testFormBuilderBlockWithCustomField(EndToEndTester $I) fieldName: 'custom_fields][' . $key, fieldID: 'custom_fields_' . $key, label: $field['label'], - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); } @@ -796,7 +809,8 @@ public function testFormBuilderBlockWithRedirectOption(EndToEndTester $I) fieldName: 'first_name', fieldID: 'first_name', label: 'First name', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); $this->seeFormBuilderField( $I, @@ -804,7 +818,8 @@ public function testFormBuilderBlockWithRedirectOption(EndToEndTester $I) fieldName: 'email', fieldID: 'email', label: 'Email address', - container: 'div.wp-block-convertkit-form-builder' + container: 'div.wp-block-convertkit-form-builder', + isFrontend: true ); // Generate email address for this test. @@ -921,7 +936,7 @@ public function testFormBuilderFieldsCanOnlyBeInsertedToFormBuilderBlock(EndToEn ); // Click an inner block within the Form Builder block. - $I->click('div[data-type="convertkit/form-builder"]'); + $I->selectGutenbergBlockInEditor($I, 'convertkit/form-builder'); $I->waitForElementVisible('.interface-interface-skeleton__sidebar[aria-label="Editor settings"]'); // Confirm the Form Field blocks can be added to the Form Builder block. @@ -975,7 +990,7 @@ public function testFormBuilderSupportsCoreBlocks(EndToEndTester $I) ); // Click an inner block within the Form Builder block. - $I->click('div[data-type="convertkit/form-builder"]'); + $I->selectGutenbergBlockInEditor($I, 'convertkit/form-builder'); $I->waitForElementVisible('.interface-interface-skeleton__sidebar[aria-label="Editor settings"]'); // Confirm some core blocks can be added to the Form Builder block. @@ -1160,7 +1175,7 @@ public function testFormBuilderWithStoreEntriesEnabled(EndToEndTester $I) ); // Focus on an inner block, so the Form Builder field blocks are available in the inserter. - $I->click('div[data-type="convertkit/form-builder-field-name"]'); + $I->selectGutenbergBlockInEditor($I, 'convertkit/form-builder-field-name'); // Add custom field block, mapping its data to the Last Name field in Kit. $I->addGutenbergBlock( @@ -1250,7 +1265,17 @@ public function _passed(EndToEndTester $I) */ private function seeFormBuilderBlock(EndToEndTester $I) { + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + $I->seeElementInDOM('div[data-type="convertkit/form-builder"]'); + + // Switch back to main window. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** @@ -1262,7 +1287,17 @@ private function seeFormBuilderBlock(EndToEndTester $I) */ private function seeFormBuilderButtonBlock(EndToEndTester $I) { + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + $I->seeElementInDOM('div[data-type="convertkit/form-builder"] div[data-type="core/button"]'); + + // Switch back to main window. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** @@ -1277,9 +1312,15 @@ private function seeFormBuilderButtonBlock(EndToEndTester $I) * @param string $label Field label. * @param bool $required Whether the field should be marked `required`. * @param string $container The container the field should be in. + * @param bool $isFrontend Whether the field is being tested in the frontend. */ - private function seeFormBuilderField(EndToEndTester $I, $fieldType, $fieldName, $fieldID, $label, $required = true, $container = 'div') + private function seeFormBuilderField(EndToEndTester $I, $fieldType, $fieldName, $fieldID, $label, $required = true, $container = 'div', $isFrontend = false) { + // Switch to the Gutenberg IFrame. + if ( ! $isFrontend && $I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + // Check field exists with correct attributes. switch ( $fieldType ) { case 'textarea': @@ -1297,6 +1338,11 @@ private function seeFormBuilderField(EndToEndTester $I, $fieldType, $fieldName, if ($required) { $I->seeElementInDOM($container . ' label[for="' . $fieldID . '"] span.convertkit-form-builder-field-required'); } + + // Switch back to main window. + if ( ! $isFrontend && $I->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** diff --git a/tests/Support/Data/dump.sql b/tests/Support/Data/dump.sql index e3ec007bf..f8c6cba2b 100644 --- a/tests/Support/Data/dump.sql +++ b/tests/Support/Data/dump.sql @@ -372,7 +372,7 @@ INSERT INTO `wp_usermeta` (`umeta_id`, `user_id`, `meta_key`, `meta_value`) VALU (19, 1, 'wp_dashboard_quick_press_last_post_id', '1'), (20, 1, 'edit_page_per_page', '100'), (21, 1, 'edit_post_per_page', '100'), -(22, 1, 'wp_persisted_preferences', 'a:4:{s:4:"core";a:1:{s:26:"isComplementaryAreaVisible";b:1;}s:14:"core/edit-post";a:1:{s:12:"welcomeGuide";b:0;}s:9:"_modified";s:24:"2024-07-18T02:45:41.491Z";s:17:"core/edit-widgets";a:2:{s:26:"isComplementaryAreaVisible";b:1;s:12:"welcomeGuide";b:0;}}'); +(22, 1, 'wp_persisted_preferences', 'a:4:{s:4:"core";a:2:{s:26:"isComplementaryAreaVisible";b:1;s:24:"enableChoosePatternModal";b:0;}s:14:"core/edit-post";a:4:{s:12:"welcomeGuide";b:0;s:23:"metaBoxesMainOpenHeight";i:540;s:20:"welcomeGuideTemplate";b:0;s:19:"metaBoxesMainIsOpen";b:1;}s:9:"_modified";s:24:"2024-07-18T02:45:41.491Z";s:17:"core/edit-widgets";a:2:{s:26:"isComplementaryAreaVisible";b:1;s:12:"welcomeGuide";b:0;}}'); DROP TABLE IF EXISTS `wp_users`; CREATE TABLE `wp_users` ( diff --git a/tests/Support/Helper/DiviBuilder.php b/tests/Support/Helper/DiviBuilder.php index 87aa7372a..5c7ff3402 100644 --- a/tests/Support/Helper/DiviBuilder.php +++ b/tests/Support/Helper/DiviBuilder.php @@ -83,7 +83,14 @@ public function createDiviPageInBackendEditor($I, $title) public function createDiviPageInFrontendEditor($I, $title, $configureMetaBox = true) { // Add a Page using the Gutenberg editor. - $I->addGutenbergPage($I, 'page', $title); + // We don't use addGutenbergPage(), as when the Divi Builder is used, the iframed Gutenberg editor is not used, + // and addGutenbergPage() may switch to an iframe based on the value of the WORDPRESS_V3_BLOCK_EDITOR_ENABLED environment variable. + // Navigate to Post Type (e.g. Pages / Posts) > Add New. + $I->amOnAdminPage('post-new.php?post_type=page'); + $I->waitForElementVisible('body.post-new-php'); + + // Define the Title. + $I->fillField('.editor-post-title__input', $title); // Configure metabox's Form setting = None, ensuring we only test the block in Gutenberg. if ($configureMetaBox) { diff --git a/tests/Support/Helper/KitPlugin.php b/tests/Support/Helper/KitPlugin.php index eadee0e93..205fff851 100644 --- a/tests/Support/Helper/KitPlugin.php +++ b/tests/Support/Helper/KitPlugin.php @@ -780,6 +780,11 @@ public function testBlockNoCredentialsPopupWindow($I, $blockName, $expectedMessa // Confirm that the Form block displays instructions to the user on how to enter their API Key. $I->seeBlockHasNoContentMessage($I, 'Not connected to Kit.'); + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + // Click the link to confirm it loads the Plugin's setup wizard. $I->click( 'Click here to connect your Kit account.', @@ -800,6 +805,11 @@ public function testBlockNoCredentialsPopupWindow($I, $blockName, $expectedMessa // Close the popup window. $I->closeTab(); + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + // Wait until the block changes to refreshing. $I->waitForElementVisible('.' . $blockName . ' .convertkit-block-refreshing', 30); @@ -807,6 +817,11 @@ public function testBlockNoCredentialsPopupWindow($I, $blockName, $expectedMessa // and that resources now exist. $I->waitForElementNotVisible('div.convertkit-no-content button.wp-convertkit-refresh-resources', 30); + // Switch back to main window. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } + // Confirm that the block displays the expected message. if ($expectedMessage) { $I->seeBlockHasNoContentMessage($I, $expectedMessage); @@ -822,11 +837,21 @@ public function testBlockNoCredentialsPopupWindow($I, $blockName, $expectedMessa */ public function clickBlockRefreshButton($I) { + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + // Click the refresh button. $I->click('div.convertkit-no-content button.wp-convertkit-refresh-resources'); // Wait for the refresh button to disappear, confirming that credentials and resources now exist. $I->waitForElementNotVisible('div.convertkit-no-content button.wp-convertkit-refresh-resources'); + + // Switch back to main window. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** @@ -839,6 +864,11 @@ public function clickBlockRefreshButton($I) */ public function seeBlockHasNoContentMessage($I, $message) { + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + $I->see( $message, [ @@ -847,7 +877,9 @@ public function seeBlockHasNoContentMessage($I, $message) ); // Switch back to main window. - $I->switchToIFrame(); + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** @@ -861,6 +893,11 @@ public function seeBlockHasNoContentMessage($I, $message) */ public function clickLinkInBlockAndAssertKitLoginScreen($I, $linkText) { + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + $I->click( $linkText, [ @@ -876,6 +913,11 @@ public function clickLinkInBlockAndAssertKitLoginScreen($I, $linkText) // Close tab. $I->closeTab(); + + // Switch back to main window. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** @@ -888,6 +930,11 @@ public function clickLinkInBlockAndAssertKitLoginScreen($I, $linkText) */ public function seeFormBlockIFrameHasMessage($I, $message) { + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + // Switch to iframe preview for the Form block. $I->switchToIFrame('iframe[class="components-sandbox"]'); @@ -969,6 +1016,11 @@ public function dontSeeCreatorNetworkRecommendationsScript($I, $pageID) */ public function selectAllText($I, $selector) { + // Switch to the Gutenberg IFrame. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + // Determine whether to use the control or command key, depending on the OS. $key = \Facebook\WebDriver\WebDriverKeys::CONTROL; @@ -979,6 +1031,11 @@ public function selectAllText($I, $selector) // Press Ctrl/Command + a on Keyboard. $I->pressKey($selector, array( $key, 'a' )); + + // Switch back to main window. + if ($I->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** diff --git a/tests/Support/Helper/WPGutenberg.php b/tests/Support/Helper/WPGutenberg.php index eedd08381..e1ae82bf1 100644 --- a/tests/Support/Helper/WPGutenberg.php +++ b/tests/Support/Helper/WPGutenberg.php @@ -10,18 +10,28 @@ class WPGutenberg extends \Codeception\Module { /** - * Helper method to switch to the Gutenberg editor Iframe. - * Use this method if all blocks use the Block API v3, - * as this means Gutenberg will be served in an Iframe. - * At present, we use v2 to provide backwards compatibility - * down to WordPress 5.6: + * Helper method to determine if the Gutenberg IFrame editor is enabled + * in tests by inspecting the WORDPRESS_V3_BLOCK_EDITOR_ENABLED environment variable. + * + * @since 3.1.4 + * + * @return bool + */ + public function isGutenbergIFrameEditorEnabled() + { + return filter_var($_ENV['WORDPRESS_V3_BLOCK_EDITOR_ENABLED'], FILTER_VALIDATE_BOOLEAN); + } + + /** + * Helper method to switch to the Gutenberg editor Iframe + * when all blocks use the Block API v3: * https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/ * * @since 2.7.7 * * @param EndToEndTester $I EndToEnd Tester. */ - public function switchToGutenbergEditor($I) + public function switchToGutenbergIFrameEditor($I) { $I->switchToIFrame('iframe[name="editor-canvas"]'); } @@ -41,8 +51,18 @@ public function addGutenbergPage($I, $postType = 'page', $title = 'Gutenberg Tit $I->amOnAdminPage('post-new.php?post_type=' . $postType); $I->waitForElementVisible('body.post-new-php'); + // Switch to the Gutenberg IFrame. + if ($this->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + // Define the Title. $I->fillField('.editor-post-title__input', $title); + + // Switch back to main window. + if ($this->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** @@ -188,9 +208,22 @@ public function addGutenbergBlock($I, $blockName, $blockProgrammaticName, $block */ public function addGutenbergParagraphBlock($I, $text) { + // Add paragraph block. $I->addGutenbergBlock($I, 'Paragraph', 'paragraph/paragraph'); + + // Switch to the Gutenberg IFrame. + if ($this->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + + // Click the editor area and enter the text in the paragraph. $I->click('.wp-block-post-content'); $I->fillField('.wp-block-post-content p[data-empty="true"]', $text); + + // Switch back to main window. + if ($this->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } } /** @@ -292,6 +325,27 @@ private function insertGutenbergLink($I, $name) $I->click($name, '.block-editor-link-control__search-results'); } + /** + * Helper method to select an existing block previously added to the Gutenberg editor. + * + * @since 3.1.4 + * + * @param EndToEndTester $I EndToEnd Tester. + * @param string $blockProgrammaticName Programmatic Block Name (e.g. 'convertkit/form-builder-field-name'). + */ + public function selectGutenbergBlockInEditor($I, $blockProgrammaticName) + { + if ($this->isGutenbergIFrameEditorEnabled()) { + $I->switchToGutenbergIFrameEditor($I); + } + + $I->click('div[data-type="' . $blockProgrammaticName . '"]'); + + if ($this->isGutenbergIFrameEditorEnabled()) { + $I->switchToIFrame(); + } + } + /** * Asserts that the given block is available in the Gutenberg block library. *