@wordpress/e2e-tests 3.1.0 → 4.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 (42) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +2 -0
  3. package/config/flaky-tests-reporter.js +1 -0
  4. package/package.json +10 -8
  5. package/specs/editor/blocks/__snapshots__/buttons.test.js.snap +8 -0
  6. package/specs/editor/blocks/__snapshots__/navigation.test.js.snap +2 -2
  7. package/specs/editor/blocks/__snapshots__/separator.test.js.snap +1 -1
  8. package/specs/editor/blocks/buttons.test.js +10 -0
  9. package/specs/editor/blocks/columns.test.js +3 -3
  10. package/specs/editor/blocks/gallery.test.js +36 -6
  11. package/specs/editor/blocks/heading.test.js +1 -1
  12. package/specs/editor/blocks/navigation.test.js +370 -72
  13. package/specs/editor/blocks/query.test.js +13 -3
  14. package/specs/editor/plugins/annotations.test.js +63 -67
  15. package/specs/editor/various/__snapshots__/block-deletion.test.js.snap +20 -12
  16. package/specs/editor/various/__snapshots__/block-editor-keyboard-shortcuts.test.js.snap +26 -0
  17. package/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap +1 -1
  18. package/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap +122 -6
  19. package/specs/editor/various/__snapshots__/writing-flow.test.js.snap +6 -6
  20. package/specs/editor/various/autosave.test.js +3 -3
  21. package/specs/editor/various/block-deletion.test.js +1 -0
  22. package/specs/editor/various/block-editor-keyboard-shortcuts.test.js +3 -5
  23. package/specs/editor/various/block-hierarchy-navigation.test.js +10 -16
  24. package/specs/editor/various/block-locking.test.js +120 -0
  25. package/specs/editor/various/keyboard-navigable-blocks.test.js +23 -0
  26. package/specs/editor/various/list-view.test.js +139 -7
  27. package/specs/editor/various/multi-block-selection.test.js +153 -9
  28. package/specs/editor/various/post-editor-template-mode.test.js +1 -1
  29. package/specs/editor/various/toolbar-roving-tabindex.test.js +10 -4
  30. package/specs/editor/various/writing-flow.test.js +10 -5
  31. package/specs/experiments/blocks/comments-query.test.js +131 -0
  32. package/specs/experiments/navigation-editor.test.js +126 -121
  33. package/specs/performance/post-editor.test.js +4 -6
  34. package/specs/site-editor/global-styles-sidebar.test.js +42 -0
  35. package/specs/site-editor/iframe-rendering-mode.test.js +31 -0
  36. package/specs/site-editor/site-editor-export.test.js +2 -2
  37. package/specs/site-editor/style-variations.test.js +9 -7
  38. package/specs/site-editor/template-part.test.js +3 -1
  39. package/specs/editor/various/__snapshots__/copy-cut-paste-whole-blocks.test.js.snap +0 -125
  40. package/specs/editor/various/copy-cut-paste-whole-blocks.test.js +0 -187
  41. package/specs/editor/various/new-post.test.js +0 -99
  42. package/specs/widgets/customizing-widgets.test.js +0 -913
@@ -21,12 +21,15 @@ import {
21
21
  openPreviewPage,
22
22
  ensureSidebarOpened,
23
23
  __experimentalRest as rest,
24
+ __experimentalBatch as batch,
24
25
  publishPost,
25
26
  createUser,
26
27
  loginUser,
27
28
  deleteUser,
28
29
  switchUserToAdmin,
29
30
  clickBlockToolbarButton,
31
+ openListView,
32
+ getListViewBlocks,
30
33
  } from '@wordpress/e2e-test-utils';
31
34
  import { addQueryArgs } from '@wordpress/url';
32
35
 
@@ -39,6 +42,47 @@ const POSTS_ENDPOINT = '/wp/v2/posts';
39
42
  const PAGES_ENDPOINT = '/wp/v2/pages';
40
43
  const DRAFT_PAGES_ENDPOINT = [ PAGES_ENDPOINT, { status: 'draft' } ];
