@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.
- package/CHANGELOG.md +6 -0
- package/README.md +2 -0
- package/config/flaky-tests-reporter.js +1 -0
- package/package.json +10 -8
- package/specs/editor/blocks/__snapshots__/buttons.test.js.snap +8 -0
- package/specs/editor/blocks/__snapshots__/navigation.test.js.snap +2 -2
- package/specs/editor/blocks/__snapshots__/separator.test.js.snap +1 -1
- package/specs/editor/blocks/buttons.test.js +10 -0
- package/specs/editor/blocks/columns.test.js +3 -3
- package/specs/editor/blocks/gallery.test.js +36 -6
- package/specs/editor/blocks/heading.test.js +1 -1
- package/specs/editor/blocks/navigation.test.js +370 -72
- package/specs/editor/blocks/query.test.js +13 -3
- package/specs/editor/plugins/annotations.test.js +63 -67
- package/specs/editor/various/__snapshots__/block-deletion.test.js.snap +20 -12
- package/specs/editor/various/__snapshots__/block-editor-keyboard-shortcuts.test.js.snap +26 -0
- package/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap +1 -1
- package/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap +122 -6
- package/specs/editor/various/__snapshots__/writing-flow.test.js.snap +6 -6
- package/specs/editor/various/autosave.test.js +3 -3
- package/specs/editor/various/block-deletion.test.js +1 -0
- package/specs/editor/various/block-editor-keyboard-shortcuts.test.js +3 -5
- package/specs/editor/various/block-hierarchy-navigation.test.js +10 -16
- package/specs/editor/various/block-locking.test.js +120 -0
- package/specs/editor/various/keyboard-navigable-blocks.test.js +23 -0
- package/specs/editor/various/list-view.test.js +139 -7
- package/specs/editor/various/multi-block-selection.test.js +153 -9
- package/specs/editor/various/post-editor-template-mode.test.js +1 -1
- package/specs/editor/various/toolbar-roving-tabindex.test.js +10 -4
- package/specs/editor/various/writing-flow.test.js +10 -5
- package/specs/experiments/blocks/comments-query.test.js +131 -0
- package/specs/experiments/navigation-editor.test.js +126 -121
- package/specs/performance/post-editor.test.js +4 -6
- package/specs/site-editor/global-styles-sidebar.test.js +42 -0
- package/specs/site-editor/iframe-rendering-mode.test.js +31 -0
- package/specs/site-editor/site-editor-export.test.js +2 -2
- package/specs/site-editor/style-variations.test.js +9 -7
- package/specs/site-editor/template-part.test.js +3 -1
- package/specs/editor/various/__snapshots__/copy-cut-paste-whole-blocks.test.js.snap +0 -125
- package/specs/editor/various/copy-cut-paste-whole-blocks.test.js +0 -187
- package/specs/editor/various/new-post.test.js +0 -99
- 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
|
-
|
779
|
-
|
780
|
-
|
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
|
-
|
892
|
+
it( 'respects the nesting level', async () => {
|
893
|
+
await createNewPost();
|
793
894
|
|
794
|
-
|
795
|
-
await navBlock.click();
|
895
|
+
await insertBlock( 'Navigation' );
|
796
896
|
|
797
|
-
|
798
|
-
await waitForBlock( 'Page List' );
|
897
|
+
const navBlock = await waitForBlock( 'Navigation' );
|
799
898
|
|
800
|
-
|
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
|
-
|
803
|
-
expect( await getNavigationMenuRawContent() ).toMatchSnapshot();
|
804
|
-
} );
|
905
|
+
await populateNavWithOneItem();
|
805
906
|
|
806
|
-
|
807
|
-
|
808
|
-
|
907
|
+
await clickOnMoreMenuItem( 'Code editor' );
|
908
|
+
const codeEditorInput = await page.waitForSelector(
|
909
|
+
'.editor-post-text-editor'
|
910
|
+
);
|
809
911
|
|
810
|
-
|
811
|
-
|
812
|
-
|
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
|
815
|
-
|
816
|
-
|
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
|
-
|
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
|
-
|
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
|
-
//
|
839
|
-
await
|
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
|
-
//
|
842
|
-
await
|
993
|
+
// Select the Page List block.
|
994
|
+
await openListView();
|
843
995
|
|
844
|
-
const
|
845
|
-
|
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
|
-
|
851
|
-
|
852
|
-
|
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
|
857
|
-
|
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.
|
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
|
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.
|
84
|
-
'
|
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.
|