|
3 | 3 | */ |
4 | 4 | const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); |
5 | 5 |
|
6 | | -test.describe( 'Revisions', () => { |
| 6 | +test.describe( 'Post revisions', () => { |
7 | 7 | test.beforeEach( async ( { admin } ) => { |
8 | 8 | await admin.createNewPost(); |
9 | 9 | } ); |
@@ -226,3 +226,128 @@ test.describe( 'Revisions', () => { |
226 | 226 | ).toHaveText( 'has-group-parent' ); |
227 | 227 | } ); |
228 | 228 | } ); |
| 229 | + |
| 230 | +test.describe( 'Template and template part revisions', () => { |
| 231 | + test.beforeAll( async ( { requestUtils } ) => { |
| 232 | + await requestUtils.activateTheme( 'emptytheme' ); |
| 233 | + } ); |
| 234 | + |
| 235 | + test.afterAll( async ( { requestUtils } ) => { |
| 236 | + await requestUtils.activateTheme( 'twentytwentyone' ); |
| 237 | + } ); |
| 238 | + |
| 239 | + test.afterEach( async ( { requestUtils } ) => { |
| 240 | + await requestUtils.deleteAllTemplates( 'wp_template' ); |
| 241 | + await requestUtils.deleteAllTemplates( 'wp_template_part' ); |
| 242 | + } ); |
| 243 | + |
| 244 | + [ |
| 245 | + { |
| 246 | + postType: 'wp_template', |
| 247 | + postId: 'emptytheme//index', |
| 248 | + tabName: 'Template', |
| 249 | + }, |
| 250 | + { |
| 251 | + postType: 'wp_template_part', |
| 252 | + postId: 'emptytheme//header', |
| 253 | + tabName: 'Template Part', |
| 254 | + }, |
| 255 | + ].forEach( ( { postType, postId, tabName } ) => { |
| 256 | + test( `should restore an older ${ postType } revision`, async ( { |
| 257 | + admin, |
| 258 | + editor, |
| 259 | + page, |
| 260 | + } ) => { |
| 261 | + await admin.visitSiteEditor( { |
| 262 | + postId, |
| 263 | + postType, |
| 264 | + canvas: 'edit', |
| 265 | + } ); |
| 266 | + |
| 267 | + await editor.setContent( '' ); |
| 268 | + |
| 269 | + // Template and template part revisions work differently from |
| 270 | + // post revisions: the first save writes directly to the database |
| 271 | + // without creating a revision, so a revision is only created from |
| 272 | + // the second save onwards. The revisions button requires at least |
| 273 | + // two revisions, which means three saves are needed here. |
| 274 | + for ( const content of [ |
| 275 | + 'First paragraph', |
| 276 | + 'Second paragraph', |
| 277 | + 'Third paragraph', |
| 278 | + ] ) { |
| 279 | + await editor.insertBlock( { |
| 280 | + name: 'core/paragraph', |
| 281 | + attributes: { content }, |
| 282 | + } ); |
| 283 | + await editor.saveSiteEditorEntities( { |
| 284 | + isOnlyCurrentEntityDirty: true, |
| 285 | + } ); |
| 286 | + const saveButton = page |
| 287 | + .getByRole( 'region', { name: 'Editor top bar' } ) |
| 288 | + .getByRole( 'button', { name: 'Save' } ); |
| 289 | + await expect( saveButton ).toBeDisabled(); |
| 290 | + await page |
| 291 | + .getByRole( 'button', { name: 'Dismiss this notice' } ) |
| 292 | + .click(); |
| 293 | + // WordPress stores revision timestamps at second precision. |
| 294 | + // Wait to ensure each save gets a unique timestamp so revisions |
| 295 | + // are ordered deterministically. |
| 296 | + // eslint-disable-next-line no-restricted-syntax, playwright/no-wait-for-timeout |
| 297 | + await page.waitForTimeout( 1000 ); |
| 298 | + } |
| 299 | + |
| 300 | + // Open the post settings sidebar and click the Revisions button. |
| 301 | + await editor.openDocumentSettingsSidebar(); |
| 302 | + const settingsSidebar = page.getByRole( 'region', { |
| 303 | + name: 'Editor settings', |
| 304 | + } ); |
| 305 | + await settingsSidebar.getByRole( 'tab', { name: tabName } ).click(); |
| 306 | + |
| 307 | + // Click the Revisions button. |
| 308 | + await settingsSidebar.getByRole( 'button', { name: '2' } ).click(); |
| 309 | + |
| 310 | + // Wait for the revisions mode to be active. |
| 311 | + const restoreButton = page.getByRole( 'button', { |
| 312 | + name: 'Restore', |
| 313 | + } ); |
| 314 | + await expect( restoreButton ).toBeVisible(); |
| 315 | + |
| 316 | + // Use the slider to navigate to the oldest revision. |
| 317 | + const slider = page.getByRole( 'slider', { name: 'Revision' } ); |
| 318 | + await slider.focus(); |
| 319 | + await page.keyboard.press( 'Home' ); |
| 320 | + |
| 321 | + // Wait for the revision content to update before restoring. |
| 322 | + // The oldest revision contains two paragraph blocks |
| 323 | + // ("First" and "Second"), while the latest has three. |
| 324 | + await expect( |
| 325 | + editor.canvas.getByRole( 'document', { |
| 326 | + name: 'Block: Paragraph', |
| 327 | + } ) |
| 328 | + ).toHaveCount( 2 ); |
| 329 | + |
| 330 | + // Restore the oldest revision. |
| 331 | + await restoreButton.click(); |
| 332 | + |
| 333 | + // Verify the success notice. |
| 334 | + const notice = page |
| 335 | + .getByRole( 'button', { name: 'Dismiss this notice' } ) |
| 336 | + .filter( { hasText: 'Restored to revision' } ); |
| 337 | + await expect( notice ).toBeVisible(); |
| 338 | + await expect( notice ).not.toHaveText( /Invalid Date/ ); |
| 339 | + |
| 340 | + // Verify the restored content. |
| 341 | + await expect.poll( editor.getBlocks ).toMatchObject( [ |
| 342 | + { |
| 343 | + name: 'core/paragraph', |
| 344 | + attributes: { content: 'First paragraph' }, |
| 345 | + }, |
| 346 | + { |
| 347 | + name: 'core/paragraph', |
| 348 | + attributes: { content: 'Second paragraph' }, |
| 349 | + }, |
| 350 | + ] ); |
| 351 | + } ); |
| 352 | + } ); |
| 353 | +} ); |
0 commit comments