@contentful/field-editor-shared 2.13.10 → 2.15.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.
@@ -4,33 +4,33 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  const _react = require("@testing-library/react");
6
6
  const _useReleaseStatus = require("./useReleaseStatus");
7
- const buildEntry = (status, id = 'entry-1')=>({
8
- sys: {
9
- id,
10
- type: 'Entry',
11
- fieldStatus: {
12
- '*': {
13
- 'en-US': status
14
- }
15
- },
16
- version: 3,
17
- publishedVersion: status === 'published' ? 2 : undefined
18
- }
19
- });
20
- const buildAsset = (status, id = 'asset-1')=>({
21
- sys: {
22
- id,
23
- type: 'Asset',
24
- fieldStatus: {
25
- '*': {
26
- 'en-US': status
7
+ const createEntityBuilder = (entityType, defaultId)=>{
8
+ let currentId = defaultId;
9
+ return {
10
+ withId (id) {
11
+ currentId = id;
12
+ return this;
13
+ },
14
+ withStatus (status) {
15
+ return {
16
+ sys: {
17
+ id: currentId,
18
+ type: entityType,
19
+ fieldStatus: {
20
+ '*': {
21
+ 'en-US': status
22
+ }
23
+ },
24
+ version: 3,
25
+ publishedVersion: status === 'published' ? 2 : undefined
27
26
  }
28
- },
29
- version: 3,
30
- publishedVersion: status === 'published' ? 2 : undefined
27
+ };
31
28
  }
32
- });
33
- const createEntryBasedReleaseEntity = ({ entityId = 'entry-1', action = 'publish', entityType = 'Entry' })=>({
29
+ };
30
+ };
31
+ const entryBuilder = ()=>createEntityBuilder('Entry', 'entry-1');
32
+ const assetBuilder = ()=>createEntityBuilder('Asset', 'asset-1');
33
+ const createEntryBasedReleaseEntity = ({ entityId, action = 'publish', entityType })=>({
34
34
  entity: {
35
35
  sys: {
36
36
  type: 'Link',
@@ -40,7 +40,7 @@ const createEntryBasedReleaseEntity = ({ entityId = 'entry-1', action = 'publish
40
40
  },
41
41
  action
42
42
  });
43
- const createEntryBasedRelease = ({ entityId, action, entityType = 'Entry' } = {})=>({
43
+ const createEntryBasedRelease = ({ entityId, action, entityType })=>({
44
44
  title: 'Release 1',
45
45
  sys: {
46
46
  id: 'release-1',
@@ -57,7 +57,7 @@ const createEntryBasedRelease = ({ entityId, action, entityType = 'Entry' } = {}
57
57
  ]
58
58
  }
59
59
  });
60
- const createLocaleBasedReleaseEntity = ({ entityId = 'entry-1', verb = 'add', entityType = 'Entry' })=>({
60
+ const createLocaleBasedReleaseEntity = ({ entityId, verb = 'add', entityType })=>({
61
61
  entity: {
62
62
  sys: {
63
63
  type: 'Link',
@@ -73,7 +73,7 @@ const createLocaleBasedReleaseEntity = ({ entityId = 'entry-1', verb = 'add', en
73
73
  }
74
74
  }
75
75
  });
76
- const createLocaleBasedRelease = ({ entityId, verb, entityType = 'Entry' } = {})=>({
76
+ const createLocaleBasedRelease = ({ entityId, verb, entityType })=>({
77
77
  title: 'Release 1',
78
78
  sys: {
79
79
  id: 'release-1',
@@ -90,224 +90,505 @@ const createLocaleBasedRelease = ({ entityId, verb, entityType = 'Entry' } = {})
90
90
  ]
91
91
  }
92
92
  });
93
+ const createDefaultLocales = ()=>[
94
+ {
95
+ code: 'en-US'
96
+ }
97
+ ];
98
+ const expectLocaleStatus = (result, localeCode, expected)=>{
99
+ expect(result.releaseStatusMap.get(localeCode)).toEqual(expected);
100
+ };
101
+ const expectEntityStatus = (result, expectedStatus)=>{
102
+ expect(result.releaseEntityStatus).toBe(expectedStatus);
103
+ };
93
104
  const ENTITY_TYPES = [
94
105
  'Entry',
95
106
  'Asset'
96
107
  ];
97
108
  describe('useReleaseStatus', ()=>{
98
- beforeEach(()=>{
99
- jest.clearAllMocks();
109
+ const locales = createDefaultLocales();
110
+ describe('Guard clauses and invalid inputs', ()=>{
111
+ it('returns empty map when entity is undefined', ()=>{
112
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
113
+ locales,
114
+ release: createEntryBasedRelease({
115
+ entityId: 'entry-1',
116
+ entityType: 'Entry'
117
+ }),
118
+ entity: undefined
119
+ }));
120
+ expect(result.current.releaseStatusMap.size).toBe(0);
121
+ });
122
+ it('returns empty map when release is undefined', ()=>{
123
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
124
+ locales,
125
+ entity: entryBuilder().withStatus('published'),
126
+ release: undefined
127
+ }));
128
+ expect(result.current.releaseStatusMap.size).toBe(0);
129
+ });
130
+ it('returns empty map when release has no schemaVersion', ()=>{
131
+ const invalidRelease = {
132
+ title: 'Release 1',
133
+ sys: {
134
+ id: 'release-1',
135
+ type: 'Release'
136
+ },
137
+ entities: {
138
+ items: []
139
+ }
140
+ };
141
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
142
+ locales,
143
+ entity: entryBuilder().withStatus('published'),
144
+ release: invalidRelease
145
+ }));
146
+ expect(result.current.releaseStatusMap.size).toBe(0);
147
+ });
148
+ it('returns empty map when release schema is not v2', ()=>{
149
+ const oldSchemaRelease = {
150
+ title: 'Release 1',
151
+ sys: {
152
+ id: 'release-1',
153
+ type: 'Release',
154
+ schemaVersion: 'Release.v1'
155
+ },
156
+ entities: {
157
+ items: []
158
+ }
159
+ };
160
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
161
+ locales,
162
+ entity: entryBuilder().withStatus('published'),
163
+ release: oldSchemaRelease
164
+ }));
165
+ expect(result.current.releaseStatusMap.size).toBe(0);
166
+ });
100
167
  });
101
- ENTITY_TYPES.forEach((entityType)=>{
102
- const entityId = entityType === 'Entry' ? 'entry-1' : 'asset-1';
103
- const baseParams = {
104
- locales: [
105
- {
168
+ describe('Edge case: Missing previousEntityOnTimeline', ()=>{
169
+ it('defaults to "Remains draft" when unpublishing without previous state (entry-based)', ()=>{
170
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
171
+ locales,
172
+ previousEntityOnTimeline: undefined,
173
+ release: createEntryBasedRelease({
174
+ entityId: 'entry-1',
175
+ entityType: 'Entry',
176
+ action: 'unpublish'
177
+ }),
178
+ entity: entryBuilder().withStatus('draft')
179
+ }));
180
+ expectLocaleStatus(result.current, 'en-US', {
181
+ variant: 'warning',
182
+ status: 'remainsDraft',
183
+ label: 'Remains draft',
184
+ locale: {
106
185
  code: 'en-US'
107
186
  }
108
- ]
109
- };
110
- function buildEntity(status) {
111
- return entityType === 'Entry' ? buildEntry(status) : buildAsset(status);
112
- }
113
- describe(`${entityType} with entry based publishing`, ()=>{
114
- it('returns Will publish status when active release has publish action', ()=>{
115
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
116
- ...baseParams,
117
- previousEntityOnTimeline: buildEntity('draft'),
118
- release: createEntryBasedRelease({
119
- entityId,
120
- entityType
121
- }),
122
- entity: buildEntity('published')
123
- }));
124
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
125
- variant: 'positive',
126
- status: 'willPublish',
127
- label: 'Will publish',
128
- locale: {
129
- code: 'en-US'
130
- }
131
- });
132
187
  });
133
- it('returns Becomes draft status when previous version has published locales and active version has unpublish action', ()=>{
134
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
135
- ...baseParams,
136
- previousEntityOnTimeline: buildEntity('published'),
137
- release: createEntryBasedRelease({
138
- action: 'unpublish',
139
- entityId,
140
- entityType
141
- }),
142
- entity: buildEntity('draft')
143
- }));
144
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
145
- variant: 'warning',
146
- status: 'becomesDraft',
147
- label: 'Becomes draft',
148
- locale: {
149
- code: 'en-US'
150
- }
151
- });
188
+ });
189
+ it('defaults to "Remains draft" when removing locale without previous state (locale-based)', ()=>{
190
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
191
+ locales,
192
+ previousEntityOnTimeline: undefined,
193
+ release: createLocaleBasedRelease({
194
+ entityId: 'entry-1',
195
+ entityType: 'Entry',
196
+ verb: 'remove'
197
+ }),
198
+ entity: entryBuilder().withStatus('draft')
199
+ }));
200
+ expectLocaleStatus(result.current, 'en-US', {
201
+ variant: 'warning',
202
+ status: 'remainsDraft',
203
+ label: 'Remains draft',
204
+ locale: {
205
+ code: 'en-US'
206
+ }
152
207
  });
153
- it('returns Remains draft status when previous version has draft locales and active version has unpublish action', ()=>{
154
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
155
- ...baseParams,
156
- previousEntityOnTimeline: buildEntity('draft'),
157
- release: createEntryBasedRelease({
158
- action: 'unpublish',
159
- entityId,
160
- entityType
161
- }),
162
- entity: buildEntity('draft')
163
- }));
164
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
165
- variant: 'warning',
166
- status: 'remainsDraft',
167
- label: 'Remains draft',
168
- locale: {
169
- code: 'en-US'
170
- }
171
- });
208
+ });
209
+ });
210
+ describe('Changed status handling', ()=>{
211
+ const buildChangedEntry = ()=>({
212
+ sys: {
213
+ id: 'entry-1',
214
+ type: 'Entry',
215
+ fieldStatus: {
216
+ '*': {
217
+ 'en-US': 'changed'
218
+ }
219
+ },
220
+ version: 5,
221
+ publishedVersion: 2
222
+ }
172
223
  });
173
- it('returns Not in release status when entity is not in the release', ()=>{
174
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
175
- ...baseParams,
176
- release: createEntryBasedRelease({
177
- entityId: entityType === 'Entry' ? 'entry-2' : 'asset-2',
178
- action: 'publish',
179
- entityType
180
- }),
181
- entity: buildEntity('draft')
182
- }));
183
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
184
- variant: 'secondary',
185
- status: 'notInRelease',
186
- label: 'Not in release',
187
- locale: {
188
- code: 'en-US'
189
- }
190
- });
224
+ it('treats "changed" as published-like when unpublishing (entry-based)', ()=>{
225
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
226
+ locales,
227
+ previousEntityOnTimeline: buildChangedEntry(),
228
+ release: createEntryBasedRelease({
229
+ entityId: 'entry-1',
230
+ entityType: 'Entry',
231
+ action: 'unpublish'
232
+ }),
233
+ entity: entryBuilder().withStatus('draft')
234
+ }));
235
+ expectLocaleStatus(result.current, 'en-US', {
236
+ variant: 'warning',
237
+ status: 'becomesDraft',
238
+ label: 'Becomes draft',
239
+ locale: {
240
+ code: 'en-US'
241
+ }
191
242
  });
