@wordpress/editor 12.2.1 → 12.4.0-next.e230fbab09.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.
Files changed (152) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/components/deprecated.js +1 -1
  3. package/build/components/deprecated.js.map +1 -1
  4. package/build/components/deprecated.native.js.map +1 -1
  5. package/build/components/editor-help/index.native.js.map +1 -1
  6. package/build/components/entities-saved-states/entity-record-item.js +1 -1
  7. package/build/components/entities-saved-states/entity-record-item.js.map +1 -1
  8. package/build/components/global-keyboard-shortcuts/register-shortcuts.js +1 -1
  9. package/build/components/global-keyboard-shortcuts/register-shortcuts.js.map +1 -1
  10. package/build/components/index.js.map +1 -1
  11. package/build/components/index.native.js.map +1 -1
  12. package/build/components/local-autosave-monitor/index.js +5 -5
  13. package/build/components/local-autosave-monitor/index.js.map +1 -1
  14. package/build/components/post-featured-image/index.js +4 -4
  15. package/build/components/post-featured-image/index.js.map +1 -1
  16. package/build/components/post-last-revision/index.js +3 -3
  17. package/build/components/post-last-revision/index.js.map +1 -1
  18. package/build/components/post-locked-modal/index.js +1 -3
  19. package/build/components/post-locked-modal/index.js.map +1 -1
  20. package/build/components/post-saved-state/index.js +1 -1
  21. package/build/components/post-saved-state/index.js.map +1 -1
  22. package/build/components/post-schedule/index.js +3 -3
  23. package/build/components/post-schedule/index.js.map +1 -1
  24. package/build/components/post-slug/index.js +2 -4
  25. package/build/components/post-slug/index.js.map +1 -1
  26. package/build/components/post-switch-to-draft-button/index.js +19 -14
  27. package/build/components/post-switch-to-draft-button/index.js.map +1 -1
  28. package/build/components/post-taxonomies/hierarchical-term-selector.js +2 -2
  29. package/build/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
  30. package/build/components/post-title/index.native.js +2 -2
  31. package/build/components/post-title/index.native.js.map +1 -1
  32. package/build/components/post-trash/index.js +15 -29
  33. package/build/components/post-trash/index.js.map +1 -1
  34. package/build/components/provider/index.js +1 -1
  35. package/build/components/provider/index.js.map +1 -1
  36. package/build/components/provider/index.native.js +24 -15
  37. package/build/components/provider/index.native.js.map +1 -1
  38. package/build/components/provider/use-block-editor-settings.js +3 -8
  39. package/build/components/provider/use-block-editor-settings.js.map +1 -1
  40. package/build/store/actions.js +231 -225
  41. package/build/store/actions.js.map +1 -1
  42. package/build/store/actions.native.js +6 -4
  43. package/build/store/actions.native.js.map +1 -1
  44. package/build/store/index.js +1 -8
  45. package/build/store/index.js.map +1 -1
  46. package/build/store/{controls.js → local-autosave.js} +1 -18
  47. package/build/store/local-autosave.js.map +1 -0
  48. package/build/store/reducer.js +0 -2
  49. package/build/store/reducer.js.map +1 -1
  50. package/build/store/selectors.js +8 -10
  51. package/build/store/selectors.js.map +1 -1
  52. package/build/store/utils/notice-builder.js +9 -4
  53. package/build/store/utils/notice-builder.js.map +1 -1
  54. package/build/utils/url.js +9 -26
  55. package/build/utils/url.js.map +1 -1
  56. package/build-module/components/deprecated.js +1 -1
  57. package/build-module/components/deprecated.js.map +1 -1
  58. package/build-module/components/deprecated.native.js +1 -1
  59. package/build-module/components/deprecated.native.js.map +1 -1
  60. package/build-module/components/editor-help/index.native.js.map +1 -1
  61. package/build-module/components/entities-saved-states/entity-record-item.js +1 -1
  62. package/build-module/components/entities-saved-states/entity-record-item.js.map +1 -1
  63. package/build-module/components/global-keyboard-shortcuts/register-shortcuts.js +1 -1
  64. package/build-module/components/global-keyboard-shortcuts/register-shortcuts.js.map +1 -1
  65. package/build-module/components/index.js +3 -3
  66. package/build-module/components/index.js.map +1 -1
  67. package/build-module/components/index.native.js +3 -3
  68. package/build-module/components/index.native.js.map +1 -1
  69. package/build-module/components/local-autosave-monitor/index.js +1 -1
  70. package/build-module/components/local-autosave-monitor/index.js.map +1 -1
  71. package/build-module/components/post-featured-image/index.js +4 -4
  72. package/build-module/components/post-featured-image/index.js.map +1 -1
  73. package/build-module/components/post-last-revision/index.js +2 -2
  74. package/build-module/components/post-last-revision/index.js.map +1 -1
  75. package/build-module/components/post-locked-modal/index.js +1 -2
  76. package/build-module/components/post-locked-modal/index.js.map +1 -1
  77. package/build-module/components/post-saved-state/index.js +1 -1
  78. package/build-module/components/post-saved-state/index.js.map +1 -1
  79. package/build-module/components/post-schedule/index.js +3 -3
  80. package/build-module/components/post-schedule/index.js.map +1 -1
  81. package/build-module/components/post-slug/index.js +1 -2
  82. package/build-module/components/post-slug/index.js.map +1 -1
  83. package/build-module/components/post-switch-to-draft-button/index.js +22 -16
  84. package/build-module/components/post-switch-to-draft-button/index.js.map +1 -1
  85. package/build-module/components/post-taxonomies/hierarchical-term-selector.js +2 -2
  86. package/build-module/components/post-taxonomies/hierarchical-term-selector.js.map +1 -1
  87. package/build-module/components/post-title/index.native.js +2 -2
  88. package/build-module/components/post-title/index.native.js.map +1 -1
  89. package/build-module/components/post-trash/index.js +15 -27
  90. package/build-module/components/post-trash/index.js.map +1 -1
  91. package/build-module/components/provider/index.js +1 -1
  92. package/build-module/components/provider/index.js.map +1 -1
  93. package/build-module/components/provider/index.native.js +26 -17
  94. package/build-module/components/provider/index.native.js.map +1 -1
  95. package/build-module/components/provider/use-block-editor-settings.js +3 -8
  96. package/build-module/components/provider/use-block-editor-settings.js.map +1 -1
  97. package/build-module/store/actions.js +208 -207
  98. package/build-module/store/actions.js.map +1 -1
  99. package/build-module/store/actions.native.js +3 -3
  100. package/build-module/store/actions.native.js.map +1 -1
  101. package/build-module/store/index.js +1 -6
  102. package/build-module/store/index.js.map +1 -1
  103. package/build-module/store/{controls.js → local-autosave.js} +1 -15
  104. package/build-module/store/local-autosave.js.map +1 -0
  105. package/build-module/store/reducer.js +0 -2
  106. package/build-module/store/reducer.js.map +1 -1
  107. package/build-module/store/selectors.js +8 -9
  108. package/build-module/store/selectors.js.map +1 -1
  109. package/build-module/store/utils/notice-builder.js +9 -4
  110. package/build-module/store/utils/notice-builder.js.map +1 -1
  111. package/build-module/utils/url.js +8 -25
  112. package/build-module/utils/url.js.map +1 -1
  113. package/package.json +26 -27
  114. package/src/components/deprecated.js +1 -1
  115. package/src/components/deprecated.native.js +1 -1
  116. package/src/components/document-outline/test/index.js +1 -1
  117. package/src/components/editor-help/index.native.js +2 -2
  118. package/src/components/entities-saved-states/entity-record-item.js +1 -1
  119. package/src/components/global-keyboard-shortcuts/register-shortcuts.js +1 -1
  120. package/src/components/index.js +3 -3
  121. package/src/components/index.native.js +3 -3
  122. package/src/components/local-autosave-monitor/index.js +4 -1
  123. package/src/components/post-author/test/check.js +1 -1
  124. package/src/components/post-featured-image/index.js +4 -4
  125. package/src/components/post-last-revision/index.js +2 -2
  126. package/src/components/post-locked-modal/index.js +1 -2
  127. package/src/components/post-saved-state/index.js +1 -1
  128. package/src/components/post-saved-state/test/index.js +2 -2
  129. package/src/components/post-schedule/index.js +3 -3
  130. package/src/components/post-slug/index.js +1 -2
  131. package/src/components/post-switch-to-draft-button/index.js +35 -24
  132. package/src/components/post-taxonomies/hierarchical-term-selector.js +2 -2
  133. package/src/components/post-text-editor/test/index.js +1 -1
  134. package/src/components/post-title/index.native.js +2 -2
  135. package/src/components/post-trash/index.js +12 -24
  136. package/src/components/provider/index.js +1 -1
  137. package/src/components/provider/index.native.js +27 -23
  138. package/src/components/provider/use-block-editor-settings.js +3 -14
  139. package/src/store/actions.js +137 -249
  140. package/src/store/actions.native.js +3 -3
  141. package/src/store/index.js +0 -6
  142. package/src/store/{controls.js → local-autosave.js} +0 -8
  143. package/src/store/reducer.js +0 -2
  144. package/src/store/selectors.js +8 -9
  145. package/src/store/test/actions.js +244 -416
  146. package/src/store/test/selectors.js +1 -1
  147. package/src/store/utils/notice-builder.js +9 -4
  148. package/src/store/utils/test/notice-builder.js +1 -0
  149. package/src/utils/url.js +8 -30
  150. package/build/store/controls.js.map +0 -1
  151. package/build-module/store/controls.js.map +0 -1
  152. package/src/utils/test/url.js +0 -22
