@api-client/core 0.14.10 → 0.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.
- package/RELEASE.md +163 -0
- package/RELEASE_SETUP.md +235 -0
- package/build/src/events/authorization/AuthorizationEvents.d.ts +1 -1
- package/build/src/events/authorization/AuthorizationEvents.d.ts.map +1 -1
- package/build/src/events/authorization/AuthorizationEvents.js +1 -1
- package/build/src/events/authorization/AuthorizationEvents.js.map +1 -1
- package/build/src/events/cookies/CookieEvents.d.ts +1 -1
- package/build/src/events/cookies/CookieEvents.d.ts.map +1 -1
- package/build/src/events/cookies/CookieEvents.js +1 -1
- package/build/src/events/cookies/CookieEvents.js.map +1 -1
- package/build/src/modeling/DomainImpactAnalysis.d.ts +22 -119
- package/build/src/modeling/DomainImpactAnalysis.d.ts.map +1 -1
- package/build/src/modeling/DomainImpactAnalysis.js +49 -155
- package/build/src/modeling/DomainImpactAnalysis.js.map +1 -1
- package/build/src/modeling/DomainValidation.d.ts +8 -0
- package/build/src/modeling/DomainValidation.d.ts.map +1 -0
- package/build/src/modeling/DomainValidation.js +99 -0
- package/build/src/modeling/DomainValidation.js.map +1 -0
- package/build/src/modeling/types.d.ts +70 -0
- package/build/src/modeling/types.d.ts.map +1 -1
- package/build/src/modeling/types.js.map +1 -1
- package/build/src/modeling/validation/rules.d.ts +2 -3
- package/build/src/modeling/validation/rules.d.ts.map +1 -1
- package/build/src/modeling/validation/rules.js.map +1 -1
- package/build/src/modeling/validation/semantic_validation.d.ts +31 -0
- package/build/src/modeling/validation/semantic_validation.d.ts.map +1 -0
- package/build/src/modeling/validation/semantic_validation.js +126 -0
- package/build/src/modeling/validation/semantic_validation.js.map +1 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +6 -6
- package/noop.ts +3 -0
- package/package.json +9 -4
- package/src/events/authorization/AuthorizationEvents.ts +1 -1
- package/src/events/cookies/CookieEvents.ts +1 -1
- package/src/modeling/DomainImpactAnalysis.ts +54 -239
- package/src/modeling/DomainValidation.ts +105 -0
- package/src/modeling/types.ts +86 -0
- package/src/modeling/validation/rules.ts +2 -4
- package/src/modeling/validation/semantic_validation.ts +145 -0
- package/tests/unit/events/EventsTestHelpers.ts +16 -0
- package/tests/unit/events/amf.spec.ts +151 -0
- package/tests/unit/events/authorization.spec.ts +150 -0
- package/tests/unit/events/cookie.spec.ts +274 -0
- package/tests/unit/events/encryption.spec.ts +108 -0
- package/tests/unit/events/events_polyfills.ts +77 -0
- package/tests/unit/events/process.spec.ts +120 -0
- package/tests/unit/events/reporting.spec.ts +82 -0
- package/tests/unit/events/telemetry.spec.ts +224 -0
- package/tests/unit/events/transport.spec.ts +139 -0
- package/tests/unit/modeling/domain_impact_analysis.spec.ts +0 -110
- package/tests/unit/modeling/domain_validation.spec.ts +94 -0
- package/tests/unit/modeling/validation/semantic_validation.spec.ts +91 -0
- package/tests/unit/models/environment.spec.ts +574 -0
- package/tests/unit/models/error_response.spec.ts +183 -0
- package/tests/unit/models/headers_array.spec.ts +86 -0
- package/tests/unit/models/http-actions/assertion/equal_assertion.spec.ts +103 -0
- package/tests/unit/models/http-actions/assertion/greater_than_assertion.spec.ts +91 -0
- package/tests/unit/models/http-actions/assertion/includes_assertion.spec.ts +71 -0
- package/tests/unit/models/http-actions/assertion/less_than_assertion.spec.ts +91 -0
- package/tests/unit/models/http-actions/assertion/matches_assertion.spec.ts +71 -0
- package/tests/unit/models/http-actions/assertion/matches_schema_assertion.spec.ts +117 -0
- package/tests/unit/models/http-actions/assertion/not_equal_assertion.spec.ts +103 -0
- package/tests/unit/models/http-actions/assertion/not_includes_assertion.spec.ts +71 -0
- package/tests/unit/models/http-actions/assertion/not_ok_assertion.spec.ts +47 -0
- package/tests/unit/models/http-actions/assertion/not_to_be_assertion.spec.ts +72 -0
- package/tests/unit/models/http-actions/assertion/ok_assertion.spec.ts +44 -0
- package/tests/unit/models/http-actions/assertion/to_be_assertion.spec.ts +71 -0
- package/tests/unit/models/http-actions/transformation/as_lower_case_step.spec.ts +47 -0
- package/tests/unit/models/http-actions/transformation/as_number_step.spec.ts +47 -0
- package/tests/unit/models/http-actions/transformation/as_upper_case_step.spec.ts +47 -0
- package/tests/unit/models/http-actions/transformation/round_step.spec.ts +69 -0
- package/tests/unit/models/http-actions/transformation/substring_step.spec.ts +85 -0
- package/tests/unit/models/http-actions/transformation/trim_step.spec.ts +44 -0
- package/tests/unit/models/http_cookie.spec.ts +516 -0
- package/tests/unit/models/http_history.spec.ts +443 -0
- package/tests/unit/models/project_folder.spec.ts +926 -0
- package/tests/unit/models/project_item.spec.ts +137 -0
- package/tests/unit/models/project_request.spec.ts +1047 -0
- package/tests/unit/models/project_schema.spec.ts +236 -0
- package/tests/unit/models/property.spec.ts +625 -0
- package/tests/unit/models/provider.spec.ts +102 -0
- package/tests/unit/models/request.spec.ts +1206 -0
- package/tests/unit/models/request_log.spec.ts +308 -0
- package/tests/unit/models/request_time.spec.ts +138 -0
- package/tests/unit/models/response_redirect.spec.ts +303 -0
- package/tests/unit/models/sent_request.spec.ts +206 -0
- package/tests/unit/models/server.spec.ts +195 -0
- package/tests/unit/models/thing.spec.ts +154 -0
- package/build/oauth-popup.html +0 -33
- /package/tests/unit/models/{Certificate.spec.ts → certificate.spec.ts} +0 -0
- /package/tests/unit/models/{HostRule.spec.ts → host_rule.spec.ts} +0 -0
- /package/tests/unit/models/{HttpProject.spec.ts → http_project.spec.ts} +0 -0
- /package/tests/unit/models/{HttpRequest.spec.ts → http_request.spec.ts} +0 -0
- /package/tests/unit/models/{HttpResponse.spec.ts → http_response.spec.ts} +0 -0
- /package/tests/unit/models/{License.spec.ts → license.spec.ts} +0 -0
- /package/tests/unit/models/{Response.spec.ts → response.spec.ts} +0 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import sinon from 'sinon'
|
|
3
|
+
import { EventTypes } from '../../../src/events/EventTypes.js'
|
|
4
|
+
import { Events } from '../../../src/events/Events.js'
|
|
5
|
+
import { ensureUnique } from './EventsTestHelpers.js'
|
|
6
|
+
import './events_polyfills.js'
|
|
7
|
+
|
|
8
|
+
test.group('Events > Telemetry > EventTypes.Telemetry', () => {
|
|
9
|
+
test('has the namespace', ({ assert }) => {
|
|
10
|
+
assert.typeOf(EventTypes.Telemetry, 'object')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('has "{prop}" property')
|
|
14
|
+
.with([
|
|
15
|
+
{ prop: 'view', value: 'telemetryscreenview' },
|
|
16
|
+
{ prop: 'event', value: 'telemetryevent' },
|
|
17
|
+
{ prop: 'exception', value: 'telemetryexception' },
|
|
18
|
+
{ prop: 'social', value: 'telemetrysocial' },
|
|
19
|
+
{ prop: 'timing', value: 'telemetrytiming' },
|
|
20
|
+
])
|
|
21
|
+
.run(({ assert }, { prop, value }) => {
|
|
22
|
+
// @ts-expect-error Used in testing
|
|
23
|
+
assert.equal(EventTypes.Telemetry[prop], value)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('has unique events for the namespace', () => {
|
|
27
|
+
ensureUnique('EventTypes.Telemetry', EventTypes.Telemetry)
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test.group('Events > Telemetry > Events.Telemetry > view()', () => {
|
|
32
|
+
const screenName = 'test-screen'
|
|
33
|
+
|
|
34
|
+
test('dispatches the event', async ({ assert }) => {
|
|
35
|
+
const spy = sinon.spy()
|
|
36
|
+
globalThis.addEventListener(EventTypes.Telemetry.view, spy)
|
|
37
|
+
Events.Telemetry.view(screenName)
|
|
38
|
+
globalThis.removeEventListener(EventTypes.Telemetry.view, spy)
|
|
39
|
+
assert.isTrue(spy.calledOnce)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('the event has screen name on the detail', async ({ assert }) => {
|
|
43
|
+
const spy = sinon.spy()
|
|
44
|
+
globalThis.addEventListener(EventTypes.Telemetry.view, spy)
|
|
45
|
+
Events.Telemetry.view(screenName)
|
|
46
|
+
globalThis.removeEventListener(EventTypes.Telemetry.view, spy)
|
|
47
|
+
const e = spy.args[0][0] as CustomEvent
|
|
48
|
+
assert.equal(e.detail.screenName, screenName)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('the event has the custom configuration', async ({ assert }) => {
|
|
52
|
+
const spy = sinon.spy()
|
|
53
|
+
const custom = {
|
|
54
|
+
customMetrics: [{ index: 1, value: 1 }],
|
|
55
|
+
customDimensions: [{ index: 1, value: 'test' }],
|
|
56
|
+
}
|
|
57
|
+
globalThis.addEventListener(EventTypes.Telemetry.view, spy)
|
|
58
|
+
Events.Telemetry.view(screenName, undefined, custom)
|
|
59
|
+
globalThis.removeEventListener(EventTypes.Telemetry.view, spy)
|
|
60
|
+
const e = spy.args[0][0] as CustomEvent
|
|
61
|
+
assert.deepEqual(e.detail.customMetrics, custom.customMetrics, 'has customMetrics')
|
|
62
|
+
assert.deepEqual(e.detail.customDimensions, custom.customDimensions, 'has customDimensions')
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test.group('Events > Telemetry > Events.Telemetry > event()', () => {
|
|
67
|
+
const init = {
|
|
68
|
+
category: 'e-cat',
|
|
69
|
+
action: 'e-act',
|
|
70
|
+
label: 'e-label',
|
|
71
|
+
value: 1,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
test('dispatches the event', async ({ assert }) => {
|
|
75
|
+
const spy = sinon.spy()
|
|
76
|
+
globalThis.addEventListener(EventTypes.Telemetry.event, spy)
|
|
77
|
+
Events.Telemetry.event(init)
|
|
78
|
+
globalThis.removeEventListener(EventTypes.Telemetry.event, spy)
|
|
79
|
+
assert.isTrue(spy.calledOnce)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('the event has the detail object', async ({ assert }) => {
|
|
83
|
+
const spy = sinon.spy()
|
|
84
|
+
globalThis.addEventListener(EventTypes.Telemetry.event, spy)
|
|
85
|
+
Events.Telemetry.event(init)
|
|
86
|
+
globalThis.removeEventListener(EventTypes.Telemetry.event, spy)
|
|
87
|
+
const e = spy.args[0][0] as CustomEvent
|
|
88
|
+
assert.deepEqual(e.detail, init)
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test.group('Events > Telemetry > Events.Telemetry > exception()', () => {
|
|
93
|
+
const description = 'event-exception'
|
|
94
|
+
const fatal = true
|
|
95
|
+
|
|
96
|
+
test('dispatches the event', async ({ assert }) => {
|
|
97
|
+
const spy = sinon.spy()
|
|
98
|
+
globalThis.addEventListener(EventTypes.Telemetry.exception, spy)
|
|
99
|
+
Events.Telemetry.exception(description)
|
|
100
|
+
globalThis.removeEventListener(EventTypes.Telemetry.exception, spy)
|
|
101
|
+
assert.isTrue(spy.calledOnce)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
test('the event has the description', async ({ assert }) => {
|
|
105
|
+
const spy = sinon.spy()
|
|
106
|
+
globalThis.addEventListener(EventTypes.Telemetry.exception, spy)
|
|
107
|
+
Events.Telemetry.exception(description)
|
|
108
|
+
globalThis.removeEventListener(EventTypes.Telemetry.exception, spy)
|
|
109
|
+
const e = spy.args[0][0] as CustomEvent
|
|
110
|
+
assert.equal(e.detail.description, description)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('the event has the fatal', async ({ assert }) => {
|
|
114
|
+
const spy = sinon.spy()
|
|
115
|
+
globalThis.addEventListener(EventTypes.Telemetry.exception, spy)
|
|
116
|
+
Events.Telemetry.exception(description, fatal)
|
|
117
|
+
globalThis.removeEventListener(EventTypes.Telemetry.exception, spy)
|
|
118
|
+
const e = spy.args[0][0] as CustomEvent
|
|
119
|
+
assert.equal(e.detail.fatal, fatal)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test('the event has custom configuration', async ({ assert }) => {
|
|
123
|
+
const spy = sinon.spy()
|
|
124
|
+
const custom = {
|
|
125
|
+
customMetrics: [{ index: 1, value: 1 }],
|
|
126
|
+
customDimensions: [{ index: 1, value: 'test' }],
|
|
127
|
+
}
|
|
128
|
+
globalThis.addEventListener(EventTypes.Telemetry.exception, spy)
|
|
129
|
+
Events.Telemetry.exception(description, fatal, undefined, custom)
|
|
130
|
+
globalThis.removeEventListener(EventTypes.Telemetry.exception, spy)
|
|
131
|
+
const e = spy.args[0][0] as CustomEvent
|
|
132
|
+
assert.deepEqual(e.detail.customMetrics, custom.customMetrics, 'has customMetrics')
|
|
133
|
+
assert.deepEqual(e.detail.customDimensions, custom.customDimensions, 'has customDimensions')
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
test.group('Events > Telemetry > Events.Telemetry > social()', () => {
|
|
138
|
+
const init = {
|
|
139
|
+
network: 'e-network',
|
|
140
|
+
action: 'e-action',
|
|
141
|
+
target: 'e-target',
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
test('dispatches the event', async ({ assert }) => {
|
|
145
|
+
const spy = sinon.spy()
|
|
146
|
+
globalThis.addEventListener(EventTypes.Telemetry.social, spy)
|
|
147
|
+
Events.Telemetry.social(init.network, init.action, init.target)
|
|
148
|
+
globalThis.removeEventListener(EventTypes.Telemetry.social, spy)
|
|
149
|
+
assert.isTrue(spy.calledOnce)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
test('the event has the detail object', async ({ assert }) => {
|
|
153
|
+
const spy = sinon.spy()
|
|
154
|
+
globalThis.addEventListener(EventTypes.Telemetry.social, spy)
|
|
155
|
+
Events.Telemetry.social(init.network, init.action, init.target)
|
|
156
|
+
globalThis.removeEventListener(EventTypes.Telemetry.social, spy)
|
|
157
|
+
const e = spy.args[0][0] as CustomEvent
|
|
158
|
+
assert.deepEqual(e.detail, init)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test('the event has custom configuration', async ({ assert }) => {
|
|
162
|
+
const spy = sinon.spy()
|
|
163
|
+
const custom = {
|
|
164
|
+
customMetrics: [{ index: 1, value: 1 }],
|
|
165
|
+
customDimensions: [{ index: 1, value: 'test' }],
|
|
166
|
+
}
|
|
167
|
+
globalThis.addEventListener(EventTypes.Telemetry.social, spy)
|
|
168
|
+
Events.Telemetry.social(init.network, init.action, init.target, undefined, custom)
|
|
169
|
+
globalThis.removeEventListener(EventTypes.Telemetry.social, spy)
|
|
170
|
+
const e = spy.args[0][0] as CustomEvent
|
|
171
|
+
assert.deepEqual(e.detail.customMetrics, custom.customMetrics, 'has customMetrics')
|
|
172
|
+
assert.deepEqual(e.detail.customDimensions, custom.customDimensions, 'has customDimensions')
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
test.group('Events > Telemetry > Events.Telemetry > timing()', () => {
|
|
177
|
+
const init = {
|
|
178
|
+
category: 'e-category',
|
|
179
|
+
variable: 'e-variable',
|
|
180
|
+
value: 100,
|
|
181
|
+
label: 'e-label',
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
test('dispatches the event', async ({ assert }) => {
|
|
185
|
+
const spy = sinon.spy()
|
|
186
|
+
globalThis.addEventListener(EventTypes.Telemetry.timing, spy)
|
|
187
|
+
Events.Telemetry.timing(init.category, init.variable, init.value, init.label)
|
|
188
|
+
globalThis.removeEventListener(EventTypes.Telemetry.timing, spy)
|
|
189
|
+
assert.isTrue(spy.calledOnce)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
test('the event has the detail object', async ({ assert }) => {
|
|
193
|
+
const spy = sinon.spy()
|
|
194
|
+
globalThis.addEventListener(EventTypes.Telemetry.timing, spy)
|
|
195
|
+
Events.Telemetry.timing(init.category, init.variable, init.value, init.label)
|
|
196
|
+
globalThis.removeEventListener(EventTypes.Telemetry.timing, spy)
|
|
197
|
+
const e = spy.args[0][0] as CustomEvent
|
|
198
|
+
assert.deepEqual(e.detail, init)
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
test('the event has custom configuration', async ({ assert }) => {
|
|
202
|
+
const spy = sinon.spy()
|
|
203
|
+
const custom = {
|
|
204
|
+
customMetrics: [{ index: 1, value: 1 }],
|
|
205
|
+
customDimensions: [{ index: 1, value: 'test' }],
|
|
206
|
+
}
|
|
207
|
+
globalThis.addEventListener(EventTypes.Telemetry.timing, spy)
|
|
208
|
+
Events.Telemetry.timing(init.category, init.variable, init.value, init.label, undefined, custom)
|
|
209
|
+
globalThis.removeEventListener(EventTypes.Telemetry.timing, spy)
|
|
210
|
+
const e = spy.args[0][0] as CustomEvent
|
|
211
|
+
assert.deepEqual(e.detail.customMetrics, custom.customMetrics, 'has customMetrics')
|
|
212
|
+
assert.deepEqual(e.detail.customDimensions, custom.customDimensions, 'has customDimensions')
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
test.group('Events > Telemetry > Events.Telemetry > State', () => {
|
|
217
|
+
test('set()', async ({ assert }) => {
|
|
218
|
+
const spy = sinon.spy()
|
|
219
|
+
globalThis.addEventListener(EventTypes.Telemetry.State.set, spy)
|
|
220
|
+
Events.Telemetry.State.set()
|
|
221
|
+
globalThis.removeEventListener(EventTypes.Telemetry.State.set, spy)
|
|
222
|
+
assert.isTrue(spy.calledOnce)
|
|
223
|
+
})
|
|
224
|
+
})
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import sinon from 'sinon'
|
|
3
|
+
import { EventTypes } from '../../../src/events/EventTypes.js'
|
|
4
|
+
import { Events } from '../../../src/events/Events.js'
|
|
5
|
+
import { ensureUnique } from './EventsTestHelpers.js'
|
|
6
|
+
import { IHttpRequest, HttpRequest, Kind as HttpRequestKind } from '../../../src/models/HttpRequest.js'
|
|
7
|
+
import { Kind as HttpProjectKind } from '../../../src/models/HttpProject.js'
|
|
8
|
+
import { IHttpRequestDetail } from '../../../src/events/transport/TransportEvents.js'
|
|
9
|
+
import { IRequestProxyInit } from '../../../src/proxy/RequestProxy.js'
|
|
10
|
+
import { ContextEventDetailWithResult } from '../../../src/events/BaseEvents.js'
|
|
11
|
+
import { IHttpProjectProxyInit, IHttpProjectStoreProxyInit } from '../../../src/proxy/HttpProjectProxy.js'
|
|
12
|
+
import './events_polyfills.js'
|
|
13
|
+
|
|
14
|
+
test.group('Events > Transport > EventTypes.Transport.Core', () => {
|
|
15
|
+
test('has "{prop}" property')
|
|
16
|
+
.with([
|
|
17
|
+
['request', 'transportcorerequest'],
|
|
18
|
+
['httpProject', 'transportcorehttpproject'],
|
|
19
|
+
])
|
|
20
|
+
.run(({ assert }, [prop, value]) => {
|
|
21
|
+
// @ts-expect-error Used in testing
|
|
22
|
+
assert.equal(EventTypes.Transport.Core[prop], value)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('has unique events for the namespace', () => {
|
|
26
|
+
ensureUnique('EventTypes.Transport.Core', EventTypes.Transport.Core)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test.group('Events > Transport > EventTypes.Transport.Http', () => {
|
|
31
|
+
test('has "{prop}" property')
|
|
32
|
+
.with([['send', 'httptransportsend']])
|
|
33
|
+
.run(({ assert }, [prop, value]) => {
|
|
34
|
+
// @ts-expect-error Used in testing
|
|
35
|
+
assert.equal(EventTypes.Transport.Http[prop], value)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('has unique events for the namespace', () => {
|
|
39
|
+
ensureUnique('EventTypes.Transport.Http', EventTypes.Transport.Http)
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test.group('Events > Transport > EventTypes.Transport.Ws', () => {
|
|
44
|
+
test('has "{prop}" property')
|
|
45
|
+
.with([
|
|
46
|
+
['connect', 'wstransportconnect'],
|
|
47
|
+
['disconnect', 'wstransportdisconnect'],
|
|
48
|
+
['send', 'wstransportsend'],
|
|
49
|
+
])
|
|
50
|
+
.run(({ assert }, [prop, value]) => {
|
|
51
|
+
// @ts-expect-error Used in testing
|
|
52
|
+
assert.equal(EventTypes.Transport.Ws[prop], value)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('has unique events for the namespace', () => {
|
|
56
|
+
ensureUnique('EventTypes.Transport.Ws', EventTypes.Transport.Ws)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test.group('Events > Transport > Events.Transport.Core > request()', () => {
|
|
61
|
+
const init: IRequestProxyInit = {
|
|
62
|
+
kind: HttpRequestKind,
|
|
63
|
+
request: new HttpRequest().toJSON(),
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
test('dispatches the event', async ({ assert }) => {
|
|
67
|
+
const spy = sinon.spy()
|
|
68
|
+
globalThis.addEventListener(EventTypes.Transport.Core.request, spy)
|
|
69
|
+
await Events.Transport.Core.request(init)
|
|
70
|
+
globalThis.removeEventListener(EventTypes.Transport.Core.request, spy)
|
|
71
|
+
assert.isTrue(spy.calledOnce)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('has the detail object', async ({ assert }) => {
|
|
75
|
+
const spy = sinon.spy()
|
|
76
|
+
globalThis.addEventListener(EventTypes.Transport.Core.request, spy)
|
|
77
|
+
await Events.Transport.Core.request(init)
|
|
78
|
+
globalThis.removeEventListener(EventTypes.Transport.Core.request, spy)
|
|
79
|
+
const e = spy.args[0][0] as CustomEvent<ContextEventDetailWithResult<IRequestProxyInit>>
|
|
80
|
+
assert.deepEqual(e.detail, { ...init, result: undefined })
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test.group('Events > Transport > Events.Transport.Core > httpProject()', () => {
|
|
85
|
+
const init: IHttpProjectStoreProxyInit = {
|
|
86
|
+
kind: HttpProjectKind,
|
|
87
|
+
pid: 'test-id',
|
|
88
|
+
options: { parallel: true },
|
|
89
|
+
organization: 'test-organization',
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
test('dispatches the event', async ({ assert }) => {
|
|
93
|
+
const spy = sinon.spy()
|
|
94
|
+
globalThis.addEventListener(EventTypes.Transport.Core.httpProject, spy)
|
|
95
|
+
await Events.Transport.Core.httpProject(init)
|
|
96
|
+
globalThis.removeEventListener(EventTypes.Transport.Core.httpProject, spy)
|
|
97
|
+
assert.isTrue(spy.calledOnce)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test('has the detail object', async ({ assert }) => {
|
|
101
|
+
const spy = sinon.spy()
|
|
102
|
+
globalThis.addEventListener(EventTypes.Transport.Core.httpProject, spy)
|
|
103
|
+
await Events.Transport.Core.httpProject(init)
|
|
104
|
+
globalThis.removeEventListener(EventTypes.Transport.Core.httpProject, spy)
|
|
105
|
+
const e = spy.args[0][0] as CustomEvent<ContextEventDetailWithResult<IHttpProjectProxyInit>>
|
|
106
|
+
assert.deepEqual(e.detail, { ...init, result: undefined })
|
|
107
|
+
})
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test.group('Events > Transport > Events.Transport.Http > send()', () => {
|
|
111
|
+
const request: IHttpRequest = new HttpRequest().toJSON()
|
|
112
|
+
const init: RequestInit = { method: 'POST' }
|
|
113
|
+
|
|
114
|
+
test('dispatches the event', async ({ assert }) => {
|
|
115
|
+
const spy = sinon.spy()
|
|
116
|
+
globalThis.addEventListener(EventTypes.Transport.Http.send, spy)
|
|
117
|
+
await Events.Transport.Http.send(request)
|
|
118
|
+
globalThis.removeEventListener(EventTypes.Transport.Http.send, spy)
|
|
119
|
+
assert.isTrue(spy.calledOnce)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test('has the request on the detail', async ({ assert }) => {
|
|
123
|
+
const spy = sinon.spy()
|
|
124
|
+
globalThis.addEventListener(EventTypes.Transport.Http.send, spy)
|
|
125
|
+
await Events.Transport.Http.send(request)
|
|
126
|
+
globalThis.removeEventListener(EventTypes.Transport.Http.send, spy)
|
|
127
|
+
const e = spy.args[0][0] as CustomEvent<IHttpRequestDetail>
|
|
128
|
+
assert.equal(e.detail.request, request)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
test('has the optional init on the detail', async ({ assert }) => {
|
|
132
|
+
const spy = sinon.spy()
|
|
133
|
+
globalThis.addEventListener(EventTypes.Transport.Http.send, spy)
|
|
134
|
+
await Events.Transport.Http.send(request, init)
|
|
135
|
+
globalThis.removeEventListener(EventTypes.Transport.Http.send, spy)
|
|
136
|
+
const e = spy.args[0][0] as CustomEvent<IHttpRequestDetail>
|
|
137
|
+
assert.deepEqual(e.detail.init, init)
|
|
138
|
+
})
|
|
139
|
+
})
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
DomainEntity,
|
|
13
13
|
DomainProperty,
|
|
14
14
|
DomainAssociation,
|
|
15
|
-
DataDomainKind,
|
|
16
15
|
} from '../../../src/index.js'
|
|
17
16
|
|
|
18
17
|
test.group('DomainImpactAnalysis', (group) => {
|
|
@@ -450,112 +449,3 @@ test.group('DomainImpactAnalysis', (group) => {
|
|
|
450
449
|
assert.lengthOf(report.impact, 0, 'has all items')
|
|
451
450
|
})
|
|
452
451
|
})
|
|
453
|
-
|
|
454
|
-
test.group('DomainImpactAnalysis.publishAnalysis()', (group) => {
|
|
455
|
-
let domain: DataDomain
|
|
456
|
-
let analysis: DomainImpactAnalysis
|
|
457
|
-
|
|
458
|
-
group.each.setup(() => {
|
|
459
|
-
domain = new DataDomain()
|
|
460
|
-
analysis = new DomainImpactAnalysis(domain)
|
|
461
|
-
})
|
|
462
|
-
|
|
463
|
-
test('publishAnalysis() should return an empty report when the domain is empty', ({ assert }) => {
|
|
464
|
-
const report = analysis.publishAnalysis()
|
|
465
|
-
assert.deepEqual(report, {
|
|
466
|
-
key: '',
|
|
467
|
-
kind: DataDomainKind,
|
|
468
|
-
impact: [],
|
|
469
|
-
canProceed: true,
|
|
470
|
-
})
|
|
471
|
-
})
|
|
472
|
-
|
|
473
|
-
test('publishAnalysis() should return validation errors for entities', ({ assert }) => {
|
|
474
|
-
const model = domain.addModel({ key: 'model' })
|
|
475
|
-
const entity = model.addEntity({ key: 'entity', info: { name: 'Invalid-Name' } }) // Invalid name
|
|
476
|
-
|
|
477
|
-
const report = analysis.publishAnalysis()
|
|
478
|
-
// no key
|
|
479
|
-
// no properties
|
|
480
|
-
// invalid name
|
|
481
|
-
// name is not a snake case
|
|
482
|
-
assert.lengthOf(report.impact, 4)
|
|
483
|
-
assert.equal(report.impact[0].key, 'entity')
|
|
484
|
-
assert.equal(report.impact[0].kind, entity.kind)
|
|
485
|
-
assert.equal(report.impact[0].type, 'publish')
|
|
486
|
-
assert.equal(report.impact[0].severity, 'error')
|
|
487
|
-
assert.equal(report.canProceed, false)
|
|
488
|
-
})
|
|
489
|
-
|
|
490
|
-
test('publishAnalysis() should return validation errors for properties', ({ assert }) => {
|
|
491
|
-
const model = domain.addModel({ key: 'model' })
|
|
492
|
-
const entity = model.addEntity({ key: 'entity', info: { name: 'entity' } })
|
|
493
|
-
const property = entity.addProperty({ key: 'invalid-property', type: 'string', info: { name: 'invalid-property' } })
|
|
494
|
-
|
|
495
|
-
const report = analysis.publishAnalysis()
|
|
496
|
-
// no key (entity)
|
|
497
|
-
// invalid name (property)
|
|
498
|
-
assert.lengthOf(report.impact, 2)
|
|
499
|
-
assert.equal(report.impact[1].key, property.key)
|
|
500
|
-
assert.equal(report.impact[1].kind, property.kind)
|
|
501
|
-
assert.equal(report.impact[1].type, 'publish')
|
|
502
|
-
assert.equal(report.impact[1].severity, 'error')
|
|
503
|
-
assert.equal(report.canProceed, false)
|
|
504
|
-
})
|
|
505
|
-
|
|
506
|
-
test('publishAnalysis() should return validation errors for associations', ({ assert }) => {
|
|
507
|
-
const model = domain.addModel({ key: 'model' })
|
|
508
|
-
const entity1 = model.addEntity({ key: 'entity1', info: { name: 'entity1' } })
|
|
509
|
-
const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
|
|
510
|
-
const association = entity1.addAssociation({ key: entity2.key }, { info: { name: 'Invalid-Name' } })
|
|
511
|
-
|
|
512
|
-
const report = analysis.publishAnalysis()
|
|
513
|
-
// no key (entity1)
|
|
514
|
-
// invalid name (association)
|
|
515
|
-
// snake case (association)
|
|
516
|
-
// no key (entity2)
|
|
517
|
-
// no properties (entity2)
|
|
518
|
-
assert.lengthOf(report.impact, 5)
|
|
519
|
-
assert.equal(report.impact[1].key, association.key)
|
|
520
|
-
assert.equal(report.impact[1].kind, association.kind)
|
|
521
|
-
assert.equal(report.impact[1].type, 'publish')
|
|
522
|
-
assert.equal(report.impact[1].severity, 'error')
|
|
523
|
-
assert.equal(report.canProceed, false)
|
|
524
|
-
})
|
|
525
|
-
|
|
526
|
-
test('publishAnalysis() should return multiple validation errors', ({ assert }) => {
|
|
527
|
-
const model = domain.addModel({ key: 'model' })
|
|
528
|
-
const entity1 = model.addEntity({ key: 'invalid-entity', info: { name: 'Invalid-Entity' } })
|
|
529
|
-
entity1.addProperty({ key: 'invalid-property', type: 'string', info: { name: 'Invalid-Property' } })
|
|
530
|
-
const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
|
|
531
|
-
entity1.addAssociation({ key: entity2.key }, { info: { name: 'Invalid-Name' } })
|
|
532
|
-
|
|
533
|
-
const report = analysis.publishAnalysis()
|
|
534
|
-
// entity1 - no key
|
|
535
|
-
// entity1 - invalid name
|
|
536
|
-
// entity1 - snake case
|
|
537
|
-
// property - invalid name
|
|
538
|
-
// property - snake case
|
|
539
|
-
// association - invalid name
|
|
540
|
-
// association - snake case
|
|
541
|
-
// entity2 - no key
|
|
542
|
-
// entity2 - no properties
|
|
543
|
-
assert.lengthOf(report.impact, 9)
|
|
544
|
-
assert.equal(report.canProceed, false)
|
|
545
|
-
})
|
|
546
|
-
|
|
547
|
-
test('publishAnalysis() should return no errors for a valid domain', ({ assert }) => {
|
|
548
|
-
const model = domain.addModel({ key: 'model' })
|
|
549
|
-
const entity1 = model.addEntity({ key: 'entity1', info: { name: 'entity1' } })
|
|
550
|
-
entity1.addProperty({ key: 'p1', type: 'string', info: { name: 'property1' } })
|
|
551
|
-
entity1.addProperty({ key: 'p2', type: 'string', primary: true, info: { name: 'property2' } })
|
|
552
|
-
const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
|
|
553
|
-
entity2.addProperty({ key: 'p3', type: 'number', info: { name: 'property3' } })
|
|
554
|
-
entity2.addProperty({ key: 'p4', type: 'string', primary: true, info: { name: 'property4' } })
|
|
555
|
-
entity1.addAssociation({ key: entity2.key }, { info: { name: 'name' } })
|
|
556
|
-
|
|
557
|
-
const report = analysis.publishAnalysis()
|
|
558
|
-
assert.lengthOf(report.impact, 0)
|
|
559
|
-
assert.equal(report.canProceed, true)
|
|
560
|
-
})
|
|
561
|
-
})
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { DomainValidation } from '../../../src/modeling/DomainValidation.js'
|
|
3
|
+
import { DataDomain, DataDomainKind } from '../../../src/index.js'
|
|
4
|
+
import { SemanticType } from '../../../src/modeling/Semantics.js'
|
|
5
|
+
|
|
6
|
+
test.group('DomainImpactAnalysis.validate()', (group) => {
|
|
7
|
+
let domain: DataDomain
|
|
8
|
+
let analysis: DomainValidation
|
|
9
|
+
|
|
10
|
+
group.each.setup(() => {
|
|
11
|
+
domain = new DataDomain()
|
|
12
|
+
analysis = new DomainValidation(domain)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('validate() should return an empty report when the domain is empty', ({ assert }) => {
|
|
16
|
+
const report = analysis.validate()
|
|
17
|
+
assert.deepEqual(report, {
|
|
18
|
+
key: '',
|
|
19
|
+
kind: DataDomainKind,
|
|
20
|
+
impact: [],
|
|
21
|
+
canProceed: true,
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('validate() should return validation errors for entities', ({ assert }) => {
|
|
26
|
+
const model = domain.addModel({ key: 'model' })
|
|
27
|
+
model.addEntity({ key: 'entity', info: { name: 'Invalid-Name' } }) // Invalid name
|
|
28
|
+
|
|
29
|
+
const report = analysis.validate()
|
|
30
|
+
assert.lengthOf(report.impact, 8)
|
|
31
|
+
// we test specific rules in the validation tests
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('validate() should return validation errors for properties', ({ assert }) => {
|
|
35
|
+
const model = domain.addModel({ key: 'model' })
|
|
36
|
+
const entity = model.addEntity({ key: 'entity', info: { name: 'entity' } })
|
|
37
|
+
entity.addProperty({ key: 'invalid-property', type: 'string', info: { name: 'invalid-property' } })
|
|
38
|
+
|
|
39
|
+
const report = analysis.validate()
|
|
40
|
+
assert.lengthOf(report.impact, 6)
|
|
41
|
+
// we test specific rules in the validation tests
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('validate() should return validation errors for associations', ({ assert }) => {
|
|
45
|
+
const model = domain.addModel({ key: 'model' })
|
|
46
|
+
const entity1 = model.addEntity({ key: 'entity1', info: { name: 'entity1' } })
|
|
47
|
+
const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
|
|
48
|
+
entity1.addAssociation({ key: entity2.key }, { info: { name: 'Invalid-Name' } })
|
|
49
|
+
|
|
50
|
+
const report = analysis.validate()
|
|
51
|
+
assert.lengthOf(report.impact, 12)
|
|
52
|
+
// we test specific rules in the validation tests
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('validate() should return multiple validation errors', ({ assert }) => {
|
|
56
|
+
const model = domain.addModel({ key: 'model' })
|
|
57
|
+
const entity1 = model.addEntity({ key: 'invalid-entity', info: { name: 'Invalid-Entity' } })
|
|
58
|
+
entity1.addProperty({ key: 'invalid-property', type: 'string', info: { name: 'Invalid-Property' } })
|
|
59
|
+
const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
|
|
60
|
+
entity1.addAssociation({ key: entity2.key }, { info: { name: 'Invalid-Name' } })
|
|
61
|
+
|
|
62
|
+
const report = analysis.validate()
|
|
63
|
+
assert.lengthOf(report.impact, 16)
|
|
64
|
+
// we test specific rules in the validation tests
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('validate() should return no errors for a valid domain', ({ assert }) => {
|
|
68
|
+
const model = domain.addModel({ key: 'model' })
|
|
69
|
+
const entity1 = model.addEntity({ key: 'entity1', info: { name: 'entity1' } })
|
|
70
|
+
entity1.addProperty({ key: 'p1', type: 'string', info: { name: 'property1' } })
|
|
71
|
+
entity1.addProperty({ key: 'p2', type: 'string', primary: true, info: { name: 'property2' } })
|
|
72
|
+
const entity2 = model.addEntity({ key: 'entity2', info: { name: 'entity2' } })
|
|
73
|
+
const p3e2 = entity2.addProperty({ key: 'p3', type: 'number', info: { name: 'property3' } })
|
|
74
|
+
entity2.addProperty({ key: 'p4', type: 'string', primary: true, info: { name: 'property4' } })
|
|
75
|
+
const p5e2 = entity2.addProperty({ key: 'p5', type: 'number', info: { name: 'property5' } })
|
|
76
|
+
const p6e2 = entity2.addProperty({ key: 'p6', type: 'number', info: { name: 'property6' } })
|
|
77
|
+
entity1.addAssociation({ key: entity2.key }, { info: { name: 'name' } })
|
|
78
|
+
const p3e1 = entity1.addProperty({ type: 'number', info: { name: 'p3e1' } })
|
|
79
|
+
const p4e1 = entity1.addProperty({ type: 'number', info: { name: 'p4e1' } })
|
|
80
|
+
const p5e1 = entity1.addProperty({ type: 'boolean', info: { name: 'p5e1' } })
|
|
81
|
+
|
|
82
|
+
entity1.addSemantic({ id: SemanticType.User })
|
|
83
|
+
p3e2.addSemantic({ id: SemanticType.CreatedTimestamp })
|
|
84
|
+
p5e2.addSemantic({ id: SemanticType.UpdatedTimestamp })
|
|
85
|
+
p6e2.addSemantic({ id: SemanticType.DeletedTimestamp })
|
|
86
|
+
p3e1.addSemantic({ id: SemanticType.CreatedTimestamp })
|
|
87
|
+
p4e1.addSemantic({ id: SemanticType.UpdatedTimestamp })
|
|
88
|
+
p5e1.addSemantic({ id: SemanticType.DeletedFlag })
|
|
89
|
+
|
|
90
|
+
const report = analysis.validate()
|
|
91
|
+
assert.lengthOf(report.impact, 0)
|
|
92
|
+
assert.equal(report.canProceed, true)
|
|
93
|
+
})
|
|
94
|
+
})
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { test } from '@japa/runner'
|
|
2
|
+
import { DataDomain } from '../../../../src/modeling/DataDomain.js'
|
|
3
|
+
import { SemanticValidation } from '../../../../src/modeling/validation/semantic_validation.js'
|
|
4
|
+
import { SemanticType } from '../../../../src/modeling/Semantics.js'
|
|
5
|
+
|
|
6
|
+
test.group('SemanticValidation', (group) => {
|
|
7
|
+
let domain: DataDomain
|
|
8
|
+
let validation: SemanticValidation
|
|
9
|
+
|
|
10
|
+
group.each.setup(() => {
|
|
11
|
+
domain = new DataDomain()
|
|
12
|
+
validation = new SemanticValidation(domain)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('validate() should return a warning when no User entity is found', ({ assert }) => {
|
|
16
|
+
const model = domain.addModel({ key: 'model' })
|
|
17
|
+
model.addEntity({ key: 'entity', info: { name: 'Entity' } })
|
|
18
|
+
const results = validation.validate()
|
|
19
|
+
assert.lengthOf(results, 4) // Warning for User + 2 info for timestamps + info for soft delete
|
|
20
|
+
assert.equal(results[0].rule, 'recommended')
|
|
21
|
+
assert.equal(results[0].severity, 'warning')
|
|
22
|
+
assert.equal(results[0].message, 'No entity with User taxonomy found in the domain.')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('validate() should not return a warning when a User entity is found', ({ assert }) => {
|
|
26
|
+
const model = domain.addModel({ key: 'model' })
|
|
27
|
+
const entity = model.addEntity({ key: 'user', info: { name: 'User' } })
|
|
28
|
+
entity.addSemantic({ id: SemanticType.User })
|
|
29
|
+
const results = validation.validate()
|
|
30
|
+
assert.lengthOf(results, 3) // Only info for timestamps (2) and soft delete
|
|
31
|
+
assert.notEqual(results[0].message, 'No entity with User taxonomy found in the domain.')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('validate() should return info when an entity has no timestamp taxonomy', ({ assert }) => {
|
|
35
|
+
const model = domain.addModel({ key: 'model' })
|
|
36
|
+
model.addEntity({ key: 'entity', info: { name: 'Entity' } })
|
|
37
|
+
const results = validation.validate()
|
|
38
|
+
assert.lengthOf(results, 4)
|
|
39
|
+
const timestampResults = results.filter(
|
|
40
|
+
(r) => r.message.includes('CreatedTimestamp') || r.message.includes('UpdatedTimestamp')
|
|
41
|
+
)
|
|
42
|
+
assert.lengthOf(timestampResults, 2)
|
|
43
|
+
assert.equal(timestampResults[0].severity, 'info')
|
|
44
|
+
assert.equal(timestampResults[1].severity, 'info')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('validate() should not return info when an entity has timestamp taxonomy', ({ assert }) => {
|
|
48
|
+
const model = domain.addModel({ key: 'model' })
|
|
49
|
+
const entity = model.addEntity({ key: 'entity', info: { name: 'Entity' } })
|
|
50
|
+
const createdProperty = entity.addProperty({
|
|
51
|
+
key: 'created_at',
|
|
52
|
+
type: 'datetime',
|
|
53
|
+
info: { name: 'created_at' },
|
|
54
|
+
})
|
|
55
|
+
const updatedProperty = entity.addProperty({
|
|
56
|
+
key: 'updated_at',
|
|
57
|
+
type: 'datetime',
|
|
58
|
+
info: { name: 'updated_at' },
|
|
59
|
+
})
|
|
60
|
+
createdProperty.addSemantic({ id: SemanticType.CreatedTimestamp })
|
|
61
|
+
updatedProperty.addSemantic({ id: SemanticType.UpdatedTimestamp })
|
|
62
|
+
const results = validation.validate()
|
|
63
|
+
const timestampResults = results.filter(
|
|
64
|
+
(r) => r.message.includes('CreatedTimestamp') || r.message.includes('UpdatedTimestamp')
|
|
65
|
+
)
|
|
66
|
+
assert.lengthOf(timestampResults, 0)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('validate() should return info when an entity has no soft delete taxonomy', ({ assert }) => {
|
|
70
|
+
const model = domain.addModel({ key: 'model' })
|
|
71
|
+
model.addEntity({ key: 'entity', info: { name: 'Entity' } })
|
|
72
|
+
const results = validation.validate()
|
|
73
|
+
const softDeleteResults = results.filter((r) => r.message.includes('soft delete taxonomy'))
|
|
74
|
+
assert.lengthOf(softDeleteResults, 1)
|
|
75
|
+
assert.equal(softDeleteResults[0].severity, 'info')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('validate() should not return info when an entity has soft delete taxonomy', ({ assert }) => {
|
|
79
|
+
const model = domain.addModel({ key: 'model' })
|
|
80
|
+
const entity = model.addEntity({ key: 'entity', info: { name: 'Entity' } })
|
|
81
|
+
const deletedProperty = entity.addProperty({
|
|
82
|
+
key: 'deleted_at',
|
|
83
|
+
type: 'datetime',
|
|
84
|
+
info: { name: 'deleted_at' },
|
|
85
|
+
})
|
|
86
|
+
deletedProperty.addSemantic({ id: SemanticType.DeletedTimestamp })
|
|
87
|
+
const results = validation.validate()
|
|
88
|
+
const softDeleteResults = results.filter((r) => r.message.includes('soft delete taxonomy'))
|
|
89
|
+
assert.lengthOf(softDeleteResults, 0)
|
|
90
|
+
})
|
|
91
|
+
})
|