41
44
  const NAVIGATION_MENUS_ENDPOINT = '/wp/v2/navigation';
45
+ // todo: consolidate with logic found in navigation-editor tests
46
+ // https://github.com/WordPress/gutenberg/blob/trunk/packages/e2e-tests/specs/experiments/navigation-editor.test.js#L71
47
+ const REST_PAGES_ROUTES = [
48
+ '/wp/v2/pages',
49
+ `rest_route=${ encodeURIComponent( '/wp/v2/pages' ) }`,
50
+ ];
51
+
52
+ /**
53
+ * Determines if a given URL matches any of a given collection of
54
+ * routes (expressed as substrings).
55
+ *
56
+ * @param {string} reqUrl the full URL to be tested for matches.
57
+ * @param {Array} routes array of strings to match against the URL.
58
+ */
59
+ function matchUrlToRoute( reqUrl, routes ) {
60
+ return routes.some( ( route ) => reqUrl.includes( route ) );
61
+ }
62
+
63
+ function getEndpointMocks( matchingRoutes, responsesByMethod ) {
64
+ return [ 'GET', 'POST', 'DELETE', 'PUT' ].reduce( ( mocks, restMethod ) => {
65
+ if ( responsesByMethod[ restMethod ] ) {
66
+ return [
67
+ ...mocks,
68
+ {
69
+ match: ( request ) =>
70
+ matchUrlToRoute( request.url(), matchingRoutes ) &&
71
+ request.method() === restMethod,
72
+ onRequestMatch: createJSONResponse(
73
+ responsesByMethod[ restMethod ]
74
+ ),
75
+ },
76
+ ];
77
+ }
78
+
79
+ return mocks;
80
+ }, [] );
81
+ }
82
+
83
+ function getPagesMocks( responsesByMethod ) {
84
+ return getEndpointMocks( REST_PAGES_ROUTES, responsesByMethod );
85
+ }
42
86
 