@@ -1,461 +1,289 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { apiFetch } from '@wordpress/data-controls';
5
- import { controls } from '@wordpress/data';
4
+ import apiFetch from '@wordpress/api-fetch';
5
+ import { store as blockEditorStore } from '@wordpress/block-editor';
6
+ import { store as coreStore } from '@wordpress/core-data';
7
+ import { createRegistry } from '@wordpress/data';
6
8
  import { store as noticesStore } from '@wordpress/notices';
7
9
 
8
10
  /**
9
11
  * Internal dependencies
10
12
  */
13
+
11
14
  import * as actions from '../actions';
12
- import { STORE_NAME, TRASH_POST_NOTICE_ID } from '../constants';
15
+ import { store as editorStore } from '..';
16
+
17
+ jest.useRealTimers();
18
+
19
+ const postId = 44;
13
20
 
14
- const postType = {
21
+ const postTypeConfig = {
22
+ kind: 'postType',
23
+ name: 'post',
24
+ baseURL: '/wp/v2/posts',
25
+ transientEdits: { blocks: true, selection: true },
26
+ mergedEdits: { meta: true },
27
+ rawAttributes: [ 'title', 'excerpt', 'content' ],
28
+ };
29
+
30
+ const postTypeEntity = {
31
+ slug: 'post',
15
32
  rest_base: 'posts',
16
33
  labels: {
17
34
  item_updated: 'Updated Post',
18
35
  item_published: 'Post published',
36
+ item_reverted_to_draft: 'Post reverted to draft.',
19
37
  },
20
38
  };
21
- const postId = 44;
22
- const postTypeSlug = 'post';
23
39
 
24
- describe( 'Post generator actions', () => {
40
+ function createRegistryWithStores() {
41
+ // Create a registry.
42
+ const registry = createRegistry();
43
+
44
+ // Register stores.
45
+ registry.register( blockEditorStore );
46
+ registry.register( coreStore );
47
+ registry.register( editorStore );
48
+ registry.register( noticesStore );
49
+
50
+ // Register post type entity.
51
+ registry.dispatch( coreStore ).addEntities( [ postTypeConfig ] );
52
+
53
+ // Store post type entity.
54
+ registry
55
+ .dispatch( coreStore )
56
+ .receiveEntityRecords( 'root', 'postType', [ postTypeEntity ] );
57
+
58
+ return registry;
59
+ }
60
+
61
+ const getMethod = ( options ) =>
62
+ options.headers?.[ 'X-HTTP-Method-Override' ] || options.method || 'GET';
63
+
64
+ describe( 'Post actions', () => {
25
65
  describe( 'savePost()', () => {
26
- let fulfillment, currentPost, currentPostStatus, isAutosave;
27
- beforeEach( () => {
28
- currentPost = () => ( {
66
+ it( 'saves a modified post', async () => {
67
+ const post = {
29
68
  id: postId,
30
- type: postTypeSlug,
69
+ type: 'post',
31
70
  title: 'bar',
32
71
  content: 'bar',
33
72
  excerpt: 'crackers',
34
- status: currentPostStatus,
35
- } );
36
- } );
37
- const reset = ( isAutosaving ) =>
38
- ( fulfillment = actions.savePost( { isAutosave: isAutosaving } ) );
39
- const testConditions = [
40
- [
41
- 'yields an action for checking if the post is saveable',
42
- () => true,
43
- () => {
44
- reset( isAutosave );
45
- const { value } = fulfillment.next();
46
- expect( value ).toEqual(
47
- controls.select( STORE_NAME, 'isEditedPostSaveable' )
48
- );
49
- },
50
- ],
51
- [
52
- 'yields an action for selecting the current edited post content',
53
- () => true,
54
- () => {
55
- const { value } = fulfillment.next( true );
56
- expect( value ).toEqual(
57
- controls.select( STORE_NAME, 'getEditedPostContent' )
58
- );
59
- },
60
- ],
61
- [
62
- "yields an action for editing the post entity's content if not an autosave",
63
- () => true,
64
- () => {
65
- if ( ! isAutosave ) {
66
- const edits = { content: currentPost().content };
67
- const { value } = fulfillment.next( edits.content );
68
- expect( value ).toEqual(
69
- controls.dispatch( STORE_NAME, 'editPost', edits, {
70
- undoIgnore: true,
71
- } )
72
- );
73
- }
74
- },
75
- ],
76
- [
77
- 'yields an action for signalling that an update to the post started',
78
- () => true,
79
- () => {
80
- const { value } = fulfillment.next();
81
- expect( value ).toEqual( {
82
- type: 'REQUEST_POST_UPDATE_START',
83
- options: { isAutosave },
84
- } );
85
- },
86
- ],
87
- [
88
- 'yields an action for selecting the current post',
89
- () => true,
90
- () => {
91
- const { value } = fulfillment.next();
92
- expect( value ).toEqual(
93
- controls.select( STORE_NAME, 'getCurrentPost' )
94
- );
95
- },
96
- ],
97
- [
98
- "yields an action for selecting the post entity's non transient edits",
99
- () => true,
100
- () => {
101
- const post = currentPost();
102
- const { value } = fulfillment.next( post );
103
- expect( value ).toEqual(
104
- controls.select(
105
- 'core',
106
- 'getEntityRecordNonTransientEdits',
107
- 'postType',
108
- post.type,
109
- post.id
110
- )
111
- );
112
- },
113
- ],
114
- [
115
- 'yields an action for dispatching an update to the post entity',
116
- () => true,
117
- () => {
118
- const post = currentPost();
119
- const { value } = fulfillment.next( post );
120
- expect( value ).toEqual(
121
- controls.dispatch(
122
- 'core',
123
- 'saveEntityRecord',
124
- 'postType',
125
- post.type,
126
- isAutosave ? { ...post, content: undefined } : post,
127
- {
128
- isAutosave,
129
- }
130
- )
131
- );
132
- },
133
- ],
134
- [
135
- 'yields an action for signalling that an update to the post finished',
136
- () => true,
137
- () => {
138
- const { value } = fulfillment.next();
139
- expect( value ).toEqual( {
140
- type: 'REQUEST_POST_UPDATE_FINISH',
141
- options: { isAutosave },
142
- } );
143
- },
144
- ],
145
- [
146
- "yields an action for selecting the entity's save error",
147
- () => true,
148
- () => {
149
- const post = currentPost();
150
- const { value } = fulfillment.next();
151
- expect( value ).toEqual(
152
- controls.select(
153
- 'core',
154
- 'getLastEntitySaveError',
155
- 'postType',
156
- post.type,
157
- post.id
158
- )
159
- );
160
- },
161
- ],
162
- [
163
- 'yields an action for selecting the current post',
164
- () => true,
165
- () => {
166
- const { value } = fulfillment.next();
167
- expect( value ).toEqual(
168
- controls.select( STORE_NAME, 'getCurrentPost' )
169
- );
170
- },
171
- ],
172
- [
173
- 'yields an action for selecting the current post type config',
174
- () => true,
175
- () => {
176
- const post = currentPost();
177
- const { value } = fulfillment.next( post );
178
- expect( value ).toEqual(
179
- controls.resolveSelect(
180
- 'core',
181
- 'getPostType',
182
- post.type
183
- )
184
- );
185
- },
186
- ],
187
- [
188
- 'yields an action for dispatching a success notice',
189
- () => true,
190
- () => {
191
- if ( ! isAutosave ) {
192
- const { value } = fulfillment.next( postType );
193
- expect( value ).toEqual(
194
- controls.dispatch(
195
- noticesStore,
196
- 'createSuccessNotice',
197
- currentPostStatus === 'publish'
198
- ? 'Updated Post'
199
- : 'Draft saved',
200
- {
201
- actions: [],
202
- id: 'SAVE_POST_NOTICE_ID',
203
- type: 'snackbar',
204
- }
205
- )
206
- );
207
- }
208
- },
209
- ],
210
- [
211
- 'yields an action for marking the last change as persistent',
212
- () => true,
213
- () => {
214
- if ( ! isAutosave ) {
215
- const { value } = fulfillment.next();
216
- expect( value ).toEqual(
217
- controls.dispatch(
218
- 'core/block-editor',
219
- '__unstableMarkLastChangeAsPersistent'
220
- )
221
- );
222
- }
223
- },
224
- ],
225
- [
226
- 'implicitly returns undefined',
227
- () => true,
228
- () => {
229
- expect( fulfillment.next() ).toEqual( {
230
- done: true,
231
- value: undefined,
232
- } );
233
- },
234
- ],
235
- ];
236
-
237
- const conditionalRunTestRoutine = ( isAutosaving ) => ( [
238
- testDescription,
239
- shouldRun,
240
- testRoutine,
241
- ] ) => {
242
- if ( shouldRun( isAutosaving ) ) {
243
- // eslint-disable-next-line jest/valid-title
244
- it( testDescription, () => {
245
- testRoutine();
246
- } );
247
- }
248
- };
249
-
250
- describe( 'yields with expected responses for when not autosaving and edited post is new', () => {
251
- beforeEach( () => {
252
- isAutosave = false;
253
- currentPostStatus = 'draft';
254
- } );
255
- testConditions.forEach( conditionalRunTestRoutine( false ) );
256
- } );
73
+ status: 'draft',
74
+ };
75
+
76
+ // Mock apiFetch response.
77
+ apiFetch.setFetchHandler( async ( options ) => {
78
+ const method = getMethod( options );
79
+ const { path, data } = options;
257
80
 
258
- describe( 'yields with expected responses for when not autosaving and edited post is not new', () => {
259
- beforeEach( () => {
260
- isAutosave = false;
261
- currentPostStatus = 'publish';
81
+ if (
82
+ method === 'PUT' &&
83
+ path.startsWith( `/wp/v2/posts/${ postId }` )
84
+ ) {
85
+ return { ...post, ...data };
86
+ }
87
+
88
+ throw {
89
+ code: 'unknown_path',
90
+ message: `Unknown path: ${ method } ${ path }`,
91
+ };
262
92
  } );
263
- testConditions.forEach( conditionalRunTestRoutine( false ) );
264
- } );
265
- describe( 'yields with expected responses for when autosaving is true and edited post is not new', () => {
266
- beforeEach( () => {
267
- isAutosave = true;
268
- currentPostStatus = 'autosave';
93
+
94
+ // Create registry.
95
+ const registry = createRegistryWithStores();
96
+
97
+ // Store post.
98
+ registry
99
+ .dispatch( coreStore )
100
+ .receiveEntityRecords( 'postType', 'post', post );
101
+
102
+ // Setup editor with post and initial edits.
103
+ registry.dispatch( editorStore ).setupEditor( post, {
104
+ content: 'new bar',
269
105
  } );
270
- testConditions.forEach( conditionalRunTestRoutine( true ) );
271
- } );
272
- } );
273
- describe( 'autosave()', () => {
274
- it( 'dispatches savePost with the correct arguments', () => {
275
- const fulfillment = actions.autosave();
276
- const { value } = fulfillment.next();
277
- expect( value.actionName ).toBe( 'savePost' );
278
- expect( value.args ).toEqual( [ { isAutosave: true } ] );
279
- } );
280
- } );
281
- describe( 'trashPost()', () => {
282
- let fulfillment;
283
- const currentPost = { id: 10, content: 'foo', status: 'publish' };
284
- const reset = () => ( fulfillment = actions.trashPost() );
285
- const rewind = () => {
286
- reset();
287
- fulfillment.next();
288
- fulfillment.next( postTypeSlug );
289
- fulfillment.next( postType );
290
- fulfillment.next();
291
- fulfillment.next( currentPost );
292
- };
293
- it( 'yields expected action for selecting the current post type slug', () => {
294
- reset();
295
- const { value } = fulfillment.next();
296
- expect( value ).toEqual(
297
- controls.select( STORE_NAME, 'getCurrentPostType' )
298
- );
299
- } );
300
- it( 'yields expected action for selecting the post type object', () => {
301
- const { value } = fulfillment.next( postTypeSlug );
302
- expect( value ).toEqual(
303
- controls.resolveSelect( 'core', 'getPostType', postTypeSlug )
304
- );
305
- } );
306
- it(
307
- 'yields expected action for dispatching removing the trash notice ' +
308
- 'for the post',
309
- () => {
310
- const { value } = fulfillment.next( postType );
311
- expect( value ).toEqual(
312
- controls.dispatch(
313
- noticesStore,
314
- 'removeNotice',
315
- TRASH_POST_NOTICE_ID
316
- )
317
- );
318
- }
319
- );
320
- it( 'yields expected action for selecting the currentPost', () => {
321
- const { value } = fulfillment.next();
322
- expect( value ).toEqual(
323
- controls.select( STORE_NAME, 'getCurrentPost' )
324
- );
325
- } );
326
- it( 'yields expected action object for the api fetch', () => {
327
- const { value } = fulfillment.next( currentPost );
328
- expect( value ).toEqual(
329
- apiFetch( {
330
- path: `/wp/v2/${ postType.rest_base }/${ currentPost.id }`,
331
- method: 'DELETE',
332
- } )
106
+
107
+ // Check that the post is dirty.
108
+ expect( registry.select( editorStore ).isEditedPostDirty() ).toBe(
109
+ true
333
110
  );
334
- } );
335
- describe( 'expected yields when fetch throws an error', () => {
336
- it( 'yields expected action for dispatching an error notice', () => {
337
- const error = { foo: 'bar', code: 'fail' };
338
- const { value } = fulfillment.throw( error );
339
- expect( value ).toEqual(
340
- controls.dispatch(
341
- noticesStore,
342
- 'createErrorNotice',
343
- 'Trashing failed',
344
- {
345
- id: TRASH_POST_NOTICE_ID,
346
- }
347
- )
348
- );
349
- } );
350
- } );
351
- describe( 'expected yields when fetch does not throw an error', () => {
352
- it( 'yields expected dispatch action for saving the post', () => {
353
- rewind();
354
- const { value } = fulfillment.next();
355
- expect( value ).toEqual(
356
- controls.dispatch( STORE_NAME, 'savePost' )
357
- );
358
- } );
359
- } );
360
- } );
361
- } );
362
111
 
363
- describe( 'Editor actions', () => {
364
- describe( 'setupEditor()', () => {
365
- it( 'should yield the setup editor actions but not reset blocks when the template is empty', () => {
366
- const post = { content: { raw: '' }, status: 'publish' };
367
- const fulfillment = actions.setupEditor( post );
368
- let { value } = fulfillment.next();
369
- expect( value ).toEqual( actions.resetPost( post ) );
370
- value = fulfillment.next().value;
371
- expect( value ).toEqual( {
372
- type: 'SETUP_EDITOR',
373
- post: { content: { raw: '' }, status: 'publish' },
374
- } );
375
- value = fulfillment.next().value;
376
- expect( value ).toEqual(
377
- actions.setupEditorState( {
378
- content: { raw: '' },
379
- status: 'publish',
380
- } )
112
+ // Save the post.
113
+ await registry.dispatch( editorStore ).savePost();
114
+
115
+ // Check the new content.
116
+ const content = registry
117
+ .select( editorStore )
118
+ .getEditedPostContent();
119
+ expect( content ).toBe( 'new bar' );
120
+
121
+ // Check that the post is no longer dirty.
122
+ expect( registry.select( editorStore ).isEditedPostDirty() ).toBe(
123
+ false
381
124
  );
382
- } );
383
- } );
384
125
 
385
- describe( 'resetPost', () => {
386
- it( 'should return the RESET_POST action', () => {
387
- const post = {};
388
- const result = actions.resetPost( post );
389
- expect( result ).toEqual( {
390
- type: 'RESET_POST',
391
- post,
392
- } );
126
+ // Check that a success notice has been shown.
127
+ const notices = registry.select( noticesStore ).getNotices();
128
+ expect( notices ).toMatchObject( [
129
+ {
130
+ status: 'success',
131
+ content: 'Draft saved',
132
+ },
133
+ ] );
393
134
  } );
394
135
  } );
395
136
 
396
- describe( 'requestPostUpdateStart', () => {
397
- it( 'should return the REQUEST_POST_UPDATE_START action', () => {
398
- const result = actions.__experimentalRequestPostUpdateStart();
399
- expect( result ).toEqual( {
400
- type: 'REQUEST_POST_UPDATE_START',
401
- options: {},
402
- } );
403
- } );
404
- } );
137
+ describe( 'autosave()', () => {
138
+ it( 'autosaves a modified post', async () => {
139
+ const post = {
140
+ id: postId,
141
+ type: 'post',
142
+ title: 'bar',
143
+ content: 'bar',
144
+ excerpt: 'crackers',
145
+ status: 'draft',
146
+ };
405
147
 
406
- describe( 'editPost', () => {
407
- it( 'should edit the relevant entity record', () => {
408
- const edits = { format: 'sample' };
409
- const fulfillment = actions.editPost( edits );
410
- expect( fulfillment.next() ).toEqual( {
411
- done: false,
412
- value: controls.select( STORE_NAME, 'getCurrentPost' ),
413
- } );
414
- const post = { id: 1, type: 'post' };
415
- expect( fulfillment.next( post ) ).toEqual( {
416
- done: false,
417
- value: controls.dispatch(
418
- 'core',
419
- 'editEntityRecord',
420
- 'postType',
421
- post.type,
422
- post.id,
423
- edits,
424
- undefined
425
- ),
148
+ // Mock apiFetch response.
149
+ apiFetch.setFetchHandler( async ( options ) => {
150
+ const method = getMethod( options );
151
+ const { path, data } = options;
152
+
153
+ if (
154
+ method === 'GET' &&
155
+ path.startsWith( '/wp/v2/users/me' )
156
+ ) {
157
+ return { id: 1 };
158
+ } else if (
159
+ path.startsWith( `/wp/v2/posts/${ postId }/autosaves` )
160
+ ) {
161
+ if ( method === 'POST' ) {
162
+ return { ...post, ...data };
163
+ } else if ( method === 'GET' ) {
164
+ return [];
165
+ }
166
+ }
167
+
168
+ throw {
169
+ code: 'unknown_path',
170
+ message: `Unknown path: ${ method } ${ path }`,
171
+ };
426
172
  } );
427
- expect( fulfillment.next() ).toEqual( {
428
- done: true,
429
- value: undefined,
173
+
174
+ // Create registry.
175
+ const registry = createRegistryWithStores();
176
+
177
+ // Set current user.
178
+ registry.dispatch( coreStore ).receiveCurrentUser( { id: 1 } );
179
+
180
+ // Store post.
181
+ registry
182
+ .dispatch( coreStore )
183
+ .receiveEntityRecords( 'postType', 'post', post );
184
+
185
+ // Setup editor with post and initial edits.
186
+ registry.dispatch( editorStore ).setupEditor( post, {
187
+ content: 'new bar',
430
188
  } );
189
+
190
+ // Check that the post is dirty.
191
+ expect( registry.select( editorStore ).isEditedPostDirty() ).toBe(
192
+ true
193
+ );
194
+
195
+ // Autosave the post.
196
+ await registry.dispatch( editorStore ).autosave();
197
+
198
+ // Check the new content.
199
+ const content = registry
200
+ .select( editorStore )
201
+ .getEditedPostContent();
202
+ expect( content ).toBe( 'new bar' );
203
+
204
+ // Check that the post is no longer dirty.
205
+ expect( registry.select( editorStore ).isEditedPostDirty() ).toBe(
206
+ false
207
+ );
208
+
209
+ // Check that no notice has been shown on autosave.
210
+ const notices = registry.select( noticesStore ).getNotices();
211
+ expect( notices ).toMatchObject( [] );
431
212
  } );
432
213
  } );
433
214
 
434
- describe( 'redo', () => {
435
- it( 'should yield the REDO action', () => {
436
- const fulfillment = actions.redo();
437
- expect( fulfillment.next() ).toEqual( {
438
- done: false,
439
- value: controls.dispatch( 'core', 'redo' ),
440
- } );
441
- expect( fulfillment.next() ).toEqual( {
442
- done: true,
443
- value: undefined,
215
+ describe( 'trashPost()', () => {
216
+ it( 'trashes a post', async () => {
217
+ const post = {
218
+ id: postId,
219
+ type: 'post',
220
+ content: 'foo',
221
+ status: 'publish',
222
+ };
223
+
224
+ let gotTrashed = false;
225
+
226
+ // Mock apiFetch response.
227
+ apiFetch.setFetchHandler( async ( options ) => {
228
+ const method = getMethod( options );
229
+ const { path, data } = options;
230
+
231
+ if ( path.startsWith( `/wp/v2/posts/${ postId }` ) ) {
232
+ if ( method === 'DELETE' ) {
233
+ gotTrashed = true;
234
+ return { ...post, status: 'trash' };
235
+ } else if ( method === 'PUT' ) {
236
+ return {
237
+ ...post,
238
+ ...( gotTrashed && { status: 'trash' } ),
239
+ ...data,
240
+ };
241
+ }
242
+ }
243
+
244
+ throw {
245
+ code: 'unknown_path',
246
+ message: `Unknown path: ${ path }`,
247
+ };
444
248
  } );
249
+
250
+ // Create registry.
251
+ const registry = createRegistryWithStores();
252
+
253
+ // Store post.
254
+ registry
255
+ .dispatch( coreStore )
256
+ .receiveEntityRecords( 'postType', 'post', post );
257
+
258
+ // Setup editor with post.
259
+ registry.dispatch( editorStore ).setupEditor( post );
260
+
261
+ // Trash the post.
262
+ await registry.dispatch( editorStore ).trashPost();
263
+
264
+ // Check that there are no notices.
265
+ const notices = registry.select( noticesStore ).getNotices();
266
+ expect( notices ).toEqual( [] );
267
+
268
+ // Check the new status.
269
+ const { status } = registry.select( editorStore ).getCurrentPost();
270
+ expect( status ).toBe( 'trash' );
445
271
  } );
446
272
  } );
273
+ } );
447
274
 
448
- describe( 'undo', () => {
449
- it( 'should yield the UNDO action', () => {
450
- const fulfillment = actions.undo();
451
- expect( fulfillment.next() ).toEqual( {
452
- done: false,
453
- value: controls.dispatch( 'core', 'undo' ),
454
- } );
455
- expect( fulfillment.next() ).toEqual( {
456
- done: true,
457
- value: undefined,
458
- } );
275
+ describe( 'Editor actions', () => {
276
+ describe( 'setupEditor()', () => {
277
+ it( 'should setup the editor', () => {
278
+ // Create registry.
279
+ const registry = createRegistryWithStores();
280
+
281
+ registry
282
+ .dispatch( editorStore )
283
+ .setupEditor( { id: 10, type: 'post' } );
284
+ expect( registry.select( editorStore ).getCurrentPostId() ).toBe(
285
+ 10
286
+ );
459
287
  } );
460
288
  } );
461
289