@wordpress/e2e-tests 3.0.7 → 3.0.8

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/e2e-tests",
3
- "version": "3.0.7",
3
+ "version": "3.0.8",
4
4
  "description": "End-To-End (E2E) tests for WordPress.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -23,10 +23,10 @@
23
23
  "node": ">=12"
24
24
  },
25
25
  "dependencies": {
26
- "@wordpress/e2e-test-utils": "^6.0.1",
26
+ "@wordpress/e2e-test-utils": "^6.0.2",
27
27
  "@wordpress/jest-console": "^5.0.1",
28
28
  "@wordpress/jest-puppeteer-axe": "^4.0.1",
29
- "@wordpress/scripts": "^22.0.0",
29
+ "@wordpress/scripts": "^22.0.1",
30
30
  "@wordpress/url": "^3.4.1",
31
31
  "chalk": "^4.0.0",
32
32
  "expect-puppeteer": "^4.4.0",
@@ -44,5 +44,5 @@
44
44
  "publishConfig": {
45
45
  "access": "public"
46
46
  },
47
- "gitHead": "f73c50580cc209814ec1a2ab8c85b69bd4220d3f"
47
+ "gitHead": "4566ac290359553d04de4eb574545309343f790b"
48
48
  }
@@ -2,25 +2,25 @@
2
2
 
3
3
  exports[`Heading can be created by prefixing existing content with number signs and a space 1`] = `
4
4
  "<!-- wp:heading {\\"level\\":4} -->
5
- <h4 id=\\"4\\">4</h4>
5
+ <h4>4</h4>
6
6
  <!-- /wp:heading -->"
7
7
  `;
8
8
 
9
9
  exports[`Heading can be created by prefixing number sign and a space 1`] = `
10
10
  "<!-- wp:heading {\\"level\\":3} -->
11
- <h3 id=\\"3\\">3</h3>
11
+ <h3>3</h3>
12
12
  <!-- /wp:heading -->"
13
13
  `;
14
14
 
15
15
  exports[`Heading should correctly apply custom colors 1`] = `
16
16
  "<!-- wp:heading {\\"level\\":3,\\"style\\":{\\"color\\":{\\"text\\":\\"#0782f6\\"}}} -->
17
- <h3 class=\\"has-text-color\\" id=\\"heading\\" style=\\"color:#0782f6\\">Heading</h3>
17
+ <h3 class=\\"has-text-color\\" style=\\"color:#0782f6\\">Heading</h3>
18
18
  <!-- /wp:heading -->"
19
19
  `;
20
20
 
21
21
  exports[`Heading should correctly apply named colors 1`] = `
22
22
  "<!-- wp:heading {\\"textColor\\":\\"luminous-vivid-orange\\"} -->
23
- <h2 class=\\"has-luminous-vivid-orange-color has-text-color\\" id=\\"heading\\">Heading</h2>
23
+ <h2 class=\\"has-luminous-vivid-orange-color has-text-color\\">Heading</h2>
24
24
  <!-- /wp:heading -->"
25
25
  `;
26
26
 
