@wordpress/block-editor 9.7.0 → 9.7.1-next.d6164808d3.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/build/components/block-alignment-control/use-available-alignments.js +1 -1
- package/build/components/block-alignment-control/use-available-alignments.js.map +1 -1
- package/build/components/block-edit-visually-button/index.js +46 -0
- package/build/components/block-edit-visually-button/index.js.map +1 -0
- package/build/components/block-popover/inbetween.js +4 -2
- package/build/components/block-popover/inbetween.js.map +1 -1
- package/build/components/block-settings-menu/index.js +2 -6
- package/build/components/block-settings-menu/index.js.map +1 -1
- package/build/components/block-switcher/index.js +10 -16
- package/build/components/block-switcher/index.js.map +1 -1
- package/build/components/block-toolbar/index.js +5 -1
- package/build/components/block-toolbar/index.js.map +1 -1
- package/build/components/border-radius-control/all-input-control.js +31 -3
- package/build/components/border-radius-control/all-input-control.js.map +1 -1
- package/build/components/border-radius-control/index.js +20 -6
- package/build/components/border-radius-control/index.js.map +1 -1
- package/build/components/border-radius-control/input-controls.js +21 -6
- package/build/components/border-radius-control/input-controls.js.map +1 -1
- package/build/components/border-radius-control/utils.js +13 -16
- package/build/components/border-radius-control/utils.js.map +1 -1
- package/build/components/colors/with-colors.js +17 -4
- package/build/components/colors/with-colors.js.map +1 -1
- package/build/components/copy-handler/index.js +6 -0
- package/build/components/copy-handler/index.js.map +1 -1
- package/build/components/date-format-picker/index.js +2 -7
- package/build/components/date-format-picker/index.js.map +1 -1
- package/build/components/duotone/components.js +5 -5
- package/build/components/duotone/components.js.map +1 -1
- package/build/components/font-family/index.js +1 -1
- package/build/components/font-family/index.js.map +1 -1
- package/build/components/font-sizes/with-font-sizes.js +17 -4
- package/build/components/font-sizes/with-font-sizes.js.map +1 -1
- package/build/components/index.js +9 -0
- package/build/components/index.js.map +1 -1
- package/build/components/inserter/search-items.js +22 -4
- package/build/components/inserter/search-items.js.map +1 -1
- package/build/components/link-control/link-preview.js +0 -1
- package/build/components/link-control/link-preview.js.map +1 -1
- package/build/components/list-view/block-select-button.js +5 -2
- package/build/components/list-view/block-select-button.js.map +1 -1
- package/build/components/list-view/use-block-selection.js +1 -7
- package/build/components/list-view/use-block-selection.js.map +1 -1
- package/build/components/rich-text/use-enter.js +0 -4
- package/build/components/rich-text/use-enter.js.map +1 -1
- package/build/components/rich-text/use-format-types.js +8 -11
- package/build/components/rich-text/use-format-types.js.map +1 -1
- package/build/components/spacing-sizes-control/all-input-control.js +53 -0
- package/build/components/spacing-sizes-control/all-input-control.js.map +1 -0
- package/build/components/spacing-sizes-control/axial-input-controls.js +69 -0
- package/build/components/spacing-sizes-control/axial-input-controls.js.map +1 -0
- package/build/components/spacing-sizes-control/index.js +100 -0
- package/build/components/spacing-sizes-control/index.js.map +1 -0
- package/build/components/spacing-sizes-control/input-controls.js +52 -0
- package/build/components/spacing-sizes-control/input-controls.js.map +1 -0
- package/build/components/spacing-sizes-control/linked-button.js +38 -0
- package/build/components/spacing-sizes-control/linked-button.js.map +1 -0
- package/build/components/spacing-sizes-control/spacing-input-control.js +208 -0
- package/build/components/spacing-sizes-control/spacing-input-control.js.map +1 -0
- package/build/components/spacing-sizes-control/utils.js +202 -0
- package/build/components/spacing-sizes-control/utils.js.map +1 -0
- package/build/components/url-input/index.js +1 -1
- package/build/components/url-input/index.js.map +1 -1
- package/build/components/writing-flow/use-multi-selection.js +4 -2
- package/build/components/writing-flow/use-multi-selection.js.map +1 -1
- package/build/components/writing-flow/use-selection-observer.js +10 -2
- package/build/components/writing-flow/use-selection-observer.js.map +1 -1
- package/build/hooks/border-radius.js +2 -7
- package/build/hooks/border-radius.js.map +1 -1
- package/build/hooks/border.js +2 -2
- package/build/hooks/border.js.map +1 -1
- package/build/hooks/color.js +4 -1
- package/build/hooks/color.js.map +1 -1
- package/build/hooks/dimensions.js +15 -0
- package/build/hooks/dimensions.js.map +1 -1
- package/build/hooks/duotone.js +4 -4
- package/build/hooks/duotone.js.map +1 -1
- package/build/hooks/gap.js +6 -4
- package/build/hooks/gap.js.map +1 -1
- package/build/hooks/generated-class-name.js +1 -7
- package/build/hooks/generated-class-name.js.map +1 -1
- package/build/hooks/layout.js +20 -12
- package/build/hooks/layout.js.map +1 -1
- package/build/hooks/margin.js +28 -12
- package/build/hooks/margin.js.map +1 -1
- package/build/hooks/padding.js +19 -8
- package/build/hooks/padding.js.map +1 -1
- package/build/hooks/style.js +4 -50
- package/build/hooks/style.js.map +1 -1
- package/build/layouts/constrained.js +215 -0
- package/build/layouts/constrained.js.map +1 -0
- package/build/layouts/flex.js +1 -1
- package/build/layouts/flex.js.map +1 -1
- package/build/layouts/flow.js +7 -169
- package/build/layouts/flow.js.map +1 -1
- package/build/layouts/index.js +3 -1
- package/build/layouts/index.js.map +1 -1
- package/build/layouts/utils.js +43 -0
- package/build/layouts/utils.js.map +1 -1
- package/build/store/actions.js +25 -3
- package/build/store/actions.js.map +1 -1
- package/build/store/selectors.js +4 -6
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/block-alignment-control/use-available-alignments.js +1 -1
- package/build-module/components/block-alignment-control/use-available-alignments.js.map +1 -1
- package/build-module/components/block-edit-visually-button/index.js +35 -0
- package/build-module/components/block-edit-visually-button/index.js.map +1 -0
- package/build-module/components/block-popover/inbetween.js +4 -2
- package/build-module/components/block-popover/inbetween.js.map +1 -1
- package/build-module/components/block-settings-menu/index.js +3 -6
- package/build-module/components/block-settings-menu/index.js.map +1 -1
- package/build-module/components/block-switcher/index.js +10 -16
- package/build-module/components/block-switcher/index.js.map +1 -1
- package/build-module/components/block-toolbar/index.js +4 -1
- package/build-module/components/block-toolbar/index.js.map +1 -1
- package/build-module/components/border-radius-control/all-input-control.js +32 -4
- package/build-module/components/border-radius-control/all-input-control.js.map +1 -1
- package/build-module/components/border-radius-control/index.js +20 -6
- package/build-module/components/border-radius-control/index.js.map +1 -1
- package/build-module/components/border-radius-control/input-controls.js +22 -7
- package/build-module/components/border-radius-control/input-controls.js.map +1 -1
- package/build-module/components/border-radius-control/utils.js +13 -16
- package/build-module/components/border-radius-control/utils.js.map +1 -1
- package/build-module/components/colors/with-colors.js +16 -3
- package/build-module/components/colors/with-colors.js.map +1 -1
- package/build-module/components/copy-handler/index.js +7 -1
- package/build-module/components/copy-handler/index.js.map +1 -1
- package/build-module/components/date-format-picker/index.js +2 -6
- package/build-module/components/date-format-picker/index.js.map +1 -1
- package/build-module/components/duotone/components.js +5 -5
- package/build-module/components/duotone/components.js.map +1 -1
- package/build-module/components/font-family/index.js +1 -1
- package/build-module/components/font-family/index.js.map +1 -1
- package/build-module/components/font-sizes/with-font-sizes.js +16 -3
- package/build-module/components/font-sizes/with-font-sizes.js.map +1 -1
- package/build-module/components/index.js +1 -0
- package/build-module/components/index.js.map +1 -1
- package/build-module/components/inserter/search-items.js +19 -5
- package/build-module/components/inserter/search-items.js.map +1 -1
- package/build-module/components/link-control/link-preview.js +0 -1
- package/build-module/components/link-control/link-preview.js.map +1 -1
- package/build-module/components/list-view/block-select-button.js +5 -2
- package/build-module/components/list-view/block-select-button.js.map +1 -1
- package/build-module/components/list-view/use-block-selection.js +1 -6
- package/build-module/components/list-view/use-block-selection.js.map +1 -1
- package/build-module/components/rich-text/use-enter.js +0 -4
- package/build-module/components/rich-text/use-enter.js.map +1 -1
- package/build-module/components/rich-text/use-format-types.js +8 -10
- package/build-module/components/rich-text/use-format-types.js.map +1 -1
- package/build-module/components/spacing-sizes-control/all-input-control.js +41 -0
- package/build-module/components/spacing-sizes-control/all-input-control.js.map +1 -0
- package/build-module/components/spacing-sizes-control/axial-input-controls.js +57 -0
- package/build-module/components/spacing-sizes-control/axial-input-controls.js.map +1 -0
- package/build-module/components/spacing-sizes-control/index.js +83 -0
- package/build-module/components/spacing-sizes-control/index.js.map +1 -0
- package/build-module/components/spacing-sizes-control/input-controls.js +41 -0
- package/build-module/components/spacing-sizes-control/input-controls.js.map +1 -0
- package/build-module/components/spacing-sizes-control/linked-button.js +28 -0
- package/build-module/components/spacing-sizes-control/linked-button.js.map +1 -0
- package/build-module/components/spacing-sizes-control/spacing-input-control.js +192 -0
- package/build-module/components/spacing-sizes-control/spacing-input-control.js.map +1 -0
- package/build-module/components/spacing-sizes-control/utils.js +174 -0
- package/build-module/components/spacing-sizes-control/utils.js.map +1 -0
- package/build-module/components/url-input/index.js +1 -1
- package/build-module/components/url-input/index.js.map +1 -1
- package/build-module/components/writing-flow/use-multi-selection.js +4 -2
- package/build-module/components/writing-flow/use-multi-selection.js.map +1 -1
- package/build-module/components/writing-flow/use-selection-observer.js +10 -2
- package/build-module/components/writing-flow/use-selection-observer.js.map +1 -1
- package/build-module/hooks/border-radius.js +2 -7
- package/build-module/hooks/border-radius.js.map +1 -1
- package/build-module/hooks/border.js +2 -2
- package/build-module/hooks/border.js.map +1 -1
- package/build-module/hooks/color.js +4 -1
- package/build-module/hooks/color.js.map +1 -1
- package/build-module/hooks/dimensions.js +13 -0
- package/build-module/hooks/dimensions.js.map +1 -1
- package/build-module/hooks/duotone.js +4 -4
- package/build-module/hooks/duotone.js.map +1 -1
- package/build-module/hooks/gap.js +3 -2
- package/build-module/hooks/gap.js.map +1 -1
- package/build-module/hooks/generated-class-name.js +1 -6
- package/build-module/hooks/generated-class-name.js.map +1 -1
- package/build-module/hooks/layout.js +20 -12
- package/build-module/hooks/layout.js.map +1 -1
- package/build-module/hooks/margin.js +26 -12
- package/build-module/hooks/margin.js.map +1 -1
- package/build-module/hooks/padding.js +17 -8
- package/build-module/hooks/padding.js.map +1 -1
- package/build-module/hooks/style.js +7 -53
- package/build-module/hooks/style.js.map +1 -1
- package/build-module/layouts/constrained.js +197 -0
- package/build-module/layouts/constrained.js.map +1 -0
- package/build-module/layouts/flex.js +1 -1
- package/build-module/layouts/flex.js.map +1 -1
- package/build-module/layouts/flow.js +8 -163
- package/build-module/layouts/flow.js.map +1 -1
- package/build-module/layouts/index.js +2 -1
- package/build-module/layouts/index.js.map +1 -1
- package/build-module/layouts/utils.js +40 -0
- package/build-module/layouts/utils.js.map +1 -1
- package/build-module/store/actions.js +25 -3
- package/build-module/store/actions.js.map +1 -1
- package/build-module/store/selectors.js +5 -7
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +115 -20
- package/build-style/style.css +115 -20
- package/package.json +30 -28
- package/src/components/block-alignment-control/use-available-alignments.js +1 -1
- package/src/components/block-edit-visually-button/index.js +39 -0
- package/src/components/block-popover/inbetween.js +4 -1
- package/src/components/block-settings-menu/index.js +11 -15
- package/src/components/block-switcher/index.js +9 -13
- package/src/components/block-switcher/test/index.js +1 -0
- package/src/components/block-toolbar/index.js +2 -0
- package/src/components/border-radius-control/all-input-control.js +41 -4
- package/src/components/border-radius-control/index.js +25 -5
- package/src/components/border-radius-control/input-controls.js +40 -13
- package/src/components/border-radius-control/test/utils.js +22 -60
- package/src/components/border-radius-control/utils.js +12 -16
- package/src/components/colors/with-colors.js +11 -1
- package/src/components/copy-handler/index.js +18 -0
- package/src/components/date-format-picker/index.js +12 -14
- package/src/components/date-format-picker/style.scss +0 -4
- package/src/components/duotone/components.js +5 -5
- package/src/components/duotone-control/style.scss +0 -4
- package/src/components/font-appearance-control/style.scss +0 -2
- package/src/components/font-family/index.js +1 -1
- package/src/components/font-sizes/with-font-sizes.js +11 -1
- package/src/components/index.js +1 -0
- package/src/components/inserter/search-items.js +17 -5
- package/src/components/link-control/link-preview.js +0 -1
- package/src/components/link-control/test/index.js +540 -893
- package/src/components/list-view/block-select-button.js +7 -2
- package/src/components/list-view/style.scss +11 -4
- package/src/components/list-view/use-block-selection.js +2 -8
- package/src/components/media-replace-flow/style.scss +1 -0
- package/src/components/rich-text/use-enter.js +0 -3
- package/src/components/rich-text/use-format-types.js +6 -6
- package/src/components/spacing-sizes-control/all-input-control.js +40 -0
- package/src/components/spacing-sizes-control/axial-input-controls.js +62 -0
- package/src/components/spacing-sizes-control/index.js +91 -0
- package/src/components/spacing-sizes-control/input-controls.js +46 -0
- package/src/components/spacing-sizes-control/linked-button.js +25 -0
- package/src/components/spacing-sizes-control/spacing-input-control.js +280 -0
- package/src/components/spacing-sizes-control/style.scss +122 -0
- package/src/components/spacing-sizes-control/test/utils.js +156 -0
- package/src/components/spacing-sizes-control/utils.js +195 -0
- package/src/components/url-input/index.js +1 -1
- package/src/components/url-input/style.scss +2 -2
- package/src/components/url-popover/style.scss +0 -3
- package/src/components/writing-flow/use-multi-selection.js +4 -1
- package/src/components/writing-flow/use-selection-observer.js +10 -2
- package/src/hooks/border-radius.js +2 -6
- package/src/hooks/border.js +2 -2
- package/src/hooks/color.js +13 -3
- package/src/hooks/dimensions.js +15 -0
- package/src/hooks/duotone.js +4 -4
- package/src/hooks/gap.js +7 -2
- package/src/hooks/generated-class-name.js +6 -9
- package/src/hooks/layout.js +45 -14
- package/src/hooks/margin.js +49 -17
- package/src/hooks/padding.js +41 -14
- package/src/hooks/style.js +5 -56
- package/src/hooks/test/gap.js +22 -0
- package/src/hooks/typography.scss +0 -1
- package/src/layouts/constrained.js +217 -0
- package/src/layouts/flex.js +1 -1
- package/src/layouts/flow.js +6 -173
- package/src/layouts/index.js +2 -1
- package/src/layouts/test/constrained.js +21 -0
- package/src/layouts/utils.js +34 -0
- package/src/store/actions.js +32 -4
- package/src/store/selectors.js +5 -4
- package/src/style.scss +1 -0
- package/build/components/block-settings-menu/block-edit-visually-button.js +0 -70
- package/build/components/block-settings-menu/block-edit-visually-button.js.map +0 -1
- package/build-module/components/block-settings-menu/block-edit-visually-button.js +0 -56
- package/build-module/components/block-settings-menu/block-edit-visually-button.js.map +0 -1
- package/src/components/block-settings-menu/block-edit-visually-button.js +0 -52
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { render,
|
|
5
|
-
import
|
|
6
|
-
|
|
4
|
+
import { act, fireEvent, render, screen } from '@testing-library/react';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
|
|
7
7
|
/**
|
|
8
8
|
* WordPress dependencies
|
|
9
9
|
*/
|
|
10
10
|
import { useState } from '@wordpress/element';
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
/**
|
|
13
13
|
* WordPress dependencies
|
|
14
14
|
*/
|
|
@@ -71,33 +71,26 @@ function eventLoopTick() {
|
|
|
71
71
|
return new Promise( ( resolve ) => setImmediate( resolve ) );
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
let container = null;
|
|
75
|
-
|
|
76
74
|
beforeEach( () => {
|
|
77
75
|
// Setup a DOM element as a render target.
|
|
78
|
-
container = document.createElement( 'div' );
|
|
79
|
-
document.body.appendChild( container );
|
|
80
76
|
mockFetchSearchSuggestions.mockImplementation( fetchFauxEntitySuggestions );
|
|
81
77
|
} );
|
|
82
78
|
|
|
83
79
|
afterEach( () => {
|
|
84
80
|
// Cleanup on exiting.
|
|
85
|
-
unmountComponentAtNode( container );
|
|
86
|
-
container.remove();
|
|
87
|
-
container = null;
|
|
88
81
|
mockFetchSearchSuggestions.mockReset();
|
|
89
82
|
mockFetchRichUrlData?.mockReset(); // Conditionally reset as it may NOT be a mock.
|
|
90
83
|
} );
|
|
91
84
|
|
|
92
85
|
function getURLInput() {
|
|
93
|
-
return
|
|
86
|
+
return screen.queryByRole( 'combobox', { name: 'URL' } );
|
|
94
87
|
}
|
|
95
88
|
|
|
96
|
-
function getSearchResults() {
|
|
89
|
+
function getSearchResults( container ) {
|
|
97
90
|
const input = getURLInput();
|
|
98
|
-
// The input has `aria-
|
|
91
|
+
// The input has `aria-controls` to indicate that it owns (and is related to)
|
|
99
92
|
// the search results with `role="listbox"`.
|
|
100
|
-
const relatedSelector = input.getAttribute( 'aria-
|
|
93
|
+
const relatedSelector = input.getAttribute( 'aria-controls' );
|
|
101
94
|
|
|
102
95
|
// Select by relationship as well as role.
|
|
103
96
|
return container.querySelectorAll(
|
|
@@ -106,24 +99,91 @@ function getSearchResults() {
|
|
|
106
99
|
}
|
|
107
100
|
|
|
108
101
|
function getCurrentLink() {
|
|
109
|
-
return
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
return screen.queryByLabelText( 'Currently selected' );
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function getSelectedResultElement() {
|
|
106
|
+
return screen.queryByRole( 'option', { selected: true } );
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Workaround to trigger an arrow up keypress event.
|
|
111
|
+
*
|
|
112
|
+
* @todo Remove this workaround in favor of userEvent.keyboard() or userEvent.type().
|
|
113
|
+
*
|
|
114
|
+
* For some reason, this doesn't work:
|
|
115
|
+
*
|
|
116
|
+
* ```
|
|
117
|
+
* await user.keyboard( '[ArrowDown]' );
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* because the event sent has a `keyCode` of `0`.
|
|
121
|
+
*
|
|
122
|
+
* @param {Element} element Element to trigger the event on.
|
|
123
|
+
*/
|
|
124
|
+
function triggerArrowUp( element ) {
|
|
125
|
+
fireEvent.keyDown( element, {
|
|
126
|
+
key: 'ArrowUp',
|
|
127
|
+
keyCode: 38,
|
|
128
|
+
} );
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Workaround to trigger an arrow down keypress event.
|
|
133
|
+
*
|
|
134
|
+
* @todo Remove this workaround in favor of userEvent.keyboard() or userEvent.type().
|
|
135
|
+
*
|
|
136
|
+
* For some reason, this doesn't work:
|
|
137
|
+
*
|
|
138
|
+
* ```
|
|
139
|
+
* await user.keyboard( '[ArrowDown]' );
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* because the event sent has a `keyCode` of `0`.
|
|
143
|
+
*
|
|
144
|
+
* @param {Element} element Element to trigger the event on.
|
|
145
|
+
*/
|
|
146
|
+
function triggerArrowDown( element ) {
|
|
147
|
+
fireEvent.keyDown( element, {
|
|
148
|
+
key: 'ArrowDown',
|
|
149
|
+
keyCode: 40,
|
|
150
|
+
} );
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Workaround to trigger an Enter keypress event.
|
|
155
|
+
*
|
|
156
|
+
* @todo Remove this workaround in favor of userEvent.keyboard() or userEvent.type().
|
|
157
|
+
*
|
|
158
|
+
* For some reason, this doesn't work:
|
|
159
|
+
*
|
|
160
|
+
* ```
|
|
161
|
+
* await user.keyboard( '[Enter]' );
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* because the event sent has a `keyCode` of `0`.
|
|
165
|
+
*
|
|
166
|
+
* @param {Element} element Element to trigger the event on.
|
|
167
|
+
*/
|
|
168
|
+
function triggerEnter( element ) {
|
|
169
|
+
fireEvent.keyDown( element, {
|
|
170
|
+
key: 'Enter',
|
|
171
|
+
keyCode: 13,
|
|
172
|
+
} );
|
|
112
173
|
}
|
|
113
174
|
|
|
114
175
|
describe( 'Basic rendering', () => {
|
|
115
176
|
it( 'should render', () => {
|
|
116
|
-
|
|
117
|
-
render( <LinkControl />, container );
|
|
118
|
-
} );
|
|
177
|
+
render( <LinkControl /> );
|
|
119
178
|
|
|
120
179
|
// Search Input UI.
|
|
121
180
|
const searchInput = getURLInput();
|
|
122
181
|
|
|
123
|
-
expect( searchInput ).
|
|
182
|
+
expect( searchInput ).toBeInTheDocument();
|
|
124
183
|
} );
|
|
125
184
|
|
|
126
185
|
it( 'should not render protocol in links', async () => {
|
|
186
|
+
const user = userEvent.setup();
|
|
127
187
|
mockFetchSearchSuggestions.mockImplementation( () =>
|
|
128
188
|
Promise.resolve( [
|
|
129
189
|
{
|
|
@@ -145,94 +205,61 @@ describe( 'Basic rendering', () => {
|
|
|
145
205
|
|
|
146
206
|
const searchTerm = 'Hello';
|
|
147
207
|
|
|
148
|
-
|
|
149
|
-
render( <LinkControl />, container );
|
|
150
|
-
} );
|
|
208
|
+
render( <LinkControl /> );
|
|
151
209
|
|
|
152
210
|
// Search Input UI.
|
|
153
211
|
const searchInput = getURLInput();
|
|
154
212
|
|
|
155
213
|
// Simulate searching for a term.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
} );
|
|
159
|
-
|
|
160
|
-
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
161
|
-
await eventLoopTick();
|
|
162
|
-
|
|
163
|
-
// Find all elements with link
|
|
164
|
-
// Filter out the element with the text 'ENTER' because it doesn't contain link.
|
|
165
|
-
const linkElements = Array.from(
|
|
166
|
-
container.querySelectorAll(
|
|
167
|
-
'.block-editor-link-control__search-item-info'
|
|
168
|
-
)
|
|
169
|
-
).filter( ( elem ) => ! elem.innerHTML.includes( 'ENTER' ) );
|
|
214
|
+
searchInput.focus();
|
|
215
|
+
await user.keyboard( searchTerm );
|
|
170
216
|
|
|
171
|
-
|
|
172
|
-
expect( elem.innerHTML ).not.toContain( '://' );
|
|
173
|
-
} );
|
|
217
|
+
expect( screen.queryByText( '://' ) ).not.toBeInTheDocument();
|
|
174
218
|
} );
|
|
175
219
|
|
|
176
220
|
describe( 'forceIsEditingLink', () => {
|
|
177
|
-
const isEditing = () => !! getURLInput();
|
|
178
|
-
|
|
179
221
|
it( 'undefined', () => {
|
|
180
|
-
|
|
181
|
-
render(
|
|
182
|
-
<LinkControl value={ { url: 'https://example.com' } } />,
|
|
183
|
-
container
|
|
184
|
-
);
|
|
185
|
-
} );
|
|
222
|
+
render( <LinkControl value={ { url: 'https://example.com' } } /> );
|
|
186
223
|
|
|
187
|
-
expect(
|
|
224
|
+
expect( getURLInput() ).not.toBeInTheDocument();
|
|
188
225
|
} );
|
|
189
226
|
|
|
190
227
|
it( 'true', () => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
container
|
|
198
|
-
);
|
|
199
|
-
} );
|
|
228
|
+
render(
|
|
229
|
+
<LinkControl
|
|
230
|
+
value={ { url: 'https://example.com' } }
|
|
231
|
+
forceIsEditingLink
|
|
232
|
+
/>
|
|
233
|
+
);
|
|
200
234
|
|
|
201
|
-
expect(
|
|
235
|
+
expect( getURLInput() ).toBeVisible();
|
|
202
236
|
} );
|
|
203
237
|
|
|
204
|
-
it( 'false', () => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
);
|
|
210
|
-
} );
|
|
238
|
+
it( 'false', async () => {
|
|
239
|
+
const user = userEvent.setup();
|
|
240
|
+
const { rerender } = render(
|
|
241
|
+
<LinkControl value={ { url: 'https://example.com' } } />
|
|
242
|
+
);
|
|
211
243
|
|
|
212
244
|
// Click the "Edit" button to trigger into the editing mode.
|
|
213
|
-
const editButton = queryByRole(
|
|
245
|
+
const editButton = screen.queryByRole( 'button', {
|
|
214
246
|
name: 'Edit',
|
|
215
247
|
} );
|
|
216
248
|
|
|
217
|
-
|
|
218
|
-
Simulate.click( editButton );
|
|
219
|
-
} );
|
|
249
|
+
await user.click( editButton );
|
|
220
250
|
|
|
221
|
-
expect(
|
|
251
|
+
expect( getURLInput() ).toBeVisible();
|
|
222
252
|
|
|
223
253
|
// If passed `forceIsEditingLink` of `false` while editing, should
|
|
224
254
|
// forcefully reset to the preview state.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
container
|
|
232
|
-
);
|
|
233
|
-
} );
|
|
255
|
+
rerender(
|
|
256
|
+
<LinkControl
|
|
257
|
+
value={ { url: 'https://example.com' } }
|
|
258
|
+
forceIsEditingLink={ false }
|
|
259
|
+
/>
|
|
260
|
+
);
|
|
234
261
|
|
|
235
|
-
expect(
|
|
262
|
+
expect( getURLInput() ).not.toBeInTheDocument();
|
|
236
263
|
} );
|
|
237
264
|
|
|
238
265
|
it( 'should display human friendly error message if value URL prop is empty when component is forced into no-editing (preview) mode', async () => {
|
|
@@ -249,65 +276,49 @@ describe( 'Basic rendering', () => {
|
|
|
249
276
|
type: 'post',
|
|
250
277
|
};
|
|
251
278
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
container
|
|
259
|
-
);
|
|
260
|
-
} );
|
|
279
|
+
render(
|
|
280
|
+
<LinkControl
|
|
281
|
+
value={ valueWithEmptyURL }
|
|
282
|
+
forceIsEditingLink={ false }
|
|
283
|
+
/>
|
|
284
|
+
);
|
|
261
285
|
|
|
262
|
-
const linkPreview =
|
|
263
|
-
name: 'Currently selected',
|
|
264
|
-
} );
|
|
286
|
+
const linkPreview = getCurrentLink();
|
|
265
287
|
|
|
266
288
|
const isPreviewError = linkPreview.classList.contains( 'is-error' );
|
|
267
289
|
expect( isPreviewError ).toBe( true );
|
|
268
290
|
|
|
269
|
-
expect( queryByText(
|
|
291
|
+
expect( screen.queryByText( 'Link is empty' ) ).toBeVisible();
|
|
270
292
|
} );
|
|
271
293
|
} );
|
|
272
294
|
|
|
273
295
|
describe( 'Unlinking', () => {
|
|
274
296
|
it( 'should not show "Unlink" button if no onRemove handler is provided', () => {
|
|
275
|
-
|
|
276
|
-
render(
|
|
277
|
-
<LinkControl value={ { url: 'https://example.com' } } />,
|
|
278
|
-
container
|
|
279
|
-
);
|
|
280
|
-
} );
|
|
297
|
+
render( <LinkControl value={ { url: 'https://example.com' } } /> );
|
|
281
298
|
|
|
282
|
-
const unLinkButton = queryByRole(
|
|
299
|
+
const unLinkButton = screen.queryByRole( 'button', {
|
|
283
300
|
name: 'Unlink',
|
|
284
301
|
} );
|
|
285
302
|
|
|
286
|
-
expect( unLinkButton ).toBeNull();
|
|
287
303
|
expect( unLinkButton ).not.toBeInTheDocument();
|
|
288
304
|
} );
|
|
289
305
|
|
|
290
|
-
it( 'should show "Unlink" button if a onRemove handler is provided', () => {
|
|
306
|
+
it( 'should show "Unlink" button if a onRemove handler is provided', async () => {
|
|
307
|
+
const user = userEvent.setup();
|
|
291
308
|
const mockOnRemove = jest.fn();
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
container
|
|
299
|
-
);
|
|
300
|
-
} );
|
|
309
|
+
render(
|
|
310
|
+
<LinkControl
|
|
311
|
+
value={ { url: 'https://example.com' } }
|
|
312
|
+
onRemove={ mockOnRemove }
|
|
313
|
+
/>
|
|
314
|
+
);
|
|
301
315
|
|
|
302
|
-
const unLinkButton = queryByRole(
|
|
316
|
+
const unLinkButton = screen.queryByRole( 'button', {
|
|
303
317
|
name: 'Unlink',
|
|
304
318
|
} );
|
|
305
|
-
expect( unLinkButton ).
|
|
306
|
-
expect( unLinkButton ).toBeInTheDocument();
|
|
319
|
+
expect( unLinkButton ).toBeVisible();
|
|
307
320
|
|
|
308
|
-
|
|
309
|
-
Simulate.click( unLinkButton );
|
|
310
|
-
} );
|
|
321
|
+
await user.click( unLinkButton );
|
|
311
322
|
|
|
312
323
|
expect( mockOnRemove ).toHaveBeenCalled();
|
|
313
324
|
} );
|
|
@@ -316,6 +327,7 @@ describe( 'Basic rendering', () => {
|
|
|
316
327
|
|
|
317
328
|
describe( 'Searching for a link', () => {
|
|
318
329
|
it( 'should display loading UI when input is valid but search results have yet to be returned', async () => {
|
|
330
|
+
const user = userEvent.setup();
|
|
319
331
|
const searchTerm = 'Hello';
|
|
320
332
|
|
|
321
333
|
let resolver;
|
|
@@ -327,28 +339,25 @@ describe( 'Searching for a link', () => {
|
|
|
327
339
|
|
|
328
340
|
mockFetchSearchSuggestions.mockImplementation( fauxRequest );
|
|
329
341
|
|
|
330
|
-
|
|
331
|
-
render( <LinkControl />, container );
|
|
332
|
-
} );
|
|
342
|
+
const { container } = render( <LinkControl /> );
|
|
333
343
|
|
|
334
344
|
// Search Input UI.
|
|
335
345
|
const searchInput = getURLInput();
|
|
336
346
|
|
|
337
347
|
// Simulate searching for a term.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
} );
|
|
348
|
+
searchInput.focus();
|
|
349
|
+
await user.keyboard( searchTerm );
|
|
341
350
|
|
|
342
351
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
343
352
|
await eventLoopTick();
|
|
344
353
|
|
|
345
|
-
const searchResultElements = getSearchResults();
|
|
354
|
+
const searchResultElements = getSearchResults( container );
|
|
346
355
|
|
|
347
|
-
let loadingUI =
|
|
356
|
+
let loadingUI = screen.queryByRole( 'presentation' );
|
|
348
357
|
|
|
349
358
|
expect( searchResultElements ).toHaveLength( 0 );
|
|
350
359
|
|
|
351
|
-
expect( loadingUI ).
|
|
360
|
+
expect( loadingUI ).toBeVisible();
|
|
352
361
|
|
|
353
362
|
act( () => {
|
|
354
363
|
resolver( fauxEntitySuggestions );
|
|
@@ -356,36 +365,29 @@ describe( 'Searching for a link', () => {
|
|
|
356
365
|
|
|
357
366
|
await eventLoopTick();
|
|
358
367
|
|
|
359
|
-
loadingUI =
|
|
368
|
+
loadingUI = screen.queryByRole( 'presentation' );
|
|
360
369
|
|
|
361
|
-
expect( loadingUI ).
|
|
370
|
+
expect( loadingUI ).not.toBeInTheDocument();
|
|
362
371
|
} );
|
|
363
372
|
|
|
364
373
|
it( 'should display only search suggestions when current input value is not URL-like', async () => {
|
|
374
|
+
const user = userEvent.setup();
|
|
365
375
|
const searchTerm = 'Hello world';
|
|
366
376
|
const firstFauxSuggestion = fauxEntitySuggestions[ 0 ];
|
|
367
377
|
|
|
368
|
-
|
|
369
|
-
render( <LinkControl />, container );
|
|
370
|
-
} );
|
|
378
|
+
const { container } = render( <LinkControl /> );
|
|
371
379
|
|
|
372
380
|
// Search Input UI.
|
|
373
381
|
const searchInput = getURLInput();
|
|
374
382
|
|
|
375
383
|
// Simulate searching for a term.
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
} );
|
|
384
|
+
searchInput.focus();
|
|
385
|
+
await user.keyboard( searchTerm );
|
|
379
386
|
|
|
380
387
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
381
388
|
await eventLoopTick();
|
|
382
|
-
// TODO: select these by aria relationship to autocomplete rather than arbitrary selector.
|
|
383
389
|
|
|
384
|
-
const searchResultElements = getSearchResults();
|
|
385
|
-
|
|
386
|
-
const firstSearchResultItemHTML = searchResultElements[ 0 ].innerHTML;
|
|
387
|
-
const lastSearchResultItemHTML =
|
|
388
|
-
searchResultElements[ searchResultElements.length - 1 ].innerHTML;
|
|
390
|
+
const searchResultElements = getSearchResults( container );
|
|
389
391
|
|
|
390
392
|
expect( searchResultElements ).toHaveLength(
|
|
391
393
|
fauxEntitySuggestions.length
|
|
@@ -394,35 +396,31 @@ describe( 'Searching for a link', () => {
|
|
|
394
396
|
expect( searchInput.getAttribute( 'aria-expanded' ) ).toBe( 'true' );
|
|
395
397
|
|
|
396
398
|
// Sanity check that a search suggestion shows up corresponding to the data.
|
|
397
|
-
expect(
|
|
398
|
-
|
|
399
|
+
expect( searchResultElements[ 0 ] ).toHaveTextContent(
|
|
400
|
+
firstFauxSuggestion.title
|
|
399
401
|
);
|
|
400
|
-
expect(
|
|
401
|
-
|
|
402
|
+
expect( searchResultElements[ 0 ] ).toHaveTextContent(
|
|
403
|
+
firstFauxSuggestion.type
|
|
402
404
|
);
|
|
403
405
|
|
|
404
406
|
// The fallback URL suggestion should not be shown when input is not URL-like.
|
|
405
|
-
expect(
|
|
406
|
-
|
|
407
|
-
);
|
|
407
|
+
expect(
|
|
408
|
+
searchResultElements[ searchResultElements.length - 1 ]
|
|
409
|
+
).not.toHaveTextContent( 'URL' );
|
|
408
410
|
} );
|
|
409
411
|
|
|
410
412
|
it( 'should trim search term', async () => {
|
|
413
|
+
const user = userEvent.setup();
|
|
411
414
|
const searchTerm = ' Hello ';
|
|
412
415
|
|
|
413
|
-
|
|
414
|
-
render( <LinkControl />, container );
|
|
415
|
-
} );
|
|
416
|
+
const { container } = render( <LinkControl /> );
|
|
416
417
|
|
|
417
418
|
// Search Input UI.
|
|
418
|
-
const searchInput =
|
|
419
|
-
'input[aria-label="URL"]'
|
|
420
|
-
);
|
|
419
|
+
const searchInput = getURLInput();
|
|
421
420
|
|
|
422
421
|
// Simulate searching for a term.
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
} );
|
|
422
|
+
searchInput.focus();
|
|
423
|
+
await user.keyboard( searchTerm );
|
|
426
424
|
|
|
427
425
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
428
426
|
await eventLoopTick();
|
|
@@ -437,11 +435,6 @@ describe( 'Searching for a link', () => {
|
|
|
437
435
|
( mark ) => mark.innerHTML !== 'Hello'
|
|
438
436
|
);
|
|
439
437
|
|
|
440
|
-
// Grab the first argument that was passed to the fetchSuggestions
|
|
441
|
-
// handler (which is mocked out).
|
|
442
|
-
const mockFetchSuggestionsFirstArg =
|
|
443
|
-
mockFetchSearchSuggestions.mock.calls[ 0 ][ 0 ];
|
|
444
|
-
|
|
445
438
|
// Given we're mocking out the results we should always have 4 mark elements.
|
|
446
439
|
expect( searchResultTextHighlightElements ).toHaveLength( 4 );
|
|
447
440
|
|
|
@@ -453,30 +446,30 @@ describe( 'Searching for a link', () => {
|
|
|
453
446
|
// with the trimmed search value. We do this because we are mocking out
|
|
454
447
|
// the fetch handler in our test so we need to assert it would be called
|
|
455
448
|
// correctly in a real world scenario.
|
|
456
|
-
expect(
|
|
449
|
+
expect( mockFetchSearchSuggestions ).toHaveBeenCalledWith(
|
|
450
|
+
'Hello',
|
|
451
|
+
expect.anything()
|
|
452
|
+
);
|
|
457
453
|
} );
|
|
458
454
|
|
|
459
455
|
it( 'should not call search handler when showSuggestions is false', async () => {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
456
|
+
const user = userEvent.setup();
|
|
457
|
+
const { container } = render(
|
|
458
|
+
<LinkControl showSuggestions={ false } />
|
|
459
|
+
);
|
|
463
460
|
|
|
464
461
|
// Search Input UI.
|
|
465
462
|
const searchInput = getURLInput();
|
|
466
463
|
|
|
467
464
|
// Simulate searching for a term.
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
target: { value: 'anything' },
|
|
471
|
-
} );
|
|
472
|
-
} );
|
|
465
|
+
searchInput.focus();
|
|
466
|
+
await user.keyboard( 'anything' );
|
|
473
467
|
|
|
474
|
-
const searchResultElements = getSearchResults();
|
|
468
|
+
const searchResultElements = getSearchResults( container );
|
|
475
469
|
|
|
476
470
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
477
471
|
await eventLoopTick();
|
|
478
472
|
|
|
479
|
-
// TODO: select these by aria relationship to autocomplete rather than arbitrary selector.
|
|
480
473
|
expect( searchResultElements ).toHaveLength( 0 );
|
|
481
474
|
expect( mockFetchSearchSuggestions ).not.toHaveBeenCalled();
|
|
482
475
|
} );
|
|
@@ -487,71 +480,54 @@ describe( 'Searching for a link', () => {
|
|
|
487
480
|
] )(
|
|
488
481
|
'should display a URL suggestion as a default fallback for the search term "%s" which could potentially be a valid url.',
|
|
489
482
|
async ( searchTerm ) => {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
} );
|
|
483
|
+
const user = userEvent.setup();
|
|
484
|
+
const { container } = render( <LinkControl /> );
|
|
493
485
|
|
|
494
486
|
// Search Input UI.
|
|
495
487
|
const searchInput = getURLInput();
|
|
496
488
|
|
|
497
489
|
// Simulate searching for a term.
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
target: { value: searchTerm },
|
|
501
|
-
} );
|
|
502
|
-
} );
|
|
490
|
+
searchInput.focus();
|
|
491
|
+
await user.keyboard( searchTerm );
|
|
503
492
|
|
|
504
493
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
505
494
|
await eventLoopTick();
|
|
506
|
-
// TODO: select these by aria relationship to autocomplete rather than arbitrary selector.
|
|
507
495
|
|
|
508
|
-
const searchResultElements = getSearchResults();
|
|
496
|
+
const searchResultElements = getSearchResults( container );
|
|
509
497
|
|
|
510
|
-
const
|
|
511
|
-
searchResultElements[ searchResultElements.length - 1 ]
|
|
512
|
-
.innerHTML;
|
|
513
|
-
const additionalDefaultFallbackURLSuggestionLength = 1;
|
|
498
|
+
const lastSearchResultItem =
|
|
499
|
+
searchResultElements[ searchResultElements.length - 1 ];
|
|
514
500
|
|
|
515
501
|
// We should see a search result for each of the expect search suggestions
|
|
516
502
|
// plus 1 additional one for the fallback URL suggestion.
|
|
517
503
|
expect( searchResultElements ).toHaveLength(
|
|
518
|
-
fauxEntitySuggestions.length +
|
|
519
|
-
additionalDefaultFallbackURLSuggestionLength
|
|
504
|
+
fauxEntitySuggestions.length + 1
|
|
520
505
|
);
|
|
521
506
|
|
|
522
507
|
// The last item should be a URL search suggestion.
|
|
523
|
-
expect(
|
|
524
|
-
|
|
525
|
-
)
|
|
526
|
-
|
|
527
|
-
expect.stringContaining( 'URL' )
|
|
528
|
-
);
|
|
529
|
-
expect( lastSearchResultItemHTML ).toEqual(
|
|
530
|
-
expect.stringContaining( 'Press ENTER to add this link' )
|
|
508
|
+
expect( lastSearchResultItem ).toHaveTextContent( searchTerm );
|
|
509
|
+
expect( lastSearchResultItem ).toHaveTextContent( 'URL' );
|
|
510
|
+
expect( lastSearchResultItem ).toHaveTextContent(
|
|
511
|
+
'Press ENTER to add this link'
|
|
531
512
|
);
|
|
532
513
|
}
|
|
533
514
|
);
|
|
534
515
|
|
|
535
516
|
it( 'should not display a URL suggestion as a default fallback when noURLSuggestion is passed.', async () => {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
} );
|
|
517
|
+
const user = userEvent.setup();
|
|
518
|
+
const { container } = render( <LinkControl noURLSuggestion /> );
|
|
539
519
|
|
|
540
520
|
// Search Input UI.
|
|
541
521
|
const searchInput = getURLInput();
|
|
542
522
|
|
|
543
523
|
// Simulate searching for a term.
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
target: { value: 'couldbeurlorentitysearchterm' },
|
|
547
|
-
} );
|
|
548
|
-
} );
|
|
524
|
+
searchInput.focus();
|
|
525
|
+
await user.keyboard( 'couldbeurlorentitysearchterm' );
|
|
549
526
|
|
|
550
527
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
551
528
|
await eventLoopTick();
|
|
552
|
-
// TODO: select these by aria relationship to autocomplete rather than arbitrary selector.
|
|
553
529
|
|
|
554
|
-
const searchResultElements = getSearchResults();
|
|
530
|
+
const searchResultElements = getSearchResults( container );
|
|
555
531
|
|
|
556
532
|
// We should see a search result for each of the expect search suggestions and nothing else.
|
|
557
533
|
expect( searchResultElements ).toHaveLength(
|
|
@@ -568,40 +544,26 @@ describe( 'Manual link entry', () => {
|
|
|
568
544
|
] )(
|
|
569
545
|
'should display a single suggestion result when the current input value is URL-like (eg: %s)',
|
|
570
546
|
async ( searchTerm ) => {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
} );
|
|
547
|
+
const user = userEvent.setup();
|
|
548
|
+
const { container } = render( <LinkControl /> );
|
|
574
549
|
|
|
575
550
|
// Search Input UI.
|
|
576
551
|
const searchInput = getURLInput();
|
|
577
552
|
|
|
578
553
|
// Simulate searching for a term.
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
target: { value: searchTerm },
|
|
582
|
-
} );
|
|
583
|
-
} );
|
|
554
|
+
searchInput.focus();
|
|
555
|
+
await user.keyboard( searchTerm );
|
|
584
556
|
|
|
585
557
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
586
558
|
await eventLoopTick();
|
|
587
559
|
|
|
588
|
-
const searchResultElements = getSearchResults();
|
|
560
|
+
const searchResultElements = getSearchResults( container );
|
|
589
561
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
expectedResultsLength
|
|
596
|
-
);
|
|
597
|
-
expect( firstSearchResultItemHTML ).toEqual(
|
|
598
|
-
expect.stringContaining( searchTerm )
|
|
599
|
-
);
|
|
600
|
-
expect( firstSearchResultItemHTML ).toEqual(
|
|
601
|
-
expect.stringContaining( 'URL' )
|
|
602
|
-
);
|
|
603
|
-
expect( firstSearchResultItemHTML ).toEqual(
|
|
604
|
-
expect.stringContaining( 'Press ENTER to add this link' )
|
|
562
|
+
expect( searchResultElements ).toHaveLength( 1 );
|
|
563
|
+
expect( searchResultElements[ 0 ] ).toHaveTextContent( searchTerm );
|
|
564
|
+
expect( searchResultElements[ 0 ] ).toHaveTextContent( 'URL' );
|
|
565
|
+
expect( searchResultElements[ 0 ] ).toHaveTextContent(
|
|
566
|
+
'Press ENTER to add this link'
|
|
605
567
|
);
|
|
606
568
|
}
|
|
607
569
|
);
|
|
@@ -609,97 +571,94 @@ describe( 'Manual link entry', () => {
|
|
|
609
571
|
describe( 'Handling of empty values', () => {
|
|
610
572
|
const testTable = [
|
|
611
573
|
[ 'containing only spaces', ' ' ],
|
|
612
|
-
[ 'containing only tabs', '
|
|
574
|
+
[ 'containing only tabs', '[Tab]' ],
|
|
613
575
|
[ 'from strings with no length', '' ],
|
|
614
576
|
];
|
|
615
577
|
|
|
616
578
|
it.each( testTable )(
|
|
617
579
|
'should not allow creation of links %s when using the keyboard',
|
|
618
580
|
async ( _desc, searchString ) => {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
581
|
+
const user = userEvent.setup();
|
|
582
|
+
|
|
583
|
+
render( <LinkControl /> );
|
|
622
584
|
|
|
623
585
|
// Search Input UI.
|
|
624
586
|
const searchInput = getURLInput();
|
|
625
587
|
|
|
626
|
-
let submitButton = queryByRole(
|
|
588
|
+
let submitButton = screen.queryByRole( 'button', {
|
|
627
589
|
name: 'Submit',
|
|
628
590
|
} );
|
|
629
591
|
|
|
630
|
-
expect( submitButton
|
|
631
|
-
expect( submitButton ).
|
|
632
|
-
expect( submitButton ).toBeInTheDocument();
|
|
592
|
+
expect( submitButton ).toBeDisabled();
|
|
593
|
+
expect( submitButton ).toBeVisible();
|
|
633
594
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
Simulate
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
595
|
+
searchInput.focus();
|
|
596
|
+
if ( searchString.length ) {
|
|
597
|
+
// Simulate searching for a term.
|
|
598
|
+
await user.keyboard( searchString );
|
|
599
|
+
} else {
|
|
600
|
+
// Simulate clearing the search term.
|
|
601
|
+
await userEvent.clear( searchInput );
|
|
602
|
+
}
|
|
640
603
|
|
|
641
604
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
642
605
|
await eventLoopTick();
|
|
643
606
|
|
|
644
607
|
// Attempt to submit the empty search value in the input.
|
|
645
|
-
|
|
646
|
-
Simulate.keyDown( searchInput, { keyCode: ENTER } );
|
|
647
|
-
} );
|
|
608
|
+
await user.keyboard( '[Enter]' );
|
|
648
609
|
|
|
649
|
-
submitButton = queryByRole(
|
|
610
|
+
submitButton = screen.queryByRole( 'button', {
|
|
650
611
|
name: 'Submit',
|
|
651
612
|
} );
|
|
652
613
|
|
|
653
614
|
// Verify the UI hasn't allowed submission.
|
|
654
615
|
expect( searchInput ).toBeInTheDocument();
|
|
655
|
-
expect( submitButton
|
|
656
|
-
expect( submitButton ).
|
|
657
|
-
expect( submitButton ).toBeInTheDocument();
|
|
616
|
+
expect( submitButton ).toBeDisabled();
|
|
617
|
+
expect( submitButton ).toBeVisible();
|
|
658
618
|
}
|
|
659
619
|
);
|
|
660
620
|
|
|
661
621
|
it.each( testTable )(
|
|
662
622
|
'should not allow creation of links %s via the UI "submit" button',
|
|
663
623
|
async ( _desc, searchString ) => {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
624
|
+
const user = userEvent.setup();
|
|
625
|
+
|
|
626
|
+
render( <LinkControl /> );
|
|
667
627
|
|
|
668
628
|
// Search Input UI.
|
|
669
629
|
const searchInput = getURLInput();
|
|
670
630
|
|
|
671
|
-
let submitButton = queryByRole(
|
|
631
|
+
let submitButton = screen.queryByRole( 'button', {
|
|
672
632
|
name: 'Submit',
|
|
673
633
|
} );
|
|
674
634
|
|
|
675
|
-
expect( submitButton
|
|
676
|
-
expect( submitButton ).
|
|
677
|
-
expect( submitButton ).toBeInTheDocument();
|
|
635
|
+
expect( submitButton ).toBeDisabled();
|
|
636
|
+
expect( submitButton ).toBeVisible();
|
|
678
637
|
|
|
679
638
|
// Simulate searching for a term.
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
}
|
|
639
|
+
searchInput.focus();
|
|
640
|
+
if ( searchString.length ) {
|
|
641
|
+
// Simulate searching for a term.
|
|
642
|
+
await user.keyboard( searchString );
|
|
643
|
+
} else {
|
|
644
|
+
// Simulate clearing the search term.
|
|
645
|
+
await userEvent.clear( searchInput );
|
|
646
|
+
}
|
|
685
647
|
|
|
686
648
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
687
649
|
await eventLoopTick();
|
|
688
650
|
|
|
689
651
|
// Attempt to submit the empty search value in the input.
|
|
690
|
-
|
|
691
|
-
Simulate.click( submitButton );
|
|
692
|
-
} );
|
|
652
|
+
await user.click( submitButton );
|
|
693
653
|
|
|
694
|
-
submitButton = queryByRole(
|
|
654
|
+
submitButton = screen.queryByRole( 'button', {
|
|
695
655
|
name: 'Submit',
|
|
696
656
|
} );
|
|
697
657
|
|
|
698
658
|
// Verify the UI hasn't allowed submission.
|
|
699
659
|
expect( searchInput ).toBeInTheDocument();
|
|
700
|
-
expect( submitButton
|
|
701
|
-
expect( submitButton ).
|
|
702
|
-
expect( submitButton ).toBeInTheDocument();
|
|
660
|
+
expect( submitButton ).toBeDisabled();
|
|
661
|
+
expect( submitButton ).toBeVisible();
|
|
703
662
|
}
|
|
704
663
|
);
|
|
705
664
|
} );
|
|
@@ -712,40 +671,30 @@ describe( 'Manual link entry', () => {
|
|
|
712
671
|
] )(
|
|
713
672
|
'should recognise "%s" as a %s link and handle as manual entry by displaying a single suggestion',
|
|
714
673
|
async ( searchTerm, searchType ) => {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
} );
|
|
674
|
+
const user = userEvent.setup();
|
|
675
|
+
const { container } = render( <LinkControl /> );
|
|
718
676
|
|
|
719
677
|
// Search Input UI.
|
|
720
678
|
const searchInput = getURLInput();
|
|
721
679
|
|
|
722
680
|
// Simulate searching for a term.
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
target: { value: searchTerm },
|
|
726
|
-
} );
|
|
727
|
-
} );
|
|
681
|
+
searchInput.focus();
|
|
682
|
+
await user.keyboard( searchTerm );
|
|
728
683
|
|
|
729
684
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
730
685
|
await eventLoopTick();
|
|
731
686
|
|
|
732
|
-
const searchResultElements = getSearchResults();
|
|
687
|
+
const searchResultElements = getSearchResults( container );
|
|
733
688
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
expect( searchResultElements ).toHaveLength(
|
|
739
|
-
expectedResultsLength
|
|
740
|
-
);
|
|
741
|
-
expect( firstSearchResultItemHTML ).toEqual(
|
|
742
|
-
expect.stringContaining( searchTerm )
|
|
689
|
+
expect( searchResultElements ).toHaveLength( 1 );
|
|
690
|
+
expect( searchResultElements[ 0 ] ).toHaveTextContent(
|
|
691
|
+
searchTerm
|
|
743
692
|
);
|
|
744
|
-
expect(
|
|
745
|
-
|
|
693
|
+
expect( searchResultElements[ 0 ] ).toHaveTextContent(
|
|
694
|
+
searchType
|
|
746
695
|
);
|
|
747
|
-
expect(
|
|
748
|
-
|
|
696
|
+
expect( searchResultElements[ 0 ] ).toHaveTextContent(
|
|
697
|
+
'Press ENTER to add this link'
|
|
749
698
|
);
|
|
750
699
|
}
|
|
751
700
|
);
|
|
@@ -756,27 +705,20 @@ describe( 'Default search suggestions', () => {
|
|
|
756
705
|
it( 'should display a list of initial search suggestions when there is no search value or suggestions', async () => {
|
|
757
706
|
const expectedResultsLength = 3; // Set within `LinkControl`.
|
|
758
707
|
|
|
759
|
-
|
|
760
|
-
render( <LinkControl showInitialSuggestions />, container );
|
|
761
|
-
} );
|
|
708
|
+
render( <LinkControl showInitialSuggestions /> );
|
|
762
709
|
|
|
763
710
|
await eventLoopTick();
|
|
764
711
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
const initialSearchResultElements =
|
|
771
|
-
searchResultsWrapper.querySelectorAll( '[role="option"]' );
|
|
772
|
-
|
|
773
|
-
const searchResultsLabel = container.querySelector(
|
|
774
|
-
`#${ searchResultsWrapper.getAttribute( 'aria-labelledby' ) }`
|
|
775
|
-
);
|
|
712
|
+
expect(
|
|
713
|
+
screen.queryByRole( 'listbox', {
|
|
714
|
+
name: 'Recently updated',
|
|
715
|
+
} )
|
|
716
|
+
).toBeVisible();
|
|
776
717
|
|
|
777
718
|
// Verify input has no value has default suggestions should only show
|
|
778
719
|
// when this does not have a value.
|
|
779
|
-
|
|
720
|
+
// Search Input UI.
|
|
721
|
+
expect( getURLInput() ).toHaveValue( '' );
|
|
780
722
|
|
|
781
723
|
// Ensure only called once as a guard against potential infinite
|
|
782
724
|
// re-render loop within `componentDidUpdate` calling `updateSuggestions`
|
|
@@ -784,25 +726,22 @@ describe( 'Default search suggestions', () => {
|
|
|
784
726
|
expect( mockFetchSearchSuggestions ).toHaveBeenCalledTimes( 1 );
|
|
785
727
|
|
|
786
728
|
// Verify the search results already display the initial suggestions.
|
|
787
|
-
expect(
|
|
729
|
+
expect( screen.queryAllByRole( 'option' ) ).toHaveLength(
|
|
788
730
|
expectedResultsLength
|
|
789
731
|
);
|
|
790
|
-
|
|
791
|
-
expect( searchResultsLabel.innerHTML ).toEqual( 'Recently updated' );
|
|
792
732
|
} );
|
|
793
733
|
|
|
794
734
|
it( 'should not display initial suggestions when input value is present', async () => {
|
|
735
|
+
const user = userEvent.setup();
|
|
736
|
+
|
|
795
737
|
// Render with an initial value an ensure that no initial suggestions
|
|
796
738
|
// are shown.
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
container
|
|
804
|
-
);
|
|
805
|
-
} );
|
|
739
|
+
const { container } = render(
|
|
740
|
+
<LinkControl
|
|
741
|
+
showInitialSuggestions
|
|
742
|
+
value={ fauxEntitySuggestions[ 0 ] }
|
|
743
|
+
/>
|
|
744
|
+
);
|
|
806
745
|
|
|
807
746
|
await eventLoopTick();
|
|
808
747
|
|
|
@@ -813,34 +752,31 @@ describe( 'Default search suggestions', () => {
|
|
|
813
752
|
const currentLinkUI = getCurrentLink();
|
|
814
753
|
const currentLinkBtn = currentLinkUI.querySelector( 'button' );
|
|
815
754
|
|
|
816
|
-
|
|
817
|
-
Simulate.click( currentLinkBtn );
|
|
818
|
-
} );
|
|
755
|
+
await user.click( currentLinkBtn );
|
|
819
756
|
|
|
820
757
|
const searchInput = getURLInput();
|
|
821
758
|
searchInput.focus();
|
|
822
759
|
|
|
823
760
|
await eventLoopTick();
|
|
824
761
|
|
|
825
|
-
const searchResultElements = getSearchResults();
|
|
762
|
+
const searchResultElements = getSearchResults( container );
|
|
826
763
|
|
|
827
764
|
// Search input is set to the URL value.
|
|
828
|
-
expect( searchInput
|
|
765
|
+
expect( searchInput ).toHaveValue( fauxEntitySuggestions[ 0 ].url );
|
|
829
766
|
|
|
830
767
|
// It should match any url that's like ?p= and also include a URL option.
|
|
831
768
|
expect( searchResultElements ).toHaveLength( 5 );
|
|
832
769
|
|
|
833
|
-
expect( searchInput.
|
|
770
|
+
expect( searchInput ).toHaveAttribute( 'aria-expanded', 'true' );
|
|
834
771
|
|
|
835
772
|
expect( mockFetchSearchSuggestions ).toHaveBeenCalledTimes( 1 );
|
|
836
773
|
} );
|
|
837
774
|
|
|
838
775
|
it( 'should display initial suggestions when input value is manually deleted', async () => {
|
|
776
|
+
const user = userEvent.setup();
|
|
839
777
|
const searchTerm = 'Hello world';
|
|
840
778
|
|
|
841
|
-
|
|
842
|
-
render( <LinkControl showInitialSuggestions />, container );
|
|
843
|
-
} );
|
|
779
|
+
const { container } = render( <LinkControl showInitialSuggestions /> );
|
|
844
780
|
|
|
845
781
|
let searchResultElements;
|
|
846
782
|
let searchInput;
|
|
@@ -849,36 +785,33 @@ describe( 'Default search suggestions', () => {
|
|
|
849
785
|
searchInput = getURLInput();
|
|
850
786
|
|
|
851
787
|
// Simulate searching for a term.
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
} );
|
|
788
|
+
searchInput.focus();
|
|
789
|
+
await user.keyboard( searchTerm );
|
|
855
790
|
|
|
856
791
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
857
792
|
await eventLoopTick();
|
|
858
793
|
|
|
859
|
-
expect( searchInput
|
|
794
|
+
expect( searchInput ).toHaveValue( searchTerm );
|
|
860
795
|
|
|
861
|
-
searchResultElements = getSearchResults();
|
|
796
|
+
searchResultElements = getSearchResults( container );
|
|
862
797
|
|
|
863
798
|
// Delete the text.
|
|
864
|
-
|
|
865
|
-
Simulate.change( searchInput, { target: { value: '' } } );
|
|
866
|
-
} );
|
|
799
|
+
await userEvent.clear( searchInput );
|
|
867
800
|
|
|
868
801
|
await eventLoopTick();
|
|
869
802
|
|
|
870
|
-
searchResultElements = getSearchResults();
|
|
803
|
+
searchResultElements = getSearchResults( container );
|
|
871
804
|
|
|
872
805
|
searchInput = getURLInput();
|
|
873
806
|
|
|
874
807
|
// Check the input is empty now.
|
|
875
|
-
expect( searchInput
|
|
808
|
+
expect( searchInput ).toHaveValue( '' );
|
|
876
809
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
810
|
+
expect(
|
|
811
|
+
screen.queryByRole( 'listbox', {
|
|
812
|
+
name: 'Recently updated',
|
|
813
|
+
} )
|
|
814
|
+
).toBeVisible();
|
|
882
815
|
|
|
883
816
|
expect( searchResultElements ).toHaveLength( 3 );
|
|
884
817
|
} );
|
|
@@ -890,25 +823,23 @@ describe( 'Default search suggestions', () => {
|
|
|
890
823
|
Promise.resolve( noResults )
|
|
891
824
|
);
|
|
892
825
|
|
|
893
|
-
|
|
894
|
-
render( <LinkControl showInitialSuggestions />, container );
|
|
895
|
-
} );
|
|
826
|
+
const { container } = render( <LinkControl showInitialSuggestions /> );
|
|
896
827
|
|
|
897
828
|
await eventLoopTick();
|
|
898
829
|
|
|
899
830
|
const searchInput = getURLInput();
|
|
900
831
|
|
|
901
|
-
const searchResultElements = getSearchResults();
|
|
832
|
+
const searchResultElements = getSearchResults( container );
|
|
902
833
|
|
|
903
834
|
const searchResultLabel = container.querySelector(
|
|
904
835
|
'.block-editor-link-control__search-results-label'
|
|
905
836
|
);
|
|
906
837
|
|
|
907
|
-
expect( searchResultLabel ).
|
|
838
|
+
expect( searchResultLabel ).not.toBeInTheDocument();
|
|
908
839
|
|
|
909
840
|
expect( searchResultElements ).toHaveLength( 0 );
|
|
910
841
|
|
|
911
|
-
expect( searchInput.
|
|
842
|
+
expect( searchInput ).toHaveAttribute( 'aria-expanded', 'false' );
|
|
912
843
|
} );
|
|
913
844
|
} );
|
|
914
845
|
|
|
@@ -928,6 +859,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
928
859
|
] )(
|
|
929
860
|
'should allow creating a link for a valid Entity title "%s" (%s)',
|
|
930
861
|
async ( entityNameText ) => {
|
|
862
|
+
const user = userEvent.setup();
|
|
931
863
|
let resolver;
|
|
932
864
|
let resolvedEntity;
|
|
933
865
|
|
|
@@ -958,43 +890,29 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
958
890
|
);
|
|
959
891
|
};
|
|
960
892
|
|
|
961
|
-
|
|
962
|
-
render( <LinkControlConsumer />, container );
|
|
963
|
-
} );
|
|
893
|
+
const { container } = render( <LinkControlConsumer /> );
|
|
964
894
|
|
|
965
895
|
// Search Input UI.
|
|
966
|
-
const searchInput =
|
|
967
|
-
'input[aria-label="URL"]'
|
|
968
|
-
);
|
|
896
|
+
const searchInput = getURLInput();
|
|
969
897
|
|
|
970
898
|
// Simulate searching for a term.
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
target: { value: entityNameText },
|
|
974
|
-
} );
|
|
975
|
-
} );
|
|
899
|
+
searchInput.focus();
|
|
900
|
+
await user.keyboard( entityNameText );
|
|
976
901
|
|
|
977
902
|
await eventLoopTick();
|
|
978
903
|
|
|
979
|
-
|
|
980
|
-
const searchResultElements = container.querySelectorAll(
|
|
981
|
-
'[role="listbox"] [role="option"]'
|
|
982
|
-
);
|
|
904
|
+
const searchResultElements = screen.queryAllByRole( 'option' );
|
|
983
905
|
|
|
984
906
|
const createButton = Array.from( searchResultElements ).filter(
|
|
985
907
|
( result ) => result.innerHTML.includes( 'Create:' )
|
|
986
908
|
)[ 0 ];
|
|
987
909
|
|
|
988
|
-
expect( createButton ).
|
|
989
|
-
expect( createButton
|
|
990
|
-
expect.stringContaining( entityNameText )
|
|
991
|
-
);
|
|
910
|
+
expect( createButton ).toBeVisible();
|
|
911
|
+
expect( createButton ).toHaveTextContent( entityNameText );
|
|
992
912
|
|
|
993
913
|
// No need to wait in this test because we control the Promise
|
|
994
914
|
// resolution manually via the `resolver` reference.
|
|
995
|
-
|
|
996
|
-
Simulate.click( createButton );
|
|
997
|
-
} );
|
|
915
|
+
await user.click( createButton );
|
|
998
916
|
|
|
999
917
|
await eventLoopTick();
|
|
1000
918
|
|
|
@@ -1002,14 +920,10 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1002
920
|
const loadingIndicator = container.querySelector(
|
|
1003
921
|
'.block-editor-link-control__loading'
|
|
1004
922
|
);
|
|
1005
|
-
const currentLinkLabel =
|
|
1006
|
-
'[aria-label="Currently selected"]'
|
|
1007
|
-
);
|
|
923
|
+
const currentLinkLabel = getCurrentLink();
|
|
1008
924
|
|
|
1009
|
-
expect( currentLinkLabel ).
|
|
1010
|
-
expect( loadingIndicator
|
|
1011
|
-
expect.stringContaining( 'Creating' )
|
|
1012
|
-
);
|
|
925
|
+
expect( currentLinkLabel ).not.toBeInTheDocument();
|
|
926
|
+
expect( loadingIndicator ).toHaveTextContent( 'Creating' );
|
|
1013
927
|
|
|
1014
928
|
// Resolve the `createSuggestion` promise.
|
|
1015
929
|
await act( async () => {
|
|
@@ -1018,22 +932,15 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1018
932
|
|
|
1019
933
|
await eventLoopTick();
|
|
1020
934
|
|
|
1021
|
-
const currentLink =
|
|
1022
|
-
'[aria-label="Currently selected"]'
|
|
1023
|
-
);
|
|
1024
|
-
|
|
1025
|
-
const currentLinkHTML = currentLink.innerHTML;
|
|
935
|
+
const currentLink = getCurrentLink();
|
|
1026
936
|
|
|
1027
|
-
expect(
|
|
1028
|
-
|
|
1029
|
-
);
|
|
1030
|
-
expect( currentLinkHTML ).toEqual(
|
|
1031
|
-
expect.stringContaining( '/?p=123' )
|
|
1032
|
-
);
|
|
937
|
+
expect( currentLink ).toHaveTextContent( entityNameText );
|
|
938
|
+
expect( currentLink ).toHaveTextContent( '/?p=123' );
|
|
1033
939
|
}
|
|
1034
940
|
);
|
|
1035
941
|
|
|
1036
942
|
it( 'should allow createSuggestion prop to return a non-Promise value', async () => {
|
|
943
|
+
const user = userEvent.setup();
|
|
1037
944
|
const LinkControlConsumer = () => {
|
|
1038
945
|
const [ link, setLink ] = useState( null );
|
|
1039
946
|
|
|
@@ -1053,21 +960,14 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1053
960
|
);
|
|
1054
961
|
};
|
|
1055
962
|
|
|
1056
|
-
|
|
1057
|
-
render( <LinkControlConsumer />, container );
|
|
1058
|
-
} );
|
|
963
|
+
const { container } = render( <LinkControlConsumer /> );
|
|
1059
964
|
|
|
1060
965
|
// Search Input UI.
|
|
1061
|
-
const searchInput =
|
|
1062
|
-
'input[aria-label="URL"]'
|
|
1063
|
-
);
|
|
966
|
+
const searchInput = getURLInput();
|
|
1064
967
|
|
|
1065
968
|
// Simulate searching for a term.
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
target: { value: 'Some new page to create' },
|
|
1069
|
-
} );
|
|
1070
|
-
} );
|
|
969
|
+
searchInput.focus();
|
|
970
|
+
await user.keyboard( 'Some new page to create' );
|
|
1071
971
|
|
|
1072
972
|
await eventLoopTick();
|
|
1073
973
|
|
|
@@ -1080,27 +980,18 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1080
980
|
( result ) => result.innerHTML.includes( 'Create:' )
|
|
1081
981
|
)[ 0 ];
|
|
1082
982
|
|
|
1083
|
-
await
|
|
1084
|
-
Simulate.click( createButton );
|
|
1085
|
-
} );
|
|
983
|
+
await user.click( createButton );
|
|
1086
984
|
|
|
1087
985
|
await eventLoopTick();
|
|
1088
986
|
|
|
1089
|
-
const currentLink =
|
|
1090
|
-
'[aria-label="Currently selected"]'
|
|
1091
|
-
);
|
|
1092
|
-
|
|
1093
|
-
const currentLinkHTML = currentLink.innerHTML;
|
|
987
|
+
const currentLink = getCurrentLink();
|
|
1094
988
|
|
|
1095
|
-
expect(
|
|
1096
|
-
|
|
1097
|
-
);
|
|
1098
|
-
expect( currentLinkHTML ).toEqual(
|
|
1099
|
-
expect.stringContaining( '/?p=123' )
|
|
1100
|
-
);
|
|
989
|
+
expect( currentLink ).toHaveTextContent( 'Some new page to create' );
|
|
990
|
+
expect( currentLink ).toHaveTextContent( '/?p=123' );
|
|
1101
991
|
} );
|
|
1102
992
|
|
|
1103
993
|
it( 'should allow creation of entities via the keyboard', async () => {
|
|
994
|
+
const user = userEvent.setup();
|
|
1104
995
|
const entityNameText = 'A new page to be created';
|
|
1105
996
|
|
|
1106
997
|
const LinkControlConsumer = () => {
|
|
@@ -1124,21 +1015,14 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1124
1015
|
);
|
|
1125
1016
|
};
|
|
1126
1017
|
|
|
1127
|
-
|
|
1128
|
-
render( <LinkControlConsumer />, container );
|
|
1129
|
-
} );
|
|
1018
|
+
const { container } = render( <LinkControlConsumer /> );
|
|
1130
1019
|
|
|
1131
1020
|
// Search Input UI.
|
|
1132
|
-
const searchInput =
|
|
1133
|
-
'input[aria-label="URL"]'
|
|
1134
|
-
);
|
|
1021
|
+
const searchInput = getURLInput();
|
|
1135
1022
|
|
|
1136
1023
|
// Simulate searching for a term.
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
target: { value: entityNameText },
|
|
1140
|
-
} );
|
|
1141
|
-
} );
|
|
1024
|
+
searchInput.focus();
|
|
1025
|
+
await user.keyboard( entityNameText );
|
|
1142
1026
|
|
|
1143
1027
|
await eventLoopTick();
|
|
1144
1028
|
|
|
@@ -1151,32 +1035,21 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1151
1035
|
)[ 0 ];
|
|
1152
1036
|
|
|
1153
1037
|
// Step down into the search results, highlighting the first result item.
|
|
1154
|
-
|
|
1155
|
-
Simulate.keyDown( searchInput, { keyCode: DOWN } );
|
|
1156
|
-
} );
|
|
1038
|
+
triggerArrowDown( searchInput );
|
|
1157
1039
|
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
} );
|
|
1040
|
+
createButton.focus();
|
|
1041
|
+
await user.keyboard( '[Enter]' );
|
|
1161
1042
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
} );
|
|
1043
|
+
searchInput.focus();
|
|
1044
|
+
await user.keyboard( '[Enter]' );
|
|
1165
1045
|
|
|
1166
1046
|
await eventLoopTick();
|
|
1167
1047
|
|
|
1168
|
-
|
|
1169
|
-
'[aria-label="Currently selected"]'
|
|
1170
|
-
);
|
|
1171
|
-
|
|
1172
|
-
const currentLinkHTML = currentLink.innerHTML;
|
|
1173
|
-
|
|
1174
|
-
expect( currentLinkHTML ).toEqual(
|
|
1175
|
-
expect.stringContaining( entityNameText )
|
|
1176
|
-
);
|
|
1048
|
+
expect( getCurrentLink() ).toHaveTextContent( entityNameText );
|
|
1177
1049
|
} );
|
|
1178
1050
|
|
|
1179
1051
|
it( 'should allow customisation of button text', async () => {
|
|
1052
|
+
const user = userEvent.setup();
|
|
1180
1053
|
const entityNameText = 'A new page to be created';
|
|
1181
1054
|
|
|
1182
1055
|
const LinkControlConsumer = () => {
|
|
@@ -1188,21 +1061,14 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1188
1061
|
);
|
|
1189
1062
|
};
|
|
1190
1063
|
|
|
1191
|
-
|
|
1192
|
-
render( <LinkControlConsumer />, container );
|
|
1193
|
-
} );
|
|
1064
|
+
const { container } = render( <LinkControlConsumer /> );
|
|
1194
1065
|
|
|
1195
1066
|
// Search Input UI.
|
|
1196
|
-
const searchInput =
|
|
1197
|
-
'input[aria-label="URL"]'
|
|
1198
|
-
);
|
|
1067
|
+
const searchInput = getURLInput();
|
|
1199
1068
|
|
|
1200
1069
|
// Simulate searching for a term.
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
target: { value: entityNameText },
|
|
1204
|
-
} );
|
|
1205
|
-
} );
|
|
1070
|
+
searchInput.focus();
|
|
1071
|
+
await user.keyboard( entityNameText );
|
|
1206
1072
|
|
|
1207
1073
|
await eventLoopTick();
|
|
1208
1074
|
|
|
@@ -1215,26 +1081,22 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1215
1081
|
( result ) => result.innerHTML.includes( 'Custom suggestion text' )
|
|
1216
1082
|
)[ 0 ];
|
|
1217
1083
|
|
|
1218
|
-
expect( createButton ).
|
|
1084
|
+
expect( createButton ).toBeVisible();
|
|
1219
1085
|
} );
|
|
1220
1086
|
|
|
1221
1087
|
describe( 'Do not show create option', () => {
|
|
1222
1088
|
it.each( [ [ undefined ], [ null ], [ false ] ] )(
|
|
1223
1089
|
'should not show not show an option to create an entity when "createSuggestion" handler is %s',
|
|
1224
1090
|
async ( handler ) => {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
);
|
|
1230
|
-
} );
|
|
1091
|
+
const { container } = render(
|
|
1092
|
+
<LinkControl createSuggestion={ handler } />
|
|
1093
|
+
);
|
|
1094
|
+
|
|
1231
1095
|
// Await the initial suggestions to be fetched.
|
|
1232
1096
|
await eventLoopTick();
|
|
1233
1097
|
|
|
1234
1098
|
// Search Input UI.
|
|
1235
|
-
const searchInput =
|
|
1236
|
-
'input[aria-label="URL"]'
|
|
1237
|
-
);
|
|
1099
|
+
const searchInput = getURLInput();
|
|
1238
1100
|
|
|
1239
1101
|
// TODO: select these by aria relationship to autocomplete rather than arbitrary selector.
|
|
1240
1102
|
const searchResultElements = container.querySelectorAll(
|
|
@@ -1245,28 +1107,24 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1245
1107
|
)[ 0 ];
|
|
1246
1108
|
|
|
1247
1109
|
// Verify input has no value.
|
|
1248
|
-
expect( searchInput
|
|
1110
|
+
expect( searchInput ).toHaveValue( '' );
|
|
1249
1111
|
expect( createButton ).toBeFalsy(); // Shouldn't exist!
|
|
1250
1112
|
}
|
|
1251
1113
|
);
|
|
1252
1114
|
|
|
1253
1115
|
it( 'should not show not show an option to create an entity when input is empty', async () => {
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
);
|
|
1262
|
-
} );
|
|
1116
|
+
const { container } = render(
|
|
1117
|
+
<LinkControl
|
|
1118
|
+
showInitialSuggestions={ true } // Should show even if we're not showing initial suggestions.
|
|
1119
|
+
createSuggestion={ jest.fn() }
|
|
1120
|
+
/>
|
|
1121
|
+
);
|
|
1122
|
+
|
|
1263
1123
|
// Await the initial suggestions to be fetched.
|
|
1264
1124
|
await eventLoopTick();
|
|
1265
1125
|
|
|
1266
1126
|
// Search Input UI.
|
|
1267
|
-
const searchInput =
|
|
1268
|
-
'input[aria-label="URL"]'
|
|
1269
|
-
);
|
|
1127
|
+
const searchInput = getURLInput();
|
|
1270
1128
|
|
|
1271
1129
|
// TODO: select these by aria relationship to autocomplete rather than arbitrary selector.
|
|
1272
1130
|
const searchResultElements = container.querySelectorAll(
|
|
@@ -1277,7 +1135,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1277
1135
|
)[ 0 ];
|
|
1278
1136
|
|
|
1279
1137
|
// Verify input has no value.
|
|
1280
|
-
expect( searchInput
|
|
1138
|
+
expect( searchInput ).toHaveValue( '' );
|
|
1281
1139
|
expect( createButton ).toBeFalsy(); // Shouldn't exist!
|
|
1282
1140
|
} );
|
|
1283
1141
|
|
|
@@ -1290,24 +1148,17 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1290
1148
|
] )(
|
|
1291
1149
|
'should not show option to "Create Page" when text is a form of direct entry (eg: %s)',
|
|
1292
1150
|
async ( inputText ) => {
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
);
|
|
1298
|
-
} );
|
|
1151
|
+
const user = userEvent.setup();
|
|
1152
|
+
const { container } = render(
|
|
1153
|
+
<LinkControl createSuggestion={ jest.fn() } />
|
|
1154
|
+
);
|
|
1299
1155
|
|
|
1300
1156
|
// Search Input UI.
|
|
1301
|
-
const searchInput =
|
|
1302
|
-
'input[aria-label="URL"]'
|
|
1303
|
-
);
|
|
1157
|
+
const searchInput = getURLInput();
|
|
1304
1158
|
|
|
1305
1159
|
// Simulate searching for a term.
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
target: { value: inputText },
|
|
1309
|
-
} );
|
|
1310
|
-
} );
|
|
1160
|
+
searchInput.focus();
|
|
1161
|
+
await user.keyboard( inputText );
|
|
1311
1162
|
|
|
1312
1163
|
await eventLoopTick();
|
|
1313
1164
|
|
|
@@ -1327,6 +1178,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1327
1178
|
|
|
1328
1179
|
describe( 'Error handling', () => {
|
|
1329
1180
|
it( 'should display human-friendly, perceivable error notice and re-show create button and search input if page creation request fails', async () => {
|
|
1181
|
+
const user = userEvent.setup();
|
|
1330
1182
|
const searchText = 'This page to be created';
|
|
1331
1183
|
let searchInput;
|
|
1332
1184
|
|
|
@@ -1336,22 +1188,16 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1336
1188
|
|
|
1337
1189
|
const createSuggestion = () => Promise.reject( throwsError() );
|
|
1338
1190
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
container
|
|
1343
|
-
);
|
|
1344
|
-
} );
|
|
1191
|
+
const { container } = render(
|
|
1192
|
+
<LinkControl createSuggestion={ createSuggestion } />
|
|
1193
|
+
);
|
|
1345
1194
|
|
|
1346
1195
|
// Search Input UI.
|
|
1347
|
-
searchInput =
|
|
1196
|
+
searchInput = getURLInput();
|
|
1348
1197
|
|
|
1349
1198
|
// Simulate searching for a term.
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
target: { value: searchText },
|
|
1353
|
-
} );
|
|
1354
|
-
} );
|
|
1199
|
+
searchInput.focus();
|
|
1200
|
+
await user.keyboard( searchText );
|
|
1355
1201
|
|
|
1356
1202
|
await eventLoopTick();
|
|
1357
1203
|
|
|
@@ -1363,13 +1209,11 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1363
1209
|
( result ) => result.innerHTML.includes( 'Create:' )
|
|
1364
1210
|
)[ 0 ];
|
|
1365
1211
|
|
|
1366
|
-
await
|
|
1367
|
-
Simulate.click( createButton );
|
|
1368
|
-
} );
|
|
1212
|
+
await user.click( createButton );
|
|
1369
1213
|
|
|
1370
1214
|
await eventLoopTick();
|
|
1371
1215
|
|
|
1372
|
-
searchInput =
|
|
1216
|
+
searchInput = getURLInput();
|
|
1373
1217
|
|
|
1374
1218
|
// This is a Notice component
|
|
1375
1219
|
// we allow selecting by className here as an edge case because the
|
|
@@ -1383,16 +1227,14 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
|
|
|
1383
1227
|
expect( throwsError ).toThrow( Error );
|
|
1384
1228
|
|
|
1385
1229
|
// Check human readable error notice is perceivable.
|
|
1386
|
-
expect( errorNotice ).
|
|
1387
|
-
expect( errorNotice
|
|
1388
|
-
|
|
1389
|
-
'API response returned invalid entity'
|
|
1390
|
-
)
|
|
1230
|
+
expect( errorNotice ).toBeVisible();
|
|
1231
|
+
expect( errorNotice ).toHaveTextContent(
|
|
1232
|
+
'API response returned invalid entity'
|
|
1391
1233
|
);
|
|
1392
1234
|
|
|
1393
1235
|
// Verify input is repopulated with original search text.
|
|
1394
|
-
expect( searchInput ).
|
|
1395
|
-
expect( searchInput
|
|
1236
|
+
expect( searchInput ).toBeVisible();
|
|
1237
|
+
expect( searchInput ).toHaveValue( searchText );
|
|
1396
1238
|
|
|
1397
1239
|
// Verify search results are re-shown and create button is available.
|
|
1398
1240
|
searchResultElements = container.querySelectorAll(
|
|
@@ -1415,27 +1257,22 @@ describe( 'Selecting links', () => {
|
|
|
1415
1257
|
return <LinkControl value={ link } />;
|
|
1416
1258
|
};
|
|
1417
1259
|
|
|
1418
|
-
|
|
1419
|
-
render( <LinkControlConsumer />, container );
|
|
1420
|
-
} );
|
|
1260
|
+
render( <LinkControlConsumer /> );
|
|
1421
1261
|
|
|
1422
|
-
// TODO: select by aria role or visible text.
|
|
1423
1262
|
const currentLink = getCurrentLink();
|
|
1424
|
-
const currentLinkHTML = currentLink.innerHTML;
|
|
1425
1263
|
const currentLinkAnchor = currentLink.querySelector(
|
|
1426
1264
|
`[href="${ selectedLink.url }"]`
|
|
1427
1265
|
);
|
|
1428
1266
|
|
|
1429
|
-
expect(
|
|
1430
|
-
expect.stringContaining( selectedLink.title )
|
|
1431
|
-
);
|
|
1267
|
+
expect( currentLink ).toHaveTextContent( selectedLink.title );
|
|
1432
1268
|
expect(
|
|
1433
|
-
queryByRole(
|
|
1434
|
-
).
|
|
1435
|
-
expect( currentLinkAnchor ).
|
|
1269
|
+
screen.queryByRole( 'button', { name: 'Edit' } )
|
|
1270
|
+
).toBeVisible();
|
|
1271
|
+
expect( currentLinkAnchor ).toBeVisible();
|
|
1436
1272
|
} );
|
|
1437
1273
|
|
|
1438
|
-
it( 'should hide "selected" link UI and display search UI prepopulated with previously selected link title when "Change" button is clicked', () => {
|
|
1274
|
+
it( 'should hide "selected" link UI and display search UI prepopulated with previously selected link title when "Change" button is clicked', async () => {
|
|
1275
|
+
const user = userEvent.setup();
|
|
1439
1276
|
const selectedLink = fauxEntitySuggestions[ 0 ];
|
|
1440
1277
|
|
|
1441
1278
|
const LinkControlConsumer = () => {
|
|
@@ -1449,26 +1286,22 @@ describe( 'Selecting links', () => {
|
|
|
1449
1286
|
);
|
|
1450
1287
|
};
|
|
1451
1288
|
|
|
1452
|
-
|
|
1453
|
-
render( <LinkControlConsumer />, container );
|
|
1454
|
-
} );
|
|
1289
|
+
render( <LinkControlConsumer /> );
|
|
1455
1290
|
|
|
1456
1291
|
// Required in order to select the button below.
|
|
1457
1292
|
let currentLinkUI = getCurrentLink();
|
|
1458
1293
|
const currentLinkBtn = currentLinkUI.querySelector( 'button' );
|
|
1459
1294
|
|
|
1460
1295
|
// Simulate searching for a term.
|
|
1461
|
-
|
|
1462
|
-
Simulate.click( currentLinkBtn );
|
|
1463
|
-
} );
|
|
1296
|
+
await user.click( currentLinkBtn );
|
|
1464
1297
|
|
|
1465
1298
|
const searchInput = getURLInput();
|
|
1466
1299
|
currentLinkUI = getCurrentLink();
|
|
1467
1300
|
|
|
1468
1301
|
// We should be back to showing the search input.
|
|
1469
|
-
expect( searchInput ).
|
|
1470
|
-
expect( searchInput
|
|
1471
|
-
expect( currentLinkUI ).
|
|
1302
|
+
expect( searchInput ).toBeVisible();
|
|
1303
|
+
expect( searchInput ).toHaveValue( selectedLink.url ); // Prepopulated with previous link's URL.
|
|
1304
|
+
expect( currentLinkUI ).not.toBeInTheDocument();
|
|
1472
1305
|
} );
|
|
1473
1306
|
|
|
1474
1307
|
describe( 'Selection using mouse click', () => {
|
|
@@ -1487,6 +1320,7 @@ describe( 'Selecting links', () => {
|
|
|
1487
1320
|
] )(
|
|
1488
1321
|
'should display a current selected link UI when a %s suggestion for the search "%s" is clicked',
|
|
1489
1322
|
async ( type, searchTerm, selectedLink ) => {
|
|
1323
|
+
const user = userEvent.setup();
|
|
1490
1324
|
const LinkControlConsumer = () => {
|
|
1491
1325
|
const [ link, setLink ] = useState();
|
|
1492
1326
|
|
|
@@ -1498,48 +1332,36 @@ describe( 'Selecting links', () => {
|
|
|
1498
1332
|
);
|
|
1499
1333
|
};
|
|
1500
1334
|
|
|
1501
|
-
|
|
1502
|
-
render( <LinkControlConsumer />, container );
|
|
1503
|
-
} );
|
|
1335
|
+
const { container } = render( <LinkControlConsumer /> );
|
|
1504
1336
|
|
|
1505
1337
|
// Search Input UI.
|
|
1506
1338
|
const searchInput = getURLInput();
|
|
1507
1339
|
|
|
1508
1340
|
// Simulate searching for a term.
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
target: { value: searchTerm },
|
|
1512
|
-
} );
|
|
1513
|
-
} );
|
|
1341
|
+
searchInput.focus();
|
|
1342
|
+
await user.keyboard( searchTerm );
|
|
1514
1343
|
|
|
1515
1344
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
1516
1345
|
await eventLoopTick();
|
|
1517
1346
|
|
|
1518
|
-
const searchResultElements = getSearchResults();
|
|
1347
|
+
const searchResultElements = getSearchResults( container );
|
|
1519
1348
|
|
|
1520
1349
|
const firstSearchSuggestion = searchResultElements[ 0 ];
|
|
1521
1350
|
|
|
1522
1351
|
// Simulate selecting the first of the search suggestions.
|
|
1523
|
-
|
|
1524
|
-
Simulate.click( firstSearchSuggestion );
|
|
1525
|
-
} );
|
|
1352
|
+
await user.click( firstSearchSuggestion );
|
|
1526
1353
|
|
|
1527
|
-
const currentLink =
|
|
1528
|
-
'.block-editor-link-control__search-item.is-current'
|
|
1529
|
-
);
|
|
1530
|
-
const currentLinkHTML = currentLink.innerHTML;
|
|
1354
|
+
const currentLink = getCurrentLink();
|
|
1531
1355
|
const currentLinkAnchor = currentLink.querySelector(
|
|
1532
1356
|
`[href="${ selectedLink.url }"]`
|
|
1533
1357
|
);
|
|
1534
1358
|
|
|
1535
1359
|
// Check that this suggestion is now shown as selected.
|
|
1536
|
-
expect(
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
);
|
|
1542
|
-
expect( currentLinkAnchor ).not.toBeNull();
|
|
1360
|
+
expect( currentLink ).toHaveTextContent( selectedLink.title );
|
|
1361
|
+
expect(
|
|
1362
|
+
screen.getByRole( 'button', { name: 'Edit' } )
|
|
1363
|
+
).toBeVisible();
|
|
1364
|
+
expect( currentLinkAnchor ).toBeVisible();
|
|
1543
1365
|
}
|
|
1544
1366
|
);
|
|
1545
1367
|
} );
|
|
@@ -1560,6 +1382,7 @@ describe( 'Selecting links', () => {
|
|
|
1560
1382
|
] )(
|
|
1561
1383
|
'should display a current selected link UI when an %s suggestion for the search "%s" is selected using the keyboard',
|
|
1562
1384
|
async ( type, searchTerm, selectedLink ) => {
|
|
1385
|
+
const user = userEvent.setup();
|
|
1563
1386
|
const LinkControlConsumer = () => {
|
|
1564
1387
|
const [ link, setLink ] = useState();
|
|
1565
1388
|
|
|
@@ -1571,37 +1394,27 @@ describe( 'Selecting links', () => {
|
|
|
1571
1394
|
);
|
|
1572
1395
|
};
|
|
1573
1396
|
|
|
1574
|
-
|
|
1575
|
-
render( <LinkControlConsumer />, container );
|
|
1576
|
-
} );
|
|
1397
|
+
const { container } = render( <LinkControlConsumer /> );
|
|
1577
1398
|
|
|
1578
1399
|
// Search Input UI.
|
|
1579
1400
|
const searchInput = getURLInput();
|
|
1580
|
-
searchInput.focus();
|
|
1581
1401
|
|
|
1582
1402
|
// Simulate searching for a term.
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
target: { value: searchTerm },
|
|
1586
|
-
} );
|
|
1587
|
-
} );
|
|
1403
|
+
searchInput.focus();
|
|
1404
|
+
await user.keyboard( searchTerm );
|
|
1588
1405
|
|
|
1589
1406
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
1590
1407
|
await eventLoopTick();
|
|
1591
1408
|
|
|
1592
1409
|
// Step down into the search results, highlighting the first result item.
|
|
1593
|
-
|
|
1594
|
-
Simulate.keyDown( searchInput, { keyCode: DOWN } );
|
|
1595
|
-
} );
|
|
1410
|
+
triggerArrowDown( searchInput );
|
|
1596
1411
|
|
|
1597
|
-
const searchResultElements = getSearchResults();
|
|
1412
|
+
const searchResultElements = getSearchResults( container );
|
|
1598
1413
|
|
|
1599
1414
|
const firstSearchSuggestion = searchResultElements[ 0 ];
|
|
1600
1415
|
const secondSearchSuggestion = searchResultElements[ 1 ];
|
|
1601
1416
|
|
|
1602
|
-
let selectedSearchResultElement =
|
|
1603
|
-
'[role="option"][aria-selected="true"]'
|
|
1604
|
-
);
|
|
1417
|
+
let selectedSearchResultElement = getSelectedResultElement();
|
|
1605
1418
|
|
|
1606
1419
|
// We should have highlighted the first item using the keyboard.
|
|
1607
1420
|
expect( selectedSearchResultElement ).toEqual(
|
|
@@ -1611,13 +1424,9 @@ describe( 'Selecting links', () => {
|
|
|
1611
1424
|
// Only entity searches contain more than 1 suggestion.
|
|
1612
1425
|
if ( type === 'entity' ) {
|
|
1613
1426
|
// Check we can go down again using the down arrow.
|
|
1614
|
-
|
|
1615
|
-
Simulate.keyDown( searchInput, { keyCode: DOWN } );
|
|
1616
|
-
} );
|
|
1427
|
+
triggerArrowDown( searchInput );
|
|
1617
1428
|
|
|
1618
|
-
selectedSearchResultElement =
|
|
1619
|
-
'[role="option"][aria-selected="true"]'
|
|
1620
|
-
);
|
|
1429
|
+
selectedSearchResultElement = getSelectedResultElement();
|
|
1621
1430
|
|
|
1622
1431
|
// We should have highlighted the first item using the keyboard
|
|
1623
1432
|
// eslint-disable-next-line jest/no-conditional-expect
|
|
@@ -1626,13 +1435,9 @@ describe( 'Selecting links', () => {
|
|
|
1626
1435
|
);
|
|
1627
1436
|
|
|
1628
1437
|
// Check we can go back up via up arrow.
|
|
1629
|
-
|
|
1630
|
-
Simulate.keyDown( searchInput, { keyCode: UP } );
|
|
1631
|
-
} );
|
|
1438
|
+
triggerArrowUp( searchInput );
|
|
1632
1439
|
|
|
1633
|
-
selectedSearchResultElement =
|
|
1634
|
-
'[role="option"][aria-selected="true"]'
|
|
1635
|
-
);
|
|
1440
|
+
selectedSearchResultElement = getSelectedResultElement();
|
|
1636
1441
|
|
|
1637
1442
|
// We should be back to highlighting the first search result again
|
|
1638
1443
|
// eslint-disable-next-line jest/no-conditional-expect
|
|
@@ -1642,70 +1447,52 @@ describe( 'Selecting links', () => {
|
|
|
1642
1447
|
}
|
|
1643
1448
|
|
|
1644
1449
|
// Submit the selected item as the current link.
|
|
1645
|
-
|
|
1646
|
-
Simulate.keyDown( searchInput, { keyCode: ENTER } );
|
|
1647
|
-
} );
|
|
1450
|
+
triggerEnter( searchInput );
|
|
1648
1451
|
|
|
1649
1452
|
// Check that the suggestion selected via is now shown as selected.
|
|
1650
|
-
const currentLink =
|
|
1651
|
-
'.block-editor-link-control__search-item.is-current'
|
|
1652
|
-
);
|
|
1653
|
-
const currentLinkHTML = currentLink.innerHTML;
|
|
1453
|
+
const currentLink = getCurrentLink();
|
|
1654
1454
|
const currentLinkAnchor = currentLink.querySelector(
|
|
1655
1455
|
`[href="${ selectedLink.url }"]`
|
|
1656
1456
|
);
|
|
1657
1457
|
|
|
1658
1458
|
// Make sure focus is retained after submission.
|
|
1659
|
-
expect( container.
|
|
1660
|
-
true
|
|
1661
|
-
);
|
|
1459
|
+
expect( container ).toContainElement( document.activeElement );
|
|
1662
1460
|
|
|
1663
|
-
expect(
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
);
|
|
1669
|
-
expect( currentLinkAnchor ).not.toBeNull();
|
|
1461
|
+
expect( currentLink ).toHaveTextContent( selectedLink.title );
|
|
1462
|
+
expect(
|
|
1463
|
+
screen.getByRole( 'button', { name: 'Edit' } )
|
|
1464
|
+
).toBeVisible();
|
|
1465
|
+
expect( currentLinkAnchor ).toBeVisible();
|
|
1670
1466
|
}
|
|
1671
1467
|
);
|
|
1672
1468
|
|
|
1673
1469
|
it( 'should allow selection of initial search results via the keyboard', async () => {
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1470
|
+
const { container } = render(
|
|
1471
|
+
<LinkControl showInitialSuggestions />
|
|
1472
|
+
);
|
|
1677
1473
|
|
|
1678
1474
|
await eventLoopTick();
|
|
1679
1475
|
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
);
|
|
1686
|
-
|
|
1687
|
-
expect( searchResultsLabel.innerHTML ).toEqual(
|
|
1688
|
-
'Recently updated'
|
|
1689
|
-
);
|
|
1476
|
+
expect(
|
|
1477
|
+
screen.queryByRole( 'listbox', {
|
|
1478
|
+
name: 'Recently updated',
|
|
1479
|
+
} )
|
|
1480
|
+
).toBeVisible();
|
|
1690
1481
|
|
|
1691
1482
|
// Search Input UI.
|
|
1692
1483
|
const searchInput = getURLInput();
|
|
1693
1484
|
|
|
1694
1485
|
// Step down into the search results, highlighting the first result item.
|
|
1695
|
-
|
|
1696
|
-
Simulate.keyDown( searchInput, { keyCode: DOWN } );
|
|
1697
|
-
} );
|
|
1486
|
+
triggerArrowDown( searchInput );
|
|
1698
1487
|
|
|
1699
1488
|
await eventLoopTick();
|
|
1700
1489
|
|
|
1701
|
-
const searchResultElements = getSearchResults();
|
|
1490
|
+
const searchResultElements = getSearchResults( container );
|
|
1702
1491
|
|
|
1703
1492
|
const firstSearchSuggestion = searchResultElements[ 0 ];
|
|
1704
1493
|
const secondSearchSuggestion = searchResultElements[ 1 ];
|
|
1705
1494
|
|
|
1706
|
-
let selectedSearchResultElement =
|
|
1707
|
-
'[role="option"][aria-selected="true"]'
|
|
1708
|
-
);
|
|
1495
|
+
let selectedSearchResultElement = getSelectedResultElement();
|
|
1709
1496
|
|
|
1710
1497
|
// We should have highlighted the first item using the keyboard.
|
|
1711
1498
|
expect( selectedSearchResultElement ).toEqual(
|
|
@@ -1713,13 +1500,9 @@ describe( 'Selecting links', () => {
|
|
|
1713
1500
|
);
|
|
1714
1501
|
|
|
1715
1502
|
// Check we can go down again using the down arrow.
|
|
1716
|
-
|
|
1717
|
-
Simulate.keyDown( searchInput, { keyCode: DOWN } );
|
|
1718
|
-
} );
|
|
1503
|
+
triggerArrowDown( searchInput );
|
|
1719
1504
|
|
|
1720
|
-
selectedSearchResultElement =
|
|
1721
|
-
'[role="option"][aria-selected="true"]'
|
|
1722
|
-
);
|
|
1505
|
+
selectedSearchResultElement = getSelectedResultElement();
|
|
1723
1506
|
|
|
1724
1507
|
// We should have highlighted the first item using the keyboard.
|
|
1725
1508
|
expect( selectedSearchResultElement ).toEqual(
|
|
@@ -1727,13 +1510,9 @@ describe( 'Selecting links', () => {
|
|
|
1727
1510
|
);
|
|
1728
1511
|
|
|
1729
1512
|
// Check we can go back up via up arrow.
|
|
1730
|
-
|
|
1731
|
-
Simulate.keyDown( searchInput, { keyCode: UP } );
|
|
1732
|
-
} );
|
|
1513
|
+
triggerArrowUp( searchInput );
|
|
1733
1514
|
|
|
1734
|
-
selectedSearchResultElement =
|
|
1735
|
-
'[role="option"][aria-selected="true"]'
|
|
1736
|
-
);
|
|
1515
|
+
selectedSearchResultElement = getSelectedResultElement();
|
|
1737
1516
|
|
|
1738
1517
|
// We should be back to highlighting the first search result again.
|
|
1739
1518
|
expect( selectedSearchResultElement ).toEqual(
|
|
@@ -1756,27 +1535,18 @@ describe( 'Addition Settings UI', () => {
|
|
|
1756
1535
|
return <LinkControl value={ link } />;
|
|
1757
1536
|
};
|
|
1758
1537
|
|
|
1759
|
-
|
|
1760
|
-
render( <LinkControlConsumer />, container );
|
|
1761
|
-
} );
|
|
1762
|
-
|
|
1763
|
-
const newTabSettingLabel = Array.from(
|
|
1764
|
-
container.querySelectorAll( 'label' )
|
|
1765
|
-
).find(
|
|
1766
|
-
( label ) =>
|
|
1767
|
-
label.innerHTML &&
|
|
1768
|
-
label.innerHTML.includes( expectedSettingText )
|
|
1769
|
-
);
|
|
1538
|
+
const { container } = render( <LinkControlConsumer /> );
|
|
1770
1539
|
|
|
1771
|
-
|
|
1540
|
+
const newTabSettingLabel = screen.getByText( expectedSettingText );
|
|
1541
|
+
expect( newTabSettingLabel ).toBeVisible();
|
|
1772
1542
|
|
|
1773
1543
|
const newTabSettingLabelForAttr =
|
|
1774
1544
|
newTabSettingLabel.getAttribute( 'for' );
|
|
1775
1545
|
const newTabSettingInput = container.querySelector(
|
|
1776
1546
|
`#${ newTabSettingLabelForAttr }`
|
|
1777
1547
|
);
|
|
1778
|
-
expect( newTabSettingInput ).
|
|
1779
|
-
expect( newTabSettingInput
|
|
1548
|
+
expect( newTabSettingInput ).toBeVisible();
|
|
1549
|
+
expect( newTabSettingInput ).not.toBeChecked();
|
|
1780
1550
|
} );
|
|
1781
1551
|
|
|
1782
1552
|
it( 'should display a setting control with correct default state for each of the custom settings provided', async () => {
|
|
@@ -1793,10 +1563,6 @@ describe( 'Addition Settings UI', () => {
|
|
|
1793
1563
|
},
|
|
1794
1564
|
];
|
|
1795
1565
|
|
|
1796
|
-
const customSettingsLabelsText = customSettings.map(
|
|
1797
|
-
( setting ) => setting.title
|
|
1798
|
-
);
|
|
1799
|
-
|
|
1800
1566
|
const LinkControlConsumer = () => {
|
|
1801
1567
|
const [ link ] = useState( selectedLink );
|
|
1802
1568
|
|
|
@@ -1808,108 +1574,78 @@ describe( 'Addition Settings UI', () => {
|
|
|
1808
1574
|
);
|
|
1809
1575
|
};
|
|
1810
1576
|
|
|
1811
|
-
|
|
1812
|
-
render( <LinkControlConsumer />, container );
|
|
1813
|
-
} );
|
|
1814
|
-
|
|
1815
|
-
// Grab the elements using user perceivable DOM queries.
|
|
1816
|
-
const settingsLegend = Array.from(
|
|
1817
|
-
container.querySelectorAll( 'legend' )
|
|
1818
|
-
).find(
|
|
1819
|
-
( legend ) =>
|
|
1820
|
-
legend.innerHTML &&
|
|
1821
|
-
legend.innerHTML.includes( 'Currently selected link settings' )
|
|
1822
|
-
);
|
|
1823
|
-
const settingsFieldset = settingsLegend.closest( 'fieldset' );
|
|
1824
|
-
const settingControlsLabels = Array.from(
|
|
1825
|
-
settingsFieldset.querySelectorAll( 'label' )
|
|
1826
|
-
);
|
|
1827
|
-
const settingControlsInputs = settingControlsLabels.map( ( label ) => {
|
|
1828
|
-
return settingsFieldset.querySelector(
|
|
1829
|
-
`#${ label.getAttribute( 'for' ) }`
|
|
1830
|
-
);
|
|
1831
|
-
} );
|
|
1832
|
-
|
|
1833
|
-
const settingControlLabelsText = Array.from(
|
|
1834
|
-
settingControlsLabels
|
|
1835
|
-
).map( ( label ) => label.innerHTML );
|
|
1577
|
+
render( <LinkControlConsumer /> );
|
|
1836
1578
|
|
|
1837
|
-
|
|
1838
|
-
expect( settingControlsLabels ).toHaveLength( 2 );
|
|
1579
|
+
expect( screen.queryAllByRole( 'checkbox' ) ).toHaveLength( 2 );
|
|
1839
1580
|
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1581
|
+
expect(
|
|
1582
|
+
screen.getByRole( 'checkbox', {
|
|
1583
|
+
name: customSettings[ 0 ].title,
|
|
1584
|
+
} )
|
|
1585
|
+
).not.toBeChecked();
|
|
1586
|
+
expect(
|
|
1587
|
+
screen.getByRole( 'checkbox', {
|
|
1588
|
+
name: customSettings[ 1 ].title,
|
|
1589
|
+
} )
|
|
1590
|
+
).toBeChecked();
|
|
1848
1591
|
} );
|
|
1849
1592
|
} );
|
|
1850
1593
|
|
|
1851
1594
|
describe( 'Post types', () => {
|
|
1852
1595
|
it( 'should display post type in search results of link', async () => {
|
|
1596
|
+
const user = userEvent.setup();
|
|
1853
1597
|
const searchTerm = 'Hello world';
|
|
1854
1598
|
|
|
1855
|
-
|
|
1856
|
-
render( <LinkControl />, container );
|
|
1857
|
-
} );
|
|
1599
|
+
const { container } = render( <LinkControl /> );
|
|
1858
1600
|
|
|
1859
1601
|
// Search Input UI.
|
|
1860
1602
|
const searchInput = getURLInput();
|
|
1861
1603
|
|
|
1862
1604
|
// Simulate searching for a term.
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
} );
|
|
1605
|
+
searchInput.focus();
|
|
1606
|
+
await user.keyboard( searchTerm );
|
|
1866
1607
|
|
|
1867
1608
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
1868
1609
|
await eventLoopTick();
|
|
1869
1610
|
|
|
1870
|
-
const searchResultElements = getSearchResults();
|
|
1611
|
+
const searchResultElements = getSearchResults( container );
|
|
1871
1612
|
|
|
1872
1613
|
searchResultElements.forEach( ( resultItem, index ) => {
|
|
1873
|
-
expect(
|
|
1874
|
-
|
|
1875
|
-
)
|
|
1614
|
+
expect( resultItem ).toHaveTextContent(
|
|
1615
|
+
fauxEntitySuggestions[ index ].type
|
|
1616
|
+
);
|
|
1876
1617
|
} );
|
|
1877
1618
|
} );
|
|
1878
1619
|
|
|
1879
1620
|
it.each( [ 'page', 'post', 'tag', 'post_tag', 'category' ] )(
|
|
1880
1621
|
'should NOT display post type in search results of %s',
|
|
1881
1622
|
async ( postType ) => {
|
|
1623
|
+
const user = userEvent.setup();
|
|
1882
1624
|
const searchTerm = 'Hello world';
|
|
1883
1625
|
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
container
|
|
1888
|
-
);
|
|
1889
|
-
} );
|
|
1626
|
+
const { container } = render(
|
|
1627
|
+
<LinkControl suggestionsQuery={ { type: postType } } />
|
|
1628
|
+
);
|
|
1890
1629
|
|
|
1891
1630
|
// Search Input UI.
|
|
1892
1631
|
const searchInput = getURLInput();
|
|
1893
1632
|
|
|
1894
1633
|
// Simulate searching for a term.
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
target: { value: searchTerm },
|
|
1898
|
-
} );
|
|
1899
|
-
} );
|
|
1634
|
+
searchInput.focus();
|
|
1635
|
+
await user.keyboard( searchTerm );
|
|
1900
1636
|
|
|
1901
1637
|
// fetchFauxEntitySuggestions resolves on next "tick" of event loop.
|
|
1902
1638
|
await eventLoopTick();
|
|
1903
1639
|
|
|
1904
|
-
const searchResultElements = getSearchResults();
|
|
1640
|
+
const searchResultElements = getSearchResults( container );
|
|
1905
1641
|
|
|
1906
1642
|
searchResultElements.forEach( ( resultItem, index ) => {
|
|
1907
1643
|
expect(
|
|
1908
|
-
queryByText(
|
|
1644
|
+
screen.queryByText(
|
|
1909
1645
|
resultItem,
|
|
1910
1646
|
fauxEntitySuggestions[ index ].type
|
|
1911
1647
|
)
|
|
1912
|
-
).
|
|
1648
|
+
).not.toBeInTheDocument();
|
|
1913
1649
|
} );
|
|
1914
1650
|
}
|
|
1915
1651
|
);
|
|
@@ -1944,18 +1680,14 @@ describe( 'Rich link previews', () => {
|
|
|
1944
1680
|
} )
|
|
1945
1681
|
);
|
|
1946
1682
|
|
|
1947
|
-
|
|
1948
|
-
render( <LinkControl value={ selectedLink } />, container );
|
|
1949
|
-
} );
|
|
1683
|
+
render( <LinkControl value={ selectedLink } /> );
|
|
1950
1684
|
|
|
1951
1685
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
1952
1686
|
await act( async () => {
|
|
1953
1687
|
await eventLoopTick();
|
|
1954
1688
|
} );
|
|
1955
1689
|
|
|
1956
|
-
const linkPreview =
|
|
1957
|
-
"[aria-label='Currently selected']"
|
|
1958
|
-
);
|
|
1690
|
+
const linkPreview = getCurrentLink();
|
|
1959
1691
|
|
|
1960
1692
|
const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
|
|
1961
1693
|
|
|
@@ -1974,21 +1706,14 @@ describe( 'Rich link previews', () => {
|
|
|
1974
1706
|
} )
|
|
1975
1707
|
);
|
|
1976
1708
|
|
|
1977
|
-
|
|
1978
|
-
render(
|
|
1979
|
-
<LinkControl value={ selectedLink } hasRichPreviews />,
|
|
1980
|
-
container
|
|
1981
|
-
);
|
|
1982
|
-
} );
|
|
1709
|
+
render( <LinkControl value={ selectedLink } hasRichPreviews /> );
|
|
1983
1710
|
|
|
1984
1711
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
1985
1712
|
await act( async () => {
|
|
1986
1713
|
await eventLoopTick();
|
|
1987
1714
|
} );
|
|
1988
1715
|
|
|
1989
|
-
const linkPreview =
|
|
1990
|
-
"[aria-label='Currently selected']"
|
|
1991
|
-
);
|
|
1716
|
+
const linkPreview = getCurrentLink();
|
|
1992
1717
|
|
|
1993
1718
|
const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
|
|
1994
1719
|
|
|
@@ -2005,21 +1730,14 @@ describe( 'Rich link previews', () => {
|
|
|
2005
1730
|
} )
|
|
2006
1731
|
);
|
|
2007
1732
|
|
|
2008
|
-
|
|
2009
|
-
render(
|
|
2010
|
-
<LinkControl value={ selectedLink } hasRichPreviews />,
|
|
2011
|
-
container
|
|
2012
|
-
);
|
|
2013
|
-
} );
|
|
1733
|
+
render( <LinkControl value={ selectedLink } hasRichPreviews /> );
|
|
2014
1734
|
|
|
2015
1735
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
2016
1736
|
await act( async () => {
|
|
2017
1737
|
await eventLoopTick();
|
|
2018
1738
|
} );
|
|
2019
1739
|
|
|
2020
|
-
const linkPreview =
|
|
2021
|
-
"[aria-label='Currently selected']"
|
|
2022
|
-
);
|
|
1740
|
+
const linkPreview = getCurrentLink();
|
|
2023
1741
|
|
|
2024
1742
|
// Todo: refactor to use user-facing queries.
|
|
2025
1743
|
const hasRichImagePreview = linkPreview.querySelector(
|
|
@@ -2031,8 +1749,8 @@ describe( 'Rich link previews', () => {
|
|
|
2031
1749
|
'.block-editor-link-control__search-item-description'
|
|
2032
1750
|
);
|
|
2033
1751
|
|
|
2034
|
-
expect( hasRichImagePreview ).
|
|
2035
|
-
expect( hasRichDescriptionPreview ).
|
|
1752
|
+
expect( hasRichImagePreview ).not.toBeInTheDocument();
|
|
1753
|
+
expect( hasRichDescriptionPreview ).not.toBeInTheDocument();
|
|
2036
1754
|
} );
|
|
2037
1755
|
|
|
2038
1756
|
it( 'should display a fallback when title is missing from rich data', async () => {
|
|
@@ -2045,21 +1763,14 @@ describe( 'Rich link previews', () => {
|
|
|
2045
1763
|
} )
|
|
2046
1764
|
);
|
|
2047
1765
|
|
|
2048
|
-
|
|
2049
|
-
render(
|
|
2050
|
-
<LinkControl value={ selectedLink } hasRichPreviews />,
|
|
2051
|
-
container
|
|
2052
|
-
);
|
|
2053
|
-
} );
|
|
1766
|
+
render( <LinkControl value={ selectedLink } hasRichPreviews /> );
|
|
2054
1767
|
|
|
2055
1768
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
2056
1769
|
await act( async () => {
|
|
2057
1770
|
await eventLoopTick();
|
|
2058
1771
|
} );
|
|
2059
1772
|
|
|
2060
|
-
const linkPreview =
|
|
2061
|
-
"[aria-label='Currently selected']"
|
|
2062
|
-
);
|
|
1773
|
+
const linkPreview = getCurrentLink();
|
|
2063
1774
|
|
|
2064
1775
|
const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
|
|
2065
1776
|
expect( isRichLinkPreview ).toBe( true );
|
|
@@ -2068,9 +1779,7 @@ describe( 'Rich link previews', () => {
|
|
|
2068
1779
|
'.block-editor-link-control__search-item-title'
|
|
2069
1780
|
);
|
|
2070
1781
|
|
|
2071
|
-
expect( titlePreview
|
|
2072
|
-
expect.stringContaining( selectedLink.title )
|
|
2073
|
-
);
|
|
1782
|
+
expect( titlePreview ).toHaveTextContent( selectedLink.title );
|
|
2074
1783
|
} );
|
|
2075
1784
|
|
|
2076
1785
|
it( 'should display a fallback when icon is missing from rich data', async () => {
|
|
@@ -2083,21 +1792,14 @@ describe( 'Rich link previews', () => {
|
|
|
2083
1792
|
} )
|
|
2084
1793
|
);
|
|
2085
1794
|
|
|
2086
|
-
|
|
2087
|
-
render(
|
|
2088
|
-
<LinkControl value={ selectedLink } hasRichPreviews />,
|
|
2089
|
-
container
|
|
2090
|
-
);
|
|
2091
|
-
} );
|
|
1795
|
+
render( <LinkControl value={ selectedLink } hasRichPreviews /> );
|
|
2092
1796
|
|
|
2093
1797
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
2094
1798
|
await act( async () => {
|
|
2095
1799
|
await eventLoopTick();
|
|
2096
1800
|
} );
|
|
2097
1801
|
|
|
2098
|
-
const linkPreview =
|
|
2099
|
-
"[aria-label='Currently selected']"
|
|
2100
|
-
);
|
|
1802
|
+
const linkPreview = getCurrentLink();
|
|
2101
1803
|
|
|
2102
1804
|
const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
|
|
2103
1805
|
expect( isRichLinkPreview ).toBe( true );
|
|
@@ -2109,8 +1811,8 @@ describe( 'Rich link previews', () => {
|
|
|
2109
1811
|
const fallBackIcon = iconPreview.querySelector( 'svg' );
|
|
2110
1812
|
const richIcon = iconPreview.querySelector( 'img' );
|
|
2111
1813
|
|
|
2112
|
-
expect( fallBackIcon ).
|
|
2113
|
-
expect( richIcon ).
|
|
1814
|
+
expect( fallBackIcon ).toBeVisible();
|
|
1815
|
+
expect( richIcon ).not.toBeInTheDocument();
|
|
2114
1816
|
} );
|
|
2115
1817
|
|
|
2116
1818
|
it.each( [ 'image', 'description' ] )(
|
|
@@ -2128,21 +1830,14 @@ describe( 'Rich link previews', () => {
|
|
|
2128
1830
|
return Promise.resolve( data );
|
|
2129
1831
|
} );
|
|
2130
1832
|
|
|
2131
|
-
|
|
2132
|
-
render(
|
|
2133
|
-
<LinkControl value={ selectedLink } hasRichPreviews />,
|
|
2134
|
-
container
|
|
2135
|
-
);
|
|
2136
|
-
} );
|
|
1833
|
+
render( <LinkControl value={ selectedLink } hasRichPreviews /> );
|
|
2137
1834
|
|
|
2138
1835
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
2139
1836
|
await act( async () => {
|
|
2140
1837
|
await eventLoopTick();
|
|
2141
1838
|
} );
|
|
2142
1839
|
|
|
2143
|
-
const linkPreview =
|
|
2144
|
-
"[aria-label='Currently selected']"
|
|
2145
|
-
);
|
|
1840
|
+
const linkPreview = getCurrentLink();
|
|
2146
1841
|
|
|
2147
1842
|
const isRichLinkPreview =
|
|
2148
1843
|
linkPreview.classList.contains( 'is-rich' );
|
|
@@ -2152,7 +1847,7 @@ describe( 'Rich link previews', () => {
|
|
|
2152
1847
|
`.block-editor-link-control__search-item-${ dataItem }`
|
|
2153
1848
|
);
|
|
2154
1849
|
|
|
2155
|
-
expect( missingDataItem ).
|
|
1850
|
+
expect( missingDataItem ).not.toBeInTheDocument();
|
|
2156
1851
|
}
|
|
2157
1852
|
);
|
|
2158
1853
|
|
|
@@ -2166,21 +1861,14 @@ describe( 'Rich link previews', () => {
|
|
|
2166
1861
|
Promise.resolve( data )
|
|
2167
1862
|
);
|
|
2168
1863
|
|
|
2169
|
-
|
|
2170
|
-
render(
|
|
2171
|
-
<LinkControl value={ selectedLink } hasRichPreviews />,
|
|
2172
|
-
container
|
|
2173
|
-
);
|
|
2174
|
-
} );
|
|
1864
|
+
render( <LinkControl value={ selectedLink } hasRichPreviews /> );
|
|
2175
1865
|
|
|
2176
1866
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
2177
1867
|
await act( async () => {
|
|
2178
1868
|
await eventLoopTick();
|
|
2179
1869
|
} );
|
|
2180
1870
|
|
|
2181
|
-
const linkPreview =
|
|
2182
|
-
"[aria-label='Currently selected']"
|
|
2183
|
-
);
|
|
1871
|
+
const linkPreview = getCurrentLink();
|
|
2184
1872
|
|
|
2185
1873
|
const isRichLinkPreview =
|
|
2186
1874
|
linkPreview.classList.contains( 'is-rich' );
|
|
@@ -2194,21 +1882,14 @@ describe( 'Rich link previews', () => {
|
|
|
2194
1882
|
|
|
2195
1883
|
mockFetchRichUrlData.mockImplementation( nonResolvingPromise );
|
|
2196
1884
|
|
|
2197
|
-
|
|
2198
|
-
render(
|
|
2199
|
-
<LinkControl value={ selectedLink } hasRichPreviews />,
|
|
2200
|
-
container
|
|
2201
|
-
);
|
|
2202
|
-
} );
|
|
1885
|
+
render( <LinkControl value={ selectedLink } hasRichPreviews /> );
|
|
2203
1886
|
|
|
2204
1887
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
2205
1888
|
await act( async () => {
|
|
2206
1889
|
await eventLoopTick();
|
|
2207
1890
|
} );
|
|
2208
1891
|
|
|
2209
|
-
const linkPreview =
|
|
2210
|
-
"[aria-label='Currently selected']"
|
|
2211
|
-
);
|
|
1892
|
+
const linkPreview = getCurrentLink();
|
|
2212
1893
|
|
|
2213
1894
|
const isFetchingRichPreview =
|
|
2214
1895
|
linkPreview.classList.contains( 'is-fetching' );
|
|
@@ -2223,21 +1904,14 @@ describe( 'Rich link previews', () => {
|
|
|
2223
1904
|
|
|
2224
1905
|
mockFetchRichUrlData.mockImplementation( simulateFailedFetch );
|
|
2225
1906
|
|
|
2226
|
-
|
|
2227
|
-
render(
|
|
2228
|
-
<LinkControl value={ selectedLink } hasRichPreviews />,
|
|
2229
|
-
container
|
|
2230
|
-
);
|
|
2231
|
-
} );
|
|
1907
|
+
render( <LinkControl value={ selectedLink } hasRichPreviews /> );
|
|
2232
1908
|
|
|
2233
1909
|
// mockFetchRichUrlData resolves on next "tick" of event loop.
|
|
2234
1910
|
await act( async () => {
|
|
2235
1911
|
await eventLoopTick();
|
|
2236
1912
|
} );
|
|
2237
1913
|
|
|
2238
|
-
const linkPreview =
|
|
2239
|
-
"[aria-label='Currently selected']"
|
|
2240
|
-
);
|
|
1914
|
+
const linkPreview = getCurrentLink();
|
|
2241
1915
|
|
|
2242
1916
|
const isFetchingRichPreview =
|
|
2243
1917
|
linkPreview.classList.contains( 'is-fetching' );
|
|
@@ -2258,16 +1932,11 @@ describe( 'Controlling link title text', () => {
|
|
|
2258
1932
|
const selectedLink = fauxEntitySuggestions[ 0 ];
|
|
2259
1933
|
|
|
2260
1934
|
it( 'should not show a means to alter the link title text by default', async () => {
|
|
2261
|
-
|
|
2262
|
-
render(
|
|
2263
|
-
<LinkControl value={ selectedLink } forceIsEditingLink />,
|
|
2264
|
-
container
|
|
2265
|
-
);
|
|
2266
|
-
} );
|
|
1935
|
+
render( <LinkControl value={ selectedLink } forceIsEditingLink /> );
|
|
2267
1936
|
|
|
2268
1937
|
expect(
|
|
2269
|
-
queryByRole(
|
|
2270
|
-
).
|
|
1938
|
+
screen.queryByRole( 'textbox', { name: 'Text' } )
|
|
1939
|
+
).not.toBeInTheDocument();
|
|
2271
1940
|
} );
|
|
2272
1941
|
|
|
2273
1942
|
it.each( [ null, undefined, ' ' ] )(
|
|
@@ -2278,38 +1947,32 @@ describe( 'Controlling link title text', () => {
|
|
|
2278
1947
|
url: urlValue,
|
|
2279
1948
|
};
|
|
2280
1949
|
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
container
|
|
2289
|
-
);
|
|
2290
|
-
} );
|
|
1950
|
+
render(
|
|
1951
|
+
<LinkControl
|
|
1952
|
+
value={ selectedLinkWithoutURL }
|
|
1953
|
+
forceIsEditingLink
|
|
1954
|
+
hasTextControl
|
|
1955
|
+
/>
|
|
1956
|
+
);
|
|
2291
1957
|
|
|
2292
1958
|
expect(
|
|
2293
|
-
queryByRole(
|
|
2294
|
-
).
|
|
1959
|
+
screen.queryByRole( 'textbox', { name: 'Text' } )
|
|
1960
|
+
).not.toBeInTheDocument();
|
|
2295
1961
|
}
|
|
2296
1962
|
);
|
|
2297
1963
|
|
|
2298
1964
|
it( 'should show a text input to alter the link title text when hasTextControl prop is truthy', async () => {
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
container
|
|
2307
|
-
);
|
|
2308
|
-
} );
|
|
1965
|
+
render(
|
|
1966
|
+
<LinkControl
|
|
1967
|
+
value={ selectedLink }
|
|
1968
|
+
forceIsEditingLink
|
|
1969
|
+
hasTextControl
|
|
1970
|
+
/>
|
|
1971
|
+
);
|
|
2309
1972
|
|
|
2310
1973
|
expect(
|
|
2311
|
-
queryByRole(
|
|
2312
|
-
).
|
|
1974
|
+
screen.queryByRole( 'textbox', { name: 'Text' } )
|
|
1975
|
+
).toBeVisible();
|
|
2313
1976
|
} );
|
|
2314
1977
|
|
|
2315
1978
|
it.each( [
|
|
@@ -2325,60 +1988,49 @@ describe( 'Controlling link title text', () => {
|
|
|
2325
1988
|
"should ensure text input reflects the current link value's `title` property %s",
|
|
2326
1989
|
async ( _unused, titleValue ) => {
|
|
2327
1990
|
const linkWithTitle = { ...selectedLink, title: titleValue };
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
container
|
|
2336
|
-
);
|
|
2337
|
-
} );
|
|
1991
|
+
render(
|
|
1992
|
+
<LinkControl
|
|
1993
|
+
value={ linkWithTitle }
|
|
1994
|
+
forceIsEditingLink
|
|
1995
|
+
hasTextControl
|
|
1996
|
+
/>
|
|
1997
|
+
);
|
|
2338
1998
|
|
|
2339
|
-
const textInput = queryByRole(
|
|
1999
|
+
const textInput = screen.queryByRole( 'textbox', {
|
|
2340
2000
|
name: 'Text',
|
|
2341
2001
|
} );
|
|
2342
2002
|
|
|
2343
|
-
expect( textInput
|
|
2003
|
+
expect( textInput ).toHaveValue( titleValue );
|
|
2344
2004
|
}
|
|
2345
2005
|
);
|
|
2346
2006
|
|
|
2347
2007
|
it( "should ensure title value matching the text input's current value is included in onChange handler value on submit", async () => {
|
|
2008
|
+
const user = userEvent.setup();
|
|
2348
2009
|
const mockOnChange = jest.fn();
|
|
2349
2010
|
const textValue = 'My new text value';
|
|
2350
2011
|
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
container
|
|
2360
|
-
);
|
|
2361
|
-
} );
|
|
2362
|
-
|
|
2363
|
-
let textInput = queryByRole( container, 'textbox', { name: 'Text' } );
|
|
2012
|
+
render(
|
|
2013
|
+
<LinkControl
|
|
2014
|
+
value={ selectedLink }
|
|
2015
|
+
forceIsEditingLink
|
|
2016
|
+
hasTextControl
|
|
2017
|
+
onChange={ mockOnChange }
|
|
2018
|
+
/>
|
|
2019
|
+
);
|
|
2364
2020
|
|
|
2365
|
-
|
|
2366
|
-
Simulate.change( textInput, {
|
|
2367
|
-
target: { value: textValue },
|
|
2368
|
-
} );
|
|
2369
|
-
} );
|
|
2021
|
+
const textInput = screen.queryByRole( 'textbox', { name: 'Text' } );
|
|
2370
2022
|
|
|
2371
|
-
textInput
|
|
2023
|
+
textInput.focus();
|
|
2024
|
+
await userEvent.clear( textInput );
|
|
2025
|
+
await user.keyboard( textValue );
|
|
2372
2026
|
|
|
2373
|
-
expect( textInput
|
|
2027
|
+
expect( textInput ).toHaveValue( textValue );
|
|
2374
2028
|
|
|
2375
|
-
const submitButton = queryByRole(
|
|
2029
|
+
const submitButton = screen.queryByRole( 'button', {
|
|
2376
2030
|
name: 'Submit',
|
|
2377
2031
|
} );
|
|
2378
2032
|
|
|
2379
|
-
|
|
2380
|
-
Simulate.click( submitButton );
|
|
2381
|
-
} );
|
|
2033
|
+
await user.click( submitButton );
|
|
2382
2034
|
|
|
2383
2035
|
expect( mockOnChange ).toHaveBeenCalledWith(
|
|
2384
2036
|
expect.objectContaining( {
|
|
@@ -2388,34 +2040,29 @@ describe( 'Controlling link title text', () => {
|
|
|
2388
2040
|
} );
|
|
2389
2041
|
|
|
2390
2042
|
it( 'should allow `ENTER` keypress within the text field to trigger submission of value', async () => {
|
|
2043
|
+
const user = userEvent.setup();
|
|
2391
2044
|
const textValue = 'My new text value';
|
|
2392
2045
|
const mockOnChange = jest.fn();
|
|
2393
|
-
act( () => {
|
|
2394
|
-
render(
|
|
2395
|
-
<LinkControl
|
|
2396
|
-
value={ selectedLink }
|
|
2397
|
-
forceIsEditingLink
|
|
2398
|
-
hasTextControl
|
|
2399
|
-
onChange={ mockOnChange }
|
|
2400
|
-
/>,
|
|
2401
|
-
container
|
|
2402
|
-
);
|
|
2403
|
-
} );
|
|
2404
2046
|
|
|
2405
|
-
|
|
2047
|
+
render(
|
|
2048
|
+
<LinkControl
|
|
2049
|
+
value={ selectedLink }
|
|
2050
|
+
forceIsEditingLink
|
|
2051
|
+
hasTextControl
|
|
2052
|
+
onChange={ mockOnChange }
|
|
2053
|
+
/>
|
|
2054
|
+
);
|
|
2406
2055
|
|
|
2407
|
-
|
|
2056
|
+
const textInput = screen.queryByRole( 'textbox', { name: 'Text' } );
|
|
2408
2057
|
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2058
|
+
expect( textInput ).toBeVisible();
|
|
2059
|
+
|
|
2060
|
+
textInput.focus();
|
|
2061
|
+
await userEvent.clear( textInput );
|
|
2062
|
+
await user.keyboard( textValue );
|
|
2414
2063
|
|
|
2415
2064
|
// Attempt to submit the empty search value in the input.
|
|
2416
|
-
|
|
2417
|
-
Simulate.keyDown( textInput, { keyCode: ENTER } );
|
|
2418
|
-
} );
|
|
2065
|
+
triggerEnter( textInput );
|
|
2419
2066
|
|
|
2420
2067
|
expect( mockOnChange ).toHaveBeenCalledWith(
|
|
2421
2068
|
expect.objectContaining( {
|
|
@@ -2426,7 +2073,7 @@ describe( 'Controlling link title text', () => {
|
|
|
2426
2073
|
|
|
2427
2074
|
// The text input should not be showing as the form is submitted.
|
|
2428
2075
|
expect(
|
|
2429
|
-
queryByRole(
|
|
2430
|
-
).
|
|
2076
|
+
screen.queryByRole( 'textbox', { name: 'Text' } )
|
|
2077
|
+
).not.toBeInTheDocument();
|
|
2431
2078
|
} );
|
|
2432
2079
|
} );
|