@byline/core 6.7.1 → 6.7.2
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/dist/schemas/zod/review-comparison-probe.test.node.d.ts +1 -0
- package/dist/schemas/zod/review-comparison-probe.test.node.js +26 -0
- package/dist/services/restore-review-probe.test.node.js +3397 -0
- package/dist/services/review-probes.test.node.d.ts +8 -0
- package/dist/services/review-probes.test.node.js +349 -0
- package/package.json +12 -12
- package/dist/config/resolve-item-view-columns.test.node.js +0 -30
- /package/dist/{config/resolve-item-view-columns.test.node.d.ts → services/restore-review-probe.test.node.d.ts} +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import { AdminAuth, AuthError, AuthErrorCodes, createRequestContext, createSuperAdminContext, } from '@byline/auth';
|
|
9
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
10
|
+
import { BylineError, DbErrorCodes, ERR_DOCUMENT_STALE, ERR_NOT_FOUND, ErrorCodes, } from '../lib/errors.js';
|
|
11
|
+
import { runReadSnapshot } from '../storage/read-snapshot.js';
|
|
12
|
+
import { unusedRevisionStore } from '../storage/revision-store.test-helper.js';
|
|
13
|
+
import { cancelDocumentScheduledPublish, changeDocumentStatus, confirmDocumentScheduledPublish, copyToLocale, createDocument, deleteDocument, deleteLocale, duplicateDocument, listDocumentPublishSchedules, restoreDocumentVersion, scheduleDocumentPublish, unpublishDocument, updateDocument, updateDocumentSystemFields, updateDocumentWithPatches, } from './document-lifecycle/index.js';
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Fixtures / Helpers
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const minimalCollection = {
|
|
18
|
+
path: 'articles',
|
|
19
|
+
labels: { singular: 'Article', plural: 'Articles' },
|
|
20
|
+
fields: [{ name: 'title', type: 'text', label: 'Title' }],
|
|
21
|
+
workflow: {
|
|
22
|
+
statuses: [
|
|
23
|
+
{ name: 'draft', label: 'Draft' },
|
|
24
|
+
{ name: 'published', label: 'Published' },
|
|
25
|
+
{ name: 'archived', label: 'Archived' },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const numericCollection = {
|
|
30
|
+
...minimalCollection,
|
|
31
|
+
fields: [
|
|
32
|
+
{ name: 'quantity', type: 'integer' },
|
|
33
|
+
{ name: 'score', type: 'float' },
|
|
34
|
+
{ name: 'price', type: 'decimal' },
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
function publishScheduleRow(overrides = {}) {
|
|
38
|
+
const now = new Date('2026-08-22T12:00:00.000Z');
|
|
39
|
+
return {
|
|
40
|
+
documentId: 'doc-1',
|
|
41
|
+
collectionId: 'col-1',
|
|
42
|
+
targetVersionId: 'ver-1',
|
|
43
|
+
authorizedRevision: 1,
|
|
44
|
+
publishAt: new Date('2026-08-23T12:00:00.000Z'),
|
|
45
|
+
state: 'armed',
|
|
46
|
+
suspendedAt: null,
|
|
47
|
+
suspendedReason: null,
|
|
48
|
+
scheduledBy: TEST_ACTOR_ID,
|
|
49
|
+
lastAuthorizedBy: TEST_ACTOR_ID,
|
|
50
|
+
lastAuthorizedAt: now,
|
|
51
|
+
scheduledAt: now,
|
|
52
|
+
updatedAt: now,
|
|
53
|
+
executionToken: null,
|
|
54
|
+
executionExpiresAt: null,
|
|
55
|
+
lastAttemptAt: null,
|
|
56
|
+
nextAttemptAt: new Date('2026-08-23T12:00:00.000Z'),
|
|
57
|
+
attemptCount: 0,
|
|
58
|
+
lastError: null,
|
|
59
|
+
...overrides,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Build a mock IDbAdapter. Returns the adapter plus individual mock fns. */
|
|
63
|
+
function createMockDb() {
|
|
64
|
+
const createDocumentVersion = vi.fn().mockResolvedValue({
|
|
65
|
+
document: { id: 'ver-1', document_id: 'doc-1' },
|
|
66
|
+
fieldCount: 3,
|
|
67
|
+
});
|
|
68
|
+
const setDocumentStatus = vi.fn().mockResolvedValue(undefined);
|
|
69
|
+
const archivePublishedVersions = vi.fn().mockResolvedValue(0);
|
|
70
|
+
const softDeleteDocument = vi.fn().mockResolvedValue(1);
|
|
71
|
+
const deleteDocumentLocale = vi.fn().mockResolvedValue({ newVersionId: 'ver-2' });
|
|
72
|
+
const getDocumentById = vi.fn().mockImplementation(async () => {
|
|
73
|
+
const metadata = await getCurrentVersionMetadata();
|
|
74
|
+
return metadata == null ? null : { ...metadata, fields: {}, path: await getCurrentPath() };
|
|
75
|
+
});
|
|
76
|
+
const getDocumentSystemFieldsForUpdate = vi.fn().mockResolvedValue(null);
|
|
77
|
+
const getCurrentVersionMetadata = vi.fn().mockResolvedValue(null);
|
|
78
|
+
const getCurrentPath = vi.fn().mockResolvedValue('current-path');
|
|
79
|
+
const publishSchedule = vi.fn().mockResolvedValue({ status: 'document_not_found' });
|
|
80
|
+
const confirmPublishSchedule = vi.fn().mockResolvedValue({ status: 'schedule_not_found' });
|
|
81
|
+
const cancelPublishSchedule = vi.fn().mockResolvedValue(null);
|
|
82
|
+
const suspendPublishSchedule = vi.fn().mockResolvedValue({ status: 'schedule_not_found' });
|
|
83
|
+
const claimDuePublishSchedules = vi.fn().mockResolvedValue([]);
|
|
84
|
+
const lockPublishScheduleClaim = vi.fn().mockResolvedValue(null);
|
|
85
|
+
const deletePublishScheduleClaim = vi.fn().mockResolvedValue(false);
|
|
86
|
+
const suspendPublishScheduleClaim = vi.fn().mockResolvedValue(false);
|
|
87
|
+
const releasePublishScheduleClaim = vi.fn().mockResolvedValue(false);
|
|
88
|
+
const getPublishSchedule = vi.fn().mockResolvedValue(null);
|
|
89
|
+
const listPublishSchedules = vi.fn().mockResolvedValue({ schedules: [], total: 0 });
|
|
90
|
+
// Audit capability (docs/07-auth-and-security/02-auditability.md — W2). `withTransaction` is a passthrough
|
|
91
|
+
// in unit tests (runs the unit of work immediately, no real tx); `append`
|
|
92
|
+
// records the calls so write-point tests can assert the audit rows emitted.
|
|
93
|
+
const auditAppend = vi.fn().mockResolvedValue({ id: 'audit-1' });
|
|
94
|
+
let transactionDepth = 0;
|
|
95
|
+
const revisions = new Map();
|
|
96
|
+
const transaction = {
|
|
97
|
+
run: async (fn) => {
|
|
98
|
+
transactionDepth++;
|
|
99
|
+
try {
|
|
100
|
+
return await fn();
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
transactionDepth--;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
const withTransaction = vi.spyOn(transaction, 'run');
|
|
108
|
+
const fail = () => {
|
|
109
|
+
throw new Error('unexpected singleton mapping call');
|
|
110
|
+
};
|
|
111
|
+
// Fake classifier mirroring db-postgres's real one closely enough for
|
|
112
|
+
// rethrowPathConflict's consumption of the seam: a pg-shaped 23505 with a
|
|
113
|
+
// constraint name classifies as a unique violation; anything else is
|
|
114
|
+
// unknown. Individual tests inject pg-shaped errors on `createDocumentVersion`
|
|
115
|
+
// (see `translates a Postgres unique-constraint violation...` below).
|
|
116
|
+
const classifyError = vi.fn((err) => {
|
|
117
|
+
const e = err;
|
|
118
|
+
if (e?.code === '23505') {
|
|
119
|
+
return { code: DbErrorCodes.UNIQUE_VIOLATION, constraint: e.constraint };
|
|
120
|
+
}
|
|
121
|
+
return { code: DbErrorCodes.UNKNOWN };
|
|
122
|
+
});
|
|
123
|
+
const db = {
|
|
124
|
+
classifyError,
|
|
125
|
+
revisions: {
|
|
126
|
+
...unusedRevisionStore,
|
|
127
|
+
isInTransaction: () => transactionDepth > 0,
|
|
128
|
+
lock: vi.fn(async (targets) => {
|
|
129
|
+
const observations = [];
|
|
130
|
+
for (const target of targets) {
|
|
131
|
+
const revision = revisions.get(target.documentId) ?? 1;
|
|
132
|
+
if (target.expectedRevision !== revision)
|
|
133
|
+
throw ERR_DOCUMENT_STALE({
|
|
134
|
+
message: 'stale',
|
|
135
|
+
details: {
|
|
136
|
+
reason: 'revision_mismatch',
|
|
137
|
+
documentId: target.documentId,
|
|
138
|
+
expectedRevision: target.expectedRevision,
|
|
139
|
+
currentRevision: revision,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
const system = await getDocumentSystemFieldsForUpdate({
|
|
143
|
+
collection_id: target.collectionId,
|
|
144
|
+
document_id: target.documentId,
|
|
145
|
+
});
|
|
146
|
+
const source = await getDocumentById.mock.results.at(-1)?.value;
|
|
147
|
+
if (!system && !source)
|
|
148
|
+
throw ERR_NOT_FOUND({ message: 'document not found' });
|
|
149
|
+
observations.push({
|
|
150
|
+
documentId: target.documentId,
|
|
151
|
+
collectionId: target.collectionId,
|
|
152
|
+
revision,
|
|
153
|
+
currentVersionId: source?.document_version_id ?? 'ver-1',
|
|
154
|
+
status: source?.status ?? 'draft',
|
|
155
|
+
sourceLocale: system?.source_locale ?? source?.source_locale ?? 'en',
|
|
156
|
+
path: system?.path ?? source?.path ?? null,
|
|
157
|
+
availableLocales: system?.availableLocales ?? source?.availableLocales ?? [],
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return observations;
|
|
161
|
+
}),
|
|
162
|
+
advance: vi.fn(async (locked) => {
|
|
163
|
+
const revision = locked.revision + 1;
|
|
164
|
+
revisions.set(locked.documentId, revision);
|
|
165
|
+
return { documentId: locked.documentId, revision };
|
|
166
|
+
}),
|
|
167
|
+
},
|
|
168
|
+
withReadSnapshot: (fn) => runReadSnapshot(db.queries, fn),
|
|
169
|
+
commands: {
|
|
170
|
+
collections: {
|
|
171
|
+
lockCollectionRegistration: vi.fn(async () => { }),
|
|
172
|
+
create: vi.fn(),
|
|
173
|
+
update: vi.fn(),
|
|
174
|
+
delete: vi.fn(),
|
|
175
|
+
},
|
|
176
|
+
documents: {
|
|
177
|
+
publishSchedules: {
|
|
178
|
+
lockDocuments: vi.fn(async () => { }),
|
|
179
|
+
schedule: publishSchedule,
|
|
180
|
+
confirm: confirmPublishSchedule,
|
|
181
|
+
cancel: cancelPublishSchedule,
|
|
182
|
+
suspendForContentEdit: suspendPublishSchedule,
|
|
183
|
+
claimDue: claimDuePublishSchedules,
|
|
184
|
+
lockClaim: lockPublishScheduleClaim,
|
|
185
|
+
deleteClaim: deletePublishScheduleClaim,
|
|
186
|
+
suspendClaimForContentEdit: suspendPublishScheduleClaim,
|
|
187
|
+
releaseClaim: releasePublishScheduleClaim,
|
|
188
|
+
},
|
|
189
|
+
createDocumentVersion,
|
|
190
|
+
updateDocumentPath: vi.fn().mockResolvedValue(undefined),
|
|
191
|
+
setDocumentAvailableLocales: vi.fn().mockResolvedValue(undefined),
|
|
192
|
+
setDocumentStatus,
|
|
193
|
+
archivePublishedVersions,
|
|
194
|
+
softDeleteDocument,
|
|
195
|
+
restoreSoftDeletedDocument: vi.fn(),
|
|
196
|
+
deleteDocumentLocale: deleteDocumentLocale,
|
|
197
|
+
setOrderKey: vi.fn(),
|
|
198
|
+
placeTreeNode: vi.fn(),
|
|
199
|
+
removeFromTree: vi.fn(),
|
|
200
|
+
promoteChildrenAndRemoveFromTree: vi.fn(async () => ({
|
|
201
|
+
removed: {
|
|
202
|
+
changed: false,
|
|
203
|
+
before: { placed: false, parentDocumentId: null, orderKey: null, index: null },
|
|
204
|
+
after: { placed: false, parentDocumentId: null, orderKey: null, index: null },
|
|
205
|
+
beforeSiblingDocumentIds: [],
|
|
206
|
+
beforeSubtreeDocumentIds: [],
|
|
207
|
+
},
|
|
208
|
+
promoted: [],
|
|
209
|
+
})),
|
|
210
|
+
},
|
|
211
|
+
counters: {
|
|
212
|
+
ensureCounterGroup: vi.fn(),
|
|
213
|
+
nextCounterValue: vi.fn(),
|
|
214
|
+
nextScopedCounterValue: vi.fn(),
|
|
215
|
+
},
|
|
216
|
+
audit: { append: auditAppend },
|
|
217
|
+
singletons: {
|
|
218
|
+
lockSlot: vi.fn(async () => { }),
|
|
219
|
+
setMapping: vi.fn(fail),
|
|
220
|
+
clearMapping: vi.fn(fail),
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
withTransaction: transaction.run,
|
|
224
|
+
queries: {
|
|
225
|
+
collections: {
|
|
226
|
+
getAllCollections: vi.fn(),
|
|
227
|
+
getCollectionByPath: vi.fn(),
|
|
228
|
+
getCollectionById: vi.fn(),
|
|
229
|
+
},
|
|
230
|
+
documents: {
|
|
231
|
+
publishSchedules: {
|
|
232
|
+
get: getPublishSchedule,
|
|
233
|
+
list: listPublishSchedules,
|
|
234
|
+
},
|
|
235
|
+
getDocumentRevision: async ({ document_id }) => revisions.get(document_id) ?? 1,
|
|
236
|
+
getDocumentSystemFieldsForUpdate,
|
|
237
|
+
getDocumentById,
|
|
238
|
+
getCurrentVersionMetadata,
|
|
239
|
+
getCurrentPath,
|
|
240
|
+
getDocumentByPath: vi.fn(),
|
|
241
|
+
getDocumentByVersion: vi.fn(),
|
|
242
|
+
getDocumentsByVersionIds: vi.fn(),
|
|
243
|
+
getDocumentsByDocumentIds: vi.fn(),
|
|
244
|
+
getDocumentHistory: vi.fn(),
|
|
245
|
+
getPublishedVersion: vi.fn(),
|
|
246
|
+
getPublishedDocumentIds: vi.fn(),
|
|
247
|
+
getDocumentCountsByStatus: vi.fn(),
|
|
248
|
+
findDocuments: vi.fn(),
|
|
249
|
+
getLastOrderKey: vi.fn(),
|
|
250
|
+
getNeighborOrderKeys: vi.fn(),
|
|
251
|
+
getCanonicalDocumentOrder: vi.fn(),
|
|
252
|
+
getTreeAncestors: vi.fn(),
|
|
253
|
+
getTreeChildren: vi.fn(),
|
|
254
|
+
getTreeParent: vi.fn(),
|
|
255
|
+
getTreeSubtree: vi.fn(),
|
|
256
|
+
},
|
|
257
|
+
audit: {
|
|
258
|
+
getDocumentAuditLog: vi.fn(async () => ({
|
|
259
|
+
entries: [],
|
|
260
|
+
meta: { total: 0, page: 1, pageSize: 20, totalPages: 0 },
|
|
261
|
+
})),
|
|
262
|
+
findAuditLog: vi.fn(async () => ({
|
|
263
|
+
entries: [],
|
|
264
|
+
meta: { total: 0, page: 1, pageSize: 20, totalPages: 0 },
|
|
265
|
+
})),
|
|
266
|
+
},
|
|
267
|
+
singletons: { getMappedDocumentId: vi.fn(fail) },
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
return {
|
|
271
|
+
db,
|
|
272
|
+
createDocumentVersion,
|
|
273
|
+
setDocumentStatus,
|
|
274
|
+
archivePublishedVersions,
|
|
275
|
+
softDeleteDocument,
|
|
276
|
+
deleteDocumentLocale,
|
|
277
|
+
getDocumentById,
|
|
278
|
+
getDocumentSystemFieldsForUpdate,
|
|
279
|
+
getCurrentVersionMetadata,
|
|
280
|
+
getCurrentPath,
|
|
281
|
+
publishSchedule,
|
|
282
|
+
confirmPublishSchedule,
|
|
283
|
+
cancelPublishSchedule,
|
|
284
|
+
suspendPublishSchedule,
|
|
285
|
+
claimDuePublishSchedules,
|
|
286
|
+
lockPublishScheduleClaim,
|
|
287
|
+
deletePublishScheduleClaim,
|
|
288
|
+
suspendPublishScheduleClaim,
|
|
289
|
+
releasePublishScheduleClaim,
|
|
290
|
+
getPublishSchedule,
|
|
291
|
+
listPublishSchedules,
|
|
292
|
+
auditAppend,
|
|
293
|
+
withTransaction,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function pathUniqueViolation() {
|
|
297
|
+
return Object.assign(new Error('duplicate key value violates unique constraint'), {
|
|
298
|
+
code: '23505',
|
|
299
|
+
constraint: 'idx_document_paths_collection_locale_path',
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
const noopLogger = {
|
|
303
|
+
log: vi.fn(),
|
|
304
|
+
fatal: vi.fn(),
|
|
305
|
+
error: vi.fn(),
|
|
306
|
+
warn: vi.fn(),
|
|
307
|
+
info: vi.fn(),
|
|
308
|
+
debug: vi.fn(),
|
|
309
|
+
trace: vi.fn(),
|
|
310
|
+
silent: vi.fn(),
|
|
311
|
+
};
|
|
312
|
+
// A real persisted-user id is a UUID; `actorId()` only attributes UUIDs (see
|
|
313
|
+
// the regression note below). Use a valid UUID so the default context's
|
|
314
|
+
// writes are attributed.
|
|
315
|
+
const TEST_ACTOR_ID = '01901234-0000-7000-8000-000000000001';
|
|
316
|
+
function buildCtx(db, definition = minimalCollection) {
|
|
317
|
+
return {
|
|
318
|
+
db,
|
|
319
|
+
definition,
|
|
320
|
+
collectionId: 'col-1',
|
|
321
|
+
collectionVersion: 1,
|
|
322
|
+
collectionPath: definition.path,
|
|
323
|
+
logger: noopLogger,
|
|
324
|
+
defaultLocale: 'en',
|
|
325
|
+
// Inject a super-admin context by default so the bulk of existing
|
|
326
|
+
// tests do not have to care about ability enforcement. The dedicated
|
|
327
|
+
// "enforcement" block below covers the missing-context / missing-ability
|
|
328
|
+
// negative cases.
|
|
329
|
+
requestContext: createSuperAdminContext({ id: TEST_ACTOR_ID }),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
// ---------------------------------------------------------------------------
|
|
333
|
+
// Tests
|
|
334
|
+
// ---------------------------------------------------------------------------
|
|
335
|
+
describe('review probes', () => {
|
|
336
|
+
it('rejects caller-selected published status for a create-only actor', async () => {
|
|
337
|
+
const { db } = createMockDb();
|
|
338
|
+
const ctx = buildCtx(db);
|
|
339
|
+
ctx.requestContext = createRequestContext({ actor: new AdminAuth({
|
|
340
|
+
id: 'editor', abilities: ['collections.articles.create'],
|
|
341
|
+
}) });
|
|
342
|
+
await expect(createDocument(ctx, { data: { title: 'Direct publish' }, status: 'published' })).rejects.toMatchObject({ code: AuthErrorCodes.FORBIDDEN });
|
|
343
|
+
});
|
|
344
|
+
it('rejects an undeclared initial workflow status', async () => {
|
|
345
|
+
const { db } = createMockDb();
|
|
346
|
+
const ctx = buildCtx(db);
|
|
347
|
+
await expect(createDocument(ctx, { data: { title: 'Invalid status' }, status: 'not-a-status' })).rejects.toBeDefined();
|
|
348
|
+
});
|
|
349
|
+
});
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@byline/core",
|
|
3
3
|
"private": false,
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
|
-
"version": "6.7.
|
|
5
|
+
"version": "6.7.2",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=20.9.0"
|
|
8
8
|
},
|
|
@@ -82,23 +82,23 @@
|
|
|
82
82
|
"dist"
|
|
83
83
|
],
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
85
|
+
"@byline/auth": "6.7.2",
|
|
86
|
+
"dotenv": "^18.0.8",
|
|
87
|
+
"pino": "^10.4.0",
|
|
88
|
+
"sharp": "^0.35.5",
|
|
89
|
+
"uuid": "^14.0.3",
|
|
90
|
+
"zod": "^4.6.7"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
|
-
"@biomejs/biome": "2.5.
|
|
94
|
-
"@types/node": "^26.6.
|
|
93
|
+
"@biomejs/biome": "2.5.15",
|
|
94
|
+
"@types/node": "^26.6.5",
|
|
95
95
|
"chokidar": "^5.0.0",
|
|
96
96
|
"chokidar-cli": "^3.0.0",
|
|
97
97
|
"npm-run-all": "^4.1.5",
|
|
98
|
-
"tsc-alias": "^1.9.
|
|
99
|
-
"tsx": "^4.23.
|
|
98
|
+
"tsc-alias": "^1.9.7",
|
|
99
|
+
"tsx": "^4.23.15",
|
|
100
100
|
"typescript": "^7.0.2",
|
|
101
|
-
"vitest": "^5.0.
|
|
101
|
+
"vitest": "^5.0.4"
|
|
102
102
|
},
|
|
103
103
|
"publishConfig": {
|
|
104
104
|
"access": "public",
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
-
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) Infonomic Company Limited
|
|
7
|
-
*/
|
|
8
|
-
import { describe, expect, it } from 'vitest';
|
|
9
|
-
import { resolveItemViewColumns } from './config.js';
|
|
10
|
-
const itemViewCols = [{ fieldName: 'title', label: 'Title' }];
|
|
11
|
-
const pickerCols = [{ fieldName: 'name', label: 'Name' }];
|
|
12
|
-
const cfg = (over) => ({ slug: 'x', ...over });
|
|
13
|
-
describe('resolveItemViewColumns', () => {
|
|
14
|
-
it('returns itemView when present', () => {
|
|
15
|
-
expect(resolveItemViewColumns(cfg({ itemView: itemViewCols }))).toBe(itemViewCols);
|
|
16
|
-
});
|
|
17
|
-
it('falls back to the deprecated picker alias', () => {
|
|
18
|
-
expect(resolveItemViewColumns(cfg({ picker: pickerCols }))).toBe(pickerCols);
|
|
19
|
-
});
|
|
20
|
-
it('prefers itemView over picker when both are present', () => {
|
|
21
|
-
expect(resolveItemViewColumns(cfg({ itemView: itemViewCols, picker: pickerCols }))).toBe(itemViewCols);
|
|
22
|
-
});
|
|
23
|
-
it('returns undefined when neither is set', () => {
|
|
24
|
-
expect(resolveItemViewColumns(cfg({}))).toBeUndefined();
|
|
25
|
-
});
|
|
26
|
-
it('tolerates null / undefined config', () => {
|
|
27
|
-
expect(resolveItemViewColumns(null)).toBeUndefined();
|
|
28
|
-
expect(resolveItemViewColumns(undefined)).toBeUndefined();
|
|
29
|
-
});
|
|
30
|
-
});
|
|
File without changes
|