192
- it('returns published when not in release but already published', ()=>{
193
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
194
- ...baseParams,
195
- release: createEntryBasedRelease({
196
- entityId: entityType === 'Entry' ? 'entry-2' : 'asset-2',
197
- action: 'publish',
198
- entityType
199
- }),
200
- entity: buildEntity('published')
201
- }));
202
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
203
- variant: 'positive',
204
- status: 'published',
205
- label: 'Published',
206
- locale: {
207
- code: 'en-US'
208
- }
209
- });
210
- expect(result.current.releaseEntityStatus).toBe('published');
243
+ });
244
+ it('treats "changed" as published-like when removing locale (locale-based)', ()=>{
245
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
246
+ locales,
247
+ previousEntityOnTimeline: buildChangedEntry(),
248
+ release: createLocaleBasedRelease({
249
+ entityId: 'entry-1',
250
+ entityType: 'Entry',
251
+ verb: 'remove'
252
+ }),
253
+ entity: entryBuilder().withStatus('draft')
254
+ }));
255
+ expectLocaleStatus(result.current, 'en-US', {
256
+ variant: 'warning',
257
+ status: 'becomesDraft',
258
+ label: 'Becomes draft',
259
+ locale: {
260
+ code: 'en-US'
261
+ }
211
262
  });
