@wordpress/e2e-tests 3.0.1-next.33ec3857e2.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +2 -1
  2. package/LICENSE.md +1 -1
  3. package/package.json +9 -9
  4. package/plugins/query-block.php +2 -2
  5. package/specs/editor/blocks/__snapshots__/navigation.test.js.snap +4 -0
  6. package/specs/editor/blocks/__snapshots__/spacer.test.js.snap +1 -1
  7. package/specs/editor/blocks/classic.test.js +5 -2
  8. package/specs/editor/blocks/navigation.test.js +280 -191
  9. package/specs/editor/plugins/block-variations.test.js +1 -1
  10. package/specs/editor/plugins/iframed-inline-styles.test.js +0 -6
  11. package/specs/editor/plugins/iframed-multiple-block-stylesheets.test.js +0 -4
  12. package/specs/editor/various/__snapshots__/block-editor-keyboard-shortcuts.test.js.snap +38 -24
  13. package/specs/editor/various/block-editor-keyboard-shortcuts.test.js +43 -3
  14. package/specs/editor/various/font-size-picker.test.js +57 -11
  15. package/specs/editor/various/post-editor-template-mode.test.js +1 -1
  16. package/specs/editor/various/preview.test.js +66 -1
  17. package/specs/editor/various/reusable-blocks.test.js +52 -5
  18. package/specs/editor/various/undo.test.js +21 -0
  19. package/specs/performance/site-editor.test.js +1 -1
  20. package/specs/site-editor/document-settings.test.js +4 -4
  21. package/specs/site-editor/multi-entity-editing.test.js +2 -2
  22. package/specs/site-editor/multi-entity-saving.test.js +15 -18
  23. package/specs/site-editor/settings-sidebar.test.js +4 -4
  24. package/specs/site-editor/site-editor-export.test.js +1 -1
  25. package/specs/site-editor/site-editor-inserter.test.js +1 -1
  26. package/specs/site-editor/template-part.test.js +9 -12
  27. package/specs/site-editor/template-revert.test.js +13 -9
  28. package/specs/widgets/customizing-widgets.test.js +3 -23
  29. package/specs/widgets/editing-widgets.test.js +36 -12
