diff --git a/packages/e2e-test-utils-playwright/src/admin/index.ts b/packages/e2e-test-utils-playwright/src/admin/index.ts index ee7ebe406fc25f..d28f68872abc51 100644 --- a/packages/e2e-test-utils-playwright/src/admin/index.ts +++ b/packages/e2e-test-utils-playwright/src/admin/index.ts @@ -11,6 +11,7 @@ import type { Browser, Page, BrowserContext } from '@playwright/test'; */ import { createNewPost } from './create-new-post'; import { getPageError } from './get-page-error'; +import { setOption } from './set-option'; import { visitAdminPage } from './visit-admin-page'; import { visitSiteEditor } from './visit-site-editor'; import type { PageUtils } from '../page-utils'; @@ -35,6 +36,7 @@ export class Admin { createNewPost = createNewPost.bind( this ); getPageError = getPageError.bind( this ); + setOption = setOption.bind( this ); visitAdminPage = visitAdminPage.bind( this ); visitSiteEditor = visitSiteEditor.bind( this ); } diff --git a/packages/e2e-test-utils-playwright/src/admin/set-option.ts b/packages/e2e-test-utils-playwright/src/admin/set-option.ts new file mode 100644 index 00000000000000..2e18563d0c587b --- /dev/null +++ b/packages/e2e-test-utils-playwright/src/admin/set-option.ts @@ -0,0 +1,14 @@ +/** + * Internal dependencies + */ +import type { Admin } from './'; + +export async function setOption( this: Admin, setting: string, value: string ) { + await this.visitAdminPage( 'options.php', '' ); + const previousValue = await this.page.inputValue( `#${ setting }` ); + + await this.page.fill( `#${ setting }`, value ); + + await this.page.click( '#Update' ); + return previousValue; +} diff --git a/packages/e2e-test-utils-playwright/src/editor/publish-post.ts b/packages/e2e-test-utils-playwright/src/editor/publish-post.ts index a1f624981bdc97..acd0ba1c5c0341 100644 --- a/packages/e2e-test-utils-playwright/src/editor/publish-post.ts +++ b/packages/e2e-test-utils-playwright/src/editor/publish-post.ts @@ -29,4 +29,9 @@ export async function publishPost( this: Editor ) { await this.page.click( 'role=region[name="Editor publish"i] >> role=button[name="Publish"i]' ); + + const urlString = await this.page.inputValue( 'text="Post address"' ); + const url = new URL( urlString ); + const postId = url.searchParams.get( 'p' ); + return postId; } diff --git a/packages/e2e-test-utils-playwright/src/request-utils/comments.ts b/packages/e2e-test-utils-playwright/src/request-utils/comments.ts new file mode 100644 index 00000000000000..a49526f167180d --- /dev/null +++ b/packages/e2e-test-utils-playwright/src/request-utils/comments.ts @@ -0,0 +1,57 @@ +/** + * Internal dependencies + */ +import type { RequestUtils } from './index'; + +export interface Comment { + id: number; + author: number; + content: string; +} + +/** + * Create new comment using the REST API. + * + * @param {} this RequestUtils. + * @param {} comment Comment. + */ +export async function createComment( this: RequestUtils, comment: Comment ) { + this.rest( { + method: 'POST', + path: '/wp/v2/comments', + data: comment, + } ); +} + +/** + * Delete all comments using the REST API. + * + * @param {} this RequestUtils. + */ +export async function deleteAllComments( this: RequestUtils ) { + // List all comments. + // https://developer.wordpress.org/rest-api/reference/comments/#list-comments + const comments = await this.rest( { + path: '/wp/v2/comments', + params: { + per_page: 100, + // All possible statuses. + status: 'unapproved,approved,spam,trash', + }, + } ); + + // Delete all comments one by one. + // https://developer.wordpress.org/rest-api/reference/comments/#delete-a-comment + // "/wp/v2/comments" doesn't support batch requests yet. + await Promise.all( + comments.map( ( comment: Comment ) => + this.rest( { + method: 'DELETE', + path: `/wp/v2/comments/${ comment.id }`, + params: { + force: true, + }, + } ) + ) + ); +} diff --git a/packages/e2e-test-utils-playwright/src/request-utils/index.ts b/packages/e2e-test-utils-playwright/src/request-utils/index.ts index 151013a8fe000c..1ea7b81acdfdb6 100644 --- a/packages/e2e-test-utils-playwright/src/request-utils/index.ts +++ b/packages/e2e-test-utils-playwright/src/request-utils/index.ts @@ -18,8 +18,10 @@ import { getPluginsMap, activatePlugin, deactivatePlugin } from './plugins'; import { deleteAllTemplates } from './templates'; import { activateTheme } from './themes'; import { deleteAllBlocks } from './blocks'; +import { createComment, deleteAllComments } from './comments'; import { deleteAllPosts } from './posts'; import { resetPreferences } from './preferences'; +import { getCurrentUser } from './user'; import { deleteAllWidgets, addWidgetBlock } from './widgets'; interface StorageState { @@ -121,6 +123,8 @@ class RequestUtils { activateTheme = activateTheme.bind( this ); deleteAllBlocks = deleteAllBlocks; deleteAllPosts = deleteAllPosts.bind( this ); + createComment = createComment.bind( this ); + deleteAllComments = deleteAllComments.bind( this ); deleteAllWidgets = deleteAllWidgets.bind( this ); addWidgetBlock = addWidgetBlock.bind( this ); deleteAllTemplates = deleteAllTemplates.bind( this ); @@ -129,6 +133,7 @@ class RequestUtils { uploadMedia = uploadMedia.bind( this ); deleteMedia = deleteMedia.bind( this ); deleteAllMedia = deleteAllMedia.bind( this ); + getCurrentUser = getCurrentUser.bind( this ); } export type { StorageState }; diff --git a/packages/e2e-test-utils-playwright/src/request-utils/user.ts b/packages/e2e-test-utils-playwright/src/request-utils/user.ts new file mode 100644 index 00000000000000..855136d80c051e --- /dev/null +++ b/packages/e2e-test-utils-playwright/src/request-utils/user.ts @@ -0,0 +1,18 @@ +/** + * Internal dependencies + */ +import type { RequestUtils } from './index'; + +/** + * Get current user + * + * @param {this} this Request utils. + */ +export async function getCurrentUser( this: RequestUtils ) { + const response = await this.rest( { + path: '/wp/v2/users/me', + method: 'GET', + } ); + + return response; +} diff --git a/packages/e2e-tests/specs/editor/blocks/comments.test.js b/packages/e2e-tests/specs/editor/blocks/comments.test.js deleted file mode 100644 index e68d23f34fb7df..00000000000000 --- a/packages/e2e-tests/specs/editor/blocks/comments.test.js +++ /dev/null @@ -1,131 +0,0 @@ -/** - * WordPress dependencies - */ -import { - activateTheme, - createNewPost, - insertBlock, - pressKeyTimes, - publishPost, - setOption, - trashAllComments, -} from '@wordpress/e2e-test-utils'; - -describe( 'Comments', () => { - let previousPageComments, - previousCommentsPerPage, - previousDefaultCommentsPage; - beforeAll( async () => { - await activateTheme( 'emptytheme' ); - previousPageComments = await setOption( 'page_comments', '1' ); - previousCommentsPerPage = await setOption( 'comments_per_page', '1' ); - previousDefaultCommentsPage = await setOption( - 'default_comments_page', - 'newest' - ); - } ); - it( 'We show no results message if there are no comments', async () => { - await trashAllComments(); - await createNewPost(); - await insertBlock( 'Comments' ); - await page.waitForXPath( '//p[contains(text(), "No results found.")]' ); - } ); - it( 'Pagination links are working as expected', async () => { - await createNewPost(); - await insertBlock( 'Comments' ); - await publishPost(); - // Visit the post that was just published. - await page.click( - '.post-publish-panel__postpublish-buttons .is-primary' - ); - - // TODO: We can extract this into a util once we find we need it elsewhere. - // Create three comments for that post. - for ( let i = 0; i < 3; i++ ) { - await page.waitForSelector( 'textarea#comment' ); - await page.click( 'textarea#comment' ); - await page.type( - `textarea#comment`, - `This is an automated comment - ${ i }` - ); - await pressKeyTimes( 'Tab', 1 ); - await Promise.all( [ - page.keyboard.press( 'Enter' ), - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - } - - // We check that there is a previous comments page link. - expect( - await page.$( '.wp-block-comments-pagination-previous' ) - ).not.toBeNull(); - expect( - await page.$( '.wp-block-comments-pagination-next' ) - ).toBeNull(); - - await Promise.all( [ - page.click( '.wp-block-comments-pagination-previous' ), - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // We check that there are a previous and a next link. - expect( - await page.$( '.wp-block-comments-pagination-previous' ) - ).not.toBeNull(); - expect( - await page.$( '.wp-block-comments-pagination-next' ) - ).not.toBeNull(); - - await Promise.all( [ - page.click( '.wp-block-comments-pagination-previous' ), - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - - // We check that there is only have a next link - expect( - await page.$( '.wp-block-comments-pagination-previous' ) - ).toBeNull(); - expect( - await page.$( '.wp-block-comments-pagination-next' ) - ).not.toBeNull(); - } ); - it( 'Pagination links are not appearing if break comments is not enabled', async () => { - await setOption( 'page_comments', '0' ); - await createNewPost(); - await insertBlock( 'Comments' ); - await publishPost(); - // Visit the post that was just published. - await page.click( - '.post-publish-panel__postpublish-buttons .is-primary' - ); - - // Create three comments for that post. - for ( let i = 0; i < 3; i++ ) { - await page.waitForSelector( 'textarea#comment' ); - await page.click( 'textarea#comment' ); - await page.type( - `textarea#comment`, - `This is an automated comment - ${ i }` - ); - await pressKeyTimes( 'Tab', 1 ); - await Promise.all( [ - page.keyboard.press( 'Enter' ), - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); - } - // We check that there are no comments page link. - expect( - await page.$( '.wp-block-comments-pagination-previous' ) - ).toBeNull(); - expect( - await page.$( '.wp-block-comments-pagination-next' ) - ).toBeNull(); - } ); - afterAll( async () => { - await trashAllComments(); - await activateTheme( 'twentytwentyone' ); - await setOption( 'page_comments', previousPageComments ); - await setOption( 'comments_per_page', previousCommentsPerPage ); - await setOption( 'default_comments_page', previousDefaultCommentsPage ); - } ); -} ); diff --git a/test/e2e/specs/editor/blocks/comments.spec.js b/test/e2e/specs/editor/blocks/comments.spec.js new file mode 100644 index 00000000000000..e487ead36e62fa --- /dev/null +++ b/test/e2e/specs/editor/blocks/comments.spec.js @@ -0,0 +1,155 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +/** + * @typedef {import('@playwright/test').Page} Page + * @typedef {import('@wordpress/e2e-test-utils-playwright').RequestUtils} RequestUtils + */ + +test.describe( 'Comments', () => { + let previousPageComments, + previousCommentsPerPage, + previousDefaultCommentsPage; + + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( 'emptytheme' ); + } ); + + test.beforeEach( async ( { admin } ) => { + // Ideally, we'd set options in beforeAll. Unfortunately, these + // aren't exposed via the REST API, so we have to set them through the + // relevant wp-admin screen, which involves page utils; but those are + // prohibited from beforeAll. + previousPageComments = await admin.setOption( 'page_comments', '1' ); + previousCommentsPerPage = await admin.setOption( + 'comments_per_page', + '1' + ); + previousDefaultCommentsPage = await admin.setOption( + 'default_comments_page', + 'newest' + ); + } ); + + test( 'We show no results message if there are no comments', async ( { + admin, + editor, + page, + requestUtils, + } ) => { + await requestUtils.deleteAllComments(); + await admin.createNewPost(); + await editor.insertBlock( { name: 'core/comments' } ); + await expect( + await page.locator( 'text="No results found."' ) + ).toHaveCount( 1 ); + } ); + + test( 'Pagination links are working as expected', async ( { + admin, + editor, + page, + requestUtils, + } ) => { + const author = requestUtils.getCurrentUser(); + await admin.createNewPost(); + await editor.insertBlock( { name: 'core/comments' } ); + const postId = await editor.publishPost(); + + // Create three comments for that post. + for ( let i = 0; i < 3; i++ ) { + await requestUtils.createComment( { + author: author.id, + content: `This is an automated comment - ${ i }`, + post: postId, + } ); + } + + // Visit the post that was just published. + await page.click( + 'role=region[name="Editor publish"i] >> "View Post"' + ); + + // We check that there is a previous comments page link. + await expect( + await page.locator( 'text="Older Comments"' ) + ).toHaveCount( 1 ); + await expect( + await page.locator( 'text="Newer Comments"' ) + ).toHaveCount( 0 ); + + await page.click( 'text="Older Comments"' ); + + // We check that there are a previous and a next link. + await expect( + await page.locator( 'text="Older Comments"' ) + ).toHaveCount( 1 ); + await expect( + await page.locator( 'text="Newer Comments"' ) + ).toHaveCount( 1 ); + + await page.click( 'text="Older Comments"' ); + + // We check that there is only have a next link + await expect( + await page.locator( 'text="Older Comments"' ) + ).toHaveCount( 0 ); + await expect( + await page.locator( 'text="Newer Comments"' ) + ).toHaveCount( 1 ); + } ); + test( 'Pagination links are not appearing if break comments is not enabled', async ( { + admin, + editor, + page, + requestUtils, + } ) => { + const author = requestUtils.getCurrentUser(); + await admin.setOption( 'page_comments', '0' ); + await admin.createNewPost(); + await editor.insertBlock( { name: 'core/comments' } ); + const postId = await editor.publishPost(); + + // Create three comments for that post. + for ( let i = 0; i < 3; i++ ) { + await requestUtils.createComment( { + author: author.id, + content: `This is an automated comment - ${ i }`, + post: postId, + } ); + } + + // Visit the post that was just published. + await page.click( + 'role=region[name="Editor publish"i] >> "View Post"' + ); + + // We check that there are no comments page link. + await expect( + await page.locator( 'text="Older Comments"' ) + ).toHaveCount( 0 ); + await expect( + await page.locator( 'text="Newer Comments"' ) + ).toHaveCount( 0 ); + } ); + + test.afterEach( async ( { admin } ) => { + // Ideally, we'd set options in afterAll. Unfortunately, these + // aren't exposed via the REST API, so we have to set them through the + // relevant wp-admin screen, which involves page utils; but those are + // prohibited from beforeAll. + await admin.setOption( 'page_comments', previousPageComments ); + await admin.setOption( 'comments_per_page', previousCommentsPerPage ); + await admin.setOption( + 'default_comments_page', + previousDefaultCommentsPage + ); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deleteAllComments(); + await requestUtils.activateTheme( 'twentytwentyone' ); + } ); +} );