@@ -30,13 +30,13 @@ exports[`Heading should create a paragraph block above when pressing enter at th
30
30
  <!-- /wp:paragraph -->
31
31
 
32
32
  <!-- wp:heading -->
33
- <h2 id=\\"a\\">a</h2>
33
+ <h2>a</h2>
34
34
  <!-- /wp:heading -->"
35
35
  `;
36
36
 
37
37
  exports[`Heading should create a paragraph block below when pressing enter at the end 1`] = `
38
38
  "<!-- wp:heading -->
39
- <h2 id=\\"a\\">a</h2>
39
+ <h2>a</h2>
40
40
  <!-- /wp:heading -->
41
41
 
42
42
  <!-- wp:paragraph -->
@@ -46,12 +46,12 @@ exports[`Heading should create a paragraph block below when pressing enter at th
46
46
 
47
47
  exports[`Heading should not work with the list input rule 1`] = `
48
48
  "<!-- wp:heading -->
49
- <h2 id=\\"1-h\\">1. H</h2>
49
+ <h2>1. H</h2>
50
50
  <!-- /wp:heading -->"
51
51
  `;
52
52
 
53
53
  exports[`Heading should work with the format input rules 1`] = `
54
54
  "<!-- wp:heading -->
55
- <h2 id=\\"code\\"><code>code</code></h2>
55
+ <h2><code>code</code></h2>
56
56
  <!-- /wp:heading -->"
57
57
  `;
@@ -40,7 +40,7 @@ exports[`Quote can be converted to paragraphs and renders only one paragraph for
40
40
 
41
41
  exports[`Quote can be created by converting a heading 1`] = `
42
42
  "<!-- wp:quote -->
43
- <blockquote class=\\"wp-block-quote\\" id=\\"test\\"><p>test</p></blockquote>
43
+ <blockquote class=\\"wp-block-quote\\"><p>test</p></blockquote>
44
44
  <!-- /wp:quote -->"
45
45
  `;
46
46
 
@@ -144,7 +144,7 @@ exports[`Quote can be split in the middle and merged back 4`] = `
144
144
 
145
145
  exports[`Quote is transformed to a heading and a quote if the quote contains a citation 1`] = `
146
146
  "<!-- wp:heading -->
147
- <h2 id=\\"one\\">one</h2>
147
+ <h2>one</h2>
148
148
  <!-- /wp:heading -->
149
149
 
150
150
  <!-- wp:quote -->
@@ -154,7 +154,7 @@ exports[`Quote is transformed to a heading and a quote if the quote contains a c
154
154
 
155
155
  exports[`Quote is transformed to a heading and a quote if the quote contains multiple paragraphs 1`] = `
156
156
  "<!-- wp:heading -->
157
- <h2 id=\\"one\\">one</h2>
157
+ <h2>one</h2>
158
158
  <!-- /wp:heading -->
159
159
 
160
160
  <!-- wp:quote -->
@@ -164,7 +164,7 @@ exports[`Quote is transformed to a heading and a quote if the quote contains mul
164
164
 
165
165
  exports[`Quote is transformed to a heading if the quote just contains one paragraph 1`] = `
166
166
  "<!-- wp:heading -->
167
- <h2 id=\\"one\\">one</h2>
167
+ <h2>one</h2>
168
168
  <!-- /wp:heading -->"
169
169
  `;
170
170
 
@@ -176,7 +176,7 @@ exports[`Quote is transformed to an empty heading if the quote is empty 1`] = `
176
176
 
177
177
  exports[`Quote the resuling quote after transforming to a heading can be transformed again 1`] = `
178
178
  "<!-- wp:heading -->
179
- <h2 id=\\"one\\">one</h2>
179
+ <h2>one</h2>
180
180
  <!-- /wp:heading -->
181
181
 
182
182
  <!-- wp:quote -->
@@ -186,11 +186,11 @@ exports[`Quote the resuling quote after transforming to a heading can be transfo
186
186
 
187
187
  exports[`Quote the resuling quote after transforming to a heading can be transformed again 2`] = `
188
188
  "<!-- wp:heading -->
189
- <h2 id=\\"one\\">one</h2>
189
+ <h2>one</h2>
190
190
  <!-- /wp:heading -->
191
191
 
192
192
  <!-- wp:heading -->
193
- <h2 id=\\"two\\">two</h2>
193
+ <h2>two</h2>
194
194
  <!-- /wp:heading -->
195
195
 
196
196
  <!-- wp:quote -->
@@ -200,14 +200,14 @@ exports[`Quote the resuling quote after transforming to a heading can be transfo
200
200
 
201
201
  exports[`Quote the resuling quote after transforming to a heading can be transformed again 3`] = `
202
202
  "<!-- wp:heading -->
203
- <h2 id=\\"one\\">one</h2>
203
+ <h2>one</h2>
204
204
  <!-- /wp:heading -->
205
205
 
206
206
  <!-- wp:heading -->
207
- <h2 id=\\"two\\">two</h2>
207
+ <h2>two</h2>
208
208
  <!-- /wp:heading -->
209
209
 
210
210
  <!-- wp:heading -->
211
- <h2 id=\\"cite\\">cite</h2>
211
+ <h2>cite</h2>
212
212
  <!-- /wp:heading -->"
213
213
  `;
@@ -103,9 +103,10 @@ describe( 'Image', () => {
103
103
  `<!-- wp:image {"id":\\d+,"sizeSlug":"full","linkDestination":"none"} -->\\s*<figure class="wp-block-image size-full"><img src="[^"]+\\/${ filename2 }\\.png" alt="" class="wp-image-\\d+"/></figure>\\s*<!-- \\/wp:image -->`
104
104
  );
105
105
  expect( await getEditedPostContent() ).toMatch( regex3 );
106
- // For some reason just clicking the block wrapper causes figcaption to get focus
107
- // in puppeteer but not in live browser, so clicking on the image wrapper div here instead.
108
- await page.click( '.wp-block-image > div' );
106
+ // Focus outside the block to avoid the image caption being selected
107
+ // It can happen on CI specially.
108
+ await page.click( '.wp-block-post-title' );
109
+ await page.click( '.wp-block-image img' );
109
110
  await page.keyboard.press( 'Backspace' );
110
111
 
111
112
  expect( await getEditedPostContent() ).toBe( '' );
@@ -26,6 +26,7 @@ import {
26
26
  loginUser,
27
27
  deleteUser,
28
28
  switchUserToAdmin,
29
+ clickBlockToolbarButton,
29
30
  } from '@wordpress/e2e-test-utils';
30
31
  import { addQueryArgs } from '@wordpress/url';
31
32
 
@@ -119,6 +120,25 @@ async function selectClassicMenu( optionText ) {
119
120
  `//*[contains(@class, 'components-menu-item__item')][ text()="${ optionText }" ]`
120
121
  );
121
122
  await theOption.click();
123
+
124
+ await page.waitForResponse(
125
+ ( response ) =>
126
+ response.url().includes( 'menu-items' ) && response.status() === 200
127
+ );
128
+ }
129
+
130
+ async function populateNavWithOneItem() {
131
+ // Add a Link block first.
132
+ const appender = await page.waitForSelector(
133
+ '.wp-block-navigation .block-list-appender'
134
+ );
135
+ await appender.click();
136
+ // Add a link to the Link block.
137
+ await updateActiveNavigationLink( {
138
+ url: 'https://wordpress.org',
139
+ label: 'WP',
140
+ type: 'url',
141
+ } );
122
142
  }
123
143
 
124
144
  const PLACEHOLDER_ACTIONS_CLASS = 'wp-block-navigation-placeholder__actions';
@@ -194,6 +214,13 @@ async function getNavigationMenuRawContent() {
194
214
  return stripPageIds( response.content.raw );
195
215
  }
196
216
 
217
+ async function waitForBlock( blockName ) {
218
+ const blockSelector = `[aria-label="Editor content"][role="region"] [aria-label="Block: ${ blockName }"]`;
219
+
220
+ // Wait for a Submenu block before making assertion.
221
+ return page.waitForSelector( blockSelector );
222
+ }
223
+
197
224
  // Disable reason - these tests are to be re-written.
198
225
  // eslint-disable-next-line jest/no-disabled-tests
199
226
  describe( 'Navigation', () => {
@@ -575,20 +602,6 @@ describe( 'Navigation', () => {
575
602
  const NAV_ENTITY_SELECTOR =
576
603
  '//div[@class="entities-saved-states__panel"]//label//strong[contains(text(), "Navigation")]';
577
604
 
578
- async function populateNavWithOneItem() {
579
- // Add a Link block first.
580
- const appender = await page.waitForSelector(
581
- '.wp-block-navigation .block-list-appender'
582
- );
583
- await appender.click();
584
- // Add a link to the Link block.
585
- await updateActiveNavigationLink( {
586
- url: 'https://wordpress.org',
587
- label: 'WP',
588
- type: 'url',
589
- } );
590
- }
591
-
592
605
  async function resetNavBlockToInitialState() {
593
606
  const selectMenuDropdown = await page.waitForSelector(
594
607
  '[aria-label="Select Menu"]'
@@ -731,6 +744,113 @@ describe( 'Navigation', () => {
731
744
  expect( tagCount ).toBe( 1 );
732
745
  } );
733
746
 
747
+ describe( 'Submenus', () => {
748
+ it( 'shows button which converts submenu to link when submenu is not-populated (empty)', async () => {
749
+ const navSubmenuSelector = `[aria-label="Editor content"][role="region"] [aria-label="Block: Submenu"]`;
750
+
751
+ await createNewPost();
752
+ await insertBlock( 'Navigation' );
753
+
754
+ const startEmptyButton = await page.waitForXPath(
755
+ START_EMPTY_XPATH
756
+ );
757
+
758
+ await startEmptyButton.click();
759
+
760
+ await populateNavWithOneItem();
761
+
762
+ await clickBlockToolbarButton( 'Add submenu' );
763
+
764
+ await waitForBlock( 'Submenu' );
765
+
766
+ // Revert the Submenu back to a Navigation Link block.
767
+ await clickBlockToolbarButton( 'Convert to Link' );
768
+
769
+ // Check the Submenu block is no longer present.
770
+ const submenuBlock = await page.$( navSubmenuSelector );
771
+
772
+ expect( submenuBlock ).toBeFalsy();
773
+ } );
774
+
775
+ it( 'shows button to convert submenu to link in disabled state when submenu is populated', async () => {
776
+ await createNewPost();
777
+ await insertBlock( 'Navigation' );
778
+
779
+ const startEmptyButton = await page.waitForXPath(
780
+ START_EMPTY_XPATH
781
+ );
782
+
783
+ await startEmptyButton.click();
784
+
785
+ await populateNavWithOneItem();
786
+
787
+ await clickBlockToolbarButton( 'Add submenu' );
788
+
789
+ await waitForBlock( 'Submenu' );
790
+
791
+ // Add a Link block first.
792
+ const appender = await page.waitForSelector(
793
+ '[aria-label="Block: Submenu"] [aria-label="Add block"]'
794
+ );
795
+
796
+ await appender.click();
797
+
798
+ await updateActiveNavigationLink( {
799
+ url: 'https://make.wordpress.org/core/',
800
+ label: 'Submenu item #1',
801
+ type: 'url',
802
+ } );
803
+
804
+ await clickBlockToolbarButton( 'Select Submenu' );
805
+
806
+ // Check button exists but is in disabled state.
807
+ const disabledConvertToLinkButton = await page.$(
808
+ '[aria-label="Block tools"] [aria-label="Convert to Link"][disabled]'
809
+ );
810
+
811
+ expect( disabledConvertToLinkButton ).toBeTruthy();
812
+ } );
813
+
814
+ it( 'shows button to convert submenu to link when submenu is populated with a single incomplete link item', async () => {
815
+ // For context on why this test is required please see:
816
+ // https://github.com/WordPress/gutenberg/pull/38203#issuecomment-1027672948.
817
+
818
+ await createNewPost();
819
+ await insertBlock( 'Navigation' );
820
+
821
+ const startEmptyButton = await page.waitForXPath(
822
+ START_EMPTY_XPATH
823
+ );
824
+
825
+ await startEmptyButton.click();
826
+
827
+ await populateNavWithOneItem();
828
+
829
+ await clickBlockToolbarButton( 'Add submenu' );
830
+
831
+ await waitForBlock( 'Submenu' );
832
+
833
+ // Add a Link block first.
834
+ const appender = await page.waitForSelector(
835
+ '[aria-label="Block: Submenu"] [aria-label="Add block"]'
836
+ );
837
+
838
+ await appender.click();
839
+
840
+ // Here we intentionally do not populate the inserted Navigation Link block.
841
+ // Rather we immediaely click away leaving the link in a state where it has
842
+ // no URL of label and can be considered unpopulated.
843
+ await clickBlockToolbarButton( 'Select Submenu' );
844
+
845
+ // Check for non-disabled Convert to Link button
846
+ const convertToLinkButton = await page.$(
847
+ '[aria-label="Block tools"] [aria-label="Convert to Link"]:not([disabled])'
848
+ );
849
+
850
+ expect( convertToLinkButton ).toBeTruthy();
851
+ } );
852
+ } );
853
+
734
854
  describe( 'Permission based restrictions', () => {
735
855
  afterEach( async () => {
736
856
  await switchUserToAdmin();
@@ -3,7 +3,7 @@
3
3
  exports[`Block Grouping Group creation creates a group from multiple blocks of different types via block transforms 1`] = `
4
4
  "<!-- wp:group -->
5
5
  <div class=\\"wp-block-group\\"><!-- wp:heading -->
6
- <h2 id=\\"group-heading\\">Group Heading</h2>
6
+ <h2>Group Heading</h2>
7
7
  <!-- /wp:heading -->
8
8
 
9
9
  <!-- wp:image -->
@@ -51,7 +51,7 @@ exports[`Block Grouping Group creation creates a group from multiple blocks of t
51
51
  exports[`Block Grouping Group creation groups and ungroups multiple blocks of different types via options toolbar 1`] = `
52
52
  "<!-- wp:group -->
53
53
  <div class=\\"wp-block-group\\"><!-- wp:heading -->
54
- <h2 id=\\"group-heading\\">Group Heading</h2>
54
+ <h2>Group Heading</h2>
55
55
  <!-- /wp:heading -->
56
56
 
57
57
  <!-- wp:image -->
@@ -66,7 +66,7 @@ exports[`Block Grouping Group creation groups and ungroups multiple blocks of di
66
66
 
67
67
  exports[`Block Grouping Group creation groups and ungroups multiple blocks of different types via options toolbar 2`] = `
68
68
  "<!-- wp:heading -->
69
- <h2 id=\\"group-heading\\">Group Heading</h2>
69
+ <h2>Group Heading</h2>
70
70
  <!-- /wp:heading -->
71
71
 
72
72
  <!-- wp:image -->
@@ -81,7 +81,7 @@ exports[`Block Grouping Group creation groups and ungroups multiple blocks of di
81
81
  exports[`Block Grouping Preserving selected blocks attributes preserves width alignment settings of selected blocks 1`] = `
82
82
  "<!-- wp:group {\\"align\\":\\"full\\"} -->
83
83
  <div class=\\"wp-block-group alignfull\\"><!-- wp:heading -->
84
- <h2 id=\\"group-heading\\">Group Heading</h2>
84
+ <h2>Group Heading</h2>
85
85
  <!-- /wp:heading -->
86
86
 
87
87
  <!-- wp:image {\\"align\\":\\"full\\"} -->
@@ -71,7 +71,7 @@ exports[`Inserting blocks inserts a block in proper place after having clicked \
71
71
  <!-- /wp:paragraph -->
72
72
 
73
73
  <!-- wp:heading -->
74
- <h2 id=\\"heading\\">Heading</h2>
74
+ <h2>Heading</h2>
75
75
  <!-- /wp:heading -->
76
76
 
77
77
  <!-- wp:paragraph -->
@@ -93,7 +93,7 @@ exports[`Inserting blocks inserts a block in proper place after having clicked \
93
93
  <!-- /wp:cover -->
94
94
 
95
95
  <!-- wp:heading -->
96
- <h2 id=\\"heading\\">Heading</h2>
96
+ <h2>Heading</h2>
97
97
  <!-- /wp:heading -->
98
98
 
99
99
  <!-- wp:paragraph -->
@@ -14,15 +14,15 @@ exports[`Keep styles on block transforms Should keep the font size during a tran
14
14
 
15
15
  exports[`Keep styles on block transforms Should keep the font size during a transform from multiple blocks into multiple blocks 1`] = `
16
16
  "<!-- wp:heading {\\"fontSize\\":\\"large\\"} -->
17
- <h2 class=\\"has-large-font-size\\" id=\\"line-1-to-be-made-large\\">Line 1 to be made large</h2>
17
+ <h2 class=\\"has-large-font-size\\">Line 1 to be made large</h2>
18
18
  <!-- /wp:heading -->
19
19
 
20
20
  <!-- wp:heading {\\"fontSize\\":\\"large\\"} -->
21
- <h2 class=\\"has-large-font-size\\" id=\\"line-2-to-be-made-large\\">Line 2 to be made large</h2>
21
+ <h2 class=\\"has-large-font-size\\">Line 2 to be made large</h2>
22
22
  <!-- /wp:heading -->
23
23
 
24
24
  <!-- wp:heading {\\"fontSize\\":\\"large\\"} -->
25
- <h2 class=\\"has-large-font-size\\" id=\\"line-3-to-be-made-large\\">Line 3 to be made large</h2>
25
+ <h2 class=\\"has-large-font-size\\">Line 3 to be made large</h2>
26
26
  <!-- /wp:heading -->"
27
27
  `;
28
28
 
@@ -5,7 +5,9 @@ import {
5
5
  createNewPost,
6
6
  insertBlock,
7
7
  getEditedPostContent,
8
+ openListView,
8
9
  pressKeyWithModifier,
10
+ pressKeyTimes,
9
11
  } from '@wordpress/e2e-test-utils';
10
12
 
11
13
  async function dragAndDrop( draggableElement, targetElement, offsetY ) {
@@ -19,6 +21,10 @@ async function dragAndDrop( draggableElement, targetElement, offsetY ) {
19
21
  return await page.mouse.dragAndDrop( draggablePoint, targetPoint );
20
22
  }
21
23
 
24
+ async function getBlockListLeafNodes() {
25
+ return await page.$$( '.block-editor-list-view-leaf' );
26
+ }
27
+
22
28
  describe( 'List view', () => {
23
29
  beforeAll( async () => {
24
30
  await page.setDragInterception( true );
@@ -54,4 +60,93 @@ describe( 'List view', () => {
54
60
 
55
61
  expect( await getEditedPostContent() ).toMatchSnapshot();
56
62
  } );
63
+
64
+ // Check for regressions of https://github.com/WordPress/gutenberg/issues/38763.
65
+ it( 'shows the correct amount of blocks after a block is removed in the canvas', async () => {
66
+ // Insert some blocks of different types.
67
+ await insertBlock( 'Image' );
68
+ await insertBlock( 'Heading' );
69
+ await insertBlock( 'Paragraph' );
70
+
71
+ // Open list view.
72
+ await pressKeyWithModifier( 'access', 'o' );
73
+
74
+ // The last inserted paragraph block should be selected in List View.
75
+ await page.waitForXPath(
76
+ '//a[contains(., "Paragraph(selected block)")]'
77
+ );
78
+
79
+ // Go to the image block in list view.
80
+ await pressKeyTimes( 'ArrowUp', 2 );
81
+ const listViewImageBlock = await page.waitForXPath(
82
+ '//a[contains(., "Image")]'
83
+ );
84
+ expect( listViewImageBlock ).toHaveFocus();
85
+
86
+ // Select the image block in the canvas.
87
+ await page.keyboard.press( 'Enter' );
88
+
89
+ const canvasImageBlock = await page.waitForSelector(
90
+ 'figure[aria-label="Block: Image"]'
91
+ );
92
+ expect( canvasImageBlock ).toHaveFocus();
93
+
94
+ // Delete the image block in the canvas.
95
+ await page.keyboard.press( 'Backspace' );
96
+
97
+ // List view should have two rows.
98
+ const listViewRows = await page.$$( 'tr.block-editor-list-view-leaf' );
99
+ expect( listViewRows ).toHaveLength( 2 );
100
+
101
+ // The console didn't throw an error as reported in
102
+ // https://github.com/WordPress/gutenberg/issues/38763.
103
+ expect( console ).not.toHaveErrored();
104
+ } );
105
+
106
+ it( 'should expand nested list items', async () => {
107
+ // Insert some blocks of different types.
108
+ await insertBlock( 'Cover' );
109
+
110
+ // Click first color option from the block placeholder's color picker to make the inner blocks appear.
111
+ const colorPickerButton = await page.waitForSelector(
112
+ '.wp-block-cover__placeholder-background-options .components-circular-option-picker__option-wrapper:first-child button'
113
+ );
114
+ await colorPickerButton.click();
115
+
116
+ // Open list view.
117
+ await openListView();
118
+
119
+ // Things start off expanded.
120
+ expect( await getBlockListLeafNodes() ).toHaveLength( 2 );
121
+
122
+ const blockListExpanders = await page.$$(
123
+ '.block-editor-list-view__expander'
124
+ );
125
+
126
+ // Collapse the first block
127
+ await blockListExpanders[ 0 ].click();
128
+
129
+ // Check that we're collapsed
130
+ expect( await getBlockListLeafNodes() ).toHaveLength( 1 );
131
+
132
+ // Focus the cover block. The paragraph is not focussed by default.
133
+ const coverBlock = await page.waitForSelector( '.wp-block-cover' );
134
+
135
+ await coverBlock.focus();
136
+
137
+ // Click the cover title placeholder.
138
+ const coverTitle = await page.waitForSelector(
139
+ '.wp-block-cover .wp-block-paragraph'
140
+ );
141
+
142
+ await coverTitle.click();
143
+
144
+ // The block list should contain two leafs and the second should be selected (and be a paragraph).
145
+ const selectedElementText = await page.$eval(
146
+ '.block-editor-list-view-leaf.is-selected .block-editor-list-view-block-contents',
147
+ ( element ) => element.innerText
148
+ );
149
+
150
+ expect( selectedElementText ).toContain( 'Paragraph' );
151
+ } );
57
152
  } );
@@ -10,6 +10,7 @@ import {
10
10
  clickBlockToolbarButton,
11
11
  clickButton,
12
12
  clickMenuItem,
13
+ openListView,
13
14
  saveDraft,
14
15
  transformBlockTo,
15
16
  } from '@wordpress/e2e-test-utils';
@@ -747,4 +748,87 @@ describe( 'Multi-block selection', () => {
747
748
  } );
748
749
  expect( selectedText ).toEqual( 'Post title' );
749
750
  } );
751
+
752
+ it( 'should multi-select in the ListView component with shift + click', async () => {
753
+ // Create four blocks.
754
+ await clickBlockAppender();
755
+ await page.keyboard.type( '1' );
756
+ await page.keyboard.press( 'Enter' );
757
+ await page.keyboard.type( '2' );
758
+ await page.keyboard.press( 'Enter' );
759
+ await page.keyboard.type( '3' );
760
+ await page.keyboard.press( 'Enter' );
761
+ await page.keyboard.type( '4' );
762
+
763
+ // Open up the list view, and get a reference to each of the list items.
764
+ await openListView();
765
+ const navButtons = await page.$$(
766
+ '.block-editor-list-view-block-select-button'
767
+ );
768
+
769
+ // Clicking on the second list item should result in the second block being selected.
770
+ await navButtons[ 1 ].click();
771
+ expect( await getSelectedFlatIndices() ).toEqual( 2 );
772
+
773
+ // Shift clicking the fourth list item should result in blocks 2 through 4 being selected.
774
+ await page.keyboard.down( 'Shift' );
775
+ await navButtons[ 3 ].click();
776
+ expect( await getSelectedFlatIndices() ).toEqual( [ 2, 3, 4 ] );
777
+
778
+ // With the shift key still held down, clicking the first block should result in
779
+ // the first two blocks being selected.
780
+ await navButtons[ 0 ].click();
781
+ expect( await getSelectedFlatIndices() ).toEqual( [ 1, 2 ] );
782
+
783
+ // With the shift key up, clicking the fourth block should result in only that block
784
+ // being selected.
785
+ await page.keyboard.up( 'Shift' );
786
+ await navButtons[ 3 ].click();
787
+ expect( await getSelectedFlatIndices() ).toEqual( 4 );
788
+ } );
789
+
790
+ it( 'should multi-select in the ListView component with shift + up and down keys', async () => {
791
+ // Create four blocks.
792
+ await clickBlockAppender();
793
+ await page.keyboard.type( '1' );
794
+ await page.keyboard.press( 'Enter' );
795
+ await page.keyboard.type( '2' );
796
+ await page.keyboard.press( 'Enter' );
797
+ await page.keyboard.type( '3' );
798
+ await page.keyboard.press( 'Enter' );
799
+ await page.keyboard.type( '4' );
800
+
801
+ // Open up the list view. The fourth block button will be focused.
802
+ await openListView();
803
+
804
+ // Press Up twice to focus over the second block.
805
+ await pressKeyTimes( 'ArrowUp', 2 );
806
+
807
+ // Shift + press Down to select the 2nd and 3rd blocks.
808
+ await page.keyboard.down( 'Shift' );
809
+ await page.keyboard.press( 'ArrowDown' );
810
+ expect( await getSelectedFlatIndices() ).toEqual( [ 2, 3 ] );
811
+
812
+ // Press Down once more to also select the 4th block.
813
+ await page.keyboard.press( 'ArrowDown' );
814
+ expect( await getSelectedFlatIndices() ).toEqual( [ 2, 3, 4 ] );
815
+
816
+ // Press Up three times to adjust the selection to only include the first two blocks.
817
+ await pressKeyTimes( 'ArrowUp', 3 );
818
+ expect( await getSelectedFlatIndices() ).toEqual( [ 1, 2 ] );
819
+
820
+ // Raise the shift key
821
+ await page.keyboard.up( 'Shift' );
822
+
823
+ // Navigate to the bottom of the list of blocks.
824
+ await pressKeyTimes( 'ArrowDown', 3 );
825
+
826
+ // Shift + press UP to select the 3rd and 4th blocks.
827
+ // This tests that shift selecting blocks by keyboard that are not adjacent
828
+ // to an existing selection resets the selection.
829
+ await page.keyboard.down( 'Shift' );
830
+ await page.keyboard.press( 'ArrowUp' );
831
+ await page.keyboard.up( 'Shift' );
832
+ expect( await getSelectedFlatIndices() ).toEqual( [ 3, 4 ] );
833
+ } );
750
834
  } );