@jskit-ai/crud-core 0.1.63 → 0.1.65
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/package.descriptor.mjs +4 -2
- package/package.json +18 -10
- package/src/server/crudModuleConfig.js +25 -5
- package/src/server/fieldAccess.js +9 -39
- package/src/server/listFilters.js +384 -389
- package/src/server/listQueryValidators.js +39 -77
- package/src/server/lookupHydration.js +4 -1
- package/src/server/repositorySupport.js +71 -121
- package/src/server/resourceRuntime/index.js +49 -74
- package/src/server/resourceRuntime/lookupHydration.js +4 -1
- package/src/server/routeContracts.js +74 -0
- package/src/server/serviceEvents.js +75 -4
- package/src/shared/crudFieldSupport.js +54 -0
- package/src/shared/crudNamespaceSupport.js +1 -27
- package/src/shared/crudResource.js +1 -0
- package/test/createCrudServiceFromResource.test.js +30 -28
- package/test/{crudFieldMetaSupport.test.js → crudFieldSupport.test.js} +1 -1
- package/test/crudModuleConfig.test.js +33 -0
- package/test/crudResource.test.js +97 -0
- package/test/listFilters.test.js +221 -59
- package/test/listQueryValidators.test.js +131 -97
- package/test/repositorySupport.test.js +241 -241
- package/test/resourceRuntime.test.js +204 -248
- package/test/routeContracts.test.js +146 -0
- package/test/serviceEvents.test.js +41 -1
- package/test/serviceMethods.test.js +12 -10
- package/src/shared/crudFieldMetaSupport.js +0 -153
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
+
import { createSchema } from "json-rest-schema";
|
|
3
4
|
import { RECORD_ID_PATTERN } from "@jskit-ai/kernel/shared/validators";
|
|
4
5
|
import { createCrudResourceRuntime } from "../src/server/resourceRuntime/index.js";
|
|
5
6
|
|
|
6
7
|
const recordIdSchema = Object.freeze({
|
|
7
8
|
type: "string",
|
|
9
|
+
minLength: 1,
|
|
8
10
|
pattern: RECORD_ID_PATTERN
|
|
9
11
|
});
|
|
10
12
|
|
|
11
13
|
const nullableRecordIdSchema = Object.freeze({
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
{ type: "null" }
|
|
15
|
-
]
|
|
14
|
+
...recordIdSchema,
|
|
15
|
+
nullable: true
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
function createKnexDouble(
|
|
@@ -202,33 +202,32 @@ function createResourceFixture() {
|
|
|
202
202
|
idColumn: "contact_id",
|
|
203
203
|
operations: {
|
|
204
204
|
view: {
|
|
205
|
-
|
|
206
|
-
schema: {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
205
|
+
output: {
|
|
206
|
+
schema: createSchema({
|
|
207
|
+
id: {
|
|
208
|
+
...recordIdSchema,
|
|
209
|
+
required: true,
|
|
210
|
+
actualField: "contact_id"
|
|
211
|
+
},
|
|
212
|
+
firstName: {
|
|
213
|
+
type: "string",
|
|
214
|
+
required: true
|
|
211
215
|
}
|
|
212
|
-
}
|
|
216
|
+
}),
|
|
217
|
+
mode: "replace"
|
|
213
218
|
}
|
|
214
219
|
},
|
|
215
220
|
create: {
|
|
216
|
-
|
|
217
|
-
schema: {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
firstName: { type: "string" }
|
|
221
|
+
body: {
|
|
222
|
+
schema: createSchema({
|
|
223
|
+
firstName: {
|
|
224
|
+
type: "string"
|
|
221
225
|
}
|
|
222
|
-
}
|
|
226
|
+
}),
|
|
227
|
+
mode: "create"
|
|
223
228
|
}
|
|
224
229
|
}
|
|
225
|
-
}
|
|
226
|
-
fieldMeta: [
|
|
227
|
-
{
|
|
228
|
-
key: "id",
|
|
229
|
-
repository: { column: "contact_id" }
|
|
230
|
-
}
|
|
231
|
-
]
|
|
230
|
+
}
|
|
232
231
|
};
|
|
233
232
|
}
|
|
234
233
|
|
|
@@ -239,56 +238,53 @@ function createLookupResourceFixture() {
|
|
|
239
238
|
idColumn: "contact_id",
|
|
240
239
|
operations: {
|
|
241
240
|
view: {
|
|
242
|
-
|
|
243
|
-
schema: {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
241
|
+
output: {
|
|
242
|
+
schema: createSchema({
|
|
243
|
+
id: {
|
|
244
|
+
...recordIdSchema,
|
|
245
|
+
required: true,
|
|
246
|
+
actualField: "contact_id"
|
|
247
|
+
},
|
|
248
|
+
firstName: {
|
|
249
|
+
type: "string",
|
|
250
|
+
required: true
|
|
251
|
+
},
|
|
252
|
+
primaryVetId: {
|
|
253
|
+
...recordIdSchema,
|
|
254
|
+
actualField: "primary_vet_id",
|
|
255
|
+
relation: {
|
|
256
|
+
kind: "lookup",
|
|
257
|
+
namespace: "vets",
|
|
258
|
+
valueKey: "id"
|
|
252
259
|
}
|
|
260
|
+
},
|
|
261
|
+
secondaryVetId: {
|
|
262
|
+
...nullableRecordIdSchema,
|
|
263
|
+
actualField: "secondary_vet_id",
|
|
264
|
+
relation: {
|
|
265
|
+
kind: "lookup",
|
|
266
|
+
namespace: "vets",
|
|
267
|
+
valueKey: "id"
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
lookups: {
|
|
271
|
+
type: "object"
|
|
253
272
|
}
|
|
254
|
-
}
|
|
273
|
+
}),
|
|
274
|
+
mode: "replace"
|
|
255
275
|
}
|
|
256
276
|
},
|
|
257
277
|
create: {
|
|
258
|
-
|
|
259
|
-
schema: {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
firstName: { type: "string" }
|
|
278
|
+
body: {
|
|
279
|
+
schema: createSchema({
|
|
280
|
+
firstName: {
|
|
281
|
+
type: "string"
|
|
263
282
|
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
fieldMeta: [
|
|
269
|
-
{
|
|
270
|
-
key: "id",
|
|
271
|
-
repository: { column: "contact_id" }
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
key: "primaryVetId",
|
|
275
|
-
repository: { column: "primary_vet_id" },
|
|
276
|
-
relation: {
|
|
277
|
-
kind: "lookup",
|
|
278
|
-
namespace: "vets",
|
|
279
|
-
valueKey: "id"
|
|
280
|
-
}
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
key: "secondaryVetId",
|
|
284
|
-
repository: { column: "secondary_vet_id" },
|
|
285
|
-
relation: {
|
|
286
|
-
kind: "lookup",
|
|
287
|
-
namespace: "vets",
|
|
288
|
-
valueKey: "id"
|
|
283
|
+
}),
|
|
284
|
+
mode: "create"
|
|
289
285
|
}
|
|
290
286
|
}
|
|
291
|
-
|
|
287
|
+
}
|
|
292
288
|
};
|
|
293
289
|
}
|
|
294
290
|
|
|
@@ -299,35 +295,29 @@ function createLeafLookupResourceFixture() {
|
|
|
299
295
|
idColumn: "user_id",
|
|
300
296
|
operations: {
|
|
301
297
|
view: {
|
|
302
|
-
|
|
303
|
-
schema: {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
298
|
+
output: {
|
|
299
|
+
schema: createSchema({
|
|
300
|
+
id: {
|
|
301
|
+
...recordIdSchema,
|
|
302
|
+
required: true,
|
|
303
|
+
actualField: "user_id"
|
|
304
|
+
},
|
|
305
|
+
name: {
|
|
306
|
+
type: "string",
|
|
307
|
+
required: true,
|
|
308
|
+
actualField: "display_name"
|
|
308
309
|
}
|
|
309
|
-
}
|
|
310
|
+
}),
|
|
311
|
+
mode: "replace"
|
|
310
312
|
}
|
|
311
313
|
},
|
|
312
314
|
create: {
|
|
313
|
-
|
|
314
|
-
schema: {
|
|
315
|
-
|
|
316
|
-
properties: {}
|
|
317
|
-
}
|
|
315
|
+
body: {
|
|
316
|
+
schema: createSchema({}),
|
|
317
|
+
mode: "create"
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
|
-
}
|
|
321
|
-
fieldMeta: [
|
|
322
|
-
{
|
|
323
|
-
key: "id",
|
|
324
|
-
repository: { column: "user_id" }
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
key: "name",
|
|
328
|
-
repository: { column: "display_name" }
|
|
329
|
-
}
|
|
330
|
-
]
|
|
320
|
+
}
|
|
331
321
|
};
|
|
332
322
|
}
|
|
333
323
|
|
|
@@ -338,89 +328,54 @@ function createNormalizedWriteResourceFixture() {
|
|
|
338
328
|
idColumn: "contact_id",
|
|
339
329
|
operations: {
|
|
340
330
|
view: {
|
|
341
|
-
|
|
342
|
-
schema: {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
331
|
+
output: {
|
|
332
|
+
schema: createSchema({
|
|
333
|
+
id: {
|
|
334
|
+
...recordIdSchema,
|
|
335
|
+
required: true,
|
|
336
|
+
actualField: "contact_id"
|
|
337
|
+
},
|
|
338
|
+
firstName: {
|
|
339
|
+
type: "string",
|
|
340
|
+
required: true,
|
|
341
|
+
actualField: "first_name"
|
|
353
342
|
}
|
|
354
|
-
}
|
|
343
|
+
}),
|
|
344
|
+
mode: "replace"
|
|
355
345
|
}
|
|
356
346
|
},
|
|
357
347
|
create: {
|
|
358
|
-
|
|
359
|
-
schema: {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
normalize(payload = {}) {
|
|
366
|
-
if (payload.firstName === "bad-create") {
|
|
367
|
-
const error = new Error("Validation failed.");
|
|
368
|
-
error.details = {
|
|
369
|
-
fieldErrors: {
|
|
370
|
-
firstName: "Invalid create value."
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
throw error;
|
|
348
|
+
body: {
|
|
349
|
+
schema: createSchema({
|
|
350
|
+
firstName: {
|
|
351
|
+
type: "string",
|
|
352
|
+
required: true,
|
|
353
|
+
minLength: 1,
|
|
354
|
+
actualField: "first_name"
|
|
374
355
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
...payload,
|
|
378
|
-
firstName: String(payload.firstName || "").trim()
|
|
379
|
-
};
|
|
380
|
-
}
|
|
356
|
+
}),
|
|
357
|
+
mode: "create"
|
|
381
358
|
}
|
|
382
359
|
},
|
|
383
360
|
patch: {
|
|
384
|
-
|
|
385
|
-
schema: {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
},
|
|
397
|
-
normalize(payload = {}, context = {}) {
|
|
398
|
-
if (payload.firstName === "bad-update") {
|
|
399
|
-
const error = new Error("Validation failed.");
|
|
400
|
-
error.details = {
|
|
401
|
-
fieldErrors: {
|
|
402
|
-
firstName: "Invalid update value."
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
throw error;
|
|
361
|
+
body: {
|
|
362
|
+
schema: createSchema({
|
|
363
|
+
firstName: {
|
|
364
|
+
type: "string",
|
|
365
|
+
required: false,
|
|
366
|
+
minLength: 1,
|
|
367
|
+
actualField: "first_name"
|
|
368
|
+
},
|
|
369
|
+
lastSeenAt: {
|
|
370
|
+
type: "string",
|
|
371
|
+
required: false,
|
|
372
|
+
actualField: "last_seen_at"
|
|
406
373
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
...payload,
|
|
410
|
-
firstName: `${String(payload.firstName || "").trim()}-${context.existingRecord?.firstName || ""}`,
|
|
411
|
-
...(Object.hasOwn(payload, "lastSeenAt")
|
|
412
|
-
? { lastSeenAt: String(payload.lastSeenAt ?? "").trim() || null }
|
|
413
|
-
: {})
|
|
414
|
-
};
|
|
415
|
-
}
|
|
374
|
+
}),
|
|
375
|
+
mode: "patch"
|
|
416
376
|
}
|
|
417
377
|
}
|
|
418
|
-
}
|
|
419
|
-
fieldMeta: [
|
|
420
|
-
{ key: "id", repository: { column: "contact_id" } },
|
|
421
|
-
{ key: "firstName", repository: { column: "first_name" } },
|
|
422
|
-
{ key: "lastSeenAt", repository: { column: "last_seen_at" } }
|
|
423
|
-
]
|
|
378
|
+
}
|
|
424
379
|
};
|
|
425
380
|
}
|
|
426
381
|
|
|
@@ -431,40 +386,38 @@ function createVirtualProjectionResourceFixture() {
|
|
|
431
386
|
idColumn: "receival_id",
|
|
432
387
|
operations: {
|
|
433
388
|
view: {
|
|
434
|
-
|
|
435
|
-
schema: {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
389
|
+
output: {
|
|
390
|
+
schema: createSchema({
|
|
391
|
+
id: {
|
|
392
|
+
...recordIdSchema,
|
|
393
|
+
required: true,
|
|
394
|
+
actualField: "receival_id"
|
|
395
|
+
},
|
|
396
|
+
firstName: {
|
|
397
|
+
type: "string",
|
|
398
|
+
required: true
|
|
399
|
+
},
|
|
400
|
+
remainingBatchWeight: {
|
|
401
|
+
type: "number",
|
|
402
|
+
storage: {
|
|
403
|
+
virtual: true
|
|
404
|
+
}
|
|
441
405
|
}
|
|
442
|
-
}
|
|
406
|
+
}),
|
|
407
|
+
mode: "replace"
|
|
443
408
|
}
|
|
444
409
|
},
|
|
445
410
|
create: {
|
|
446
|
-
|
|
447
|
-
schema: {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
firstName: { type: "string" }
|
|
411
|
+
body: {
|
|
412
|
+
schema: createSchema({
|
|
413
|
+
firstName: {
|
|
414
|
+
type: "string"
|
|
451
415
|
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
},
|
|
456
|
-
fieldMeta: [
|
|
457
|
-
{
|
|
458
|
-
key: "id",
|
|
459
|
-
repository: { column: "receival_id" }
|
|
460
|
-
},
|
|
461
|
-
{
|
|
462
|
-
key: "remainingBatchWeight",
|
|
463
|
-
repository: {
|
|
464
|
-
storage: "virtual"
|
|
416
|
+
}),
|
|
417
|
+
mode: "create"
|
|
465
418
|
}
|
|
466
419
|
}
|
|
467
|
-
|
|
420
|
+
}
|
|
468
421
|
};
|
|
469
422
|
}
|
|
470
423
|
|
|
@@ -475,25 +428,23 @@ test("createCrudResourceRuntime requires table metadata from resource", () => {
|
|
|
475
428
|
createCrudResourceRuntime({
|
|
476
429
|
operations: {
|
|
477
430
|
view: {
|
|
478
|
-
|
|
479
|
-
schema: {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
431
|
+
output: {
|
|
432
|
+
schema: createSchema({
|
|
433
|
+
id: {
|
|
434
|
+
...recordIdSchema,
|
|
435
|
+
required: true
|
|
483
436
|
}
|
|
484
|
-
}
|
|
437
|
+
}),
|
|
438
|
+
mode: "replace"
|
|
485
439
|
}
|
|
486
440
|
},
|
|
487
441
|
create: {
|
|
488
|
-
|
|
489
|
-
schema: {
|
|
490
|
-
|
|
491
|
-
properties: {}
|
|
492
|
-
}
|
|
442
|
+
body: {
|
|
443
|
+
schema: createSchema({}),
|
|
444
|
+
mode: "create"
|
|
493
445
|
}
|
|
494
446
|
}
|
|
495
|
-
}
|
|
496
|
-
fieldMeta: []
|
|
447
|
+
}
|
|
497
448
|
}, knex),
|
|
498
449
|
/requires resource\.tableName or resource\.namespace/
|
|
499
450
|
);
|
|
@@ -774,28 +725,26 @@ test("listByIds supports alternate valueKey and listByForeignIds delegates to it
|
|
|
774
725
|
operations: {
|
|
775
726
|
...createResourceFixture().operations,
|
|
776
727
|
view: {
|
|
777
|
-
|
|
778
|
-
schema: {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
728
|
+
output: {
|
|
729
|
+
schema: createSchema({
|
|
730
|
+
id: {
|
|
731
|
+
...recordIdSchema,
|
|
732
|
+
required: true,
|
|
733
|
+
actualField: "contact_id"
|
|
734
|
+
},
|
|
735
|
+
foreignId: {
|
|
736
|
+
...recordIdSchema,
|
|
737
|
+
actualField: "foreign_id"
|
|
738
|
+
},
|
|
739
|
+
firstName: {
|
|
740
|
+
type: "string",
|
|
741
|
+
required: true
|
|
784
742
|
}
|
|
785
|
-
}
|
|
743
|
+
}),
|
|
744
|
+
mode: "replace"
|
|
786
745
|
}
|
|
787
746
|
}
|
|
788
|
-
},
|
|
789
|
-
fieldMeta: [
|
|
790
|
-
{
|
|
791
|
-
key: "id",
|
|
792
|
-
repository: { column: "contact_id" }
|
|
793
|
-
},
|
|
794
|
-
{
|
|
795
|
-
key: "foreignId",
|
|
796
|
-
repository: { column: "foreign_id" }
|
|
797
747
|
}
|
|
798
|
-
]
|
|
799
748
|
};
|
|
800
749
|
const { knex, calls } = createKnexDouble([
|
|
801
750
|
{
|
|
@@ -833,35 +782,42 @@ test("create uses operations.create.prepareInsertPayload before insert", async (
|
|
|
833
782
|
idColumn: "contact_id",
|
|
834
783
|
operations: {
|
|
835
784
|
view: {
|
|
836
|
-
|
|
837
|
-
schema: {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
785
|
+
output: {
|
|
786
|
+
schema: createSchema({
|
|
787
|
+
id: {
|
|
788
|
+
...recordIdSchema,
|
|
789
|
+
required: true,
|
|
790
|
+
actualField: "contact_id"
|
|
791
|
+
},
|
|
792
|
+
firstName: {
|
|
793
|
+
type: "string",
|
|
794
|
+
required: true
|
|
795
|
+
},
|
|
796
|
+
createdAt: {
|
|
797
|
+
type: "string",
|
|
798
|
+
required: true,
|
|
799
|
+
actualField: "created_at"
|
|
800
|
+
},
|
|
801
|
+
updatedAt: {
|
|
802
|
+
type: "string",
|
|
803
|
+
required: true,
|
|
804
|
+
actualField: "updated_at"
|
|
844
805
|
}
|
|
845
|
-
}
|
|
806
|
+
}),
|
|
807
|
+
mode: "replace"
|
|
846
808
|
}
|
|
847
809
|
},
|
|
848
810
|
create: {
|
|
849
|
-
|
|
850
|
-
schema: {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
firstName: { type: "string" }
|
|
811
|
+
body: {
|
|
812
|
+
schema: createSchema({
|
|
813
|
+
firstName: {
|
|
814
|
+
type: "string"
|
|
854
815
|
}
|
|
855
|
-
}
|
|
816
|
+
}),
|
|
817
|
+
mode: "create"
|
|
856
818
|
}
|
|
857
819
|
}
|
|
858
|
-
}
|
|
859
|
-
fieldMeta: [
|
|
860
|
-
{ key: "id", repository: { column: "contact_id" } },
|
|
861
|
-
{ key: "firstName", repository: { column: "first_name" } },
|
|
862
|
-
{ key: "createdAt", repository: { column: "created_at" } },
|
|
863
|
-
{ key: "updatedAt", repository: { column: "updated_at" } }
|
|
864
|
-
]
|
|
820
|
+
}
|
|
865
821
|
};
|
|
866
822
|
const repository = createCrudResourceRuntime(resource, knex, {
|
|
867
823
|
operations: {
|
|
@@ -928,7 +884,7 @@ test("update and delete keep canonical by-id behavior", async () => {
|
|
|
928
884
|
});
|
|
929
885
|
});
|
|
930
886
|
|
|
931
|
-
test("update normalizes resource patch payloads
|
|
887
|
+
test("update normalizes resource patch payloads before persistence", async () => {
|
|
932
888
|
const rows = [
|
|
933
889
|
{
|
|
934
890
|
contact_id: 11,
|
|
@@ -945,7 +901,7 @@ test("update normalizes resource patch payloads using the existing record", asyn
|
|
|
945
901
|
firstName: " Tom "
|
|
946
902
|
});
|
|
947
903
|
|
|
948
|
-
assert.equal(state.updatePayloads[0].first_name, "Tom
|
|
904
|
+
assert.equal(state.updatePayloads[0].first_name, "Tom");
|
|
949
905
|
});
|
|
950
906
|
|
|
951
907
|
test("update maps patch-only resource fields into the DB payload", async () => {
|
|
@@ -968,7 +924,7 @@ test("update maps patch-only resource fields into the DB payload", async () => {
|
|
|
968
924
|
assert.equal(state.updatePayloads[0].last_seen_at, "2026-01-01T00:00:00.000Z");
|
|
969
925
|
});
|
|
970
926
|
|
|
971
|
-
test("resourceRuntime maps
|
|
927
|
+
test("resourceRuntime maps schema field errors for create and update", async () => {
|
|
972
928
|
const rows = [
|
|
973
929
|
{
|
|
974
930
|
contact_id: 11,
|
|
@@ -981,18 +937,18 @@ test("resourceRuntime maps body normalization field errors for create and update
|
|
|
981
937
|
const repository = createCrudResourceRuntime(createNormalizedWriteResourceFixture(), knex);
|
|
982
938
|
|
|
983
939
|
await assert.rejects(
|
|
984
|
-
() => repository.create({ firstName: "
|
|
940
|
+
() => repository.create({ firstName: " " }),
|
|
985
941
|
(error) => (
|
|
986
942
|
error?.status === 400 &&
|
|
987
|
-
error?.details?.fieldErrors?.firstName === "
|
|
943
|
+
typeof error?.details?.fieldErrors?.firstName === "string"
|
|
988
944
|
)
|
|
989
945
|
);
|
|
990
946
|
|
|
991
947
|
await assert.rejects(
|
|
992
|
-
() => repository.updateById("11", { firstName: "
|
|
948
|
+
() => repository.updateById("11", { firstName: " " }),
|
|
993
949
|
(error) => (
|
|
994
950
|
error?.status === 400 &&
|
|
995
|
-
error?.details?.fieldErrors?.firstName === "
|
|
951
|
+
typeof error?.details?.fieldErrors?.firstName === "string"
|
|
996
952
|
)
|
|
997
953
|
);
|
|
998
954
|
});
|