43
87
  async function mockSearchResponse( items ) {
44
88
  const mappedItems = items.map( ( { title, slug }, index ) => ( {
@@ -48,7 +92,6 @@ async function mockSearchResponse( items ) {
48
92
  type: 'post',
49
93
  url: `https://this/is/a/test/search/${ slug }`,
50
94
  } ) );
51
-
52
95
  await setUpResponseMocking( [
53
96
  {
54
97
  match: ( request ) =>
@@ -56,9 +99,44 @@ async function mockSearchResponse( items ) {
56
99
  request.url().includes( `search` ),
57
100
  onRequestMatch: createJSONResponse( mappedItems ),
58
101
  },
102
+ ...getPagesMocks( {
103
+ GET: [
104
+ {
105
+ type: 'page',
106
+ id: 1,
107
+ link: 'https://example.com/1',
108
+ title: {
109
+ rendered: 'My page',
110
+ },
111
+ },
112
+ ],
113
+ } ),
59
114
  ] );
60
115
  }
61
116
 
117
+ async function forceSelectNavigationBlock() {
118
+ const navBlock = await waitForBlock( 'Navigation' );
119
+
120
+ if ( ! navBlock ) {
121
+ return;
122
+ }
123
+
124
+ await page.evaluate( () => {
125
+ const blocks = wp.data.select( 'core/block-editor' ).getBlocks();
126
+ const navigationBlock = blocks.find(
127
+ ( block ) => block.name === 'core/navigation'
128
+ );
129
+
130
+ if ( ! navigationBlock ) {
131
+ return;
132
+ }
133
+
134
+ return wp.data
135
+ .dispatch( 'core/block-editor' )
136
+ .selectBlock( navigationBlock?.clientId, 0 );
137
+ } );
138
+ }
139
+
62
140
  /**
63
141
  * Interacts with the LinkControl to perform a search and select a returned suggestion
64
142
  *
@@ -144,7 +222,6 @@ async function populateNavWithOneItem() {
144
222
  const PLACEHOLDER_ACTIONS_CLASS = 'wp-block-navigation-placeholder__actions';
145
223
  const PLACEHOLDER_ACTIONS_XPATH = `//*[contains(@class, '${ PLACEHOLDER_ACTIONS_CLASS }')]`;
146
224
  const START_EMPTY_XPATH = `${ PLACEHOLDER_ACTIONS_XPATH }//button[text()='Start empty']`;
147
- const SELECT_MENU_XPATH = `${ PLACEHOLDER_ACTIONS_XPATH }//button[text()='Select Menu']`;
148
225
 
149
226
  /**
150
227
  * Delete all items for the given REST resources using the REST API.
@@ -173,6 +250,17 @@ async function deleteAll( endpoints ) {
173
250
  }
174
251
  }
175
252
 
253
+ async function resetNavBlockToInitialState() {
254
+ const selectMenuDropdown = await page.waitForSelector(
255
+ '[aria-label="Select Menu"]'
256
+ );
257
+ await selectMenuDropdown.click();
258
+ const newMenuButton = await page.waitForXPath(
259
+ '//span[text()="Create new menu"]'
260
+ );
261
+ newMenuButton.click();
262
+ }
263
+
176
264
  /**
177
265
  * Replace unique ids in nav block content, since these won't be consistent
178
266
  * between test runs.
@@ -265,9 +353,17 @@ describe( 'Navigation', () => {
265
353
  } );
266
354
 
267
355
  describe( 'loading states', () => {
268
- it( 'does not show a loading indicator if there is no ref to a Navigation post', async () => {
356
+ it( 'does not show a loading indicator if there is no ref to a Navigation post and Nav Menus have loaded', async () => {
269
357
  await createNewPost();
358
+
359
+ // Insert an empty block to trigger resolution of Nav Menu items.
360
+ await insertBlock( 'Navigation' );
361
+ await waitForBlock( 'Navigation' );
362
+ await page.waitForXPath( START_EMPTY_XPATH );
363
+
364
+ // Now we have Nav Menu items resolved. Continue to assert.
270
365
  await clickOnMoreMenuItem( 'Code editor' );
366
+
271
367
  const codeEditorInput = await page.waitForSelector(
272
368
  '.editor-post-text-editor'
273
369
  );
@@ -304,17 +400,20 @@ describe( 'Navigation', () => {
304
400
  await setUpResponseMocking( [
305
401
  {
306
402
  match: ( request ) =>
403
+ request.method() === 'GET' &&
307
404
  request.url().includes( `rest_route` ) &&
308
405
  request.url().includes( `navigation` ) &&
309
406
  request.url().includes( testNavId ),
310
- onRequestMatch: () => {
407
+ onRequestMatch: ( request ) => {
311
408
  // The Promise simulates a REST API request whose resolultion
312
409
  // the test has full control over.
313
410
  return new Promise( ( resolve ) => {
314
411
  // Assign the resolution function to the var in the
315
412
  // upper scope to afford control over resolution.
316
413
  resolveNavigationRequest = resolve;
317
- } );
414
+
415
+ // Call request.continue() is required to fully resolve the mock.
416
+ } ).then( () => request.continue() );
318
417
  },
319
418
  },
320
419
  ] );
@@ -338,7 +437,9 @@ describe( 'Navigation', () => {
338
437
  await navBlock.waitForSelector( '.components-spinner' );
339
438
 
340
439
  // Resolve the controlled mocked API request.
341
- resolveNavigationRequest();
440
+ if ( typeof resolveNavigationRequest === 'function' ) {
441
+ resolveNavigationRequest();
442
+ }
342
443
  } );
343
444
 
344
445
  it( 'shows a loading indicator whilst empty Navigation menu is being created', async () => {
@@ -355,15 +456,17 @@ describe( 'Navigation', () => {
355
456
  match: ( request ) =>
356
457
  request.url().includes( `rest_route` ) &&
357
458
  request.url().includes( `navigation` ) &&
358
- request.url().includes( testNavId ),
359
- onRequestMatch: () => {
459
+ request.url().includes( `${ testNavId }?` ),
460
+ onRequestMatch: ( request ) => {
360
461
  // The Promise simulates a REST API request whose resolultion
361
462
  // the test has full control over.
362
463
  return new Promise( ( resolve ) => {
363
464
  // Assign the resolution function to the var in the
364
465
  // upper scope to afford control over resolution.
365
466
  resolveNavigationRequest = resolve;
366
- } );
467
+
468
+ // Call request.continue() is required to fully resolve the mock.
469
+ } ).then( () => request.continue() );
367
470
  },
368
471
  },
369
472
  ] );
@@ -385,7 +488,9 @@ describe( 'Navigation', () => {
385
488
  await navBlock.waitForSelector( '.components-spinner' );
386
489
 
387
490
  // Resolve the controlled mocked API request.
388
- resolveNavigationRequest();
491
+ if ( typeof resolveNavigationRequest === 'function' ) {
492
+ resolveNavigationRequest();
493
+ }
389
494
  } );
390
495
  } );
391
496
 
@@ -433,6 +538,11 @@ describe( 'Navigation', () => {
433
538
  );
434
539
  await startEmptyButton.click();
435
540
 
541
+ // Wait for Navigation creation to complete.
542
+ await page.waitForXPath(
543
+ '//*[contains(@class, "components-snackbar")]/*[text()="Navigation Menu successfully created."]'
544
+ );
545
+
436
546
  // Wait for block to resolve
437
547
  let navBlock = await waitForBlock( 'Navigation' );
438
548
 
@@ -775,50 +885,90 @@ describe( 'Navigation', () => {
775
885
  expect( quickInserter ).toBeTruthy();
776
886
  } );
777
887
 
778
- it( 'supports navigation blocks that have inner blocks within their markup and converts them to wp_navigation posts', async () => {
779
- // Insert 'old-school' inner blocks via the code editor.
780
- await createNewPost();
781
- await clickOnMoreMenuItem( 'Code editor' );
782
- const codeEditorInput = await page.waitForSelector(
783
- '.editor-post-text-editor'
784
- );
785
- await codeEditorInput.click();
786
- const markup =
787
- '<!-- wp:navigation --><!-- wp:page-list /--><!-- /wp:navigation -->';
788
- await page.keyboard.type( markup );
789
-
790
- await clickButton( 'Exit code editor' );
888
+ describe( 'Creating and restarting', () => {
889
+ const NAV_ENTITY_SELECTOR =
890
+ '//div[@class="entities-saved-states__panel"]//label//strong[contains(text(), "Navigation")]';
791
891
 
792
- const navBlock = await waitForBlock( 'Navigation' );
892
+ it( 'respects the nesting level', async () => {
893
+ await createNewPost();
793
894
 
794
- // Select the block to convert to a wp_navigation.
795
- await navBlock.click();
895
+ await insertBlock( 'Navigation' );
796
896
 
797
- // The Page List block is rendered within Navigation InnerBlocks when saving is complete.
798
- await waitForBlock( 'Page List' );
897
+ const navBlock = await waitForBlock( 'Navigation' );
799
898
 
800
- await publishPost();
899
+ // Create empty Navigation block with no items
900
+ const startEmptyButton = await page.waitForXPath(
901
+ START_EMPTY_XPATH
902
+ );
903
+ await startEmptyButton.click();
801
904
 
802
- // Check that the wp_navigation post has the page list block.
803
- expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
804
- } );
905
+ await populateNavWithOneItem();
805
906
 
806
- describe( 'Creating and restarting', () => {
807
- const NAV_ENTITY_SELECTOR =
808
- '//div[@class="entities-saved-states__panel"]//label//strong[contains(text(), "Navigation")]';
907
+ await clickOnMoreMenuItem( 'Code editor' );
908
+ const codeEditorInput = await page.waitForSelector(
909
+ '.editor-post-text-editor'
910
+ );
809
911
 
810
- async function resetNavBlockToInitialState() {
811
- const selectMenuDropdown = await page.waitForSelector(
812
- '[aria-label="Select Menu"]'
912
+ let code = await codeEditorInput.evaluate( ( el ) => el.value );
913
+ code = code.replace( '} /-->', ',"maxNestingLevel":0} /-->' );
914
+ await codeEditorInput.evaluate(
915
+ ( el, newCode ) => ( el.value = newCode ),
916
+ code
813
917
  );
814
- await selectMenuDropdown.click();
815
- const newMenuButton = await page.waitForXPath(
816
- '//span[text()="Create new menu"]'
918
+ await clickButton( 'Exit code editor' );
919
+
920
+ const blockAppender = navBlock.$( '.block-list-appender' );
921
+
922
+ expect( blockAppender ).not.toBeNull();
923
+
924
+ // Check the Submenu block is no longer present.
925
+ const navSubmenuSelector =
926
+ '[aria-label="Editor content"][role="region"] [aria-label="Block: Submenu"]';
927
+ const submenuBlock = await page.$( navSubmenuSelector );
928
+
929
+ expect( submenuBlock ).toBeFalsy();
930
+ } );
931
+
932
+ it( 'retains initial uncontrolled inner blocks whilst there are no modifications to those blocks', async () => {
933
+ await createNewPost();
934
+ await clickOnMoreMenuItem( 'Code editor' );
935
+ const codeEditorInput = await page.waitForSelector(
936
+ '.editor-post-text-editor'
817
937
  );
818
- newMenuButton.click();
819
- }
938
+ await codeEditorInput.click();
939
+
940
+ const markup =
941
+ '<!-- wp:navigation --><!-- wp:page-list /--><!-- /wp:navigation -->';
942
+ await page.keyboard.type( markup );
943
+ await clickButton( 'Exit code editor' );
944
+
945
+ const navBlock = await waitForBlock( 'Navigation' );
820
946
 
821
- it( 'does not retain uncontrolled inner blocks when creating a new entity', async () => {
947
+ // Select the block
948
+ await navBlock.click();
949
+
950
+ const hasUncontrolledInnerBlocks = await page.evaluate( () => {
951
+ const blocks = wp.data
952
+ .select( 'core/block-editor' )
953
+ .getBlocks();
954
+ return !! blocks[ 0 ]?.innerBlocks?.length;
955
+ } );
956
+
957
+ expect( hasUncontrolledInnerBlocks ).toBe( true );
958
+ } );
959
+
960
+ it( 'converts uncontrolled inner blocks to an entity when modifications are made to the blocks', async () => {
961
+ await rest( {
962
+ method: 'POST',
963
+ path: `/wp/v2/pages/`,
964
+ data: {
965
+ status: 'publish',
966
+ title: 'A Test Page',
967
+ content: 'Hello world',
968
+ },
969
+ } );
970
+
971
+ // Insert 'old-school' inner blocks via the code editor.
822
972
  await createNewPost();
823
973
  await clickOnMoreMenuItem( 'Code editor' );
824
974
  const codeEditorInput = await page.waitForSelector(
@@ -828,33 +978,52 @@ describe( 'Navigation', () => {
828
978
  const markup =
829
979
  '<!-- wp:navigation --><!-- wp:page-list /--><!-- /wp:navigation -->';
830
980
  await page.keyboard.type( markup );
981
+
831
982
  await clickButton( 'Exit code editor' );
832
983
 
833
984
  const navBlock = await waitForBlock( 'Navigation' );
834
985
 
835
- // Select the block to convert to a wp_navigation.
836
986
  await navBlock.click();
837
987
 
838
- // The Page List block is rendered within Navigation InnerBlocks when saving is complete.
839
- await waitForBlock( 'Page List' );
988
+ // Wait for the Page List to have resolved and render as a `<ul>`.
989
+ await page.waitForSelector(
990
+ `[aria-label="Editor content"][role="region"] ul[aria-label="Block: Page List"]`
991
+ );
840
992
 
841
- // Reset the nav block to create a new entity.
842
- await resetNavBlockToInitialState();
993
+ // Select the Page List block.
994
+ await openListView();
843
995
 
844
- const startEmptyButton = await page.waitForXPath(
845
- START_EMPTY_XPATH
996
+ const navExpander = await page.waitForXPath(
997
+ `//a[span[text()='Navigation']]/span[contains(@class, 'block-editor-list-view__expander')]`
846
998
  );
847
- await startEmptyButton.click();
848
- await populateNavWithOneItem();
849
999
 
850
- // Confirm that only the last menu entity was updated.
851
- const publishPanelButton2 = await page.waitForSelector(
852
- '.editor-post-publish-button__button:not([aria-disabled="true"])'
1000
+ await navExpander.click();
1001
+
1002
+ const pageListBlock = (
1003
+ await getListViewBlocks( 'Page List' )
1004
+ )[ 0 ];
1005
+
1006
+ await pageListBlock.click();
1007
+
1008
+ // Modify the uncontrolled inner blocks by converting Page List.
1009
+ await clickBlockToolbarButton( 'Edit' );
1010
+
1011
+ // Must wait for button to be enabled.
1012
+ const convertButton = await page.waitForXPath(
1013
+ `//button[not(@disabled) and text()="Convert"]`
853
1014
  );
854
- await publishPanelButton2.click();
855
1015
 
856
- await page.waitForXPath( NAV_ENTITY_SELECTOR );
857
- expect( await page.$x( NAV_ENTITY_SELECTOR ) ).toHaveLength( 1 );
1016
+ await convertButton.click();
1017
+
1018
+ // Wait for new Nav Menu entity to be created as a result of the modification to inner blocks.
1019
+ await page.waitForXPath(
1020
+ `//*[contains(@class, 'components-snackbar__content')][ text()="New Navigation Menu created." ]`
1021
+ );
1022
+
1023
+ await publishPost();
1024
+
1025
+ // Check that the wp_navigation post exists and has the page list block.
1026
+ expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
858
1027
  } );
859
1028
 
860
1029
  it( 'only updates a single entity currently linked with the block', async () => {
@@ -887,12 +1056,16 @@ describe( 'Navigation', () => {
887
1056
  await publishButton.click();
888
1057
 
889
1058
  // A success notice should show up.
890
- await page.waitForSelector( '.components-snackbar' );
1059
+ await page.waitForXPath(
1060
+ `//*[contains(@class, 'components-snackbar__content')][ text()="Post published." ]`
1061
+ );
891
1062
 
892
1063
  // Now try inserting another Link block via the quick inserter.
893
- await page.click( 'nav[aria-label="Block: Navigation"]' );
1064
+ // await page.click( 'nav[aria-label="Block: Navigation"]' );
1065
+ await forceSelectNavigationBlock();
894
1066
 
895
1067
  await resetNavBlockToInitialState();
1068
+
896
1069
  const startEmptyButton2 = await page.waitForXPath(
897
1070
  START_EMPTY_XPATH
898
1071
  );
@@ -910,6 +1083,35 @@ describe( 'Navigation', () => {
910
1083
  } );
911
1084
  } );
912
1085
 
1086
+ it( 'applies accessible label to block element', async () => {
1087
+ await createNewPost();
1088
+ await insertBlock( 'Navigation' );
1089
+ const startEmptyButton = await page.waitForXPath( START_EMPTY_XPATH );
1090
+ await startEmptyButton.click();
1091
+
1092
+ const appender = await page.waitForSelector(
1093
+ '.wp-block-navigation .block-list-appender'
1094
+ );
1095
+ await appender.click();
1096
+
1097
+ // Add a link to the Link block.
1098
+ await updateActiveNavigationLink( {
1099
+ url: 'https://wordpress.org',
1100
+ label: 'WP',
1101
+ type: 'url',
1102
+ } );
1103
+
1104
+ const previewPage = await openPreviewPage();
1105
+ await previewPage.bringToFront();
1106
+ await previewPage.waitForNetworkIdle();
1107
+
1108
+ const isAccessibleLabelPresent = await previewPage.$(
1109
+ 'nav[aria-label="Navigation"]'
1110
+ );
1111
+
1112
+ expect( isAccessibleLabelPresent ).toBeTruthy();
1113
+ } );
1114
+
913
1115
  it( 'does not load the frontend script if no navigation blocks are present', async () => {
914
1116
  await createNewPost();
915
1117
  await insertBlock( 'Paragraph' );
@@ -1083,19 +1285,10 @@ describe( 'Navigation', () => {
1083
1285
 
1084
1286
  await createNewPost();
1085
1287
 
1288
+ // At this point the block will automatically pick the first Navigation Menu
1289
+ // which will be the one created by the Admin User.
1086
1290
  await insertBlock( 'Navigation' );
1087
1291
 
1088
- // Select the Navigation post created by the Admin earlier
1089
- // in the test.
1090
- const navigationPostCreatedByAdminName = 'Navigation';
1091
-
1092
- const dropdown = await page.waitForXPath( SELECT_MENU_XPATH );
1093
- await dropdown.click();
1094
- const theOption = await page.waitForXPath(
1095
- `//*[contains(@class, 'components-menu-item__item')][ text()="${ navigationPostCreatedByAdminName }" ]`
1096
- );
1097
- await theOption.click();
1098
-
1099
1292
  // Make sure the snackbar error shows up.
1100
1293
  await page.waitForXPath(
1101
1294
  `//*[contains(@class, 'components-snackbar__content')][ text()="You do not have permission to edit this Menu. Any changes made will not be saved." ]`
@@ -1132,4 +1325,109 @@ describe( 'Navigation', () => {
1132
1325
  expect( console ).toHaveErrored();
1133
1326
  } );
1134
1327
  } );
1328
+
1329
+ describe( 'Initial block insertion state', () => {
1330
+ async function createNavigationMenu( menu = {} ) {
1331
+ return rest( {
1332
+ method: 'POST',
1333
+ path: '/wp/v2/navigation',
1334
+ data: {
1335
+ status: 'publish',
1336
+ ...menu,
1337
+ },
1338
+ } );
1339
+ }
1340
+
1341
+ afterEach( async () => {
1342
+ const navMenusEndpoint = '/wp/v2/navigation';
1343
+ const allNavMenus = await rest( { path: navMenusEndpoint } );
1344
+
1345
+ if ( ! allNavMenus?.length ) {
1346
+ return;
1347
+ }
1348
+
1349
+ return batch(
1350
+ allNavMenus.map( ( menu ) => ( {
1351
+ method: 'DELETE',
1352
+ path: `${ navMenusEndpoint }/${ menu.id }?force=true`,
1353
+ } ) )
1354
+ );
1355
+ } );
1356
+
1357
+ it( 'automatically uses the first Navigation Menu if only one is available', async () => {
1358
+ await createNavigationMenu( {
1359
+ title: 'Example Navigation',
1360
+ content:
1361
+ '<!-- wp:navigation-link {"label":"WordPress","type":"custom","url":"http://www.wordpress.org/","kind":"custom","isTopLevelLink":true} /-->',
1362
+ } );
1363
+
1364
+ await createNewPost();
1365
+
1366
+ await insertBlock( 'Navigation' );
1367
+
1368
+ await waitForBlock( 'Navigation' );
1369
+
1370
+ const innerLinkBlock = await waitForBlock( 'Custom Link' );
1371
+
1372
+ const linkText = await innerLinkBlock.$eval(
1373
+ '[aria-label="Navigation link text"]',
1374
+ ( element ) => {
1375
+ return element.innerText;
1376
+ }
1377
+ );
1378
+
1379
+ expect( linkText ).toBe( 'WordPress' );
1380
+ } );
1381
+
1382
+ it( 'does not automatically use first Navigation Menu if more than one exists', async () => {
1383
+ await createNavigationMenu( {
1384
+ title: 'Example Navigation',
1385
+ content:
1386
+ '<!-- wp:navigation-link {"label":"WordPress","type":"custom","url":"http://www.wordpress.org/","kind":"custom","isTopLevelLink":true} /-->',
1387
+ } );
1388
+
1389
+ await createNavigationMenu( {
1390
+ title: 'Second Example Navigation',
1391
+ content:
1392
+ '<!-- wp:navigation-link {"label":"WordPress","type":"custom","url":"http://www.wordpress.org/","kind":"custom","isTopLevelLink":true} /-->',
1393
+ } );
1394
+
1395
+ await createNewPost();
1396
+
1397
+ await insertBlock( 'Navigation' );
1398
+
1399
+ await waitForBlock( 'Navigation' );
1400
+
1401
+ await page.waitForXPath( START_EMPTY_XPATH );
1402
+ } );
1403
+
1404
+ it( 'allows users to manually create new empty menu when block has automatically selected the first available Navigation Menu', async () => {
1405
+ await createNavigationMenu( {
1406
+ title: 'Example Navigation',
1407
+ content:
1408
+ '<!-- wp:navigation-link {"label":"WordPress","type":"custom","url":"http://www.wordpress.org/","kind":"custom","isTopLevelLink":true} /-->',
1409
+ } );
1410
+
1411
+ await createNewPost();
1412
+
1413
+ await insertBlock( 'Navigation' );
1414
+
1415
+ await waitForBlock( 'Navigation' );
1416
+
1417
+ await waitForBlock( 'Custom Link' );
1418
+
1419
+ // Reset the nav block to create a new entity.
1420
+ await resetNavBlockToInitialState();
1421
+
1422
+ const startEmptyButton = await page.waitForXPath(
1423
+ START_EMPTY_XPATH
1424
+ );
1425
+ await startEmptyButton.click();
1426
+
1427
+ // Wait for Navigation creation of empty Navigation to complete.
1428
+ await page.waitForXPath(
1429
+ '//*[contains(@class, "components-snackbar")]/*[text()="Navigation Menu successfully created."]'
1430
+ );
1431
+ } );
1432
+ } );
1135
1433
  } );
@@ -33,9 +33,14 @@ describe( 'Query block', () => {
33
33
  describe( 'Query block insertion', () => {
34
34
  it( 'Carousel', async () => {
35
35
  await insertBlock( 'Query' );
36
+ // Wait for the choose pattern button
37
+ const choosePatternButton = await page.waitForSelector(
38
+ 'div[data-type="core/query"] button.is-primary'
39
+ );
40
+ await choosePatternButton.click();
36
41
  // Wait for pattern blocks to be loaded.
37
42
  await page.waitForSelector(
38
- '.block-editor-block-pattern-setup__container .wp-block-post-title'
43
+ '.block-editor-block-pattern-setup__container iframe[title="Editor canvas"]'
39
44
  );
40
45
  /**
41
46
  * Ensure that carousel is working by checking slider css classes
@@ -70,6 +75,11 @@ describe( 'Query block', () => {
70
75
  } );
71
76
  it( 'Grid view', async () => {
72
77
  await insertBlock( 'Query' );
78
+ // Wait for the choose pattern button
79
+ const choosePatternButton = await page.waitForSelector(
80
+ 'div[data-type="core/query"] button.is-primary'
81
+ );
82
+ await choosePatternButton.click();
73
83
  // Wait for patterns setup to be loaded.
74
84
  await page.waitForSelector(
75
85
  '.block-editor-block-pattern-setup__display-controls'
@@ -80,8 +90,8 @@ describe( 'Query block', () => {
80
90
  );
81
91
  await gridViewButton.click();
82
92
  // Wait for patterns to be loaded and click the wanted pattern.
83
- const gridPattern = await page.waitForXPath(
84
- '//div[@class="block-editor-block-pattern-setup-list__item-title" and contains(text(), "Query Test 2")]'
93
+ const gridPattern = await page.waitForSelector(
94
+ '.block-editor-block-pattern-setup-list__list-item[aria-label="Query Test 2"]'
85
95
  );
86
96
  await gridPattern.click();
87
97
  // Wait for pattern setup to go away.