@@ -1,7 +1,14 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { uniqueId } from 'lodash';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
4
9
  import {
10
+ clickButton,
11
+ clickOnMoreMenuItem,
5
12
  createJSONResponse,
6
13
  createNewPost,
7
14
  createMenu as createClassicMenu,
@@ -12,12 +19,15 @@ import {
12
19
  saveDraft,
13
20
  showBlockToolbar,
14
21
  openPreviewPage,
15
- selectBlockByClientId,
16
- getAllBlocks,
17
22
  ensureSidebarOpened,
18
23
  __experimentalRest as rest,
19
24
  publishPost,
25
+ createUser,
26
+ loginUser,
27
+ deleteUser,
28
+ switchUserToAdmin,
20
29
  } from '@wordpress/e2e-test-utils';
30
+ import { addQueryArgs } from '@wordpress/url';
21
31
 
22
32
  /**
23
33
  * Internal dependencies
@@ -26,6 +36,7 @@ import menuItemsFixture from '../fixtures/menu-items-request-fixture.json';
26
36
 
27
37
  const POSTS_ENDPOINT = '/wp/v2/posts';
28
38
  const PAGES_ENDPOINT = '/wp/v2/pages';
39
+ const DRAFT_PAGES_ENDPOINT = [ PAGES_ENDPOINT, { status: 'draft' } ];
29
40
  const NAVIGATION_MENUS_ENDPOINT = '/wp/v2/navigation';
30
41
 
31
42
  async function mockSearchResponse( items ) {
@@ -63,7 +74,10 @@ async function updateActiveNavigationLink( { url, label, type } ) {
63
74
  };
64
75
 
65
76
  if ( url ) {
66
- await page.type( 'input[placeholder="Search or type url"]', url );
77
+ const input = await page.waitForSelector(
78
+ 'input[placeholder="Search or type url"]'
79
+ );
80
+ await input.type( url );
67
81
 
68
82
  const suggestionPath = `//button[contains(@class, 'block-editor-link-control__search-item') and contains(@class, '${ typeClasses[ type ] }')]/span/span[@class='block-editor-link-control__search-item-title']/mark[text()="${ url }"]`;
69
83
 
@@ -111,21 +125,7 @@ const PLACEHOLDER_ACTIONS_CLASS = 'wp-block-navigation-placeholder__actions';
111
125
  const PLACEHOLDER_ACTIONS_XPATH = `//*[contains(@class, '${ PLACEHOLDER_ACTIONS_CLASS }')]`;
112
126
  const START_EMPTY_XPATH = `${ PLACEHOLDER_ACTIONS_XPATH }//button[text()='Start empty']`;
113
127
  const ADD_ALL_PAGES_XPATH = `${ PLACEHOLDER_ACTIONS_XPATH }//button[text()='Add all pages']`;
114
-
115
- async function turnResponsivenessOn() {
116
- const blocks = await getAllBlocks();
117
-
118
- await selectBlockByClientId( blocks[ 0 ].clientId );
119
- await ensureSidebarOpened();
120
-
121
- const [ responsivenessToggleButton ] = await page.$x(
122
- '//label[text()[contains(.,"Enable responsive menu")]]'
123
- );
124
-
125
- await responsivenessToggleButton.click();
126
-
127
- await saveDraft();
128
- }
128
+ const SELECT_MENU_XPATH = `${ PLACEHOLDER_ACTIONS_XPATH }//button[text()='Select menu']`;
129
129
 
130
130
  /**
131
131
  * Delete all items for the given REST resources using the REST API.
@@ -133,8 +133,17 @@ async function turnResponsivenessOn() {
133
133
  * @param {*} endpoints The endpoints of the resources to delete.
134
134
  */
135
135
  async function deleteAll( endpoints ) {
136
- for ( const path of endpoints ) {
137
- const items = await rest( { path } );
136
+ for ( const endpoint of endpoints ) {
137
+ const defaultArgs = { per_page: -1 };
138
+ const isArrayEndpoint = Array.isArray( endpoint );
139
+ const path = isArrayEndpoint ? endpoint[ 0 ] : endpoint;
140
+ const args = isArrayEndpoint
141
+ ? { ...defaultArgs, ...endpoint[ 1 ] }
142
+ : defaultArgs;
143
+
144
+ const items = await rest( {
145
+ path: addQueryArgs( path, args ),
146
+ } );
138
147
 
139
148
  for ( const item of items ) {
140
149
  await rest( {
@@ -192,6 +201,10 @@ async function getNavigationMenuRawContent() {
192
201
  return navigationBlock.attributes.ref;
193
202
  } );
194
203
 
204
+ if ( ! menuRef ) {
205
+ throw 'getNavigationMenuRawContent was unable to find a ref attribute on the first navigation block';
206
+ }
207
+
195
208
  const response = await rest( {
196
209
  method: 'GET',
197
210
  path: `/wp/v2/navigation/${ menuRef }?context=edit`,
@@ -203,10 +216,23 @@ async function getNavigationMenuRawContent() {
203
216
  // Disable reason - these tests are to be re-written.
204
217
  // eslint-disable-next-line jest/no-disabled-tests
205
218
  describe( 'Navigation', () => {
219
+ const contributorUsername = uniqueId( 'contributoruser_' );
220
+ let contributorPassword;
221
+
222
+ beforeAll( async () => {
223
+ // Creation of the contributor user **MUST** be at the top level describe block
224
+ // otherwise this test will become unstable. This action only happens once
225
+ // so there is no huge performance hit.
226
+ contributorPassword = await createUser( contributorUsername, {
227
+ role: 'contributor',
228
+ } );
229
+ } );
230
+
206
231
  beforeEach( async () => {
207
232
  await deleteAll( [
208
233
  POSTS_ENDPOINT,
209
234
  PAGES_ENDPOINT,
235
+ DRAFT_PAGES_ENDPOINT,
210
236
  NAVIGATION_MENUS_ENDPOINT,
211
237
  ] );
212
238
  await deleteAllClassicMenus();
@@ -220,9 +246,14 @@ describe( 'Navigation', () => {
220
246
  await deleteAll( [
221
247
  POSTS_ENDPOINT,
222
248
  PAGES_ENDPOINT,
249
+ DRAFT_PAGES_ENDPOINT,
223
250
  NAVIGATION_MENUS_ENDPOINT,
224
251
  ] );
225
252
  await deleteAllClassicMenus();
253
+
254
+ // As per the creation in the beforeAll() above, this
255
+ // action must be done at the root level describe() block.
256
+ await deleteUser( contributorUsername );
226
257
  } );
227
258
 
228
259
  describe( 'placeholder', () => {
@@ -252,7 +283,7 @@ describe( 'Navigation', () => {
252
283
  await allPagesButton.click();
253
284
 
254
285
  // Wait for the page list block to be present
255
- await page.waitForSelector( 'div[aria-label="Block: Page List"]' );
286
+ await page.waitForSelector( 'ul[aria-label="Block: Page List"]' );
256
287
 
257
288
  expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
258
289
  } );
@@ -438,52 +469,53 @@ describe( 'Navigation', () => {
438
469
  expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
439
470
  } );
440
471
 
441
- // URL details endpoint is throwing a 404, which causes this test to fail.
442
- it.skip( 'allows pages to be created from the navigation block and their links added to menu', async () => {
472
+ it( 'allows pages to be created from the navigation block and their links added to menu', async () => {
443
473
  await createNewPost();
444
474
  await insertBlock( 'Navigation' );
445
475
  const startEmptyButton = await page.waitForXPath( START_EMPTY_XPATH );
446
476
  await startEmptyButton.click();
447
-
448
477
  const appender = await page.waitForSelector(
449
478
  '.wp-block-navigation .block-list-appender'
450
479
  );
451
480
  await appender.click();
452
481
 
453
482
  // Wait for URL input to be focused
454
- await page.waitForSelector(
455
- 'input.block-editor-url-input__input:focus'
456
- );
457
-
458
483
  // Insert name for the new page.
459
- await page.type(
460
- 'input[placeholder="Search or type url"]',
461
- 'A really long page name that will not exist'
462
- );
463
-
464
- // Wait for URL input to be focused
465
- await page.waitForSelector(
484
+ const pageTitle = 'A really long page name that will not exist';
485
+ const input = await page.waitForSelector(
466
486
  'input.block-editor-url-input__input:focus'
467
487
  );
468
-
469
- // Wait for the create button to appear and click it.
470
- await page.waitForSelector(
488
+ await input.type( pageTitle );
489
+
490
+ // When creating a page, the URLControl makes a request to the
491
+ // url-details endpoint to fetch information about the page.
492
+ // Because the draft is inaccessible publicly, this request
493
+ // returns a 404 response. Wait for the response and expect
494
+ // the error to have occurred.
495
+ const createPageButton = await page.waitForSelector(
471
496
  '.block-editor-link-control__search-create'
472
497
  );
473
-
474
- const createPageButton = await page.$(
475
- '.block-editor-link-control__search-create'
498
+ const responsePromise = page.waitForResponse(
499
+ ( response ) =>
500
+ response.url().includes( 'url-details' ) &&
501
+ response.status() === 404
476
502
  );
503
+ const createPagePromise = createPageButton.click();
504
+ await Promise.all( [ responsePromise, createPagePromise ] );
477
505
 
478
- await createPageButton.click();
479
-
480
- const draftLink = await page.waitForSelector(
481
- '.wp-block-navigation-item__content'
506
+ // Creating a draft is async, so wait for a sign of completion. In this
507
+ // case the link that shows in the URL popover once a link is added.
508
+ await page.waitForXPath(
509
+ `//a[contains(@class, "block-editor-link-control__search-item-title") and contains(., "${ pageTitle }")]`
482
510
  );
483
- await draftLink.click();
511
+
512
+ await publishPost();
484
513
 
485
514
  // Expect a Navigation Block with a link for "A really long page name that will not exist".
486
515
  expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
516
+ expect( console ).toHaveErroredWith(
517
+ 'Failed to load resource: the server responded with a status of 404 (Not Found)'
518
+ );
487
519
  } );
488
520
 
489
521
  it( 'renders buttons for the submenu opener elements when the block is set to open on click instead of hover', async () => {
@@ -564,125 +596,41 @@ describe( 'Navigation', () => {
564
596
  expect( quickInserter ).toBeTruthy();
565
597
  } );
566
598
 
567
- // The following tests are unstable, roughly around when https://github.com/WordPress/wordpress-develop/pull/1412
568
- // landed. The block manually tests well, so let's skip to unblock other PRs and immediately follow up. cc @vcanales
569
- it.skip( 'loads frontend code only if the block is present', async () => {
570
- // Mock the response from the Pages endpoint. This is done so that the pages returned are always
571
- // consistent and to test the feature more rigorously than the single default sample page.
572
- // await mockPagesResponse( [
573
- // {
574
- // title: 'Home',
575
- // slug: 'home',
576
- // },
577
- // {
578
- // title: 'About',
579
- // slug: 'about',
580
- // },
581
- // {
582
- // title: 'Contact Us',
583
- // slug: 'contact',
584
- // },
585
- // ] );
586
-
587
- // Create first block at the start in order to enable preview.
588
- await insertBlock( 'Navigation' );
589
- await saveDraft();
590
-
591
- const previewPage = await openPreviewPage();
592
- const isScriptLoaded = await previewPage.evaluate(
593
- () =>
594
- null !==
595
- document.querySelector(
596
- 'script[src*="navigation/view.min.js"]'
597
- )
599
+ it( 'supports navigation blocks that have inner blocks within their markup and converts them to wp_navigation posts', async () => {
600
+ // Insert 'old-school' inner blocks via the code editor.
601
+ await createNewPost();
602
+ await clickOnMoreMenuItem( 'Code editor' );
603
+ const codeEditorInput = await page.waitForSelector(
604
+ '.editor-post-text-editor'
598
605
  );
599
-
600
- expect( isScriptLoaded ).toBe( false );
601
-
602
- const allPagesButton = await page.waitForXPath( ADD_ALL_PAGES_XPATH );
603
- await allPagesButton.click();
604
- await insertBlock( 'Navigation' );
605
- const allPagesButton2 = await page.waitForXPath( ADD_ALL_PAGES_XPATH );
606
- await allPagesButton2.click();
607
- await turnResponsivenessOn();
608
-
609
- await previewPage.reload( {
610
- waitFor: [ 'networkidle0', 'domcontentloaded' ],
611
- } );
612
-
613
- /*
614
- Count instances of the tag to make sure that it's been loaded only once,
615
- regardless of the number of navigation blocks present.
616
- */
617
- const tagCount = await previewPage.evaluate(
618
- () =>
619
- Array.from(
620
- document.querySelectorAll(
621
- 'script[src*="navigation/view.min.js"]'
622
- )
623
- ).length
606
+ await codeEditorInput.click();
607
+ const markup =
608
+ '<!-- wp:navigation --><!-- wp:page-list /--><!-- /wp:navigation -->';
609
+ await page.keyboard.type( markup );
610
+ await clickButton( 'Exit code editor' );
611
+ const navBlock = await page.waitForSelector(
612
+ 'nav[aria-label="Block: Navigation"]'
624
613
  );
614
+ // Select the block to convert to a wp_navigation and publish.
615
+ // The select menu button shows up when saving is complete.
616
+ await navBlock.click();
617
+ await page.waitForSelector( 'button[aria-label="Select Menu"]' );
618
+ await publishPost();
625
619
 
626
- expect( tagCount ).toBe( 1 );
620
+ // Check that the wp_navigation post has the page list block.
621
+ expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
627
622
  } );
628
623
 
629
- it.skip( 'loads frontend code only if responsiveness is turned on', async () => {
630
- // await mockPagesResponse( [
631
- // {
632
- // title: 'Home',
633
- // slug: 'home',
634
- // },
635
- // {
636
- // title: 'About',
637
- // slug: 'about',
638
- // },
639
- // {
640
- // title: 'Contact Us',
641
- // slug: 'contact',
642
- // },
643
- // ] );
624
+ describe( 'Creating and restarting', () => {
625
+ const NAV_ENTITY_SELECTOR =
626
+ '//div[@class="entities-saved-states__panel"]//label//strong[contains(text(), "Navigation")]';
644
627
 
645
- await insertBlock( 'Navigation' );
646
- await saveDraft();
647
-
648
- const previewPage = await openPreviewPage();
649
- let isScriptLoaded = await previewPage.evaluate(
650
- () =>
651
- null !==
652
- document.querySelector(
653
- 'script[src*="navigation/view.min.js"]'
654
- )
655
- );
656
-
657
- expect( isScriptLoaded ).toBe( false );
658
-
659
- const allPagesButton = await page.waitForXPath( ADD_ALL_PAGES_XPATH );
660
- await allPagesButton.click();
661
-
662
- await turnResponsivenessOn();
663
-
664
- await previewPage.reload( {
665
- waitFor: [ 'networkidle0', 'domcontentloaded' ],
666
- } );
667
-
668
- isScriptLoaded = await previewPage.evaluate(
669
- () =>
670
- null !==
671
- document.querySelector(
672
- 'script[src*="navigation/view.min.js"]'
673
- )
674
- );
675
-
676
- expect( isScriptLoaded ).toBe( true );
677
- } );
678
-
679
- describe.skip( 'Creating and restarting', () => {
680
628
  async function populateNavWithOneItem() {
681
629
  // Add a Link block first.
682
- await page.waitForSelector(
630
+ const appender = await page.waitForSelector(
683
631
  '.wp-block-navigation .block-list-appender'
684
632
  );
685
- await page.click( '.wp-block-navigation .block-list-appender' );
633
+ await appender.click();
686
634
  // Add a link to the Link block.
687
635
  await updateActiveNavigationLink( {
688
636
  url: 'https://wordpress.org',
@@ -692,62 +640,88 @@ describe( 'Navigation', () => {
692
640
  }
693
641
 
694
642
  async function resetNavBlockToInitialState() {
695
- await page.waitForSelector( '[aria-label="Select Menu"]' );
696
- await page.click( '[aria-label="Select Menu"]' );
697
-
698
- await page.waitForXPath( '//span[text()="Create new menu"]' );
699
- const newMenuButton = await page.$x(
643
+ const selectMenuDropdown = await page.waitForSelector(
644
+ '[aria-label="Select Menu"]'
645
+ );
646
+ await selectMenuDropdown.click();
647
+ const newMenuButton = await page.waitForXPath(
700
648
  '//span[text()="Create new menu"]'
701
649
  );
702
- newMenuButton[ 0 ].click();
650
+ newMenuButton.click();
703
651
  }
704
652
 
705
- it( 'only update a single entity currently linked with the block', async () => {
706
- // Mock the response from the Pages endpoint. This is done so that the pages returned are always
707
- // consistent and to test the feature more rigorously than the single default sample page.
708
- // await mockPagesResponse( [
709
- // {
710
- // title: 'Home',
711
- // slug: 'home',
712
- // },
713
- // {
714
- // title: 'About',
715
- // slug: 'about',
716
- // },
717
- // {
718
- // title: 'Contact Us',
719
- // slug: 'contact',
720
- // },
721
- // ] );
653
+ it( 'does not retain uncontrolled inner blocks when creating a new entity', async () => {
654
+ await createNewPost();
655
+ await clickOnMoreMenuItem( 'Code editor' );
656
+ const codeEditorInput = await page.waitForSelector(
657
+ '.editor-post-text-editor'
658
+ );
659
+ await codeEditorInput.click();
660
+ const markup =
661
+ '<!-- wp:navigation --><!-- wp:page-list /--><!-- /wp:navigation -->';
662
+ await page.keyboard.type( markup );
663
+ await clickButton( 'Exit code editor' );
664
+ const navBlock = await page.waitForSelector(
665
+ 'nav[aria-label="Block: Navigation"]'
666
+ );
667
+
668
+ // Select the block to convert to a wp_navigation and publish.
669
+ // The select menu button shows up when saving is complete.
670
+ await navBlock.click();
671
+ await page.waitForSelector( 'button[aria-label="Select Menu"]' );
672
+
673
+ // Reset the nav block to create a new entity.
674
+ await resetNavBlockToInitialState();
675
+ const startEmptyButton = await page.waitForXPath(
676
+ START_EMPTY_XPATH
677
+ );
678
+ await startEmptyButton.click();
679
+ await populateNavWithOneItem();
680
+
681
+ // Confirm that only the last menu entity was updated.
682
+ const publishPanelButton2 = await page.waitForSelector(
683
+ '.editor-post-publish-button__button:not([aria-disabled="true"])'
684
+ );
685
+ await publishPanelButton2.click();
722
686
 
687
+ await page.waitForXPath( NAV_ENTITY_SELECTOR );
688
+ expect( await page.$x( NAV_ENTITY_SELECTOR ) ).toHaveLength( 1 );
689
+ } );
690
+
691
+ it( 'only updates a single entity currently linked with the block', async () => {
692
+ await createNewPost();
723
693
  await insertBlock( 'Navigation' );
694
+
724
695
  const startEmptyButton = await page.waitForXPath(
725
696
  START_EMPTY_XPATH
726
697
  );
727
698
  await startEmptyButton.click();
728
699
  await populateNavWithOneItem();
729
700
 
730
- // Let's confirm that the menu entity was updated.
731
- await page.waitForSelector(
701
+ // Confirm that the menu entity was updated.
702
+ const publishPanelButton = await page.waitForSelector(
732
703
  '.editor-post-publish-panel__toggle:not([aria-disabled="true"])'
733
704
  );
734
- await page.click( '.editor-post-publish-panel__toggle' );
705
+ await publishPanelButton.click();
735
706
 
736
- const NAV_ENTITY_SELECTOR =
737
- '//div[@class="entities-saved-states__panel"]//label//strong[contains(text(), "Navigation")]';
738
707
  await page.waitForXPath( NAV_ENTITY_SELECTOR );
739
708
  expect( await page.$x( NAV_ENTITY_SELECTOR ) ).toHaveLength( 1 );
740
709
 
741
710
  // Publish the post
742
- await page.click( '.editor-entities-saved-states__save-button' );
743
- await page.waitForSelector( '.editor-post-publish-button' );
744
- await page.click( '.editor-post-publish-button' );
711
+ const entitySaveButton = await page.waitForSelector(
712
+ '.editor-entities-saved-states__save-button'
713
+ );
714
+ await entitySaveButton.click();
715
+ const publishButton = await page.waitForSelector(
716
+ '.editor-post-publish-button:not([aria-disabled="true"])'
717
+ );
718
+ await publishButton.click();
745
719
 
746
- // A success notice should show up
720
+ // A success notice should show up.
747
721
  await page.waitForSelector( '.components-snackbar' );
748
722
 
749
723
  // Now try inserting another Link block via the quick inserter.
750
- await page.focus( '.wp-block-navigation' );
724
+ await page.click( 'nav[aria-label="Block: Navigation"]' );
751
725
 
752
726
  await resetNavBlockToInitialState();
753
727
  const startEmptyButton2 = await page.waitForXPath(
@@ -756,14 +730,129 @@ describe( 'Navigation', () => {
756
730
  await startEmptyButton2.click();
757
731
  await populateNavWithOneItem();
758
732
 
759
- // Let's confirm that only the last menu entity was updated.
760
- await page.waitForSelector(
733
+ // Confirm that only the last menu entity was updated.
734
+ const publishPanelButton2 = await page.waitForSelector(
761
735
  '.editor-post-publish-button__button:not([aria-disabled="true"])'
762
736
  );
763
- await page.click( '.editor-post-publish-button__button' );
737
+ await publishPanelButton2.click();
764
738
 
765
739
  await page.waitForXPath( NAV_ENTITY_SELECTOR );
766
740
  expect( await page.$x( NAV_ENTITY_SELECTOR ) ).toHaveLength( 1 );
767
741
  } );
768
742
  } );
743
+
744
+ it( 'does not load the frontend script if no navigation blocks are present', async () => {
745
+ await createNewPost();
746
+ await insertBlock( 'Paragraph' );
747
+ await page.waitForSelector( 'p[data-title="Paragraph"]:focus' );
748
+ await page.keyboard.type( 'Hello' );
749
+
750
+ const previewPage = await openPreviewPage();
751
+ await previewPage.bringToFront();
752
+ await previewPage.waitForNetworkIdle();
753
+
754
+ const isScriptLoaded = await previewPage.evaluate(
755
+ () =>
756
+ null !==
757
+ document.querySelector(
758
+ 'script[src*="navigation/view.min.js"]'
759
+ )
760
+ );
761
+
762
+ expect( isScriptLoaded ).toBe( false );
763
+ } );
764
+
765
+ it( 'loads the frontend script only once even when multiple navigation blocks are present', async () => {
766
+ await createNewPost();
767
+ await insertBlock( 'Navigation' );
768
+ await insertBlock( 'Navigation' );
769
+
770
+ const previewPage = await openPreviewPage();
771
+ await previewPage.bringToFront();
772
+ await previewPage.waitForNetworkIdle();
773
+
774
+ const tagCount = await previewPage.evaluate(
775
+ () =>
776
+ document.querySelectorAll(
777
+ 'script[src*="navigation/view.min.js"]'
778
+ ).length
779
+ );
780
+
781
+ expect( tagCount ).toBe( 1 );
782
+ } );
783
+
784
+ describe( 'Permission based restrictions', () => {
785
+ afterEach( async () => {
786
+ await switchUserToAdmin();
787
+ } );
788
+
789
+ it( 'shows a warning if user does not have permission to edit or update navigation menus', async () => {
790
+ await createNewPost();
791
+ await insertBlock( 'Navigation' );
792
+
793
+ const startEmptyButton = await page.waitForXPath(
794
+ START_EMPTY_XPATH
795
+ );
796
+
797
+ // This creates an empty Navigation post type entity.
798
+ await startEmptyButton.click();
799
+
800
+ // Publishing the Post ensures the Navigation entity is saved.
801
+ // The Post itself is irrelevant.
802
+ await publishPost();
803
+
804
+ // Switch to a Contributor role user - they should not have
805
+ // permission to update Navigation menus.
806
+ await loginUser( contributorUsername, contributorPassword );
807
+
808
+ await createNewPost();
809
+
810
+ await insertBlock( 'Navigation' );
811
+
812
+ // Select the Navigation post created by the Admin early
813
+ // in the test.
814
+ const navigationPostCreatedByAdminName = 'Navigation';
815
+ const dropdown = await page.waitForXPath( SELECT_MENU_XPATH );
816
+ await dropdown.click();
817
+ const theOption = await page.waitForXPath(
818
+ `//*[contains(@class, 'components-menu-item__item')][ text()="${ navigationPostCreatedByAdminName }" ]`
819
+ );
820
+ await theOption.click();
821
+
822
+ // Make sure the snackbar error shows up
823
+ await page.waitForXPath(
824
+ `//*[contains(@class, 'components-snackbar__content')][ text()="You do not have permission to edit this Menu. Any changes made will not be saved." ]`
825
+ );
826
+
827
+ // Expect a console 403 for request to Navigation Areas for lower permission users.
828
+ // This is because reading requires the `edit_theme_options` capability
829
+ // which the Contributor level user does not have.
830
+ // See: https://github.com/WordPress/gutenberg/blob/4cedaf0c4abb0aeac4bfd4289d63e9889efe9733/lib/class-wp-rest-block-navigation-areas-controller.php#L81-L91.
831
+ // Todo: removed once Nav Areas are removed from the Gutenberg Plugin.
832
+ expect( console ).toHaveErrored();
833
+ } );
834
+
835
+ it( 'shows a warning if user does not have permission to create navigation menus', async () => {
836
+ const noticeText =
837
+ 'You do not have permission to create Navigation Menus.';
838
+ // Switch to a Contributor role user - they should not have
839
+ // permission to update Navigations.
840
+ await loginUser( contributorUsername, contributorPassword );
841
+
842
+ await createNewPost();
843
+ await insertBlock( 'Navigation' );
844
+
845
+ // Make sure the snackbar error shows up
846
+ await page.waitForXPath(
847
+ `//*[contains(@class, 'components-snackbar__content')][ text()="${ noticeText }" ]`
848
+ );
849
+
850
+ // Expect a console 403 for request to Navigation Areas for lower permission users.
851
+ // This is because reading requires the `edit_theme_options` capability
852
+ // which the Contributor level user does not have.
853
+ // See: https://github.com/WordPress/gutenberg/blob/4cedaf0c4abb0aeac4bfd4289d63e9889efe9733/lib/class-wp-rest-block-navigation-areas-controller.php#L81-L91.
854
+ // Todo: removed once Nav Areas are removed from the Gutenberg Plugin.
855
+ expect( console ).toHaveErrored();
856
+ } );
857
+ } );
769
858
  } );
@@ -181,7 +181,7 @@ describe( 'Block variations', () => {
181
181
  ).toBeTruthy();
182
182
  const description = await getBlockCardDescription();
183
183
  expect( description ).toEqual(
184
- 'Start with the building block of all narrative.'
184
+ 'Start with the basic building block of all narrative.'
185
185
  );
186
186
  } );
187
187
  } );
@@ -57,11 +57,5 @@ describe( 'iframed inline styles', () => {
57
57
  expect( await getComputedStyle( canvas(), 'border-width' ) ).toBe(
58
58
  '2px'
59
59
  );
60
-
61
- expect( console ).toHaveWarned(
62
- `Stylesheet iframed-inline-styles-compat-style-css was not properly added.
63
- For blocks, use the block API's style (https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#style) or editorStyle (https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#editor-style).
64
- For themes, use add_editor_style (https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-support/#editor-styles). <link rel="stylesheet" id="iframed-inline-styles-compat-style-css" href="http://localhost:8889/wp-content/plugins/gutenberg-test-plugins/iframed-inline-styles/compat-style.css?ver=1626189899" media="all">`
65
- );
66
60
  } );
67
61
  } );
@@ -63,9 +63,5 @@ describe( 'iframed multiple block stylesheets', () => {
63
63
  expect( await getComputedStyle( canvas(), 'background-color' ) ).toBe(
64
64
  'rgb(0, 0, 0)'
65
65
  );
66
-
67
- // Skip warnings related to block-styles enqueing and the use of add_editor_style.
68
- // The issue is tracked on https://github.com/WordPress/gutenberg/issues/33212.
69
- expect( console ).toHaveWarned();
70
66
  } );
71
67
  } );