212
263
  });
213
- describe(`${entityType} with locale based publishing`, ()=>{
214
- it('returns Will publish status when active release has publish action', ()=>{
215
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
216
- ...baseParams,
217
- previousEntityOnTimeline: buildEntity('draft'),
218
- release: createLocaleBasedRelease({
219
- entityId,
220
- entityType
221
- }),
222
- entity: buildEntity('published')
223
- }));
224
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
225
- variant: 'positive',
226
- status: 'willPublish',
227
- label: 'Will publish',
228
- locale: {
229
- code: 'en-US'
230
- }
231
- });
264
+ it('shows "Published" for changed reference not in release', ()=>{
265
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
266
+ locales,
267
+ release: createEntryBasedRelease({
268
+ entityId: 'entry-2',
269
+ entityType: 'Entry',
270
+ action: 'publish'
271
+ }),
272
+ entity: buildChangedEntry(),
273
+ isReference: true
274
+ }));
275
+ expectLocaleStatus(result.current, 'en-US', {
276
+ variant: 'positive',
277
+ status: 'published',
278
+ label: 'Published',
279
+ locale: {
280
+ code: 'en-US'
281
+ }
232
282
  });
233
- it('returns Becomes draft status when previous version has published locales and active version has unpublish action', ()=>{
234
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
235
- ...baseParams,
236
- previousEntityOnTimeline: buildEntity('published'),
237
- release: createLocaleBasedRelease({
238
- verb: 'remove',
239
- entityId,
240
- entityType
241
- }),
242
- entity: buildEntity('draft')
243
- }));
244
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
245
- variant: 'warning',
246
- status: 'becomesDraft',
247
- label: 'Becomes draft',
248
- locale: {
249
- code: 'en-US'
250
- }
251
- });
283
+ });
284
+ });
285
+ describe('Multi-locale scenarios', ()=>{
286
+ const multiLocales = [
287
+ {
288
+ code: 'en-US'
289
+ },
290
+ {
291
+ code: 'de-DE'
292
+ }
293
+ ];
294
+ const buildMultiLocaleEntry = (enStatus, deStatus)=>({
295
+ sys: {
296
+ id: 'entry-1',
297
+ type: 'Entry',
298
+ fieldStatus: {
299
+ '*': {
300
+ 'en-US': enStatus,
301
+ 'de-DE': deStatus
302
+ }
303
+ },
304
+ version: 3,
305
+ publishedVersion: enStatus === 'published' || deStatus === 'published' ? 2 : undefined
306
+ }
252
307
  });
253
- it('returns Remains draft status when previous version has draft locales and active version has unpublish action', ()=>{
254
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
255
- ...baseParams,
256
- previousEntityOnTimeline: buildEntity('draft'),
257
- release: createLocaleBasedRelease({
258
- verb: 'remove',
259
- entityId,
260
- entityType
261
- }),
262
- entity: buildEntity('draft')
263
- }));
264
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
265
- variant: 'warning',
266
- status: 'remainsDraft',
267
- label: 'Remains draft',
268
- locale: {
269
- code: 'en-US'
270
- }
271
- });
308
+ it('creates status for each locale', ()=>{
309
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
310
+ locales: multiLocales,
311
+ release: createEntryBasedRelease({
312
+ entityId: 'entry-1',
313
+ entityType: 'Entry',
314
+ action: 'publish'
315
+ }),
316
+ entity: buildMultiLocaleEntry('draft', 'draft')
317
+ }));
318
+ expect(result.current.releaseStatusMap.size).toBe(2);
319
+ expect(result.current.releaseStatusMap.has('en-US')).toBe(true);
320
+ expect(result.current.releaseStatusMap.has('de-DE')).toBe(true);
321
+ });
322
+ it('aggregates to "published" when any locale is published', ()=>{
323
+ const publishedEntity = buildMultiLocaleEntry('published', 'draft');
324
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
325
+ locales: multiLocales,
326
+ release: createEntryBasedRelease({
327
+ entityId: 'entry-2',
328
+ entityType: 'Entry',
329
+ action: 'publish'
330
+ }),
331
+ entity: publishedEntity,
332
+ isReference: true
333
+ }));
334
+ expectEntityStatus(result.current, 'published');
335
+ });
336
+ it('aggregates to "willPublish" when any locale will publish', ()=>{
337
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
338
+ locales: multiLocales,
339
+ release: createEntryBasedRelease({
340
+ entityId: 'entry-1',
341
+ entityType: 'Entry',
342
+ action: 'publish'
343
+ }),
344
+ entity: buildMultiLocaleEntry('draft', 'draft')
345
+ }));
346
+ expectEntityStatus(result.current, 'willPublish');
347
+ });
348
+ it('handles locale not in add/remove arrays', ()=>{
349
+ const releaseWithDifferentLocale = {
350
+ title: 'Release 1',
351
+ sys: {
352
+ id: 'release-1',
353
+ type: 'Release',
354
+ schemaVersion: 'Release.v2'
355
+ },
356
+ entities: {
357
+ items: [
358
+ {
359
+ entity: {
360
+ sys: {
361
+ type: 'Link',
362
+ linkType: 'Entry',
363
+ id: 'entry-1'
364
+ }
365
+ },
366
+ add: {
367
+ fields: {
368
+ '*': [
369
+ 'de-DE'
370
+ ]
371
+ }
372
+ }
373
+ }
374
+ ]
375
+ }
376
+ };
377
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
378
+ locales,
379
+ release: releaseWithDifferentLocale,
380
+ entity: entryBuilder().withStatus('draft')
381
+ }));
382
+ expectLocaleStatus(result.current, 'en-US', {
383
+ variant: 'warning',
384
+ status: 'remainsDraft',
385
+ label: 'Remains draft',
386
+ locale: {
387
+ code: 'en-US'
388
+ }
272
389
  });
