@wordpress/components 30.2.1-next.f34ab90e9.0 → 30.2.2-next.e256d081a.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/build/context/context-connect.js.map +1 -1
- package/build/tabs/styles.js +5 -5
- package/build/tabs/styles.js.map +1 -1
- package/build/utils/font-size.js.map +1 -1
- package/build/utils/get-valid-children.js.map +1 -1
- package/build/validated-form-controls/control-with-error.js +16 -16
- package/build/validated-form-controls/control-with-error.js.map +1 -1
- package/build-module/context/context-connect.js.map +1 -1
- package/build-module/tabs/styles.js +6 -6
- package/build-module/tabs/styles.js.map +1 -1
- package/build-module/utils/font-size.js.map +1 -1
- package/build-module/utils/get-valid-children.js.map +1 -1
- package/build-module/validated-form-controls/control-with-error.js +16 -16
- package/build-module/validated-form-controls/control-with-error.js.map +1 -1
- package/build-types/context/context-connect.d.ts +2 -2
- package/build-types/context/context-connect.d.ts.map +1 -1
- package/build-types/tabs/styles.d.ts.map +1 -1
- package/build-types/utils/font-size.d.ts +2 -2
- package/build-types/utils/font-size.d.ts.map +1 -1
- package/build-types/utils/get-valid-children.d.ts +2 -2
- package/build-types/utils/get-valid-children.d.ts.map +1 -1
- package/build-types/validated-form-controls/components/stories/overview.story.d.ts.map +1 -1
- package/build-types/validated-form-controls/control-with-error.d.ts.map +1 -1
- package/build-types/validated-form-controls/test/control-with-error.d.ts +2 -0
- package/build-types/validated-form-controls/test/control-with-error.d.ts.map +1 -0
- package/package.json +19 -19
- package/src/context/context-connect.ts +2 -2
- package/src/tabs/styles.ts +2 -1
- package/src/tools-panel/stories/index.story.tsx +3 -3
- package/src/utils/font-size.ts +2 -2
- package/src/utils/get-valid-children.ts +4 -2
- package/src/validated-form-controls/components/stories/overview.story.tsx +109 -27
- package/src/validated-form-controls/control-with-error.tsx +19 -18
- package/src/validated-form-controls/test/control-with-error.tsx +224 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { render, screen, waitFor, act } from '@testing-library/react';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* WordPress dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { useState, useCallback } from '@wordpress/element';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Internal dependencies
|
|
14
|
+
*/
|
|
15
|
+
import { ValidatedInputControl } from '../components';
|
|
16
|
+
|
|
17
|
+
describe( 'ControlWithError', () => {
|
|
18
|
+
describe( 'Async Validation', () => {
|
|
19
|
+
beforeEach( () => {
|
|
20
|
+
jest.useFakeTimers();
|
|
21
|
+
} );
|
|
22
|
+
|
|
23
|
+
afterEach( () => {
|
|
24
|
+
jest.useRealTimers();
|
|
25
|
+
} );
|
|
26
|
+
|
|
27
|
+
const AsyncValidatedInputControl = ( {
|
|
28
|
+
serverDelayMs,
|
|
29
|
+
...restProps
|
|
30
|
+
}: {
|
|
31
|
+
serverDelayMs: number;
|
|
32
|
+
} & React.ComponentProps< typeof ValidatedInputControl > ) => {
|
|
33
|
+
const [ text, setText ] = useState( '' );
|
|
34
|
+
const [ customValidity, setCustomValidity ] =
|
|
35
|
+
useState<
|
|
36
|
+
React.ComponentProps<
|
|
37
|
+
typeof ValidatedInputControl
|
|
38
|
+
>[ 'customValidity' ]
|
|
39
|
+
>( undefined );
|
|
40
|
+
|
|
41
|
+
const onValidate = useCallback(
|
|
42
|
+
( value?: string ) => {
|
|
43
|
+
setCustomValidity( {
|
|
44
|
+
type: 'validating',
|
|
45
|
+
message: 'Validating...',
|
|
46
|
+
} );
|
|
47
|
+
|
|
48
|
+
// Simulate delayed server response
|
|
49
|
+
setTimeout( () => {
|
|
50
|
+
if ( value?.toLowerCase() === 'error' ) {
|
|
51
|
+
setCustomValidity( {
|
|
52
|
+
type: 'invalid',
|
|
53
|
+
message: 'The word "error" is not allowed.',
|
|
54
|
+
} );
|
|
55
|
+
} else {
|
|
56
|
+
setCustomValidity( {
|
|
57
|
+
type: 'valid',
|
|
58
|
+
message: 'Validated',
|
|
59
|
+
} );
|
|
60
|
+
}
|
|
61
|
+
}, serverDelayMs );
|
|
62
|
+
},
|
|
63
|
+
[ serverDelayMs ]
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<ValidatedInputControl
|
|
68
|
+
label="Text"
|
|
69
|
+
value={ text }
|
|
70
|
+
onChange={ ( newValue ) => {
|
|
71
|
+
setText( newValue ?? '' );
|
|
72
|
+
} }
|
|
73
|
+
onValidate={ onValidate }
|
|
74
|
+
customValidity={ customValidity }
|
|
75
|
+
{ ...restProps }
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
it( 'should not show "validating" state if it takes less than 1000ms', async () => {
|
|
81
|
+
const user = userEvent.setup( {
|
|
82
|
+
advanceTimers: jest.advanceTimersByTime,
|
|
83
|
+
} );
|
|
84
|
+
render( <AsyncValidatedInputControl serverDelayMs={ 500 } /> );
|
|
85
|
+
|
|
86
|
+
const input = screen.getByRole( 'textbox' );
|
|
87
|
+
|
|
88
|
+
await user.type( input, 'valid text' );
|
|
89
|
+
|
|
90
|
+
// Blur to trigger validation
|
|
91
|
+
await user.tab();
|
|
92
|
+
|
|
93
|
+
// Fast-forward to right before the server response
|
|
94
|
+
act( () => jest.advanceTimersByTime( 499 ) );
|
|
95
|
+
|
|
96
|
+
// The validating state should not be shown
|
|
97
|
+
await waitFor( () => {
|
|
98
|
+
expect(
|
|
99
|
+
screen.queryByText( 'Validating...' )
|
|
100
|
+
).not.toBeInTheDocument();
|
|
101
|
+
} );
|
|
102
|
+
|
|
103
|
+
// Fast-forward past the server delay to show validation result
|
|
104
|
+
act( () => jest.advanceTimersByTime( 1 ) );
|
|
105
|
+
|
|
106
|
+
await waitFor( () => {
|
|
107
|
+
expect( screen.getByText( 'Validated' ) ).toBeVisible();
|
|
108
|
+
} );
|
|
109
|
+
} );
|
|
110
|
+
|
|
111
|
+
it( 'should show "validating" state if it takes more than 1000ms', async () => {
|
|
112
|
+
const user = userEvent.setup( {
|
|
113
|
+
advanceTimers: jest.advanceTimersByTime,
|
|
114
|
+
} );
|
|
115
|
+
render( <AsyncValidatedInputControl serverDelayMs={ 1200 } /> );
|
|
116
|
+
|
|
117
|
+
const input = screen.getByRole( 'textbox' );
|
|
118
|
+
|
|
119
|
+
await user.type( input, 'valid text' );
|
|
120
|
+
|
|
121
|
+
// Blur to trigger validation
|
|
122
|
+
await user.tab();
|
|
123
|
+
|
|
124
|
+
// Initially, no validating message should be shown (before 1s delay)
|
|
125
|
+
expect(
|
|
126
|
+
screen.queryByText( 'Validating...' )
|
|
127
|
+
).not.toBeInTheDocument();
|
|
128
|
+
|
|
129
|
+
// Fast-forward past the 1s delay to show validating state
|
|
130
|
+
act( () => jest.advanceTimersByTime( 1000 ) );
|
|
131
|
+
|
|
132
|
+
await waitFor( () => {
|
|
133
|
+
expect( screen.getByText( 'Validating...' ) ).toBeVisible();
|
|
134
|
+
} );
|
|
135
|
+
|
|
136
|
+
// Fast-forward past the server delay to show validation result
|
|
137
|
+
act( () => jest.advanceTimersByTime( 200 ) );
|
|
138
|
+
|
|
139
|
+
await waitFor( () => {
|
|
140
|
+
expect( screen.getByText( 'Validated' ) ).toBeVisible();
|
|
141
|
+
} );
|
|
142
|
+
|
|
143
|
+
// Test error case
|
|
144
|
+
await user.clear( input );
|
|
145
|
+
await user.type( input, 'error' );
|
|
146
|
+
|
|
147
|
+
// Blur to trigger validation
|
|
148
|
+
await user.tab();
|
|
149
|
+
|
|
150
|
+
act( () => jest.advanceTimersByTime( 1000 ) );
|
|
151
|
+
|
|
152
|
+
await waitFor( () => {
|
|
153
|
+
expect( screen.getByText( 'Validating...' ) ).toBeVisible();
|
|
154
|
+
} );
|
|
155
|
+
|
|
156
|
+
act( () => jest.advanceTimersByTime( 200 ) );
|
|
157
|
+
|
|
158
|
+
await waitFor( () => {
|
|
159
|
+
expect(
|
|
160
|
+
screen.getByText( 'The word "error" is not allowed.' )
|
|
161
|
+
).toBeVisible();
|
|
162
|
+
} );
|
|
163
|
+
|
|
164
|
+
// Test editing after error
|
|
165
|
+
await user.type( input, '{backspace}' );
|
|
166
|
+
|
|
167
|
+
act( () => jest.advanceTimersByTime( 1000 ) );
|
|
168
|
+
|
|
169
|
+
await waitFor( () => {
|
|
170
|
+
expect( screen.getByText( 'Validating...' ) ).toBeVisible();
|
|
171
|
+
} );
|
|
172
|
+
|
|
173
|
+
act( () => jest.advanceTimersByTime( 200 ) );
|
|
174
|
+
|
|
175
|
+
await waitFor( () => {
|
|
176
|
+
expect( screen.getByText( 'Validated' ) ).toBeVisible();
|
|
177
|
+
} );
|
|
178
|
+
} );
|
|
179
|
+
|
|
180
|
+
it( 'should not show a "valid" state until the server response is received, even if locally valid', async () => {
|
|
181
|
+
const user = userEvent.setup( {
|
|
182
|
+
advanceTimers: jest.advanceTimersByTime,
|
|
183
|
+
} );
|
|
184
|
+
render(
|
|
185
|
+
<AsyncValidatedInputControl serverDelayMs={ 1200 } required />
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const input = screen.getByRole( 'textbox' );
|
|
189
|
+
|
|
190
|
+
await user.type( input, 'valid text' );
|
|
191
|
+
|
|
192
|
+
await user.tab();
|
|
193
|
+
act( () => jest.advanceTimersByTime( 1200 ) );
|
|
194
|
+
|
|
195
|
+
await waitFor( () => {
|
|
196
|
+
expect( screen.getByText( 'Validated' ) ).toBeVisible();
|
|
197
|
+
} );
|
|
198
|
+
|
|
199
|
+
await user.clear( input );
|
|
200
|
+
|
|
201
|
+
act( () => jest.advanceTimersByTime( 1000 ) );
|
|
202
|
+
|
|
203
|
+
await waitFor( () => {
|
|
204
|
+
expect(
|
|
205
|
+
screen.getByText( 'Constraints not satisfied' )
|
|
206
|
+
).toBeVisible();
|
|
207
|
+
} );
|
|
208
|
+
|
|
209
|
+
await user.type( input, 'error' );
|
|
210
|
+
|
|
211
|
+
act( () => jest.advanceTimersByTime( 200 ) );
|
|
212
|
+
|
|
213
|
+
expect( screen.queryByText( 'Validated' ) ).not.toBeInTheDocument();
|
|
214
|
+
|
|
215
|
+
act( () => jest.advanceTimersByTime( 1000 ) );
|
|
216
|
+
|
|
217
|
+
await waitFor( () => {
|
|
218
|
+
expect(
|
|
219
|
+
screen.getByText( 'The word "error" is not allowed.' )
|
|
220
|
+
).toBeVisible();
|
|
221
|
+
} );
|
|
222
|
+
} );
|
|
223
|
+
} );
|
|
224
|
+
} );
|