Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7535f4a
Run Tests against WordPress 6.9 Beta
n7studios Oct 23, 2025
00202a5
Bump DB version
n7studios Oct 23, 2025
90ff202
Refresh Resources: Improve detection of block editor in 6.9 using wp.…
n7studios Oct 24, 2025
df693e5
Use wp.editPost check to register pre-publish actions
n7studios Oct 24, 2025
1b3284b
JS Coding Standards
n7studios Oct 24, 2025
e10ba93
Merge branch 'improve-block-editor-detection' into test-wp-6.9
n7studios Oct 24, 2025
b21bd1b
Merge branch 'improve-block-editor-detection' into test-wp-6.9
n7studios Oct 24, 2025
9befd61
Merge branch 'improve-block-editor-detection' into test-wp-6.9
n7studios Oct 25, 2025
cdd82eb
Fix Divi Tests
n7studios Oct 27, 2025
c569a4f
Fix Uncode tests
n7studios Oct 27, 2025
c29a1c0
Merge remote-tracking branch 'origin/improve-divi-tests' into test-wp…
n7studios Oct 27, 2025
cc4dbee
Merge remote-tracking branch 'origin/improve-divi-tests' into test-wp…
n7studios Oct 28, 2025
a1fe73d
Merge remote-tracking branch 'origin/improve-divi-tests' into test-wp…
n7studios Oct 28, 2025
2fbc043
Tests: Uncode: Restrict Content: Ignore xdebug errors
n7studios Oct 28, 2025
1a9f8a3
Merge branch 'main' into test-wp-6.9
n7studios Nov 3, 2025
78773b5
Run Tests against WordPress 6.9 beta 2
n7studios Nov 3, 2025
a3525a8
Run Coding Standards against WordPress 6.9 beta 2
n7studios Nov 3, 2025
565c163
Merge branch 'main' into test-wp-6.9
n7studios Nov 6, 2025
f7e591c
Merge branch 'main' into test-wp-6.9
n7studios Nov 13, 2025
55d6050
Run Tests against WordPress 6.9 RC1
n7studios Nov 13, 2025
69f2b76
Revert code comments
n7studios Nov 13, 2025
b3aba42
Tests: Update heading and paragraph selectors
n7studios Nov 13, 2025
034e16f
Merge branch 'main' into test-wp-6.9
n7studios Nov 19, 2025
ef2ec7e
Merge branch 'main' into test-wp-6.9
n7studios Nov 20, 2025
d2b79fc
Run tests against WordPress 6.9 RC2
n7studios Nov 20, 2025
8fd0f47
Merge branch 'main' into test-wp-6.9
n7studios Nov 26, 2025
e929b24
Run tests against WordPress 6.9 RC3
n7studios Nov 26, 2025
a7a77dc
Merge branch 'main' into test-wp-6.9
n7studios Dec 3, 2025
3d5a62c
Run Tests against WordPress 6.9
n7studios Dec 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -979,8 +979,8 @@ public function testFormBuilderSupportsCoreBlocks(EndToEndTester $I)
$I->waitForElementVisible('.interface-interface-skeleton__sidebar[aria-label="Editor settings"]');

// Confirm some core blocks can be added to the Form Builder block.
$I->seeGutenbergBlockAvailable($I, 'Paragraph', 'paragraph');
$I->seeGutenbergBlockAvailable($I, 'Heading', 'heading');
$I->seeGutenbergBlockAvailable($I, 'Paragraph', 'paragraph/paragraph');
$I->seeGutenbergBlockAvailable($I, 'Heading', 'heading/heading');
$I->seeGutenbergBlockAvailable($I, 'List', 'list');
$I->seeGutenbergBlockAvailable($I, 'Image', 'image');
$I->seeGutenbergBlockAvailable($I, 'Spacer', 'spacer');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ public function testRestrictContentByProductWithUncodeThemeAndVisualComposer(End
options: [
'visible_content' => '',
'member_content' => 'Member-only content.',
]
],
// Don't check for warnings and notices, as Uncode uses deprecated functions which WordPress 6.9 warn about.
checkNoWarningsAndNotices: false
);

// Deactivate Visual Composer Page Builder.
Expand Down Expand Up @@ -122,7 +124,9 @@ public function testRestrictContentByProductWithUncodeTheme(EndToEndTester $I)
options: [
'visible_content' => '',
'member_content' => 'Member-only content.',
]
],
// Don't check for warnings and notices, as Uncode uses deprecated functions which WordPress 6.9 warn about.
checkNoWarningsAndNotices: false
);
}