273
- it('returns Not in release status when entry is in draft state and not in the release', ()=>{
274
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
275
- ...baseParams,
276
- release: createLocaleBasedRelease({
277
- entityId: entityType === 'Entry' ? 'entry-2' : 'asset-2',
278
- entityType,
279
- verb: 'add'
280
- }),
281
- entity: buildEntity('draft')
282
- }));
283
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
284
- variant: 'secondary',
285
- status: 'notInRelease',
286
- label: 'Not in release',
287
- locale: {
288
- code: 'en-US'
289
- }
390
+ });
391
+ });
392
+ const testPublishingScenarios = (config)=>{
393
+ const { isReference, publishingModel } = config;
394
+ const locales = createDefaultLocales();
395
+ ENTITY_TYPES.forEach((entityType)=>{
396
+ const defaultEntityId = entityType === 'Entry' ? 'entry-1' : 'asset-1';
397
+ const differentEntityId = entityType === 'Entry' ? 'entry-2' : 'asset-2';
398
+ const buildEntity = (status)=>{
399
+ const builder = entityType === 'Entry' ? entryBuilder() : assetBuilder();
400
+ return builder.withStatus(status);
401
+ };
402
+ const createRelease = (options)=>{
403
+ return publishingModel === 'entry-based' ? createEntryBasedRelease({
404
+ entityId: options.entityId,
405
+ entityType,
406
+ action: options.action || 'publish'
407
+ }) : createLocaleBasedRelease({
408
+ entityId: options.entityId,
409
+ entityType,
410
+ verb: options.verb || 'add'
290
411
  });
291
- });
292
- it('returns published status when entry is in published state and not in the release', ()=>{
293
- const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
294
- ...baseParams,
295
- release: createLocaleBasedRelease({
296
- entityId: entityType === 'Entry' ? 'entry-2' : 'asset-2',
297
- entityType,
298
- verb: 'add'
299
- }),
300
- entity: buildEntity('published')
301
- }));
302
- expect(result.current.releaseStatusMap.get('en-US')).toEqual({
303
- variant: 'positive',
304
- status: 'published',
305
- label: 'Published',
306
- locale: {
307
- code: 'en-US'
308
- }
412
+ };
413
+ const publishAction = publishingModel === 'entry-based' ? 'publish' : 'add';
414
+ const unpublishAction = publishingModel === 'entry-based' ? 'unpublish' : 'remove';
415
+ describe(`${entityType}`, ()=>{
416
+ it(`[${publishAction}] shows "Will publish" when entity transitions draft → published`, ()=>{
417
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
418
+ locales,
419
+ previousEntityOnTimeline: buildEntity('draft'),
420
+ release: createRelease({
421
+ entityId: defaultEntityId,
422
+ action: 'publish',
423
+ verb: 'add'
424
+ }),
425
+ entity: buildEntity('published'),
426
+ isReference
427
+ }));
428
+ expectLocaleStatus(result.current, 'en-US', {
429
+ variant: 'positive',
430
+ status: 'willPublish',
431
+ label: 'Will publish',
432
+ locale: {
433
+ code: 'en-US'
434
+ }
435
+ });
309
436
  });
310
- expect(result.current.releaseEntityStatus).toBe('published');
437
+ it(`[${unpublishAction}] shows "Becomes draft" when entity transitions published → draft`, ()=>{
438
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
439
+ locales,
440
+ previousEntityOnTimeline: buildEntity('published'),
441
+ release: createRelease({
442
+ entityId: defaultEntityId,
443
+ action: 'unpublish',
444
+ verb: 'remove'
445
+ }),
446
+ entity: buildEntity('draft'),
447
+ isReference
448
+ }));
449
+ expectLocaleStatus(result.current, 'en-US', {
450
+ variant: 'warning',
451
+ status: 'becomesDraft',
452
+ label: 'Becomes draft',
453
+ locale: {
454
+ code: 'en-US'
455
+ }
456
+ });
457
+ });
458
+ it(`[${unpublishAction}] shows "Remains draft" when entity stays draft → draft`, ()=>{
459
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
460
+ locales,
461
+ previousEntityOnTimeline: buildEntity('draft'),
462
+ release: createRelease({
463
+ entityId: defaultEntityId,
464
+ action: 'unpublish',
465
+ verb: 'remove'
466
+ }),
467
+ entity: buildEntity('draft'),
468
+ isReference
469
+ }));
470
+ expectLocaleStatus(result.current, 'en-US', {
471
+ variant: 'warning',
472
+ status: 'remainsDraft',
473
+ label: 'Remains draft',
474
+ locale: {
475
+ code: 'en-US'
476
+ }
477
+ });
478
+ });
479
+ if (isReference) {
480
+ it('[not in release] shows "Published" when entity is published (returns actual state)', ()=>{
481
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
482
+ locales,
483
+ release: createRelease({
484
+ entityId: differentEntityId,
485
+ action: 'publish',
486
+ verb: 'add'
487
+ }),
488
+ entity: buildEntity('published'),
489
+ isReference
490
+ }));
491
+ expectLocaleStatus(result.current, 'en-US', {
492
+ variant: 'positive',
493
+ status: 'published',
494
+ label: 'Published',
495
+ locale: {
496
+ code: 'en-US'
497
+ }
498
+ });
499
+ expectEntityStatus(result.current, 'published');
500
+ });
501
+ it('[not in release] shows "Not in release" when entity is draft (returns actual state)', ()=>{
502
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
503
+ locales,
504
+ release: createRelease({
505
+ entityId: differentEntityId,
506
+ action: 'publish',
507
+ verb: 'add'
508
+ }),
509
+ entity: buildEntity('draft'),
510
+ isReference
511
+ }));
512
+ expectLocaleStatus(result.current, 'en-US', {
513
+ variant: 'secondary',
514
+ status: 'notInRelease',
515
+ label: 'Not in release',
516
+ locale: {
517
+ code: 'en-US'
518
+ }
519
+ });
520
+ });
521
+ } else {
522
+ it('[not in release] returns "notInRelease" even when published (ignores actual state)', ()=>{
523
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
524
+ locales,
525
+ release: createRelease({
526
+ entityId: differentEntityId,
527
+ action: 'publish',
528
+ verb: 'add'
529
+ }),
530
+ entity: buildEntity('published'),
531
+ isReference
532
+ }));
533
+ expectLocaleStatus(result.current, 'en-US', {
534
+ variant: 'secondary',
535
+ status: 'notInRelease',
536
+ label: 'Not in release',
537
+ locale: {
538
+ code: 'en-US'
539
+ }
540
+ });
541
+ expectEntityStatus(result.current, 'notInRelease');
542
+ });
543
+ it('[not in release] returns "notInRelease" when draft (consistent regardless of state)', ()=>{
544
+ const { result } = (0, _react.renderHook)(()=>(0, _useReleaseStatus.useReleaseStatus)({
545
+ locales,
546
+ release: createRelease({
547
+ entityId: differentEntityId,
548
+ action: 'publish',
549
+ verb: 'add'
550
+ }),
551
+ entity: buildEntity('draft'),
552
+ isReference
553
+ }));
554
+ expectLocaleStatus(result.current, 'en-US', {
555
+ variant: 'secondary',
556
+ status: 'notInRelease',
557
+ label: 'Not in release',
558
+ locale: {
559
+ code: 'en-US'
560
+ }
561
+ });
562
+ });
563
+ }
564
+ });
565
+ });
566
+ };
567
+ describe('When entity is a reference (isReference: true)', ()=>{
568
+ describe('Entry-based publishing', ()=>{
569
+ testPublishingScenarios({
570
+ isReference: true,
571
+ publishingModel: 'entry-based'
572
+ });
573
+ });
574
+ describe('Locale-based publishing', ()=>{
575
+ testPublishingScenarios({
576
+ isReference: true,
577
+ publishingModel: 'locale-based'
578
+ });
579
+ });
580
+ });
581
+ describe('When entity is NOT a reference (isReference: false)', ()=>{
582
+ describe('Entry-based publishing', ()=>{
583
+ testPublishingScenarios({
584
+ isReference: false,
585
+ publishingModel: 'entry-based'
586
+ });
587
+ });
588
+ describe('Locale-based publishing', ()=>{
589
+ testPublishingScenarios({
590
+ isReference: false,
591
+ publishingModel: 'locale-based'
311
592
  });
312
593
  });
313
594
  });