@api-client/core 0.18.48 → 0.18.50
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/build/src/mocking/lib/DataCatalog.d.ts +4 -4
- package/build/src/mocking/lib/DataCatalog.d.ts.map +1 -1
- package/build/src/mocking/lib/DataCatalog.js +8 -8
- package/build/src/mocking/lib/DataCatalog.js.map +1 -1
- package/build/src/mocking/lib/File.d.ts +2 -2
- package/build/src/mocking/lib/File.d.ts.map +1 -1
- package/build/src/mocking/lib/File.js +5 -5
- package/build/src/mocking/lib/File.js.map +1 -1
- package/build/src/mocking/lib/Group.d.ts +1 -1
- package/build/src/mocking/lib/Group.d.ts.map +1 -1
- package/build/src/mocking/lib/Group.js +2 -2
- package/build/src/mocking/lib/Group.js.map +1 -1
- package/build/src/mocking/lib/Invitation.d.ts +1 -1
- package/build/src/mocking/lib/Invitation.d.ts.map +1 -1
- package/build/src/mocking/lib/Invitation.js +2 -2
- package/build/src/mocking/lib/Invitation.js.map +1 -1
- package/build/src/mocking/lib/Organization.d.ts +1 -1
- package/build/src/mocking/lib/Organization.d.ts.map +1 -1
- package/build/src/mocking/lib/Organization.js +2 -2
- package/build/src/mocking/lib/Organization.js.map +1 -1
- package/build/src/mocking/lib/Patch.d.ts +1 -1
- package/build/src/mocking/lib/Patch.d.ts.map +1 -1
- package/build/src/mocking/lib/Patch.js +2 -2
- package/build/src/mocking/lib/Patch.js.map +1 -1
- package/build/src/mocking/lib/Trash.d.ts +1 -1
- package/build/src/mocking/lib/Trash.d.ts.map +1 -1
- package/build/src/mocking/lib/Trash.js +2 -2
- package/build/src/mocking/lib/Trash.js.map +1 -1
- package/build/src/modeling/ApiModel.d.ts +12 -4
- package/build/src/modeling/ApiModel.d.ts.map +1 -1
- package/build/src/modeling/ApiModel.js +76 -31
- package/build/src/modeling/ApiModel.js.map +1 -1
- package/build/src/modeling/ExposedEntity.d.ts +9 -0
- package/build/src/modeling/ExposedEntity.d.ts.map +1 -1
- package/build/src/modeling/ExposedEntity.js +23 -0
- package/build/src/modeling/ExposedEntity.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +24 -24
- package/package.json +2 -2
- package/src/mocking/README.md +40 -0
- package/src/mocking/lib/DataCatalog.ts +8 -8
- package/src/mocking/lib/File.ts +5 -5
- package/src/mocking/lib/Group.ts +2 -2
- package/src/mocking/lib/Invitation.ts +2 -2
- package/src/mocking/lib/Organization.ts +2 -2
- package/src/mocking/lib/Patch.ts +2 -2
- package/src/mocking/lib/Trash.ts +2 -2
- package/src/modeling/ApiModel.ts +82 -37
- package/src/modeling/ExposedEntity.ts +28 -0
- package/src/models/README.md +5 -4
- package/tests/unit/mocking/current/DataCatalog.spec.ts +28 -0
- package/tests/unit/mocking/current/File.spec.ts +79 -0
- package/tests/unit/mocking/current/Group.spec.ts +49 -0
- package/tests/unit/mocking/current/Invitation.spec.ts +49 -0
- package/tests/unit/mocking/current/Organization.spec.ts +50 -0
- package/tests/unit/mocking/current/Patch.spec.ts +47 -0
- package/tests/unit/mocking/current/Trash.spec.ts +49 -0
- package/tests/unit/modeling/api_model.spec.ts +20 -0
- package/tests/unit/modeling/api_model_expose_entity.spec.ts +25 -0
- package/tests/unit/modeling/api_model_remove_entity.spec.ts +17 -10
- package/tests/unit/modeling/exposed_entity_setter_validation.spec.ts +107 -0
|
@@ -138,6 +138,13 @@ test.group('dataCatalogs()', (group) => {
|
|
|
138
138
|
catalog.dataCatalogs(5)
|
|
139
139
|
assert.equal(spy.callCount, 5)
|
|
140
140
|
})
|
|
141
|
+
|
|
142
|
+
test('uses passed initialization values', ({ assert }) => {
|
|
143
|
+
const result = catalog.dataCatalogs(3, { name: 'Batch Catalog' })
|
|
144
|
+
result.forEach((item) => {
|
|
145
|
+
assert.equal(item.name, 'Batch Catalog')
|
|
146
|
+
})
|
|
147
|
+
})
|
|
141
148
|
})
|
|
142
149
|
|
|
143
150
|
test.group('dataCatalogVersion()', (group) => {
|
|
@@ -265,6 +272,13 @@ test.group('dataCatalogVersions()', (group) => {
|
|
|
265
272
|
catalog.dataCatalogVersions(3)
|
|
266
273
|
assert.equal(spy.callCount, 3)
|
|
267
274
|
})
|
|
275
|
+
|
|
276
|
+
test('uses passed initialization values', ({ assert }) => {
|
|
277
|
+
const result = catalog.dataCatalogVersions(3, { version: 'v1.2.3' })
|
|
278
|
+
result.forEach((item) => {
|
|
279
|
+
assert.equal(item.version, 'v1.2.3')
|
|
280
|
+
})
|
|
281
|
+
})
|
|
268
282
|
})
|
|
269
283
|
|
|
270
284
|
test.group('dataCatalogWithVersion()', (group) => {
|
|
@@ -372,6 +386,13 @@ test.group('dataCatalogsWithVersion()', (group) => {
|
|
|
372
386
|
assert.isAtLeast(item.versions.length, 1)
|
|
373
387
|
})
|
|
374
388
|
})
|
|
389
|
+
|
|
390
|
+
test('uses passed initialization values', ({ assert }) => {
|
|
391
|
+
const result = catalog.dataCatalogsWithVersion(3, { name: 'Versioned Batch' })
|
|
392
|
+
result.forEach((item) => {
|
|
393
|
+
assert.equal(item.name, 'Versioned Batch')
|
|
394
|
+
})
|
|
395
|
+
})
|
|
375
396
|
})
|
|
376
397
|
|
|
377
398
|
test.group('versionInfo()', (group) => {
|
|
@@ -446,4 +467,11 @@ test.group('versionInfos()', (group) => {
|
|
|
446
467
|
catalog.versionInfos(6)
|
|
447
468
|
assert.equal(spy.callCount, 6)
|
|
448
469
|
})
|
|
470
|
+
|
|
471
|
+
test('uses passed initialization values', ({ assert }) => {
|
|
472
|
+
const result = catalog.versionInfos(3, { version: 'v9.9.9' })
|
|
473
|
+
result.forEach((item) => {
|
|
474
|
+
assert.equal(item.version, 'v9.9.9')
|
|
475
|
+
})
|
|
476
|
+
})
|
|
449
477
|
})
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { File } from '../../../../src/mocking/lib/File.js'
|
|
3
|
+
import { FolderKind, ProjectKind } from '../../../../src/models/kinds.js'
|
|
4
|
+
import type { IFile } from '../../../../src/models/store/File.js'
|
|
5
|
+
|
|
6
|
+
test.group('File', (group) => {
|
|
7
|
+
let fileMock: File
|
|
8
|
+
|
|
9
|
+
group.each.setup(() => {
|
|
10
|
+
fileMock = new File()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('file() returns a valid object', ({ assert }) => {
|
|
14
|
+
const result = fileMock.file()
|
|
15
|
+
assert.typeOf(result, 'object')
|
|
16
|
+
assert.property(result, 'kind')
|
|
17
|
+
assert.property(result, 'info')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('file(init) allows overriding properties', ({ assert }) => {
|
|
21
|
+
const init: Partial<IFile> = {
|
|
22
|
+
kind: ProjectKind,
|
|
23
|
+
info: { name: 'My Project' },
|
|
24
|
+
}
|
|
25
|
+
const result = fileMock.file(init)
|
|
26
|
+
assert.equal(result.kind, ProjectKind)
|
|
27
|
+
assert.equal(result.info.name, 'My Project')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('files() returns a list', ({ assert }) => {
|
|
31
|
+
const result = fileMock.files(5)
|
|
32
|
+
assert.isArray(result)
|
|
33
|
+
assert.lengthOf(result, 5)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('files(size, init) allows overriding properties', ({ assert }) => {
|
|
37
|
+
const init: Partial<IFile> = {
|
|
38
|
+
kind: ProjectKind,
|
|
39
|
+
}
|
|
40
|
+
const result = fileMock.files(3, init)
|
|
41
|
+
assert.lengthOf(result, 3)
|
|
42
|
+
result.forEach((item) => {
|
|
43
|
+
assert.equal(item.kind, ProjectKind)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('folder() returns a valid object', ({ assert }) => {
|
|
48
|
+
const result = fileMock.folder()
|
|
49
|
+
assert.typeOf(result, 'object')
|
|
50
|
+
assert.equal(result.kind, FolderKind)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('folder(init) allows overriding properties', ({ assert }) => {
|
|
54
|
+
const init: Partial<IFile> = {
|
|
55
|
+
key: 'custom-folder-key',
|
|
56
|
+
}
|
|
57
|
+
const result = fileMock.folder(init)
|
|
58
|
+
assert.equal(result.kind, FolderKind)
|
|
59
|
+
assert.equal(result.key, 'custom-folder-key')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('folders() returns a list', ({ assert }) => {
|
|
63
|
+
const result = fileMock.folders(5)
|
|
64
|
+
assert.isArray(result)
|
|
65
|
+
assert.lengthOf(result, 5)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('folders(size, init) allows overriding properties', ({ assert }) => {
|
|
69
|
+
const init: Partial<IFile> = {
|
|
70
|
+
key: 'batch-key',
|
|
71
|
+
}
|
|
72
|
+
const result = fileMock.folders(3, init)
|
|
73
|
+
assert.lengthOf(result, 3)
|
|
74
|
+
result.forEach((item) => {
|
|
75
|
+
assert.equal(item.kind, FolderKind)
|
|
76
|
+
assert.equal(item.key, 'batch-key')
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { Group } from '../../../../src/mocking/lib/Group.js'
|
|
3
|
+
import { GroupKind } from '../../../../src/models/kinds.js'
|
|
4
|
+
import type { GroupSchema } from '../../../../src/models/store/Group.js'
|
|
5
|
+
|
|
6
|
+
test.group('Group', (group) => {
|
|
7
|
+
let groupMock: Group
|
|
8
|
+
|
|
9
|
+
group.each.setup(() => {
|
|
10
|
+
groupMock = new Group()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('group() returns a valid object', ({ assert }) => {
|
|
14
|
+
const result = groupMock.group()
|
|
15
|
+
assert.typeOf(result, 'object')
|
|
16
|
+
assert.equal(result.kind, GroupKind)
|
|
17
|
+
assert.property(result, 'key')
|
|
18
|
+
assert.property(result, 'name')
|
|
19
|
+
assert.property(result, 'color')
|
|
20
|
+
assert.property(result, 'users')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('group(init) allows overriding properties', ({ assert }) => {
|
|
24
|
+
const init: Partial<GroupSchema> = {
|
|
25
|
+
name: 'Custom Group',
|
|
26
|
+
color: '#ff0000',
|
|
27
|
+
}
|
|
28
|
+
const result = groupMock.group(init)
|
|
29
|
+
assert.equal(result.name, 'Custom Group')
|
|
30
|
+
assert.equal(result.color, '#ff0000')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('groups() returns a list', ({ assert }) => {
|
|
34
|
+
const result = groupMock.groups(5)
|
|
35
|
+
assert.isArray(result)
|
|
36
|
+
assert.lengthOf(result, 5)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('groups(size, init) allows overriding properties', ({ assert }) => {
|
|
40
|
+
const init: Partial<GroupSchema> = {
|
|
41
|
+
description: 'Batch Description',
|
|
42
|
+
}
|
|
43
|
+
const result = groupMock.groups(3, init)
|
|
44
|
+
assert.lengthOf(result, 3)
|
|
45
|
+
result.forEach((item) => {
|
|
46
|
+
assert.equal(item.description, 'Batch Description')
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { Invitation } from '../../../../src/mocking/lib/Invitation.js'
|
|
3
|
+
import { InvitationKind } from '../../../../src/models/kinds.js'
|
|
4
|
+
import type { InvitationSchema } from '../../../../src/models/store/Invitation.js'
|
|
5
|
+
|
|
6
|
+
test.group('Invitation', (group) => {
|
|
7
|
+
let invitation: Invitation
|
|
8
|
+
|
|
9
|
+
group.each.setup(() => {
|
|
10
|
+
invitation = new Invitation()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('invitation() returns a valid object', ({ assert }) => {
|
|
14
|
+
const result = invitation.invitation()
|
|
15
|
+
assert.typeOf(result, 'object')
|
|
16
|
+
assert.equal(result.kind, InvitationKind)
|
|
17
|
+
assert.property(result, 'key')
|
|
18
|
+
assert.property(result, 'email')
|
|
19
|
+
assert.property(result, 'token')
|
|
20
|
+
assert.property(result, 'status')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('invitation(init) allows overriding properties', ({ assert }) => {
|
|
24
|
+
const init: Partial<InvitationSchema> = {
|
|
25
|
+
email: 'test@example.com',
|
|
26
|
+
status: 'accepted',
|
|
27
|
+
}
|
|
28
|
+
const result = invitation.invitation(init)
|
|
29
|
+
assert.equal(result.email, 'test@example.com')
|
|
30
|
+
assert.equal(result.status, 'accepted')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('invitations() returns a list', ({ assert }) => {
|
|
34
|
+
const result = invitation.invitations(5)
|
|
35
|
+
assert.isArray(result)
|
|
36
|
+
assert.lengthOf(result, 5)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('invitations(size, init) allows overriding properties', ({ assert }) => {
|
|
40
|
+
const init: Partial<InvitationSchema> = {
|
|
41
|
+
status: 'declined',
|
|
42
|
+
}
|
|
43
|
+
const result = invitation.invitations(3, init)
|
|
44
|
+
assert.lengthOf(result, 3)
|
|
45
|
+
result.forEach((item) => {
|
|
46
|
+
assert.equal(item.status, 'declined')
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { Organization } from '../../../../src/mocking/lib/Organization.js'
|
|
3
|
+
import { OrganizationKind } from '../../../../src/models/kinds.js'
|
|
4
|
+
import type { IOrganization } from '../../../../src/models/store/Organization.js'
|
|
5
|
+
|
|
6
|
+
test.group('Organization', (group) => {
|
|
7
|
+
let organization: Organization
|
|
8
|
+
|
|
9
|
+
group.each.setup(() => {
|
|
10
|
+
organization = new Organization()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('organization() returns a valid object', ({ assert }) => {
|
|
14
|
+
const result = organization.organization()
|
|
15
|
+
assert.typeOf(result, 'object')
|
|
16
|
+
assert.equal(result.kind, OrganizationKind)
|
|
17
|
+
assert.property(result, 'key')
|
|
18
|
+
assert.property(result, 'name')
|
|
19
|
+
assert.property(result, 'createdBy')
|
|
20
|
+
assert.property(result, 'createdDate')
|
|
21
|
+
assert.property(result, 'grantType')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('organization(init) allows overriding properties', ({ assert }) => {
|
|
25
|
+
const init: Partial<IOrganization> = {
|
|
26
|
+
key: 'custom-org-key',
|
|
27
|
+
name: 'Custom Org',
|
|
28
|
+
}
|
|
29
|
+
const result = organization.organization(init)
|
|
30
|
+
assert.equal(result.key, 'custom-org-key')
|
|
31
|
+
assert.equal(result.name, 'Custom Org')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('organizations() returns a list', ({ assert }) => {
|
|
35
|
+
const result = organization.organizations(5)
|
|
36
|
+
assert.isArray(result)
|
|
37
|
+
assert.lengthOf(result, 5)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('organizations(size, init) allows overriding properties', ({ assert }) => {
|
|
41
|
+
const init: Partial<IOrganization> = {
|
|
42
|
+
name: 'Batch Org',
|
|
43
|
+
}
|
|
44
|
+
const result = organization.organizations(3, init)
|
|
45
|
+
assert.lengthOf(result, 3)
|
|
46
|
+
result.forEach((item) => {
|
|
47
|
+
assert.equal(item.name, 'Batch Org')
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { Patch } from '../../../../src/mocking/lib/Patch.js'
|
|
3
|
+
import type { MediaPatchRevision } from '../../../../src/patch/types.js'
|
|
4
|
+
|
|
5
|
+
test.group('Patch', (group) => {
|
|
6
|
+
let patch: Patch
|
|
7
|
+
|
|
8
|
+
group.each.setup(() => {
|
|
9
|
+
patch = new Patch()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('mediaPatchRevision() returns a valid object', ({ assert }) => {
|
|
13
|
+
const result = patch.mediaPatchRevision()
|
|
14
|
+
assert.typeOf(result, 'object')
|
|
15
|
+
assert.property(result, 'id')
|
|
16
|
+
assert.property(result, 'timestamp')
|
|
17
|
+
assert.property(result, 'patch')
|
|
18
|
+
assert.property(result, 'version')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('mediaPatchRevision(init) allows overriding properties', ({ assert }) => {
|
|
22
|
+
const init: Partial<MediaPatchRevision> = {
|
|
23
|
+
id: 'custom-id',
|
|
24
|
+
version: 99,
|
|
25
|
+
}
|
|
26
|
+
const result = patch.mediaPatchRevision(init)
|
|
27
|
+
assert.equal(result.id, 'custom-id')
|
|
28
|
+
assert.equal(result.version, 99)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('mediaPatchRevisions() returns a list', ({ assert }) => {
|
|
32
|
+
const result = patch.mediaPatchRevisions(5)
|
|
33
|
+
assert.isArray(result)
|
|
34
|
+
assert.lengthOf(result, 5)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('mediaPatchRevisions(size, init) allows overriding properties', ({ assert }) => {
|
|
38
|
+
const init: Partial<MediaPatchRevision> = {
|
|
39
|
+
version: 123,
|
|
40
|
+
}
|
|
41
|
+
const result = patch.mediaPatchRevisions(3, init)
|
|
42
|
+
assert.lengthOf(result, 3)
|
|
43
|
+
result.forEach((item) => {
|
|
44
|
+
assert.equal(item.version, 123)
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { Trash } from '../../../../src/mocking/lib/Trash.js'
|
|
3
|
+
import { ProjectKind } from '../../../../src/models/kinds.js'
|
|
4
|
+
import type { TrashEntry } from '../../../../src/models/TrashEntry.js'
|
|
5
|
+
|
|
6
|
+
test.group('Trash', (group) => {
|
|
7
|
+
let trash: Trash
|
|
8
|
+
|
|
9
|
+
group.each.setup(() => {
|
|
10
|
+
trash = new Trash()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('trashEntry() returns a valid object', ({ assert }) => {
|
|
14
|
+
const result = trash.trashEntry()
|
|
15
|
+
assert.typeOf(result, 'object')
|
|
16
|
+
assert.property(result, 'key')
|
|
17
|
+
assert.property(result, 'refKey')
|
|
18
|
+
assert.property(result, 'kind')
|
|
19
|
+
assert.property(result, 'info')
|
|
20
|
+
assert.property(result, 'capabilities')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('trashEntry(init) allows overriding properties', ({ assert }) => {
|
|
24
|
+
const init: Partial<TrashEntry> = {
|
|
25
|
+
key: 'custom-key',
|
|
26
|
+
kind: ProjectKind,
|
|
27
|
+
}
|
|
28
|
+
const result = trash.trashEntry(init)
|
|
29
|
+
assert.equal(result.key, 'custom-key')
|
|
30
|
+
assert.equal(result.kind, ProjectKind)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('trashEntries() returns a list', ({ assert }) => {
|
|
34
|
+
const result = trash.trashEntries(5)
|
|
35
|
+
assert.isArray(result)
|
|
36
|
+
assert.lengthOf(result, 5)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('trashEntries(size, init) allows overriding properties', ({ assert }) => {
|
|
40
|
+
const init: Partial<TrashEntry> = {
|
|
41
|
+
kind: ProjectKind,
|
|
42
|
+
}
|
|
43
|
+
const result = trash.trashEntries(3, init)
|
|
44
|
+
assert.lengthOf(result, 3)
|
|
45
|
+
result.forEach((item) => {
|
|
46
|
+
assert.equal(item.kind, ProjectKind)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -163,6 +163,26 @@ test.group('ApiModel.constructor()', () => {
|
|
|
163
163
|
assert.equal(model.domain!.key, 'my-domain')
|
|
164
164
|
}).tags(['@modeling', '@api', '@creation'])
|
|
165
165
|
|
|
166
|
+
test('initializes domain dependency correctly when passed to constructor', ({ assert }) => {
|
|
167
|
+
const domain = new DataDomain()
|
|
168
|
+
domain.info.version = '1.0.0'
|
|
169
|
+
|
|
170
|
+
const model = new ApiModel({}, domain)
|
|
171
|
+
|
|
172
|
+
assert.isDefined(model.domain)
|
|
173
|
+
assert.equal(model.domain?.key, domain.key)
|
|
174
|
+
assert.lengthOf(model.dependencyList, 1)
|
|
175
|
+
assert.equal(model.dependencyList[0].key, domain.key)
|
|
176
|
+
assert.equal(model.dependencyList[0].version, '1.0.0')
|
|
177
|
+
}).tags(['@modeling', '@api', '@creation'])
|
|
178
|
+
|
|
179
|
+
test('throws if passed domain has no version', ({ assert }) => {
|
|
180
|
+
const domain = new DataDomain()
|
|
181
|
+
// No version set
|
|
182
|
+
|
|
183
|
+
assert.throws(() => new ApiModel({}, domain), /must have a version/)
|
|
184
|
+
}).tags(['@modeling', '@api', '@creation'])
|
|
185
|
+
|
|
166
186
|
test('notifies change when info is modified', async ({ assert }) => {
|
|
167
187
|
const model = new ApiModel()
|
|
168
188
|
let notified = false
|
|
@@ -186,4 +186,29 @@ test.group('ApiModel.exposeEntity()', () => {
|
|
|
186
186
|
assert.isDefined(nestedC)
|
|
187
187
|
assert.isUndefined(nestedD)
|
|
188
188
|
})
|
|
189
|
+
test('resolves root path collision by appending a number', ({ assert }) => {
|
|
190
|
+
const domain = new DataDomain()
|
|
191
|
+
domain.info.version = '1.0.0'
|
|
192
|
+
const dm = domain.addModel()
|
|
193
|
+
// Two entities that will generate the same plural path "/items"
|
|
194
|
+
const e1 = dm.addEntity({ info: { name: 'Item' } })
|
|
195
|
+
const e2 = dm.addEntity({ info: { name: 'Item' } }) // Same name
|
|
196
|
+
|
|
197
|
+
const model = new ApiModel()
|
|
198
|
+
model.attachDataDomain(domain)
|
|
199
|
+
|
|
200
|
+
// Expose first entity -> /items
|
|
201
|
+
const exp1 = model.exposeEntity({ key: e1.key })
|
|
202
|
+
assert.equal(exp1.collectionPath, '/items')
|
|
203
|
+
|
|
204
|
+
// Expose second entity -> should resolve collision to /items-1
|
|
205
|
+
const exp2 = model.exposeEntity({ key: e2.key })
|
|
206
|
+
assert.equal(exp2.collectionPath, '/items-1')
|
|
207
|
+
assert.equal(exp2.resourcePath, '/items-1/{id}')
|
|
208
|
+
|
|
209
|
+
// Expose third entity -> /items-2
|
|
210
|
+
const e3 = dm.addEntity({ info: { name: 'Item' } })
|
|
211
|
+
const exp3 = model.exposeEntity({ key: e3.key })
|
|
212
|
+
assert.equal(exp3.collectionPath, '/items-2')
|
|
213
|
+
}).tags(['@modeling', '@api'])
|
|
189
214
|
})
|
|
@@ -9,10 +9,10 @@ test.group('ApiModel.removeEntity()', () => {
|
|
|
9
9
|
const e1 = dm.addEntity()
|
|
10
10
|
const model = new ApiModel()
|
|
11
11
|
model.attachDataDomain(domain)
|
|
12
|
-
model.exposeEntity({ key: e1.key })
|
|
12
|
+
const exposure = model.exposeEntity({ key: e1.key })
|
|
13
13
|
assert.lengthOf(model.exposes, 1)
|
|
14
14
|
|
|
15
|
-
model.
|
|
15
|
+
model.removeExposedEntity(exposure.key)
|
|
16
16
|
assert.lengthOf(model.exposes, 0)
|
|
17
17
|
}).tags(['@modeling', '@api'])
|
|
18
18
|
|
|
@@ -26,18 +26,18 @@ test.group('ApiModel.removeEntity()', () => {
|
|
|
26
26
|
eA.addAssociation({ key: eB.key }, { info: { name: 'toB' } })
|
|
27
27
|
const model = new ApiModel()
|
|
28
28
|
model.attachDataDomain(domain)
|
|
29
|
-
model.exposeEntity({ key: eA.key }, { followAssociations: true })
|
|
29
|
+
const rootExposure = model.exposeEntity({ key: eA.key }, { followAssociations: true })
|
|
30
30
|
// Ensure nested exposure for B was created
|
|
31
31
|
const nestedB = model.exposes.find((e) => !e.isRoot && e.entity.key === eB.key)
|
|
32
32
|
assert.isDefined(nestedB)
|
|
33
33
|
assert.isAbove(model.exposes.length, 1)
|
|
34
34
|
|
|
35
|
-
// Remove root
|
|
36
|
-
model.
|
|
35
|
+
// Remove root exposure for A and expect children to be removed as well
|
|
36
|
+
model.removeExposedEntity(rootExposure.key)
|
|
37
37
|
assert.lengthOf(model.exposes, 0)
|
|
38
38
|
}).tags(['@modeling', '@api'])
|
|
39
39
|
|
|
40
|
-
test('
|
|
40
|
+
test('throws error if entity does not exist', ({ assert }) => {
|
|
41
41
|
const domain = new DataDomain()
|
|
42
42
|
domain.info.version = '1.0.0'
|
|
43
43
|
const dm = domain.addModel()
|
|
@@ -46,7 +46,10 @@ test.group('ApiModel.removeEntity()', () => {
|
|
|
46
46
|
model.attachDataDomain(domain)
|
|
47
47
|
model.exposeEntity({ key: e1.key })
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
assert.throws(
|
|
50
|
+
() => model.removeExposedEntity('non-existing-key'),
|
|
51
|
+
'Exposed entity with key "non-existing-key" not found.'
|
|
52
|
+
)
|
|
50
53
|
assert.lengthOf(model.exposes, 1, 'exposes count should remain unchanged')
|
|
51
54
|
}).tags(['@modeling', '@api'])
|
|
52
55
|
|
|
@@ -57,13 +60,13 @@ test.group('ApiModel.removeEntity()', () => {
|
|
|
57
60
|
const e1 = dm.addEntity()
|
|
58
61
|
const model = new ApiModel()
|
|
59
62
|
model.attachDataDomain(domain)
|
|
60
|
-
model.exposeEntity({ key: e1.key })
|
|
63
|
+
const exposure = model.exposeEntity({ key: e1.key })
|
|
61
64
|
|
|
62
65
|
let notified = false
|
|
63
66
|
model.addEventListener('change', () => {
|
|
64
67
|
notified = true
|
|
65
68
|
})
|
|
66
|
-
model.
|
|
69
|
+
model.removeExposedEntity(exposure.key)
|
|
67
70
|
await Promise.resolve() // Allow microtask to run
|
|
68
71
|
assert.isTrue(notified)
|
|
69
72
|
}).tags(['@modeling', '@api'])
|
|
@@ -74,7 +77,11 @@ test.group('ApiModel.removeEntity()', () => {
|
|
|
74
77
|
model.addEventListener('change', () => {
|
|
75
78
|
notified = true
|
|
76
79
|
})
|
|
77
|
-
|
|
80
|
+
try {
|
|
81
|
+
model.removeExposedEntity('no-notify-remove-entity')
|
|
82
|
+
} catch {
|
|
83
|
+
// ignore error
|
|
84
|
+
}
|
|
78
85
|
await Promise.resolve() // Allow microtask to run
|
|
79
86
|
assert.isFalse(notified)
|
|
80
87
|
}).tags(['@modeling', '@api'])
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { ApiModel, DataDomain } from '../../../src/index.js'
|
|
3
|
+
|
|
4
|
+
test.group('ExposedEntity Path Setter Validation', () => {
|
|
5
|
+
test('throws when setting collection path that collides with another root entity', ({ assert }) => {
|
|
6
|
+
const domain = new DataDomain()
|
|
7
|
+
domain.info.version = '1.0.0'
|
|
8
|
+
const dm = domain.addModel()
|
|
9
|
+
const e1 = dm.addEntity({ info: { name: 'A' } })
|
|
10
|
+
const e2 = dm.addEntity({ info: { name: 'B' } })
|
|
11
|
+
|
|
12
|
+
const model = new ApiModel()
|
|
13
|
+
model.attachDataDomain(domain)
|
|
14
|
+
|
|
15
|
+
model.exposeEntity({ key: e1.key }) // /as
|
|
16
|
+
const exp2 = model.exposeEntity({ key: e2.key }) // /bs
|
|
17
|
+
|
|
18
|
+
// Try to rename exp2's collection path to /as (collision)
|
|
19
|
+
assert.throws(
|
|
20
|
+
() => exp2.setCollectionPath('/as'),
|
|
21
|
+
'Collection path "/as" is already in use by another root entity.'
|
|
22
|
+
)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('throws when setting resource path that collides with another root entity (singleton)', ({ assert }) => {
|
|
26
|
+
const domain = new DataDomain()
|
|
27
|
+
domain.info.version = '1.0.0'
|
|
28
|
+
const dm = domain.addModel()
|
|
29
|
+
const e1 = dm.addEntity({ info: { name: 'A' } })
|
|
30
|
+
const e2 = dm.addEntity({ info: { name: 'B' } }) // Collection-less
|
|
31
|
+
|
|
32
|
+
const model = new ApiModel()
|
|
33
|
+
model.attachDataDomain(domain)
|
|
34
|
+
|
|
35
|
+
const exp1 = model.exposeEntity({ key: e1.key }) // /as, /as/{id}
|
|
36
|
+
// Manually force a collision for testing resource path (singleton vs singleton or singleton vs resource)
|
|
37
|
+
// Let's make exp2 a singleton
|
|
38
|
+
const exp2 = model.exposeEntity({ key: e2.key })
|
|
39
|
+
// Remove collection from exp2 so we can set arbitrary resource path
|
|
40
|
+
// Note: implementation of setResourcePath for collection-less allows any 2 segments
|
|
41
|
+
// We need to simulate the state where hasCollection is false
|
|
42
|
+
exp2.hasCollection = false
|
|
43
|
+
|
|
44
|
+
// Set exp1 resource path to something specific
|
|
45
|
+
exp1.hasCollection = false
|
|
46
|
+
exp1.setResourcePath('/shared/path')
|
|
47
|
+
|
|
48
|
+
// Try to set exp2 resource path to same
|
|
49
|
+
assert.throws(
|
|
50
|
+
() => exp2.setResourcePath('/shared/path'),
|
|
51
|
+
'Resource path "/shared/path" is already in use by another root entity.'
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('allows setting non-colliding paths for root entity', ({ assert }) => {
|
|
56
|
+
const domain = new DataDomain()
|
|
57
|
+
domain.info.version = '1.0.0'
|
|
58
|
+
const dm = domain.addModel()
|
|
59
|
+
const e1 = dm.addEntity({ info: { name: 'A' } })
|
|
60
|
+
|
|
61
|
+
const model = new ApiModel()
|
|
62
|
+
model.attachDataDomain(domain)
|
|
63
|
+
|
|
64
|
+
const exp1 = model.exposeEntity({ key: e1.key }) // /as
|
|
65
|
+
|
|
66
|
+
exp1.setCollectionPath('/new-path')
|
|
67
|
+
assert.equal(exp1.collectionPath, '/new-path')
|
|
68
|
+
|
|
69
|
+
exp1.hasCollection = false // allow arbitrary resource path
|
|
70
|
+
exp1.setResourcePath('/custom/resource')
|
|
71
|
+
assert.equal(exp1.resourcePath, '/custom/resource')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('does not validate collision for non-root entities', ({ assert }) => {
|
|
75
|
+
const domain = new DataDomain()
|
|
76
|
+
domain.info.version = '1.0.0'
|
|
77
|
+
const dm = domain.addModel()
|
|
78
|
+
const eA = dm.addEntity({ info: { name: 'A' } })
|
|
79
|
+
const eB = dm.addEntity({ info: { name: 'B' } })
|
|
80
|
+
eA.addAssociation({ key: eB.key }, { info: { name: 'toB' } })
|
|
81
|
+
|
|
82
|
+
const model = new ApiModel()
|
|
83
|
+
model.attachDataDomain(domain)
|
|
84
|
+
|
|
85
|
+
// expose A -> B
|
|
86
|
+
const rootExp = model.exposeEntity({ key: eA.key }, { followAssociations: true })
|
|
87
|
+
const nestedExp = model.exposes.find((e) => !e.isRoot)
|
|
88
|
+
|
|
89
|
+
assert.isDefined(nestedExp)
|
|
90
|
+
// Assuming root entity has collection path /as
|
|
91
|
+
assert.equal(rootExp.collectionPath, '/as')
|
|
92
|
+
|
|
93
|
+
// Try to set nested entity's collection path to /as
|
|
94
|
+
// Since it's not root, it should NOT check for collision with rootExp
|
|
95
|
+
// (In reality this path is technically valid relative to parent, but here we just check that
|
|
96
|
+
// it doesn't throw the specific root collision error)
|
|
97
|
+
|
|
98
|
+
// setCollectionPath logic for non-root:
|
|
99
|
+
// It doesn't check checks.
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
nestedExp?.setCollectionPath('/as')
|
|
103
|
+
} catch (e) {
|
|
104
|
+
assert.notInclude((e as Error).message, 'already in use by another root entity')
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
})
|