Expand Down
4 changes: 2 additions & 2 deletions tests/Support/Data/dump.sql
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`
(43, 'html_type', 'text/html', 'on'),
(44, 'use_trackback', '0', 'on'),
(45, 'default_role', 'subscriber', 'on'),
(46, 'db_version', '60421', 'on'),
(46, 'db_version', '60717', 'on'),
(47, 'uploads_use_yearmonth_folders', '1', 'on'),
(48, 'upload_path', '', 'on'),
(49, 'blog_public', '1', 'on'),
Expand Down Expand Up @@ -208,7 +208,7 @@ INSERT INTO `wp_options` (`option_id`, `option_name`, `option_value`, `autoload`
(96, 'auto_update_core_minor', 'enabled', 'on'),
(97, 'auto_update_core_major', 'enabled', 'on'),
(98, 'wp_force_deactivated_plugins', 'a:0:{}', 'on'),
(99, 'initial_db_version', '60421', 'on'),
(99, 'initial_db_version', '60717', 'on'),
(100, 'wp_user_roles', 'a:5:{s:13:\"administrator\";a:2:{s:4:\"name\";s:13:\"Administrator\";s:12:\"capabilities\";a:61:{s:13:\"switch_themes\";b:1;s:11:\"edit_themes\";b:1;s:16:\"activate_plugins\";b:1;s:12:\"edit_plugins\";b:1;s:10:\"edit_users\";b:1;s:10:\"edit_files\";b:1;s:14:\"manage_options\";b:1;s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:6:\"import\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:8:\"level_10\";b:1;s:7:\"level_9\";b:1;s:7:\"level_8\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;s:12:\"delete_users\";b:1;s:12:\"create_users\";b:1;s:17:\"unfiltered_upload\";b:1;s:14:\"edit_dashboard\";b:1;s:14:\"update_plugins\";b:1;s:14:\"delete_plugins\";b:1;s:15:\"install_plugins\";b:1;s:13:\"update_themes\";b:1;s:14:\"install_themes\";b:1;s:11:\"update_core\";b:1;s:10:\"list_users\";b:1;s:12:\"remove_users\";b:1;s:13:\"promote_users\";b:1;s:18:\"edit_theme_options\";b:1;s:13:\"delete_themes\";b:1;s:6:\"export\";b:1;}}s:6:\"editor\";a:2:{s:4:\"name\";s:6:\"Editor\";s:12:\"capabilities\";a:34:{s:17:\"moderate_comments\";b:1;s:17:\"manage_categories\";b:1;s:12:\"manage_links\";b:1;s:12:\"upload_files\";b:1;s:15:\"unfiltered_html\";b:1;s:10:\"edit_posts\";b:1;s:17:\"edit_others_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:10:\"edit_pages\";b:1;s:4:\"read\";b:1;s:7:\"level_7\";b:1;s:7:\"level_6\";b:1;s:7:\"level_5\";b:1;s:7:\"level_4\";b:1;s:7:\"level_3\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:17:\"edit_others_pages\";b:1;s:20:\"edit_published_pages\";b:1;s:13:\"publish_pages\";b:1;s:12:\"delete_pages\";b:1;s:19:\"delete_others_pages\";b:1;s:22:\"delete_published_pages\";b:1;s:12:\"delete_posts\";b:1;s:19:\"delete_others_posts\";b:1;s:22:\"delete_published_posts\";b:1;s:20:\"delete_private_posts\";b:1;s:18:\"edit_private_posts\";b:1;s:18:\"read_private_posts\";b:1;s:20:\"delete_private_pages\";b:1;s:18:\"edit_private_pages\";b:1;s:18:\"read_private_pages\";b:1;}}s:6:\"author\";a:2:{s:4:\"name\";s:6:\"Author\";s:12:\"capabilities\";a:10:{s:12:\"upload_files\";b:1;s:10:\"edit_posts\";b:1;s:20:\"edit_published_posts\";b:1;s:13:\"publish_posts\";b:1;s:4:\"read\";b:1;s:7:\"level_2\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:12:\"delete_posts\";b:1;s:22:\"delete_published_posts\";b:1;}}s:11:\"contributor\";a:2:{s:4:\"name\";s:11:\"Contributor\";s:12:\"capabilities\";a:5:{s:10:\"edit_posts\";b:1;s:4:\"read\";b:1;s:7:\"level_1\";b:1;s:7:\"level_0\";b:1;s:12:\"delete_posts\";b:1;}}s:10:\"subscriber\";a:2:{s:4:\"name\";s:10:\"Subscriber\";s:12:\"capabilities\";a:2:{s:4:\"read\";b:1;s:7:\"level_0\";b:1;}}}', 'on'),
(101, 'fresh_site', '1', 'on'),
(102, 'user_count', '1', 'off'),
Expand Down
25 changes: 16 additions & 9 deletions tests/Support/Helper/KitRestrictContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,9 @@ public function createRestrictedContentPage($I, $options = false)
* @type string $member_content Content that should only be available to authenticated subscribers.
* @type array $settings Restrict content settings. If not defined, uses expected defaults.
* }
* @param bool $checkNoWarningsAndNotices Whether to check for errors.
*/
public function testRestrictedContentByProductOnFrontend($I, $urlOrPageID, $options = false)
public function testRestrictedContentByProductOnFrontend($I, $urlOrPageID, $options = false, $checkNoWarningsAndNotices = true)
{
// Setup test.
$options = $this->setupRestrictContentTest($I, $options, $urlOrPageID);
Expand All @@ -203,7 +204,7 @@ public function testRestrictedContentByProductOnFrontend($I, $urlOrPageID, $opti
$I->seeInSource('<link rel="stylesheet" id="convertkit-restrict-content-css" href="' . $_ENV['WORDPRESS_URL'] . '/wp-content/plugins/convertkit/resources/frontend/css/restrict-content.css');

// Check content is not displayed, and CTA displays with expected text.
$this->testRestrictContentByProductHidesContentWithCTA($I, $options);
$this->testRestrictContentByProductHidesContentWithCTA($I, $options, $checkNoWarningsAndNotices);

// Login as a Kit subscriber who does not exist in Kit.
$this->loginToRestrictContentWithEmail($I, 'fail@kit.com');
Expand All @@ -212,7 +213,7 @@ public function testRestrictedContentByProductOnFrontend($I, $urlOrPageID, $opti
$this->seeRestrictContentError($I, 'invalid: Email address is invalid');

// Check content is not displayed, and CTA displays with expected text.
$this->testRestrictContentByProductHidesContentWithCTA($I, $options);
$this->testRestrictContentByProductHidesContentWithCTA($I, $options, $checkNoWarningsAndNotices);

// Set cookie with signed subscriber ID and reload the restricted content page, as if we entered the
// code sent in the email as a Kit subscriber who has not subscribed to the product.
Expand All @@ -222,7 +223,7 @@ public function testRestrictedContentByProductOnFrontend($I, $urlOrPageID, $opti
$this->seeRestrictContentError($I, $options['settings']['no_access_text']);

// Check content is not displayed, and CTA displays with expected text.
$this->testRestrictContentByProductHidesContentWithCTA($I, $options);
$this->testRestrictContentByProductHidesContentWithCTA($I, $options, $checkNoWarningsAndNotices);

// Login as a Kit subscriber who has subscribed to the product.
$this->loginToRestrictContentWithEmail($I, $_ENV['CONVERTKIT_API_SUBSCRIBER_EMAIL']);
Expand All @@ -248,7 +249,7 @@ public function testRestrictedContentByProductOnFrontend($I, $urlOrPageID, $opti
// Test that the restricted content displays when a valid signed subscriber ID is used,
// as if we entered the code sent in the email.
$this->setRestrictContentCookieAndReload($I, $_ENV['CONVERTKIT_API_SIGNED_SUBSCRIBER_ID'], $urlOrPageID);
$this->testRestrictContentDisplaysContent($I, $options);
$this->testRestrictContentDisplaysContent($I, $options, $checkNoWarningsAndNotices);
}

/**
Expand Down Expand Up @@ -618,14 +619,17 @@ public function testRestrictedContentModal($I, $urlOrPageID, $options = false)
* @type string $member_content Content that should only be available to authenticated subscribers.
* @type array $settings Restrict content settings. If not defined, uses expected defaults.
* }
* @param bool $checkNoWarningsAndNotices Whether to check for errors.
*/
public function testRestrictContentByProductHidesContentWithCTA($I, $options = false)
public function testRestrictContentByProductHidesContentWithCTA($I, $options = false, $checkNoWarningsAndNotices = true)
{
// Merge options with defaults.
$options = $this->getRestrictedContentOptionsWithDefaultsMerged($options);

// Check that no PHP warnings or notices were output.
$I->checkNoWarningsAndNoticesOnScreen($I);
if ($checkNoWarningsAndNotices) {
$I->checkNoWarningsAndNoticesOnScreen($I);
}

// Confirm that the visible text displays, hidden text does not display and the CTA displays.
if ( ! empty($options['visible_content'])) {
Expand Down Expand Up @@ -750,14 +754,17 @@ public function testRestrictContentByFormHidesContentWithCTA($I, $formID, $optio
* @type string $member_content Content that should only be available to authenticated subscribers.
* @type array $settings Restrict content settings. If not defined, uses expected defaults.
* }
* @param bool $checkNoWarningsAndNotices Whether to check for errors.
*/
public function testRestrictContentDisplaysContent($I, $options = false)
public function testRestrictContentDisplaysContent($I, $options = false, $checkNoWarningsAndNotices = true)
{
// Merge options with defaults.
$options = $this->getRestrictedContentOptionsWithDefaultsMerged($options);

// Check that no PHP warnings or notices were output.
$I->checkNoWarningsAndNoticesOnScreen($I);
if ($checkNoWarningsAndNotices) {
$I->checkNoWarningsAndNoticesOnScreen($I);
}

// Confirm that the visible and hidden text displays.
if ( ! empty($options['visible_content'])) {
Expand Down
29 changes: 24 additions & 5 deletions tests/Support/Helper/WPGutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,18 @@ public function addGutenbergBlock($I, $blockName, $blockProgrammaticName, $block
$I->wait(2);

// Insert the block.
$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);
$I->click('.block-editor-inserter__panel-content button.editor-block-list-item-' . $blockProgrammaticName);
if (strpos($blockProgrammaticName, '/') !== false) {
// Use XPath if $blockProgrammaticName contains a forward slash.
$xpath = '//button[contains(@class, "editor-block-list-item-' . $blockProgrammaticName . '") and contains(@class,"block-editor-block-types-list__item") and contains(@class,"components-button")]';
$I->waitForElementVisible([ 'xpath' => $xpath ]);
$I->seeElementInDOM([ 'xpath' => $xpath ]);
$I->click([ 'xpath' => $xpath ]);
} else {
$selector = '.block-editor-inserter__panel-content button.editor-block-list-item-' . $blockProgrammaticName;
$I->waitForElementVisible($selector);
$I->seeElementInDOM($selector);
$I->click($selector);
}

// Close block inserter.
$I->click('button.editor-document-tools__inserter-toggle');
Expand Down Expand Up @@ -139,7 +148,7 @@ public function addGutenbergBlock($I, $blockName, $blockProgrammaticName, $block
*/
public function addGutenbergParagraphBlock($I, $text)
{
$I->addGutenbergBlock($I, 'Paragraph', 'paragraph');
$I->addGutenbergBlock($I, 'Paragraph', 'paragraph/paragraph');

$I->click('.wp-block-post-content');
$I->fillField('.wp-block-post-content p[data-empty="true"]', $text);
Expand Down Expand Up @@ -268,7 +277,17 @@ public function seeGutenbergBlockAvailable($I, $blockName, $blockProgrammaticNam
$I->wait(2);

// Confirm the block is available.
$I->waitForElementVisible('.block-editor-inserter__panel-content button.editor-block-list-item-' . $blockProgrammaticName);
// $blockProgrammaticName may contain a slash, which is not valid in a CSS class selector.
// Use XPath to check for a button containing the relevant class.
if (strpos($blockProgrammaticName, '/') !== false) {
// XPath: class attribute contains all required classes including block-programmatic-name.
$classParts = explode('/', $blockProgrammaticName);
$xpath = '//button[contains(@class, "editor-block-list-item-' . $blockProgrammaticName . '") and contains(@class,"block-editor-block-types-list__item") and contains(@class,"components-button")]';
$I->waitForElementVisible([ 'xpath' => $xpath ]);
} else {
$selector = '.block-editor-inserter__panel-content button.editor-block-list-item-' . $blockProgrammaticName;
$I->waitForElementVisible($selector);
}

// Clear the search field.
$I->click('button[aria-label="Reset search"]');
Expand Down
Loading