Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E2E Utils: Use frameLocator for retrieving editor canvas #54911

Merged
merged 33 commits into from
Oct 5, 2023

Conversation

WunderBart
Copy link
Member

@WunderBart WunderBart commented Sep 28, 2023

What?

Improve E2E tests stability by referencing the editor canvas via lazily evaluated frameLocator instead of frame. For example, we'll no longer need to explicitly wait for the canvas frame before calling editor.canvas.*:

Before

await page
  .frameLocator( '[name=editor-canvas]' )
  .locator( 'body' )
  .waitFor();

const editorPostTitle = editor.canvas.getByRole( 'textbox', { name: 'Add title' } );
await editorPostTitle.focus();

After

const editorPostTitle = editor.canvas.getByRole( 'textbox', { name: 'Add title' } );  
await editorPostTitle.focus();

Related: WordPress/wordpress-develop#5333 (comment)

Bonus: Like this one, I was able to switch many other tests to be run against the iframed canvas. 🎉
Some still required legacy canvas to pass, but addressing them is out of the scope of this PR.

Major changes

This migration enforces some changes to how we work with canvas, as it's no longer of type Frame:

  • Use canvas.locator('selector').click() instead of canvas.click('selector').

    This will now be enforced, but it's also recommended as the direct frame.click has been deprecated. This also includes other actions like fill, focus, hover, etc.

    Before

    await editor.canvas.click( 'role=button[name="Add default block"i]' );
    await editor.canvas.focus( '[data-type="core/paragraph"]' );

    After

    await editor.canvas
      .getByRole( 'button', { name: 'Add default block' } )
      .click();
    await editor.canvas
      .getByRole( 'document', { name: 'Block: Paragraph' } )
      .focus();
  • Use editor.canvas.locator(':root').evaluate() instead of editor.canvas.evaluate(). For example:

    Before

    const activeElementId = await editor.canvas.evaluate(
      'document.activeElement.id'
    );

    After

    const activeElementId = await editor.canvas
      .locator( ':root' )
      .evaluate( 'document.activeElement.id' );
  • Use expect.poll(editor.canvas.evaluate()) instead of editor.canvas.waitForFunction().

    This is not an equivalent, but I'm afraid there is no better alternative ATM. There's an open request for frameLocator.waitForFunction we can +1, though. :)

    Before

    await editor.canvas.waitForFunction(
      () => window.getSelection().type === 'Caret'
    );

    After

    await expect
      .poll(
        editor.canvas
          .locator( ':root' )
          .evaluate( () => window.getSelection().type )
    )
    .toBe( 'Caret' );
  • Inner locators cannot use frameLocator, so at this time it's not possible to match via the has: property if the inner locator contains frameLocator.

    Before

    const submenuLink = this.editor.canvas
      .locator( 'a' )
      .filter( { hasText: 'Submenu Link' } );
    const submenuWrapper = this.editor.canvas
      .getByRole( 'document', { name: 'Block: Custom Link' } )
      .filter( { has: submenuLink } );  ```

    After

    const submenuWrapper = this.editor.canvas
      .getByRole( 'document', { name: 'Block: Custom Link' } )
      .filter( { hasText: 'Submenu Link' } );
    const submenuLink = submenuWrapper
      .locator( 'a' )
      .filter( { hasText: 'Submenu Link' } );
  • For tests that require the legacy (non-iframed) canvas, use the editor.switchToLegacyCanvas() utility.

    Before

    await admin.createNewPost();
    await page.evaluate( () => {
      window.wp.blocks.registerBlockType( 'test/v2', {
        apiVersion: '2',
        title: 'test',
      } );
    } );

    After

    await admin.createNewPost();
    await editor.switchToLegacyCanvas();

Testing instructions

E2E tests should pass.

@WunderBart WunderBart self-assigned this Sep 28, 2023
@Mamaduka
Copy link
Member

@WunderBart, I just remembered this conversation #51824 (comment). Just in case, it's helpful.

@WunderBart
Copy link
Member Author

@WunderBart, I just remembered this conversation #51824 (comment). Just in case, it's helpful.

It is, thanks! Some useful context there, like the issue with replacing waitForFunction that is specific to frame only. Let's see if we can find some good replacement case-by-case and forget about frame() once and for all! 🤞

@github-actions
Copy link

github-actions bot commented Sep 28, 2023

Size Change: +5.03 kB (0%)

Total Size: 1.65 MB

Filename Size Change
build/block-editor/index.min.js 218 kB -32 B (0%)
build/block-library/blocks/image/style-rtl.css 1.45 kB +45 B (+3%)
build/block-library/blocks/image/style.css 1.44 kB +46 B (+3%)
build/block-library/editor-rtl.css 12.4 kB +225 B (+2%)
build/block-library/editor.css 12.4 kB +226 B (+2%)
build/block-library/index.min.js 211 kB +4.01 kB (+2%)
build/block-library/style-rtl.css 14.3 kB +241 B (+2%)
build/block-library/style.css 14.3 kB +237 B (+2%)
build/edit-site/index.min.js 203 kB +38 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 964 B
build/annotations/index.min.js 2.71 kB
build/api-fetch/index.min.js 2.29 kB
build/autop/index.min.js 2.11 kB
build/blob/index.min.js 461 B
build/block-directory/index.min.js 7.07 kB
build/block-directory/style-rtl.css 1.04 kB
build/block-directory/style.css 1.04 kB
build/block-editor/content-rtl.css 4.28 kB
build/block-editor/content.css 4.27 kB
build/block-editor/default-editor-styles-rtl.css 403 B
build/block-editor/default-editor-styles.css 403 B
build/block-editor/style-rtl.css 15.6 kB
build/block-editor/style.css 15.6 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 138 B
build/block-library/blocks/audio/theme.css 138 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 587 B
build/block-library/blocks/button/editor.css 587 B
build/block-library/blocks/button/style-rtl.css 633 B
build/block-library/blocks/button/style.css 632 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.7 kB
build/block-library/blocks/cover/style.css 1.69 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 98 B
build/block-library/blocks/details/style.css 98 B
build/block-library/blocks/embed/editor-rtl.css 293 B
build/block-library/blocks/embed/editor.css 293 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 138 B
build/block-library/blocks/embed/theme.css 138 B
build/block-library/blocks/file/editor-rtl.css 316 B
build/block-library/blocks/file/editor.css 316 B
build/block-library/blocks/file/style-rtl.css 311 B
build/block-library/blocks/file/style.css 312 B
build/block-library/blocks/file/view.min.js 321 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 229 B
build/block-library/blocks/form-input/editor.css 228 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 343 B
build/block-library/blocks/form-submission-notification/editor.css 342 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 452 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 957 B
build/block-library/blocks/gallery/editor.css 962 B
build/block-library/blocks/gallery/style-rtl.css 1.55 kB
build/block-library/blocks/gallery/style.css 1.55 kB
build/block-library/blocks/gallery/theme-rtl.css 122 B
build/block-library/blocks/gallery/theme.css 122 B
build/block-library/blocks/group/editor-rtl.css 654 B
build/block-library/blocks/group/editor.css 654 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 340 B
build/block-library/blocks/html/editor.css 341 B
build/block-library/blocks/image/editor-rtl.css 834 B
build/block-library/blocks/image/editor.css 833 B
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/image/view.min.js 1.83 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 505 B
build/block-library/blocks/media-text/style.css 503 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 671 B
build/block-library/blocks/navigation-link/editor.css 672 B
build/block-library/blocks/navigation-link/style-rtl.css 103 B
build/block-library/blocks/navigation-link/style.css 103 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 299 B
build/block-library/blocks/navigation-submenu/editor.css 299 B
build/block-library/blocks/navigation/editor-rtl.css 2.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.26 kB
build/block-library/blocks/navigation/style.css 2.25 kB
build/block-library/blocks/navigation/view.min.js 1.01 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 401 B
build/block-library/blocks/page-list/editor.css 401 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 588 B
build/block-library/blocks/post-featured-image/editor.css 586 B
build/block-library/blocks/post-featured-image/style-rtl.css 345 B
build/block-library/blocks/post-featured-image/style.css 345 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 409 B
build/block-library/blocks/post-template/style.css 408 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 335 B
build/block-library/blocks/pullquote/style.css 335 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/style-rtl.css 375 B
build/block-library/blocks/query/style.css 372 B
build/block-library/blocks/query/view.min.js 609 B
build/block-library/blocks/quote/style-rtl.css 222 B
build/block-library/blocks/quote/style.css 222 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 132 B
build/block-library/blocks/read-more/style.css 132 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 613 B
build/block-library/blocks/search/style.css 613 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 471 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 234 B
build/block-library/blocks/separator/style.css 234 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 329 B
build/block-library/blocks/shortcode/editor.css 329 B
build/block-library/blocks/site-logo/editor-rtl.css 760 B
build/block-library/blocks/site-logo/editor.css 760 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.45 kB
build/block-library/blocks/social-links/style.css 1.45 kB
build/block-library/blocks/spacer/editor-rtl.css 359 B
build/block-library/blocks/spacer/editor.css 359 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 432 B
build/block-library/blocks/table/editor.css 432 B
build/block-library/blocks/table/style-rtl.css 646 B
build/block-library/blocks/table/style.css 645 B
build/block-library/blocks/table/theme-rtl.css 157 B
build/block-library/blocks/table/theme.css 157 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 403 B
build/block-library/blocks/template-part/editor.css 403 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 191 B
build/block-library/blocks/video/style.css 191 B
build/block-library/blocks/video/theme-rtl.css 139 B
build/block-library/blocks/video/theme.css 139 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/theme-rtl.css 700 B
build/block-library/theme.css 705 B
build/block-serialization-default-parser/index.min.js 1.13 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.5 kB
build/commands/index.min.js 15.5 kB
build/commands/style-rtl.css 947 B
build/commands/style.css 942 B
build/components/index.min.js 248 kB
build/components/style-rtl.css 11.9 kB
build/components/style.css 11.9 kB
build/compose/index.min.js 12.7 kB
build/core-commands/index.min.js 2.72 kB
build/core-data/index.min.js 70.5 kB
build/customize-widgets/index.min.js 12 kB
build/customize-widgets/style-rtl.css 1.51 kB
build/customize-widgets/style.css 1.5 kB
build/data-controls/index.min.js 651 B
build/data/index.min.js 8.78 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 462 B
build/dom-ready/index.min.js 336 B
build/dom/index.min.js 4.68 kB
build/edit-post/classic-rtl.css 571 B
build/edit-post/classic.css 571 B
build/edit-post/index.min.js 35.6 kB
build/edit-post/style-rtl.css 7.89 kB
build/edit-post/style.css 7.88 kB
build/edit-site/style-rtl.css 14.1 kB
build/edit-site/style.css 14.1 kB
build/edit-widgets/index.min.js 17 kB
build/edit-widgets/style-rtl.css 4.84 kB
build/edit-widgets/style.css 4.84 kB
build/editor/index.min.js 45.9 kB
build/editor/style-rtl.css 3.58 kB
build/editor/style.css 3.58 kB
build/element/index.min.js 4.87 kB
build/escape-html/index.min.js 548 B
build/format-library/index.min.js 7.79 kB
build/format-library/style-rtl.css 577 B
build/format-library/style.css 577 B
build/hooks/index.min.js 1.57 kB
build/html-entities/index.min.js 454 B
build/i18n/index.min.js 3.61 kB
build/interactivity/index.min.js 11.4 kB
build/is-shallow-equal/index.min.js 535 B
build/keyboard-shortcuts/index.min.js 1.76 kB
build/keycodes/index.min.js 1.9 kB
build/list-reusable-blocks/index.min.js 2.21 kB
build/list-reusable-blocks/style-rtl.css 865 B
build/list-reusable-blocks/style.css 865 B
build/media-utils/index.min.js 2.92 kB
build/notices/index.min.js 964 B
build/nux/index.min.js 2.01 kB
build/nux/style-rtl.css 775 B
build/nux/style.css 771 B
build/patterns/index.min.js 3.57 kB
build/patterns/style-rtl.css 325 B
build/patterns/style.css 325 B
build/plugins/index.min.js 1.81 kB
build/preferences-persistence/index.min.js 1.85 kB
build/preferences/index.min.js 1.26 kB
build/primitives/index.min.js 994 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 972 B
build/react-i18n/index.min.js 631 B
build/react-refresh-entry/index.min.js 9.46 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.71 kB
build/reusable-blocks/index.min.js 2.73 kB
build/reusable-blocks/style-rtl.css 265 B
build/reusable-blocks/style.css 265 B
build/rich-text/index.min.js 10.2 kB
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.96 kB
build/shortcode/index.min.js 1.4 kB
build/style-engine/index.min.js 1.98 kB
build/token-list/index.min.js 587 B
build/url/index.min.js 3.84 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 967 B
build/warning/index.min.js 259 B
build/widgets/index.min.js 7.18 kB
build/widgets/style-rtl.css 1.18 kB
build/widgets/style.css 1.18 kB
build/wordcount/index.min.js 1.03 kB

compressed-size-action

@github-actions
Copy link

github-actions bot commented Sep 28, 2023

Flaky tests detected in bab65f8.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/6416319195
📝 Reported issues:

@WunderBart
Copy link
Member Author

WunderBart commented Oct 3, 2023

Fantastic work, @WunderBart! Do you mind listing the major changes in this PR so I can watch for those?

I'll try to review it this week.

Thanks, @Mamaduka! I've listed the changes in the description. Hope it helps!

Copy link
Member

@kevin940726 kevin940726 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! I hope that you didn't just change these files by hand because that's a lot of work 😱 . Glad to see that it's possible, and perhaps not too late to make the switch!

The .locator( ':root' ) is a bit weird but I think it's not too bad. I just have to rethink canvas as a locator and not a frame now in my head.

Comment on lines 48 to 50
if ( this.useLegacyCanvas ) {
return this.page;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we still need this. If the user has to opt-in to legacy canvas then they should be able to just use page than editor.canvas?

This also prevents the typescript awkwardness with FrameLocator | Page which doesn't really extend each other 😅 .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes that switching to legacy canvas is intentional, but that's not always true. Can we still return the this.page page as a fallback?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing something, but won't useLegacyCanvas only be true if we call switchToLegacyCanvas? If the user opts in to call switchToLegacyCanvas then I guess we can expect them to use page instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's say the consumer enables the metabox plugin in the test (which forces the editor to render legacy canvas) and forgets to call switchToLegacyCanvas; this won't work.

It would be great to hide editors' implementation details for legacy canvas vs. iframe. It shouldn't be noticeable for people writing tests or using the editor, IMO.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like it as well and would be more than happy to remove it! 😄 There might be an issue with some Editor utils that reference canvas (e.g. selectBlocks() IIRC) while running against the legacy one, but it might as well just pass - will check it! 🤞

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in fd96c75

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to hide editors' implementation details for legacy canvas vs. iframe. It shouldn't be noticeable for people writing tests or using the editor, IMO.

This is also a good point. Unfortunately, I don't think automatically "piercing" through iframe boundaries can be done trivially in Playwright, yet (I don't know really, I haven't given it any thoughts 😅). There's a trade-off to make here, and I would personally prefer predictable types and autocomplete for package-level utility here.

Copy link
Member Author

@WunderBart WunderBart Oct 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed a part of this exchange - GH is not great at refreshing discussions. 😑

Anyway, I've been on edge with this one because, on one side, there's the desirable autocomplete without the type ambiguity (FrameLocator | Page), and on the other side, there's the implementation detail or the potentially broken editor utils that depend on the canvas reference (like the aforementioned selectBlocks().

As for the solution, we can't do it the old "page fallback" way because frameLocator doesn't return null like the frame does – it will time out if not found. The only solution that worked for me (considering we want to hide the implementation detail) has been turning the canvas into an async getter and evaluating the parent element by wrapping framed and unframed locators with Promise.any(). Unfortunately, it would be still far from ideal as it also would:

  • involve a hefty refactor caused by the inability to chain from editor.canvas (it would become (await editor.canvas()).getByRole(....
  • still mess with the canvas types.

@kevin940726
Copy link
Member

Do you think the reported flaky tests are related? The most recent reports seem to only happen on this branch. 🤔

If we can fix it here it will be best, but I think we can also fix them in follow-ups.

@WunderBart
Copy link
Member Author

WunderBart commented Oct 4, 2023

@Mamaduka, just a heads up as I've added more examples to the changes involved! 🙌

Comment on lines +33 to +35
await editor.canvas
.locator( 'role=button[name="Add default block"i]' )
.click();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sidenote: This is a really common pattern; I wonder if we should extract it into a utility method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
await editor.canvas
.locator( 'role=button[name="Add default block"i]' )
.click();
await editor.canvas
.getByRole( 'button', {
name: "Add default block"
})
.click();

Nit: I have previously been advised to prefer getByRole wherever possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably not worth refactoring old code for this standard, especially if we plan to extract this in helper.

Both ways are fine, but using RTL-style locators is preferred.

Comment on lines -66 to -71
await page.evaluate( () => {
window.wp.blocks.registerBlockType( 'test/v2', {
apiVersion: '2',
title: 'test',
} );
} );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume there's no longer a need for a legacy canvas switch. There're some left overs, so removal is appreciated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some tests still fail when running against iframed canvas, so I'd leave the switch. I tried migrating most of the legacy tests to iframed canvas, but it wasn't possible for some of them. For example, cancels dragging blocks from the global inserter by pressing Escape in inserting-blocks.spec.js does not hide the insertion point after pressing Escape, no matter what I do. It seems to be an issue with Playwright, because the tested functionality works as expected 100% of the time when testing manually.

Comment on lines -33 to -44
// Wait for both iframed and non-iframed canvas and resolve once the
// currently available one is ready. To make this work, we need an inner
// legacy canvas selector that is unavailable directly when the canvas is
// iframed.
await Promise.any( [
this.page.locator( '.wp-block-post-content' ).waitFor(),
this.page
.frameLocator( '[name=editor-canvas]' )
.locator( 'body > *' )
.first()
.waitFor(),
] );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep this. The missing lazy evaluation from editor.canvas wasn't the only reason for this safeguard.

Why?

  • Expectation that editor canvas is loaded when performing an action after the createNewPost call. Inherited from Puppeteer utils. It could count as a breaking change.
  • Some of the test patterns don't use locators for creating blocks. See examples below.

Examples

// Insert a block using `editor` utils. Was flaky before https://github.com/WordPress/gutenberg/pull/51824.
await admin.createNewPost();
await editor.insertBlock( { name: 'core/heading' } );

// Add blocks using writing flow "shortcut":
await admin.createNewPost();
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'Content' );

The last pattern was very common in Puppeteer but became flaky after #48286 (before #51824), so we had to switch to editor.canvas.click( 'role=button[name="Add default block"i]' ).

Copy link
Member Author

@WunderBart WunderBart Oct 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Believing that the entire editor is immediately ready upon invoking callingNewPost(), especially considering editor's dynamic nature, can be a risky assumption. Instead of making such assumptions, we should directly ensure that the resources we intend to use are available at the time of reference in the context where the resource is accessed.

From the sample you shared, it seems more logical to adjust the insertBlock() function.
Rather than having:

async function insertBlock(
	this: Editor,
	blockRepresentation: BlockRepresentation
) {
	await this.page.evaluate( ( _blockRepresentation ) => {

		//...

		window.wp.data.dispatch( 'core/block-editor' ).insertBlock( block );
	}, blockRepresentation );

I propose this version:

async function insertBlock(
	this: Editor,
	blockRepresentation: BlockRepresentation
) {
	await this.page.waitForFunction( ( _blockRepresentation ) => {
		if ( ! window?.wp?.data ) {
			return false;
		}

		//...

		window.wp.data.dispatch( 'core/block-editor' ).insertBlock( block );
	}, blockRepresentation );

In this alternative, the function waits until the window.wp.data resource is ready before proceeding. The immediate use of evaluate() presupposes the availability of window.wp.data, effectively moving the responsibility of ensuring its presence outside this function. To illustrate:

await admin.createNewPost();
await editor.insertBlock( { name: 'core/heading' } );

await this.page.reload();
await editor.insertBlock( { name: 'core/heading' } );

If the responsibility to check resource availability lies within createNewPost(), the second insertBlock() call could be unstable. However, if insertBlock() self-validates that its required resources are ready, we ensure a more robust outcome.

Does that perspective make sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that perspective make sense?

For me, it does. I don't feel a strong attachment to previous behavior 😄

As I mentioned, this changes the "expected" behavior of createNewPost(), and not everyone actively follows changes to the e2e test environment.

I like your suggestion for improving the insertBlock utility 🚀

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for the second example you provided, it involves some ambiguity because we assume the cursor is in the correct spot, but we don't really know what that spot is. Instead of shifting the burden of ensuring the cursor is where it should be to createNewPost() (which is not even the case, because we'd only wait for the editor body to be visible, which doesn't ensure cursor position!), I propose adding a step that explicitly waits for the cursor to be in the right spot:

await admin.createNewPost();
await expect(
  editor.canvas.getByRole( 'textbox', { name: 'Add title' } )
).toBeFocused();

await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'Content' );

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One DX benefit of removing this is it cleans up a little noise in the trace viewer that is caused by one of these locators timing out.

@Mamaduka
Copy link
Member

Mamaduka commented Oct 4, 2023

Thank you, @WunderBart!

I left a couple of notes, but the changes look good in general ✅

I agree with @kevin940726. Fixing the related flaky test reports would be nice, but this can done after merging as well.

@WunderBart
Copy link
Member Author

WunderBart commented Oct 4, 2023

Do you think the reported flaky tests are related? The most recent reports seem to only happen on this branch. 🤔

It very well might be, @kevin940726. The locator itself is lazily evaluated but there still can be some flakiness from situations where we e.g. evaluate() instantly after creating a new post. The window.wp.* might not be instantly available, so we either need to use page.waitForFunction() or expect.poll instead.

I'm checking the flakies now!

Copy link
Contributor

@stokesman stokesman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wunderful work Bart!

@WunderBart
Copy link
Member Author

@kevin940726 PR-specific flakies seem to be gone. 🥳 There's one more that is not specific to this PR so I've opened a separate PR for it.

@WunderBart WunderBart merged commit 6fe6d2b into trunk Oct 5, 2023
50 checks passed
@WunderBart WunderBart deleted the refactor/e2e-use-frame-locator-for-canvas branch October 5, 2023 10:50
@github-actions github-actions bot added this to the Gutenberg 16.9 milestone Oct 5, 2023
getdave added a commit that referenced this pull request Oct 6, 2023
getdave added a commit that referenced this pull request Oct 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] E2E Tests /packages/e2e-tests [Tool] E2E Test Utils /packages/e2e-test-utils [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants