@wordpress/e2e-tests 2.5.17 → 3.0.0
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/CHANGELOG.md +7 -0
- package/LICENSE.md +1 -1
- package/config/flaky-tests-reporter.js +2 -1
- package/package.json +12 -11
- package/plugins/query-block.php +2 -2
- package/specs/editor/blocks/__snapshots__/heading.test.js.snap +2 -2
- package/specs/editor/blocks/__snapshots__/navigation.test.js.snap +29 -57
- package/specs/editor/blocks/__snapshots__/spacer.test.js.snap +1 -1
- package/specs/editor/blocks/classic.test.js +5 -2
- package/specs/editor/blocks/columns.test.js +1 -1
- package/specs/editor/blocks/cover.test.js +1 -1
- package/specs/editor/blocks/heading.test.js +15 -3
- package/specs/editor/blocks/image.test.js +1 -2
- package/specs/editor/blocks/navigation.test.js +311 -439
- package/specs/editor/blocks/preformatted.test.js +2 -1
- package/specs/editor/blocks/site-title.test.js +2 -31
- package/specs/editor/fixtures/menu-items-request-fixture.json +84 -0
- package/specs/editor/fixtures/menu-items-response-fixture.json +240 -144
- package/specs/editor/plugins/block-variations.test.js +1 -1
- package/specs/editor/plugins/custom-post-types.test.js +4 -3
- package/specs/editor/various/__snapshots__/block-editor-keyboard-shortcuts.test.js.snap +38 -24
- package/specs/editor/various/adding-patterns.test.js +1 -1
- package/specs/editor/various/block-editor-keyboard-shortcuts.test.js +43 -3
- package/specs/editor/various/block-grouping.test.js +2 -18
- package/specs/editor/various/block-hierarchy-navigation.test.js +3 -3
- package/specs/editor/various/change-detection.test.js +5 -0
- package/specs/editor/various/editor-modes.test.js +7 -0
- package/specs/editor/various/font-size-picker.test.js +58 -18
- package/specs/editor/various/inserting-blocks.test.js +6 -2
- package/specs/editor/various/keyboard-navigable-blocks.test.js +6 -0
- package/specs/editor/various/list-view.test.js +2 -2
- package/specs/editor/various/navigable-toolbar.test.js +2 -2
- package/specs/editor/various/post-editor-template-mode.test.js +1 -1
- package/specs/editor/various/preview.test.js +67 -2
- package/specs/editor/various/reusable-blocks.test.js +53 -31
- package/specs/editor/various/undo.test.js +21 -0
- package/specs/editor/various/writing-flow.test.js +8 -4
- package/specs/performance/site-editor.test.js +1 -1
- package/specs/site-editor/document-settings.test.js +5 -5
- package/specs/site-editor/multi-entity-editing.test.js +2 -2
- package/specs/site-editor/multi-entity-saving.test.js +53 -63
- package/specs/site-editor/settings-sidebar.test.js +4 -4
- package/specs/site-editor/site-editor-export.test.js +1 -1
- package/specs/site-editor/site-editor-inserter.test.js +1 -1
- package/specs/site-editor/template-part.test.js +95 -79
- package/specs/site-editor/template-revert.test.js +13 -9
- package/specs/widgets/customizing-widgets.test.js +7 -3
@@ -1,3 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* External dependencies
|
3
|
+
*/
|
4
|
+
import { uniqueId } from 'lodash';
|
5
|
+
|
1
6
|
/**
|
2
7
|
* WordPress dependencies
|
3
8
|
*/
|
@@ -6,83 +11,33 @@ import {
|
|
6
11
|
clickOnMoreMenuItem,
|
7
12
|
createJSONResponse,
|
8
13
|
createNewPost,
|
9
|
-
|
14
|
+
createMenu as createClassicMenu,
|
15
|
+
deleteAllMenus as deleteAllClassicMenus,
|
10
16
|
insertBlock,
|
11
17
|
setUpResponseMocking,
|
12
18
|
pressKeyWithModifier,
|
13
19
|
saveDraft,
|
14
20
|
showBlockToolbar,
|
15
21
|
openPreviewPage,
|
16
|
-
|
17
|
-
|
22
|
+
ensureSidebarOpened,
|
23
|
+
__experimentalRest as rest,
|
24
|
+
publishPost,
|
25
|
+
createUser,
|
26
|
+
loginUser,
|
27
|
+
deleteUser,
|
28
|
+
switchUserToAdmin,
|
18
29
|
} from '@wordpress/e2e-test-utils';
|
30
|
+
import { addQueryArgs } from '@wordpress/url';
|
19
31
|
|
20
32
|
/**
|
21
33
|
* Internal dependencies
|
22
34
|
*/
|
23
|
-
import menuItemsFixture from '../fixtures/menu-items-
|
24
|
-
|
25
|
-
const menusFixture = [
|
26
|
-
{
|
27
|
-
name: 'Test Menu 1',
|
28
|
-
slug: 'test-menu-1',
|
29
|
-
},
|
30
|
-
{
|
31
|
-
name: 'Test Menu 2',
|
32
|
-
slug: 'test-menu-2',
|
33
|
-
},
|
34
|
-
{
|
35
|
-
name: 'Test Menu 3',
|
36
|
-
slug: 'test-menu-3',
|
37
|
-
},
|
38
|
-
];
|
39
|
-
|
40
|
-
// Matching against variations of the same URL encoded and non-encoded
|
41
|
-
// produces the most reliable mocking.
|
42
|
-
const REST_MENUS_ROUTES = [
|
43
|
-
'/wp/v2/menus',
|
44
|
-
`rest_route=${ encodeURIComponent( '/wp/v2/menus' ) }`,
|
45
|
-
];
|
46
|
-
const REST_MENU_ITEMS_ROUTES = [
|
47
|
-
'/wp/v2/menu-items',
|
48
|
-
`rest_route=${ encodeURIComponent( '/wp/v2/menu-items' ) }`,
|
49
|
-
];
|
50
|
-
|
51
|
-
const REST_PAGES_ROUTES = [
|
52
|
-
'/wp/v2/pages',
|
53
|
-
`rest_route=${ encodeURIComponent( '/wp/v2/pages' ) }`,
|
54
|
-
];
|
35
|
+
import menuItemsFixture from '../fixtures/menu-items-request-fixture.json';
|
55
36
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
* @param {string} reqUrl the full URL to be tested for matches.
|
61
|
-
* @param {Array} routes array of strings to match against the URL.
|
62
|
-
*/
|
63
|
-
function matchUrlToRoute( reqUrl, routes ) {
|
64
|
-
return routes.some( ( route ) => reqUrl.includes( route ) );
|
65
|
-
}
|
66
|
-
|
67
|
-
async function mockPagesResponse( pages ) {
|
68
|
-
const mappedPages = pages.map( ( { title, slug }, index ) => ( {
|
69
|
-
id: index + 1,
|
70
|
-
type: 'page',
|
71
|
-
link: `https://this/is/a/test/page/${ slug }`,
|
72
|
-
title: {
|
73
|
-
rendered: title,
|
74
|
-
raw: title,
|
75
|
-
},
|
76
|
-
} ) );
|
77
|
-
|
78
|
-
await setUpResponseMocking( [
|
79
|
-
{
|
80
|
-
match: ( request ) =>
|
81
|
-
matchUrlToRoute( request.url(), REST_PAGES_ROUTES ),
|
82
|
-
onRequestMatch: createJSONResponse( mappedPages ),
|
83
|
-
},
|
84
|
-
] );
|
85
|
-
}
|
37
|
+
const POSTS_ENDPOINT = '/wp/v2/posts';
|
38
|
+
const PAGES_ENDPOINT = '/wp/v2/pages';
|
39
|
+
const DRAFT_PAGES_ENDPOINT = [ PAGES_ENDPOINT, { status: 'draft' } ];
|
40
|
+
const NAVIGATION_MENUS_ENDPOINT = '/wp/v2/navigation';
|
86
41
|
|
87
42
|
async function mockSearchResponse( items ) {
|
88
43
|
const mappedItems = items.map( ( { title, slug }, index ) => ( {
|
@@ -103,76 +58,6 @@ async function mockSearchResponse( items ) {
|
|
103
58
|
] );
|
104
59
|
}
|
105
60
|
|
106
|
-
/**
|
107
|
-
* Creates mocked REST API responses for calls to menus and menu-items
|
108
|
-
* endpoints.
|
109
|
-
* Note: this needs to be within a single call to
|
110
|
-
* `setUpResponseMocking` as you can only setup response mocking once per test run.
|
111
|
-
*
|
112
|
-
* @param {Array} menus menus to provide as mocked responses to menus entity API requests.
|
113
|
-
* @param {Array} menuItems menu items to provide as mocked responses to menu-items entity API requests.
|
114
|
-
*/
|
115
|
-
async function mockAllMenusResponses(
|
116
|
-
menus = menusFixture,
|
117
|
-
menuItems = menuItemsFixture
|
118
|
-
) {
|
119
|
-
const mappedMenus = menus.length
|
120
|
-
? menus.map( ( menu, index ) => ( {
|
121
|
-
...menu,
|
122
|
-
id: index + 1,
|
123
|
-
} ) )
|
124
|
-
: [];
|
125
|
-
|
126
|
-
await setUpResponseMocking( [
|
127
|
-
{
|
128
|
-
match: ( request ) =>
|
129
|
-
matchUrlToRoute( request.url(), REST_MENUS_ROUTES ),
|
130
|
-
onRequestMatch: createJSONResponse( mappedMenus ),
|
131
|
-
},
|
132
|
-
{
|
133
|
-
match: ( request ) =>
|
134
|
-
matchUrlToRoute( request.url(), REST_MENU_ITEMS_ROUTES ),
|
135
|
-
onRequestMatch: createJSONResponse( menuItems ),
|
136
|
-
},
|
137
|
-
] );
|
138
|
-
}
|
139
|
-
|
140
|
-
async function mockEmptyMenusAndPagesResponses() {
|
141
|
-
const emptyResponse = [];
|
142
|
-
await setUpResponseMocking( [
|
143
|
-
{
|
144
|
-
match: ( request ) =>
|
145
|
-
matchUrlToRoute( request.url(), REST_MENUS_ROUTES ),
|
146
|
-
onRequestMatch: createJSONResponse( emptyResponse ),
|
147
|
-
},
|
148
|
-
{
|
149
|
-
match: ( request ) =>
|
150
|
-
matchUrlToRoute( request.url(), REST_PAGES_ROUTES ),
|
151
|
-
onRequestMatch: createJSONResponse( emptyResponse ),
|
152
|
-
},
|
153
|
-
] );
|
154
|
-
}
|
155
|
-
|
156
|
-
async function mockCreatePageResponse( title, slug ) {
|
157
|
-
const page = {
|
158
|
-
id: 1,
|
159
|
-
title: { raw: title, rendered: title },
|
160
|
-
type: 'page',
|
161
|
-
link: `https://this/is/a/test/create/page/${ slug }`,
|
162
|
-
slug,
|
163
|
-
};
|
164
|
-
|
165
|
-
await setUpResponseMocking( [
|
166
|
-
{
|
167
|
-
match: ( request ) =>
|
168
|
-
request.url().includes( `rest_route` ) &&
|
169
|
-
request.url().includes( `pages` ) &&
|
170
|
-
request.method() === 'POST',
|
171
|
-
onRequestMatch: createJSONResponse( page ),
|
172
|
-
},
|
173
|
-
] );
|
174
|
-
}
|
175
|
-
|
176
61
|
/**
|
177
62
|
* Interacts with the LinkControl to perform a search and select a returned suggestion
|
178
63
|
*
|
@@ -225,7 +110,7 @@ async function updateActiveNavigationLink( { url, label, type } ) {
|
|
225
110
|
}
|
226
111
|
}
|
227
112
|
|
228
|
-
async function
|
113
|
+
async function selectClassicMenu( optionText ) {
|
229
114
|
const dropdown = await page.waitForXPath(
|
230
115
|
"//*[contains(@class, 'wp-block-navigation-placeholder__actions__dropdown')]"
|
231
116
|
);
|
@@ -242,154 +127,200 @@ const START_EMPTY_XPATH = `${ PLACEHOLDER_ACTIONS_XPATH }//button[text()='Start
|
|
242
127
|
const ADD_ALL_PAGES_XPATH = `${ PLACEHOLDER_ACTIONS_XPATH }//button[text()='Add all pages']`;
|
243
128
|
const SELECT_MENU_XPATH = `${ PLACEHOLDER_ACTIONS_XPATH }//button[text()='Select menu']`;
|
244
129
|
|
245
|
-
|
246
|
-
|
247
|
-
|
130
|
+
/**
|
131
|
+
* Delete all items for the given REST resources using the REST API.
|
132
|
+
*
|
133
|
+
* @param {*} endpoints The endpoints of the resources to delete.
|
134
|
+
*/
|
135
|
+
async function deleteAll( endpoints ) {
|
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
|
+
} );
|
147
|
+
|
148
|
+
for ( const item of items ) {
|
149
|
+
await rest( {
|
150
|
+
method: 'DELETE',
|
151
|
+
path: `${ path }/${ item.id }?force=true`,
|
152
|
+
} );
|
153
|
+
}
|
154
|
+
}
|
248
155
|
}
|
249
156
|
|
250
|
-
|
251
|
-
|
252
|
-
|
157
|
+
/**
|
158
|
+
* Create a set of pages using the REST API.
|
159
|
+
*
|
160
|
+
* @param {Array} pages An array of page objects.
|
161
|
+
*/
|
162
|
+
async function createPages( pages ) {
|
163
|
+
for ( const page of pages ) {
|
164
|
+
await rest( {
|
165
|
+
method: 'POST',
|
166
|
+
path: PAGES_ENDPOINT,
|
167
|
+
data: {
|
168
|
+
status: 'publish',
|
169
|
+
...page,
|
170
|
+
},
|
171
|
+
} );
|
172
|
+
}
|
253
173
|
}
|
254
174
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
175
|
+
/**
|
176
|
+
* Replace unique ids in nav block content, since these won't be consistent
|
177
|
+
* between test runs.
|
178
|
+
*
|
179
|
+
* @param {string} content HTML block content, either raw or rendered.
|
180
|
+
*
|
181
|
+
* @return {string} HTML block content with stripped ids
|
182
|
+
*/
|
183
|
+
function stripPageIds( content ) {
|
184
|
+
return content
|
185
|
+
.replace( /page_id=\d+/gm, 'page_id=[number]' )
|
186
|
+
.replace( /"id":\d+/gm, '"id":[number]' );
|
259
187
|
}
|
260
188
|
|
261
|
-
|
262
|
-
|
189
|
+
/**
|
190
|
+
* Check navigation block content by fetching the navigation menu.
|
191
|
+
*
|
192
|
+
* @return {string} Menu content.
|
193
|
+
*/
|
194
|
+
async function getNavigationMenuRawContent() {
|
195
|
+
const menuRef = await page.evaluate( () => {
|
196
|
+
const blocks = wp.data.select( 'core/block-editor' ).getBlocks();
|
197
|
+
const navigationBlock = blocks.find(
|
198
|
+
( block ) => block.name === 'core/navigation'
|
199
|
+
);
|
263
200
|
|
264
|
-
|
265
|
-
|
201
|
+
return navigationBlock.attributes.ref;
|
202
|
+
} );
|
266
203
|
|
267
|
-
|
268
|
-
'
|
269
|
-
|
204
|
+
if ( ! menuRef ) {
|
205
|
+
throw 'getNavigationMenuRawContent was unable to find a ref attribute on the first navigation block';
|
206
|
+
}
|
270
207
|
|
271
|
-
await
|
208
|
+
const response = await rest( {
|
209
|
+
method: 'GET',
|
210
|
+
path: `/wp/v2/navigation/${ menuRef }?context=edit`,
|
211
|
+
} );
|
272
212
|
|
273
|
-
|
213
|
+
return stripPageIds( response.content.raw );
|
274
214
|
}
|
275
215
|
|
276
|
-
beforeEach( async () => {
|
277
|
-
await createNewPost();
|
278
|
-
} );
|
279
|
-
|
280
|
-
afterEach( async () => {
|
281
|
-
await setUpResponseMocking( [] );
|
282
|
-
} );
|
283
|
-
|
284
216
|
// Disable reason - these tests are to be re-written.
|
285
217
|
// eslint-disable-next-line jest/no-disabled-tests
|
286
|
-
describe
|
287
|
-
|
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
|
+
|
231
|
+
beforeEach( async () => {
|
232
|
+
await deleteAll( [
|
233
|
+
POSTS_ENDPOINT,
|
234
|
+
PAGES_ENDPOINT,
|
235
|
+
DRAFT_PAGES_ENDPOINT,
|
236
|
+
NAVIGATION_MENUS_ENDPOINT,
|
237
|
+
] );
|
238
|
+
await deleteAllClassicMenus();
|
239
|
+
} );
|
240
|
+
|
241
|
+
afterEach( async () => {
|
242
|
+
await setUpResponseMocking( [] );
|
243
|
+
} );
|
244
|
+
|
245
|
+
afterAll( async () => {
|
246
|
+
await deleteAll( [
|
247
|
+
POSTS_ENDPOINT,
|
248
|
+
PAGES_ENDPOINT,
|
249
|
+
DRAFT_PAGES_ENDPOINT,
|
250
|
+
NAVIGATION_MENUS_ENDPOINT,
|
251
|
+
] );
|
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 );
|
257
|
+
} );
|
258
|
+
|
259
|
+
describe( 'placeholder', () => {
|
288
260
|
it( 'allows a navigation block to be created using existing pages', async () => {
|
289
|
-
|
290
|
-
// consistent and to test the feature more rigorously than the single default sample page.
|
291
|
-
await mockPagesResponse( [
|
292
|
-
{
|
293
|
-
title: 'Home',
|
294
|
-
slug: 'home',
|
295
|
-
},
|
261
|
+
await createPages( [
|
296
262
|
{
|
297
263
|
title: 'About',
|
298
|
-
|
264
|
+
menu_order: 0,
|
299
265
|
},
|
300
266
|
{
|
301
267
|
title: 'Contact Us',
|
302
|
-
|
268
|
+
menu_order: 1,
|
269
|
+
},
|
270
|
+
{
|
271
|
+
title: 'FAQ',
|
272
|
+
menu_order: 2,
|
303
273
|
},
|
304
274
|
] );
|
305
275
|
|
306
|
-
|
307
|
-
await insertBlock( 'Navigation' );
|
308
|
-
|
309
|
-
await createNavBlockWithAllPages();
|
310
|
-
|
311
|
-
// Snapshot should contain the mocked pages.
|
312
|
-
expect( await getEditedPostContent() ).toMatchSnapshot();
|
313
|
-
} );
|
314
|
-
|
315
|
-
it( 'does not display option to create from existing Pages if there are no Pages', async () => {
|
316
|
-
// Force no Pages or Menus to be returned by API responses.
|
317
|
-
await mockEmptyMenusAndPagesResponses();
|
276
|
+
await createNewPost();
|
318
277
|
|
319
278
|
// Add the navigation block.
|
320
279
|
await insertBlock( 'Navigation' );
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
const placeholderActionsLength = await page.$$eval(
|
325
|
-
`.${ PLACEHOLDER_ACTIONS_CLASS } button`,
|
326
|
-
( els ) => els.length
|
280
|
+
const allPagesButton = await page.waitForXPath(
|
281
|
+
ADD_ALL_PAGES_XPATH
|
327
282
|
);
|
283
|
+
await allPagesButton.click();
|
328
284
|
|
329
|
-
//
|
330
|
-
|
285
|
+
// Wait for the page list block to be present
|
286
|
+
await page.waitForSelector( 'ul[aria-label="Block: Page List"]' );
|
287
|
+
|
288
|
+
expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
|
331
289
|
} );
|
332
|
-
} );
|
333
290
|
|
334
|
-
describe( 'Creating from existing Menus', () => {
|
335
291
|
it( 'allows a navigation block to be created from existing menus', async () => {
|
336
|
-
await
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
await selectDropDownOption( 'Test Menu 2' );
|
342
|
-
|
343
|
-
// Scope element selector to the Editor's "Content" region as otherwise it picks up on
|
344
|
-
// block previews.
|
345
|
-
const navLinkSelector =
|
346
|
-
'[aria-label="Editor content"][role="region"] .wp-block-navigation-item';
|
347
|
-
|
348
|
-
await page.waitForSelector( navLinkSelector );
|
349
|
-
|
350
|
-
const navBlockItemsLength = await page.$$eval(
|
351
|
-
navLinkSelector,
|
352
|
-
( els ) => els.length
|
292
|
+
await createClassicMenu( { name: 'Test Menu 1' } );
|
293
|
+
await createClassicMenu(
|
294
|
+
{ name: 'Test Menu 2' },
|
295
|
+
menuItemsFixture
|
353
296
|
);
|
354
297
|
|
355
|
-
|
356
|
-
|
298
|
+
await createNewPost();
|
299
|
+
await insertBlock( 'Navigation' );
|
300
|
+
await selectClassicMenu( 'Test Menu 2' );
|
357
301
|
|
358
|
-
//
|
359
|
-
|
302
|
+
// Wait for a navigation link block before making assertion.
|
303
|
+
await page.waitForSelector( '*[aria-label="Block: Custom Link"]' );
|
304
|
+
expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
|
360
305
|
} );
|
361
306
|
|
362
307
|
it( 'creates an empty navigation block when the selected existing menu is also empty', async () => {
|
363
|
-
|
364
|
-
|
365
|
-
await mockAllMenusResponses( menusFixture, emptyMenuItems );
|
366
|
-
|
367
|
-
// Add the navigation block.
|
308
|
+
await createClassicMenu( { name: 'Test Menu 1' } );
|
309
|
+
await createNewPost();
|
368
310
|
await insertBlock( 'Navigation' );
|
311
|
+
await selectClassicMenu( 'Test Menu 1' );
|
369
312
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
// Block Style live previews.
|
374
|
-
const navBlockItemsLength = await page.$$eval(
|
375
|
-
'[aria-label="Editor content"][role="region"] li[aria-label="Block: Link"]',
|
376
|
-
( els ) => els.length
|
313
|
+
// Wait for the appender so that we know the navigation menu was created.
|
314
|
+
await page.waitForSelector(
|
315
|
+
'nav[aria-label="Block: Navigation"] button[aria-label="Add block"]'
|
377
316
|
);
|
378
|
-
|
379
|
-
// Assert an empty Nav Block is created.
|
380
|
-
expect( navBlockItemsLength ).toEqual( 0 );
|
381
|
-
|
382
|
-
// Snapshot should contain the mocked menu items.
|
383
|
-
expect( await getEditedPostContent() ).toMatchSnapshot();
|
317
|
+
expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
|
384
318
|
} );
|
385
319
|
|
386
|
-
it( 'does not display
|
387
|
-
|
388
|
-
await mockEmptyMenusAndPagesResponses();
|
320
|
+
it( 'does not display the options to create from pages or menus if there are none', async () => {
|
321
|
+
await createNewPost();
|
389
322
|
|
390
|
-
// Add the navigation block.
|
391
323
|
await insertBlock( 'Navigation' );
|
392
|
-
|
393
324
|
await page.waitForXPath( START_EMPTY_XPATH );
|
394
325
|
|
395
326
|
const placeholderActionsLength = await page.$$eval(
|
@@ -397,21 +328,21 @@ describe.skip( 'Navigation', () => {
|
|
397
328
|
( els ) => els.length
|
398
329
|
);
|
399
330
|
|
400
|
-
// Should only be showing
|
331
|
+
// Should only be showing "Start empty".
|
401
332
|
expect( placeholderActionsLength ).toEqual( 1 );
|
402
333
|
} );
|
403
334
|
} );
|
404
335
|
|
405
336
|
it( 'allows an empty navigation block to be created and manually populated using a mixture of internal and external links', async () => {
|
406
|
-
|
337
|
+
await createNewPost();
|
407
338
|
await insertBlock( 'Navigation' );
|
339
|
+
const startEmptyButton = await page.waitForXPath( START_EMPTY_XPATH );
|
340
|
+
await startEmptyButton.click();
|
408
341
|
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
await
|
413
|
-
|
414
|
-
await page.click( '.wp-block-navigation .block-list-appender' );
|
342
|
+
const appender = await page.waitForSelector(
|
343
|
+
'.wp-block-navigation .block-list-appender'
|
344
|
+
);
|
345
|
+
await appender.click();
|
415
346
|
|
416
347
|
// Add a link to the Link block.
|
417
348
|
await updateActiveNavigationLink( {
|
@@ -420,9 +351,14 @@ describe.skip( 'Navigation', () => {
|
|
420
351
|
type: 'url',
|
421
352
|
} );
|
422
353
|
|
354
|
+
// Select the parent navigation block to show the appender.
|
423
355
|
await showBlockToolbar();
|
356
|
+
await page.click( 'button[aria-label="Select Navigation"]' );
|
424
357
|
|
425
|
-
await page.
|
358
|
+
const appenderAgain = await page.waitForSelector(
|
359
|
+
'.wp-block-navigation .block-list-appender'
|
360
|
+
);
|
361
|
+
await appenderAgain.click();
|
426
362
|
|
427
363
|
// After adding a new block, search input should be shown immediately.
|
428
364
|
// Verify that Escape would close the popover.
|
@@ -442,7 +378,7 @@ describe.skip( 'Navigation', () => {
|
|
442
378
|
expect( isInURLInput ).toBe( true );
|
443
379
|
await page.keyboard.press( 'Escape' );
|
444
380
|
|
445
|
-
//
|
381
|
+
// Click the link placeholder.
|
446
382
|
const placeholder = await page.waitForSelector(
|
447
383
|
'.wp-block-navigation-link__placeholder'
|
448
384
|
);
|
@@ -461,20 +397,22 @@ describe.skip( 'Navigation', () => {
|
|
461
397
|
type: 'entity',
|
462
398
|
} );
|
463
399
|
|
400
|
+
await publishPost();
|
401
|
+
|
464
402
|
// Expect a Navigation Block with two Links in the snapshot.
|
465
|
-
expect( await
|
403
|
+
expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
|
466
404
|
} );
|
467
405
|
|
468
406
|
it( 'encodes URL when create block if needed', async () => {
|
469
|
-
|
407
|
+
await createNewPost();
|
470
408
|
await insertBlock( 'Navigation' );
|
409
|
+
const startEmptyButton = await page.waitForXPath( START_EMPTY_XPATH );
|
410
|
+
await startEmptyButton.click();
|
471
411
|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
await
|
476
|
-
|
477
|
-
await page.click( '.wp-block-navigation .block-list-appender' );
|
412
|
+
const appender = await page.waitForSelector(
|
413
|
+
'.wp-block-navigation .block-list-appender'
|
414
|
+
);
|
415
|
+
await appender.click();
|
478
416
|
|
479
417
|
// Add a link to the Link block.
|
480
418
|
await updateActiveNavigationLink( {
|
@@ -483,8 +421,12 @@ describe.skip( 'Navigation', () => {
|
|
483
421
|
} );
|
484
422
|
|
485
423
|
await showBlockToolbar();
|
424
|
+
await page.click( 'button[aria-label="Select Navigation"]' );
|
486
425
|
|
487
|
-
await page.
|
426
|
+
const appenderAgain = await page.waitForSelector(
|
427
|
+
'.wp-block-navigation .block-list-appender'
|
428
|
+
);
|
429
|
+
await appenderAgain.click();
|
488
430
|
|
489
431
|
// Wait for URL input to be focused
|
490
432
|
await page.waitForSelector(
|
@@ -520,92 +462,70 @@ describe.skip( 'Navigation', () => {
|
|
520
462
|
type: 'entity',
|
521
463
|
} );
|
522
464
|
|
465
|
+
await publishPost();
|
466
|
+
|
523
467
|
// Expect a Navigation Block with two Links in the snapshot.
|
524
468
|
// The 2nd link should not be double encoded.
|
525
|
-
expect( await
|
469
|
+
expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
|
526
470
|
} );
|
527
471
|
|
528
472
|
it( 'allows pages to be created from the navigation block and their links added to menu', async () => {
|
529
|
-
|
530
|
-
// We mock the page search to return no results and we use a very long
|
531
|
-
// page name because if the search returns existing pages then the
|
532
|
-
// "Create" suggestion might be below the scroll fold within the
|
533
|
-
// `LinkControl` search suggestions UI. If this happens then it's not
|
534
|
-
// possible to wait for the element to appear and the test will
|
535
|
-
// erroneously fail.
|
536
|
-
await mockSearchResponse( [] );
|
537
|
-
await mockCreatePageResponse(
|
538
|
-
'A really long page name that will not exist',
|
539
|
-
'my-new-page'
|
540
|
-
);
|
541
|
-
|
542
|
-
// Add the navigation block.
|
473
|
+
await createNewPost();
|
543
474
|
await insertBlock( 'Navigation' );
|
544
|
-
|
545
|
-
|
546
|
-
await
|
547
|
-
|
548
|
-
await page.click( '.wp-block-navigation .block-list-appender' );
|
549
|
-
|
550
|
-
// Wait for URL input to be focused
|
551
|
-
await page.waitForSelector(
|
552
|
-
'input.block-editor-url-input__input:focus'
|
553
|
-
);
|
554
|
-
|
555
|
-
// After adding a new block, search input should be shown immediately.
|
556
|
-
const isInURLInput = await page.evaluate(
|
557
|
-
() =>
|
558
|
-
!! document.activeElement.matches(
|
559
|
-
'input.block-editor-url-input__input'
|
560
|
-
)
|
561
|
-
);
|
562
|
-
expect( isInURLInput ).toBe( true );
|
563
|
-
|
564
|
-
// Insert name for the new page.
|
565
|
-
await page.type(
|
566
|
-
'input[placeholder="Search or type url"]',
|
567
|
-
'A really long page name that will not exist'
|
475
|
+
const startEmptyButton = await page.waitForXPath( START_EMPTY_XPATH );
|
476
|
+
await startEmptyButton.click();
|
477
|
+
const appender = await page.waitForSelector(
|
478
|
+
'.wp-block-navigation .block-list-appender'
|
568
479
|
);
|
480
|
+
await appender.click();
|
569
481
|
|
570
482
|
// Wait for URL input to be focused
|
571
|
-
|
483
|
+
// Insert name for the new page.
|
484
|
+
const pageTitle = 'A really long page name that will not exist';
|
485
|
+
const input = await page.waitForSelector(
|
572
486
|
'input.block-editor-url-input__input:focus'
|
573
487
|
);
|
574
|
-
|
575
|
-
|
576
|
-
|
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(
|
577
496
|
'.block-editor-link-control__search-create'
|
578
497
|
);
|
579
|
-
|
580
|
-
|
581
|
-
|
498
|
+
const responsePromise = page.waitForResponse(
|
499
|
+
( response ) =>
|
500
|
+
response.url().includes( 'url-details' ) &&
|
501
|
+
response.status() === 404
|
582
502
|
);
|
503
|
+
const createPagePromise = createPageButton.click();
|
504
|
+
await Promise.all( [ responsePromise, createPagePromise ] );
|
583
505
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
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 }")]`
|
588
510
|
);
|
589
|
-
|
511
|
+
|
512
|
+
await publishPost();
|
590
513
|
|
591
514
|
// Expect a Navigation Block with a link for "A really long page name that will not exist".
|
592
|
-
expect( await
|
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
|
+
);
|
593
519
|
} );
|
594
520
|
|
595
|
-
it( '
|
596
|
-
await
|
597
|
-
|
598
|
-
// Add the navigation block.
|
521
|
+
it( 'renders buttons for the submenu opener elements when the block is set to open on click instead of hover', async () => {
|
522
|
+
await createClassicMenu( { name: 'Test Menu 2' }, menuItemsFixture );
|
523
|
+
await createNewPost();
|
599
524
|
await insertBlock( 'Navigation' );
|
525
|
+
await selectClassicMenu( 'Test Menu 2' );
|
600
526
|
|
601
|
-
await
|
602
|
-
|
603
|
-
// const blocks = await getAllBlocks();
|
604
|
-
// await selectBlockByClientId( blocks[ 0 ].clientId );
|
605
|
-
|
606
|
-
await toggleSidebar();
|
607
|
-
|
608
|
-
const [ openOnClickButton ] = await page.$x(
|
527
|
+
await ensureSidebarOpened();
|
528
|
+
const openOnClickButton = await page.waitForXPath(
|
609
529
|
'//label[contains(text(),"Open on click")]'
|
610
530
|
);
|
611
531
|
|
@@ -640,16 +560,15 @@ describe.skip( 'Navigation', () => {
|
|
640
560
|
} );
|
641
561
|
|
642
562
|
it( 'Shows the quick inserter when the block contains non-navigation specific blocks', async () => {
|
643
|
-
|
563
|
+
await createNewPost();
|
644
564
|
await insertBlock( 'Navigation' );
|
565
|
+
const startEmptyButton = await page.waitForXPath( START_EMPTY_XPATH );
|
566
|
+
await startEmptyButton.click();
|
645
567
|
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
await
|
650
|
-
|
651
|
-
// Add a Link block first.
|
652
|
-
await page.click( '.wp-block-navigation .block-list-appender' );
|
568
|
+
const appender = await page.waitForSelector(
|
569
|
+
'.wp-block-navigation .block-list-appender'
|
570
|
+
);
|
571
|
+
await appender.click();
|
653
572
|
|
654
573
|
// Add a link to the Link block.
|
655
574
|
await updateActiveNavigationLink( {
|
@@ -661,24 +580,20 @@ describe.skip( 'Navigation', () => {
|
|
661
580
|
// Now add a different block type.
|
662
581
|
await insertBlock( 'Site Title' );
|
663
582
|
|
664
|
-
|
665
|
-
await page.
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
const linkButton = await page.waitForSelector(
|
670
|
-
'.block-editor-inserter__quick-inserter .editor-block-list-item-navigation-link'
|
583
|
+
await showBlockToolbar();
|
584
|
+
await page.click( 'button[aria-label="Select Navigation"]' );
|
585
|
+
const appenderAgain = await page.waitForSelector(
|
586
|
+
'.wp-block-navigation .block-list-appender'
|
671
587
|
);
|
672
|
-
await
|
588
|
+
await appenderAgain.click();
|
673
589
|
|
674
|
-
await
|
675
|
-
|
676
|
-
|
677
|
-
type: 'url',
|
678
|
-
} );
|
590
|
+
const quickInserter = await page.waitForSelector(
|
591
|
+
'.block-editor-inserter__quick-inserter'
|
592
|
+
);
|
679
593
|
|
680
|
-
// Expect
|
681
|
-
|
594
|
+
// Expect the quick inserter to be truthy, which it will be because we
|
595
|
+
// waited for it. It's nice to end a test with an assertion though.
|
596
|
+
expect( quickInserter ).toBeTruthy();
|
682
597
|
} );
|
683
598
|
|
684
599
|
it( 'supports navigation blocks that have inner blocks within their markup and converts them to wp_navigation posts', async () => {
|
@@ -700,10 +615,10 @@ describe.skip( 'Navigation', () => {
|
|
700
615
|
// The select menu button shows up when saving is complete.
|
701
616
|
await navBlock.click();
|
702
617
|
await page.waitForSelector( 'button[aria-label="Select Menu"]' );
|
703
|
-
|
618
|
+
await publishPost();
|
704
619
|
|
705
620
|
// Check that the wp_navigation post has the page list block.
|
706
|
-
|
621
|
+
expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
|
707
622
|
} );
|
708
623
|
|
709
624
|
describe( 'Creating and restarting', () => {
|
@@ -773,7 +688,7 @@ describe.skip( 'Navigation', () => {
|
|
773
688
|
expect( await page.$x( NAV_ENTITY_SELECTOR ) ).toHaveLength( 1 );
|
774
689
|
} );
|
775
690
|
|
776
|
-
it( 'only
|
691
|
+
it( 'only updates a single entity currently linked with the block', async () => {
|
777
692
|
await createNewPost();
|
778
693
|
await insertBlock( 'Navigation' );
|
779
694
|
|
@@ -826,31 +741,16 @@ describe.skip( 'Navigation', () => {
|
|
826
741
|
} );
|
827
742
|
} );
|
828
743
|
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
await mockPagesResponse( [
|
835
|
-
{
|
836
|
-
title: 'Home',
|
837
|
-
slug: 'home',
|
838
|
-
},
|
839
|
-
{
|
840
|
-
title: 'About',
|
841
|
-
slug: 'about',
|
842
|
-
},
|
843
|
-
{
|
844
|
-
title: 'Contact Us',
|
845
|
-
slug: 'contact',
|
846
|
-
},
|
847
|
-
] );
|
848
|
-
|
849
|
-
// Create first block at the start in order to enable preview.
|
850
|
-
await insertBlock( 'Navigation' );
|
851
|
-
await saveDraft();
|
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' );
|
852
749
|
|
853
750
|
const previewPage = await openPreviewPage();
|
751
|
+
await previewPage.bringToFront();
|
752
|
+
await previewPage.waitForNetworkIdle();
|
753
|
+
|
854
754
|
const isScriptLoaded = await previewPage.evaluate(
|
855
755
|
() =>
|
856
756
|
null !==
|
@@ -860,83 +760,32 @@ describe.skip( 'Navigation', () => {
|
|
860
760
|
);
|
861
761
|
|
862
762
|
expect( isScriptLoaded ).toBe( false );
|
763
|
+
} );
|
863
764
|
|
864
|
-
|
765
|
+
it( 'loads the frontend script only once even when multiple navigation blocks are present', async () => {
|
766
|
+
await createNewPost();
|
767
|
+
await insertBlock( 'Navigation' );
|
865
768
|
await insertBlock( 'Navigation' );
|
866
|
-
await createNavBlockWithAllPages();
|
867
|
-
await turnResponsivenessOn();
|
868
769
|
|
869
|
-
await
|
870
|
-
|
871
|
-
|
770
|
+
const previewPage = await openPreviewPage();
|
771
|
+
await previewPage.bringToFront();
|
772
|
+
await previewPage.waitForNetworkIdle();
|
872
773
|
|
873
|
-
/*
|
874
|
-
Count instances of the tag to make sure that it's been loaded only once,
|
875
|
-
regardless of the number of navigation blocks present.
|
876
|
-
*/
|
877
774
|
const tagCount = await previewPage.evaluate(
|
878
775
|
() =>
|
879
|
-
|
880
|
-
|
881
|
-
'script[src*="navigation/view.min.js"]'
|
882
|
-
)
|
776
|
+
document.querySelectorAll(
|
777
|
+
'script[src*="navigation/view.min.js"]'
|
883
778
|
).length
|
884
779
|
);
|
885
780
|
|
886
781
|
expect( tagCount ).toBe( 1 );
|
887
782
|
} );
|
888
783
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
{
|
893
|
-
title: 'Home',
|
894
|
-
slug: 'home',
|
895
|
-
},
|
896
|
-
{
|
897
|
-
title: 'About',
|
898
|
-
slug: 'about',
|
899
|
-
},
|
900
|
-
{
|
901
|
-
title: 'Contact Us',
|
902
|
-
slug: 'contact',
|
903
|
-
},
|
904
|
-
] );
|
905
|
-
|
906
|
-
await insertBlock( 'Navigation' );
|
907
|
-
await saveDraft();
|
908
|
-
|
909
|
-
const previewPage = await openPreviewPage();
|
910
|
-
let isScriptLoaded = await previewPage.evaluate(
|
911
|
-
() =>
|
912
|
-
null !==
|
913
|
-
document.querySelector(
|
914
|
-
'script[src*="navigation/view.min.js"]'
|
915
|
-
)
|
916
|
-
);
|
917
|
-
|
918
|
-
expect( isScriptLoaded ).toBe( false );
|
919
|
-
|
920
|
-
await createNavBlockWithAllPages();
|
921
|
-
|
922
|
-
await turnResponsivenessOn();
|
923
|
-
|
924
|
-
await previewPage.reload( {
|
925
|
-
waitFor: [ 'networkidle0', 'domcontentloaded' ],
|
784
|
+
describe( 'Permission based restrictions', () => {
|
785
|
+
afterEach( async () => {
|
786
|
+
await switchUserToAdmin();
|
926
787
|
} );
|
927
788
|
|
928
|
-
isScriptLoaded = await previewPage.evaluate(
|
929
|
-
() =>
|
930
|
-
null !==
|
931
|
-
document.querySelector(
|
932
|
-
'script[src*="navigation/view.min.js"]'
|
933
|
-
)
|
934
|
-
);
|
935
|
-
|
936
|
-
expect( isScriptLoaded ).toBe( true );
|
937
|
-
} );
|
938
|
-
|
939
|
-
describe( 'Permission based restrictions', () => {
|
940
789
|
it( 'shows a warning if user does not have permission to edit or update navigation menus', async () => {
|
941
790
|
await createNewPost();
|
942
791
|
await insertBlock( 'Navigation' );
|
@@ -950,11 +799,11 @@ describe.skip( 'Navigation', () => {
|
|
950
799
|
|
951
800
|
// Publishing the Post ensures the Navigation entity is saved.
|
952
801
|
// The Post itself is irrelevant.
|
953
|
-
|
802
|
+
await publishPost();
|
954
803
|
|
955
804
|
// Switch to a Contributor role user - they should not have
|
956
|
-
// permission to update
|
957
|
-
|
805
|
+
// permission to update Navigation menus.
|
806
|
+
await loginUser( contributorUsername, contributorPassword );
|
958
807
|
|
959
808
|
await createNewPost();
|
960
809
|
|
@@ -975,7 +824,30 @@ describe.skip( 'Navigation', () => {
|
|
975
824
|
`//*[contains(@class, 'components-snackbar__content')][ text()="You do not have permission to edit this Menu. Any changes made will not be saved." ]`
|
976
825
|
);
|
977
826
|
|
978
|
-
// Expect a console 403 for request to Navigation Areas for lower
|
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.
|
979
851
|
// This is because reading requires the `edit_theme_options` capability
|
980
852
|
// which the Contributor level user does not have.
|
981
853
|
// See: https://github.com/WordPress/gutenberg/blob/4cedaf0c4abb0aeac4bfd4289d63e9889efe9733/lib/class-wp-rest-block-navigation-areas-controller.php#L81-L91.
|