diff --git a/tests/EndToEnd/broadcasts/import-export/BroadcastsToPostsSettingsCest.php b/tests/EndToEnd/broadcasts/import-export/BroadcastsToPostsSettingsCest.php index c295cfad3..81210d21d 100644 --- a/tests/EndToEnd/broadcasts/import-export/BroadcastsToPostsSettingsCest.php +++ b/tests/EndToEnd/broadcasts/import-export/BroadcastsToPostsSettingsCest.php @@ -76,6 +76,9 @@ public function testEnableDisableImport(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -102,6 +105,9 @@ public function testEnableDisableImport(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -145,6 +151,9 @@ public function testSaveSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); diff --git a/tests/EndToEnd/general/other/ActivateDeactivatePluginCest.php b/tests/EndToEnd/general/other/ActivateDeactivatePluginCest.php index 82760c62a..c143d1632 100644 --- a/tests/EndToEnd/general/other/ActivateDeactivatePluginCest.php +++ b/tests/EndToEnd/general/other/ActivateDeactivatePluginCest.php @@ -53,6 +53,9 @@ public function testPluginActivationAndDeactivationWithOtherPlugins(EndToEndTest // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); diff --git a/tests/EndToEnd/general/other/LegacyFormDropdownCest.php b/tests/EndToEnd/general/other/LegacyFormDropdownCest.php index ccf7047f5..05a768fed 100644 --- a/tests/EndToEnd/general/other/LegacyFormDropdownCest.php +++ b/tests/EndToEnd/general/other/LegacyFormDropdownCest.php @@ -139,6 +139,9 @@ public function testWarningDisplayedForLegacyDefaultFormsSetting(EndToEndTester ); $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Confirm the warning is no longer displayed. $I->waitForElementNotVisible('#convertkit-legacy-settings-warning'); } diff --git a/tests/EndToEnd/general/other/ReviewRequestCest.php b/tests/EndToEnd/general/other/ReviewRequestCest.php index 8f34351c3..d64cdd503 100644 --- a/tests/EndToEnd/general/other/ReviewRequestCest.php +++ b/tests/EndToEnd/general/other/ReviewRequestCest.php @@ -54,6 +54,9 @@ public function testReviewRequestOnSaveSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -83,6 +86,9 @@ public function testReviewRequestOnSaveBlankSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); diff --git a/tests/EndToEnd/general/plugin-screens/PluginSettingsGeneralCest.php b/tests/EndToEnd/general/plugin-screens/PluginSettingsGeneralCest.php index f7c705e98..b02c7a762 100644 --- a/tests/EndToEnd/general/plugin-screens/PluginSettingsGeneralCest.php +++ b/tests/EndToEnd/general/plugin-screens/PluginSettingsGeneralCest.php @@ -149,6 +149,9 @@ public function testValidCredentials(EndToEndTester $I) // Save Changes to confirm credentials are not lost. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -270,6 +273,7 @@ public function testChangeDefaultFormSettingAndPreviewFormLinks(EndToEndTester $ // Setup Plugin, without defining default Forms. $I->setupKitPluginNoDefaultForms($I); + $I->setupKitPluginResources($I); // Go to the Plugin's Settings Screen. $I->loadKitSettingsGeneralScreen($I); @@ -326,6 +330,9 @@ public function testChangeDefaultFormSettingAndPreviewFormLinks(EndToEndTester $ // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -349,6 +356,7 @@ public function testChangeDefaultSiteWideFormsSettingAndPreviewFormLinks(EndToEn { // Setup Plugin, without defining default Forms. $I->setupKitPluginNoDefaultForms($I); + $I->setupKitPluginResources($I); // Go to the Plugin's Settings Screen. $I->loadKitSettingsGeneralScreen($I); @@ -404,6 +412,9 @@ public function testChangeDefaultSiteWideFormsSettingAndPreviewFormLinks(EndToEn // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -431,6 +442,7 @@ public function testChangeDefaultFormPositionAfterElementSetting(EndToEndTester { // Setup Plugin, without defining default Forms. $I->setupKitPluginNoDefaultForms($I); + $I->setupKitPluginResources($I); // Go to the Plugin's Settings Screen. $I->loadKitSettingsGeneralScreen($I); @@ -476,6 +488,9 @@ public function testChangeDefaultFormPositionAfterElementSetting(EndToEndTester // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -530,6 +545,7 @@ public function testPublicPrivateCustomPostTypeSettingsExist(EndToEndTester $I) // Setup Plugin, without defining default Forms. $I->setupKitPluginNoDefaultForms($I); + $I->setupKitPluginResources($I); // Go to the Plugin's Settings Screen. $I->loadKitSettingsGeneralScreen($I); @@ -547,6 +563,9 @@ public function testPublicPrivateCustomPostTypeSettingsExist(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -638,6 +657,9 @@ public function testRecaptchaSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -654,6 +676,9 @@ public function testRecaptchaSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -704,6 +729,9 @@ public function testCloudflareTurnstileSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -718,6 +746,9 @@ public function testCloudflareTurnstileSettings(EndToEndTester $I) $I->clearField('#cloudflare_turnstile_secret_key'); $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -748,6 +779,9 @@ public function testEnableAndDisableDebugSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -760,6 +794,9 @@ public function testEnableAndDisableDebugSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -789,6 +826,9 @@ public function testEnableAndDisableJavaScriptSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -801,6 +841,9 @@ public function testEnableAndDisableJavaScriptSettings(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -831,6 +874,9 @@ public function testEnableAndDisableCSSSetting(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -852,6 +898,9 @@ public function testEnableAndDisableCSSSetting(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -888,6 +937,9 @@ public function testEnableAndDisableAddNewLandingPageMemberContentButtonSetting( // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -900,6 +952,9 @@ public function testEnableAndDisableAddNewLandingPageMemberContentButtonSetting( // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -930,6 +985,9 @@ public function testEnableAndDisableUsageTrackingSetting(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -942,6 +1000,9 @@ public function testEnableAndDisableUsageTrackingSetting(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -993,6 +1054,9 @@ public function testSettingsScreenWhenNoResources(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -1011,6 +1075,9 @@ public function testSettingsScreenWhenNoResources(EndToEndTester $I) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); diff --git a/tests/EndToEnd/general/plugin-screens/PluginSettingsMCPCest.php b/tests/EndToEnd/general/plugin-screens/PluginSettingsMCPCest.php index 976306ba7..d41501db4 100644 --- a/tests/EndToEnd/general/plugin-screens/PluginSettingsMCPCest.php +++ b/tests/EndToEnd/general/plugin-screens/PluginSettingsMCPCest.php @@ -55,6 +55,9 @@ public function testEnableAndDisableMCPServerSetting(EndToEndTester $I) $I->checkOption('#enabled'); $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -70,6 +73,9 @@ public function testEnableAndDisableMCPServerSetting(EndToEndTester $I) $I->uncheckOption('#enabled'); $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -115,6 +121,9 @@ public function testGenerateAndRevokeApplicationPassword(EndToEndTester $I) $I->checkOption('#enabled'); $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); diff --git a/tests/EndToEnd/integrations/elementor/ElementorBroadcastsCest.php b/tests/EndToEnd/integrations/elementor/ElementorBroadcastsCest.php index c429cde3f..463595a40 100644 --- a/tests/EndToEnd/integrations/elementor/ElementorBroadcastsCest.php +++ b/tests/EndToEnd/integrations/elementor/ElementorBroadcastsCest.php @@ -44,8 +44,14 @@ public function testBroadcastsWidgetIsRegistered(EndToEndTester $I) // Click Edit with Elementor button. $I->click('#elementor-switch-mode-button'); + // Wait for Elementor to load, as its loading overlay covers the widget panel, + // which makes the panel's search field not interactable. + $I->waitForElementVisible('#elementor-preview-iframe'); + $I->waitForElementNotVisible('#elementor-loading'); + // Search for the Kit Broadcasts block. - $I->waitForElementVisible('#elementor-panel-elements-search-input'); + $I->waitForElementVisible('#elementor-panel-page-elements .elementor-element'); + $I->waitForElementClickable('#elementor-panel-elements-search-input'); $I->fillField('#elementor-panel-elements-search-input', 'Kit Broadcasts'); // Confirm that the Broadcasts widget is displayed as an option. @@ -70,8 +76,14 @@ public function testBroadcastsWidgetConditionalFields(EndToEndTester $I) // Click Edit with Elementor button. $I->click('#elementor-switch-mode-button'); + // Wait for Elementor to load, as its loading overlay covers the widget panel, + // which makes the panel's search field not interactable. + $I->waitForElementVisible('#elementor-preview-iframe'); + $I->waitForElementNotVisible('#elementor-loading'); + // Search for the Kit Broadcasts block. - $I->waitForElementVisible('#elementor-panel-elements-search-input'); + $I->waitForElementVisible('#elementor-panel-page-elements .elementor-element'); + $I->waitForElementClickable('#elementor-panel-elements-search-input'); $I->fillField('#elementor-panel-elements-search-input', 'Kit Broadcasts'); // Insert the Broadcasts widget. diff --git a/tests/EndToEnd/integrations/elementor/ElementorFormCest.php b/tests/EndToEnd/integrations/elementor/ElementorFormCest.php index 405cccc2e..3dd870992 100644 --- a/tests/EndToEnd/integrations/elementor/ElementorFormCest.php +++ b/tests/EndToEnd/integrations/elementor/ElementorFormCest.php @@ -46,8 +46,14 @@ public function testFormWidgetIsRegistered(EndToEndTester $I) // Click Edit with Elementor button. $I->click('#elementor-switch-mode-button'); + // Wait for Elementor to load, as its loading overlay covers the widget panel, + // which makes the panel's search field not interactable. + $I->waitForElementVisible('#elementor-preview-iframe'); + $I->waitForElementNotVisible('#elementor-loading'); + // Search for the Kit Form block. - $I->waitForElementVisible('#elementor-panel-elements-search-input'); + $I->waitForElementVisible('#elementor-panel-page-elements .elementor-element'); + $I->waitForElementClickable('#elementor-panel-elements-search-input'); $I->fillField('#elementor-panel-elements-search-input', 'Kit Form'); // Confirm that the Form widget is displayed as an option. diff --git a/tests/EndToEnd/integrations/elementor/ElementorFormTriggerCest.php b/tests/EndToEnd/integrations/elementor/ElementorFormTriggerCest.php index 05fa479d5..0fb13bb0c 100644 --- a/tests/EndToEnd/integrations/elementor/ElementorFormTriggerCest.php +++ b/tests/EndToEnd/integrations/elementor/ElementorFormTriggerCest.php @@ -44,8 +44,14 @@ public function testFormTriggerWidgetIsRegistered(EndToEndTester $I) // Click Edit with Elementor button. $I->click('#elementor-switch-mode-button'); + // Wait for Elementor to load, as its loading overlay covers the widget panel, + // which makes the panel's search field not interactable. + $I->waitForElementVisible('#elementor-preview-iframe'); + $I->waitForElementNotVisible('#elementor-loading'); + // Search for the Kit Form Trigger block. - $I->waitForElementVisible('#elementor-panel-elements-search-input'); + $I->waitForElementVisible('#elementor-panel-page-elements .elementor-element'); + $I->waitForElementClickable('#elementor-panel-elements-search-input'); $I->fillField('#elementor-panel-elements-search-input', 'Kit Form Trigger'); // Confirm that the Form Trigger widget is displayed as an option. diff --git a/tests/EndToEnd/integrations/elementor/ElementorMemberContentLoginCest.php b/tests/EndToEnd/integrations/elementor/ElementorMemberContentLoginCest.php index fa6c73c80..1af51a480 100644 --- a/tests/EndToEnd/integrations/elementor/ElementorMemberContentLoginCest.php +++ b/tests/EndToEnd/integrations/elementor/ElementorMemberContentLoginCest.php @@ -44,8 +44,14 @@ public function testMemberContentLoginWidgetIsRegistered(EndToEndTester $I) // Click Edit with Elementor button. $I->click('#elementor-switch-mode-button'); + // Wait for Elementor to load, as its loading overlay covers the widget panel, + // which makes the panel's search field not interactable. + $I->waitForElementVisible('#elementor-preview-iframe'); + $I->waitForElementNotVisible('#elementor-loading'); + // Search for the Kit Member Content Login block. - $I->waitForElementVisible('#elementor-panel-elements-search-input'); + $I->waitForElementVisible('#elementor-panel-page-elements .elementor-element'); + $I->waitForElementClickable('#elementor-panel-elements-search-input'); $I->fillField('#elementor-panel-elements-search-input', 'Kit Member Content Login'); // Confirm that the Member Content Login widget is displayed as an option. diff --git a/tests/EndToEnd/integrations/elementor/ElementorProductCest.php b/tests/EndToEnd/integrations/elementor/ElementorProductCest.php index 920e700c4..f29b59a0b 100644 --- a/tests/EndToEnd/integrations/elementor/ElementorProductCest.php +++ b/tests/EndToEnd/integrations/elementor/ElementorProductCest.php @@ -44,8 +44,14 @@ public function testProductWidgetIsRegistered(EndToEndTester $I) // Click Edit with Elementor button. $I->click('#elementor-switch-mode-button'); + // Wait for Elementor to load, as its loading overlay covers the widget panel, + // which makes the panel's search field not interactable. + $I->waitForElementVisible('#elementor-preview-iframe'); + $I->waitForElementNotVisible('#elementor-loading'); + // Search for the Kit Product block. - $I->waitForElementVisible('#elementor-panel-elements-search-input'); + $I->waitForElementVisible('#elementor-panel-page-elements .elementor-element'); + $I->waitForElementClickable('#elementor-panel-elements-search-input'); $I->fillField('#elementor-panel-elements-search-input', 'Kit Product'); // Confirm that the Product widget is displayed as an option. diff --git a/tests/EndToEnd/integrations/other/ContactForm7FormCest.php b/tests/EndToEnd/integrations/other/ContactForm7FormCest.php index af15beb77..d68395af4 100644 --- a/tests/EndToEnd/integrations/other/ContactForm7FormCest.php +++ b/tests/EndToEnd/integrations/other/ContactForm7FormCest.php @@ -323,6 +323,9 @@ public function testSettingsContactForm7CreatorNetworkRecommendationsWhenEnabled // Save. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -470,6 +473,9 @@ private function _contactForm7SetupForm(EndToEndTester $I, string $optionName) $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); diff --git a/tests/EndToEnd/integrations/other/ForminatorCest.php b/tests/EndToEnd/integrations/other/ForminatorCest.php index 23aa6ebfe..912da6e1d 100644 --- a/tests/EndToEnd/integrations/other/ForminatorCest.php +++ b/tests/EndToEnd/integrations/other/ForminatorCest.php @@ -533,6 +533,9 @@ public function testSettingsForminatorCreatorNetworkRecommendationsWhenEnabledOn // Save. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -830,6 +833,9 @@ private function _forminatorSetupForm(EndToEndTester $I, string $optionName) $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); @@ -879,6 +885,9 @@ private function _forminatorSetupQuiz(EndToEndTester $I, string $optionName) $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); diff --git a/tests/EndToEnd/restrict-content/general/RestrictContentSettingsCest.php b/tests/EndToEnd/restrict-content/general/RestrictContentSettingsCest.php index ca4b9626e..0f649f12c 100644 --- a/tests/EndToEnd/restrict-content/general/RestrictContentSettingsCest.php +++ b/tests/EndToEnd/restrict-content/general/RestrictContentSettingsCest.php @@ -207,6 +207,9 @@ public function testDisableCSSSetting(EndToEndTester $I) $I->checkOption('#no_css'); $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Create Restricted Content Page. $pageID = $I->createRestrictedContentPage( $I, @@ -255,6 +258,9 @@ public function _setupKitPluginRestrictContent($I, $settings = false) // Click the Save Changes button. $I->click('Save Changes'); + // Wait for the settings to save. + $I->waitForElementVisible('#setting-error-settings_updated'); + // Check that no PHP warnings or notices were output. $I->checkNoWarningsAndNoticesOnScreen($I); } diff --git a/tests/Support/Helper/Divi5Theme.php b/tests/Support/Helper/Divi5Theme.php index 78cd4fe53..43add45ef 100644 --- a/tests/Support/Helper/Divi5Theme.php +++ b/tests/Support/Helper/Divi5Theme.php @@ -38,7 +38,14 @@ public function createDivi5Page($I, $title) ); // Edit Page. - $I->amOnPage('/wp-admin/post.php?post=' . $pageID . '&action=edit'); + // Chrome waits for the load event before returning, which external resources on the + // editor screen (such as Divi's Google Fonts stylesheet) can delay indefinitely. + try { + $I->amOnPage('/wp-admin/post.php?post=' . $pageID . '&action=edit'); + } catch (\Facebook\WebDriver\Exception\TimeoutException $e) { + // Stop loading the outstanding resources, as the editor has rendered by this point. + $I->executeJS('window.stop();'); + } // Switch to the Gutenberg IFrame. if ($I->isGutenbergIFrameEditorEnabled()) { @@ -46,6 +53,7 @@ public function createDivi5Page($I, $title) } // Click "Use The Divi Builder" button. + $I->waitForElementVisible('#et-switch-to-divi'); $I->click('#et-switch-to-divi'); // Switch back to main window. diff --git a/tests/Support/Helper/KitAPI.php b/tests/Support/Helper/KitAPI.php index b331e0f28..2f3d2bc74 100644 --- a/tests/Support/Helper/KitAPI.php +++ b/tests/Support/Helper/KitAPI.php @@ -432,7 +432,7 @@ public function apiRequest($endpoint, $method = 'GET', $params = array()) 'headers' => [ 'Authorization' => 'Bearer ' . $_ENV['CONVERTKIT_OAUTH_ACCESS_TOKEN'], ], - 'timeout' => 5, + 'timeout' => 30, ] ); break; @@ -447,7 +447,7 @@ public function apiRequest($endpoint, $method = 'GET', $params = array()) 'Content-Type' => 'application/json; charset=utf-8', 'Authorization' => 'Bearer ' . $_ENV['CONVERTKIT_OAUTH_ACCESS_TOKEN'], ], - 'timeout' => 5, + 'timeout' => 30, 'body' => (string) json_encode($params), // phpcs:ignore WordPress.WP.AlternativeFunctions ] ); diff --git a/tests/Support/Helper/ThirdPartyPlugin.php b/tests/Support/Helper/ThirdPartyPlugin.php index 93c91205e..45a5ee498 100644 --- a/tests/Support/Helper/ThirdPartyPlugin.php +++ b/tests/Support/Helper/ThirdPartyPlugin.php @@ -53,8 +53,10 @@ public function activateThirdPartyPlugin($I, $name, $wizardExpectsToDisplay = tr switch ($name) { case 'convertkit': // Wait for the Plugin Setup Wizard screen to load, if it's expected to display. + // The Setup Wizard's first screen builds an OAuth URL using the API, so allow + // longer than the default timeout for it to render. if ( $wizardExpectsToDisplay ) { - $I->waitForElementVisible('body.convertkit'); + $I->waitForElementVisible('body.convertkit', 30); } break; @@ -192,12 +194,24 @@ public function doLoginAsAdmin($I) $I->waitForElementVisible('#wp-submit'); $I->waitForElementVisible('#backtoblog'); - // Fill in the login form. - $I->click('#user_login'); - $I->fillField('#user_login', $_ENV['WORDPRESS_ADMIN_USER']); + // WordPress' login screen focuses and selects the username field 200ms after it loads. + // Wait for that to happen before typing, otherwise focus is stolen part way through + // completing the form, and the password is typed over the selected username. + $I->wait(1); + + // Fill in the login form, retrying if focus was stolen while typing. + for ($attempt = 0; $attempt < 3; $attempt++) { + $I->fillField('#user_login', $_ENV['WORDPRESS_ADMIN_USER']); + $I->fillField('#user_pass', $_ENV['WORDPRESS_ADMIN_PASSWORD']); + + if ($I->grabValueFrom('#user_login') === $_ENV['WORDPRESS_ADMIN_USER'] + && $I->grabValueFrom('#user_pass') === $_ENV['WORDPRESS_ADMIN_PASSWORD']) { + break; + } + } + + // Confirm the login form is completed. $I->seeInField('#user_login', $_ENV['WORDPRESS_ADMIN_USER']); - $I->click('#user_pass'); - $I->fillField('#user_pass', $_ENV['WORDPRESS_ADMIN_PASSWORD']); $I->seeInField('#user_pass', $_ENV['WORDPRESS_ADMIN_PASSWORD']); // Submit. diff --git a/tests/Support/Helper/WPClassicEditor.php b/tests/Support/Helper/WPClassicEditor.php index c8a1aca82..1509cb95e 100644 --- a/tests/Support/Helper/WPClassicEditor.php +++ b/tests/Support/Helper/WPClassicEditor.php @@ -134,6 +134,9 @@ public function openVisualEditorShortcodeModal($I, $shortcodeName, $targetEditor // Click the Visual tab on the applicable TinyMCE editor. $I->click('button#' . $targetEditor . '-tmce'); + // Wait for TinyMCE to initialise, as its toolbar isn't in the DOM until it has. + $I->waitForElementVisible('#wp-' . $targetEditor . '-editor-container div.mce-container div[aria-label="' . $shortcodeName . '"] button'); + // Click the TinyMCE Button for this shortcode. $I->click('#wp-' . $targetEditor . '-editor-container div.mce-container div[aria-label="' . $shortcodeName . '"] button'); diff --git a/tests/Support/Helper/WPGutenberg.php b/tests/Support/Helper/WPGutenberg.php index a4d9d4b2a..5ce35f9d0 100644 --- a/tests/Support/Helper/WPGutenberg.php +++ b/tests/Support/Helper/WPGutenberg.php @@ -117,6 +117,7 @@ public function addGutenbergBlock($I, $blockName, $blockProgrammaticName, $block // When the Blocks sidebar appears, search for the block. $I->waitForElementVisible('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); $I->seeElementInDOM('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); + $I->waitForElementClickable('.block-editor-inserter__menu input[type=search]'); $I->fillField('.block-editor-inserter__menu input[type=search]', $blockName); // Let WordPress load any matching block patterns, which reloads the DOM elements. @@ -162,6 +163,9 @@ public function addGutenbergBlock($I, $blockName, $blockProgrammaticName, $block // Close block inserter. $this->clickAddGutenbergBlockButton($I); + // Wait for the block inserter to close. + $I->waitForElementNotVisible('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); + // If a Block configuration is specified, apply it to the Block now. if ($blockConfiguration) { $I->waitForElementVisible('.interface-interface-skeleton__sidebar[aria-label="Editor settings"]'); @@ -394,6 +398,7 @@ public function seeGutenbergBlockAvailable($I, $blockName, $blockProgrammaticNam // When the Blocks sidebar appears, search for the block. $I->waitForElementVisible('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); $I->seeElementInDOM('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); + $I->waitForElementClickable('.block-editor-inserter__menu input[type=search]'); $I->fillField('.block-editor-inserter__menu input[type=search]', $blockName); // Let WordPress load any matching block patterns, which reloads the DOM elements. @@ -451,6 +456,9 @@ public function seeGutenbergBlockAvailable($I, $blockName, $blockProgrammaticNam // Close block inserter. $this->clickAddGutenbergBlockButton($I); + + // Wait for the block inserter to close. + $I->waitForElementNotVisible('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); } /** @@ -470,6 +478,7 @@ public function dontSeeGutenbergBlockAvailable($I, $blockName, $blockProgrammati // When the Blocks sidebar appears, search for the block. $I->waitForElementVisible('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); $I->seeElementInDOM('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); + $I->waitForElementClickable('.block-editor-inserter__menu input[type=search]'); $I->fillField('.block-editor-inserter__menu input[type=search]', $blockName); // Let WordPress load any matching block patterns, which reloads the DOM elements. @@ -484,6 +493,9 @@ public function dontSeeGutenbergBlockAvailable($I, $blockName, $blockProgrammati // Close block inserter. $this->clickAddGutenbergBlockButton($I); + + // Wait for the block inserter to close. + $I->waitForElementNotVisible('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); } /** diff --git a/tests/Support/Helper/WPWidget.php b/tests/Support/Helper/WPWidget.php index ef38eb353..cde22a97b 100644 --- a/tests/Support/Helper/WPWidget.php +++ b/tests/Support/Helper/WPWidget.php @@ -29,6 +29,7 @@ public function addLegacyWidget($I, $blockName, $blockProgrammaticName, $blockCo // When the Blocks sidebar appears, search for the legacy widget. $I->waitForElementVisible('.interface-interface-skeleton__secondary-sidebar'); + $I->waitForElementClickable('.block-editor-inserter__menu input[type=search]'); $I->fillField('.block-editor-inserter__menu input[type=search]', $blockName); // First matching item will be the legacy widget; any blocks will follow. @@ -114,13 +115,22 @@ public function addBlockWidget($I, $blockName, $blockProgrammaticName, $blockCon // When the Blocks sidebar appears, search for the block. $I->waitForElementVisible('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); $I->seeElementInDOM('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); + $I->waitForElementClickable('.block-editor-inserter__menu input[type=search]'); $I->fillField('.block-editor-inserter__menu input[type=search]', $blockName); - $I->waitForElementVisible('.block-editor-inserter__panel-content button.editor-block-list-item-' . $blockProgrammaticName); - $I->seeElementInDOM('.block-editor-inserter__panel-content button.editor-block-list-item-' . $blockProgrammaticName); + + // Let WordPress load any matching block patterns, which reloads the DOM elements. + // If we don't do this, we get stale reference errors when trying to click a block to insert. + $I->wait(2); + + $I->waitForElementClickable('.block-editor-inserter__panel-content button.editor-block-list-item-' . $blockProgrammaticName); $I->click('.block-editor-inserter__panel-content button.editor-block-list-item-' . $blockProgrammaticName); // Close block inserter. $I->click('button.edit-widgets-header-toolbar__inserter-toggle'); + $I->waitForElementNotVisible('.interface-interface-skeleton__secondary-sidebar[aria-label="Block Library"]'); + + // Confirm the block inserted. + $I->waitForElementVisible('.interface-interface-skeleton__content .wp-block-' . $blockProgrammaticName); // If a Block configuration is specified, apply it to the Block now. if ($blockConfiguration) { @@ -167,23 +177,26 @@ public function addBlockWidget($I, $blockName, $blockProgrammaticName, $blockCon } // Save. - $I->click('Update'); - - // Wait for save to complete. - $I->waitForElementVisible('.components-snackbar__content'); - $result = $I->grabTextFrom('.components-snackbar__content'); - // Sometimes, WordPress throws an intermittent "There was an error. The response is not a valid JSON response." // when saving Widgets in WordPress 5.8+ using the block editor // It's not clear why - see https://wordpress.org/support/topic/widget-config-json-error/, https://wordpress.org/support/topic/there-was-an-error-the-response-is-not-a-valid-json-response/ // If this happens, attempt to save again after a couple of seconds. - if ($result !== 'Widgets saved.') { - $I->wait(5); - $I->click('Update'); + $I->click('Update'); - // Wait for save to complete. + // Wait for the save to complete. + $I->waitForElementVisible('.components-snackbar__content'); + + // If this happens, attempt to save again. + if ($I->grabTextFrom('.components-snackbar__content') !== 'Widgets saved.') { + // Wait for this notice to clear, so we read the next save's notice and not this one. + $I->waitForElementNotVisible('.components-snackbar__content', 15); + $I->click('Update'); $I->waitForElementVisible('.components-snackbar__content'); } + + // Confirm the widgets saved, so a failed save is reported here, and not as + // missing output when viewing the frontend site. + $I->see('Widgets saved.', '.components-snackbar__content'); } /**