@api-client/core 0.14.9 → 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/DataDomain.d.ts +45 -3
- package/build/src/modeling/DataDomain.d.ts.map +1 -1
- package/build/src/modeling/DataDomain.js +81 -3
- package/build/src/modeling/DataDomain.js.map +1 -1
- package/build/src/modeling/DomainElement.d.ts +7 -0
- package/build/src/modeling/DomainElement.d.ts.map +1 -1
- package/build/src/modeling/DomainElement.js +14 -0
- package/build/src/modeling/DomainElement.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/entity_validation.js +1 -1
- package/build/src/modeling/validation/entity_validation.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 +12 -12
- 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/DataDomain.ts +84 -3
- package/src/modeling/DomainElement.ts +16 -0
- 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/entity_validation.ts +1 -1
- 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/data_domain_foreign.spec.ts +244 -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
package/src/modeling/types.ts
CHANGED
|
@@ -5,6 +5,14 @@ import type { DomainEntity } from './DomainEntity.js'
|
|
|
5
5
|
import type { DomainModel } from './DomainModel.js'
|
|
6
6
|
import type { DomainNamespace } from './DomainNamespace.js'
|
|
7
7
|
import type { DomainProperty } from './DomainProperty.js'
|
|
8
|
+
import type {
|
|
9
|
+
DomainNamespaceKind,
|
|
10
|
+
DomainEntityKind,
|
|
11
|
+
DomainModelKind,
|
|
12
|
+
DomainPropertyKind,
|
|
13
|
+
DomainAssociationKind,
|
|
14
|
+
DataDomainKind,
|
|
15
|
+
} from '../models/kinds.js'
|
|
8
16
|
|
|
9
17
|
export interface DataDomainRemoveOptions {
|
|
10
18
|
/**
|
|
@@ -732,3 +740,81 @@ export interface RateLimitRule {
|
|
|
732
740
|
*/
|
|
733
741
|
burst: number
|
|
734
742
|
}
|
|
743
|
+
|
|
744
|
+
export type DomainImpactKinds =
|
|
745
|
+
| typeof DomainNamespaceKind
|
|
746
|
+
| typeof DomainEntityKind
|
|
747
|
+
| typeof DomainModelKind
|
|
748
|
+
| typeof DomainPropertyKind
|
|
749
|
+
| typeof DomainAssociationKind
|
|
750
|
+
| typeof DataDomainKind
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* The impact analysis report
|
|
754
|
+
*/
|
|
755
|
+
export interface DomainImpactReport {
|
|
756
|
+
/**
|
|
757
|
+
* The key of the impacted data object.
|
|
758
|
+
* This is the key of the object that is being changed.
|
|
759
|
+
*/
|
|
760
|
+
key: string
|
|
761
|
+
/**
|
|
762
|
+
* The kind of the impacted data object.
|
|
763
|
+
* This is the kind of the object that is being changed.
|
|
764
|
+
*/
|
|
765
|
+
kind: DomainImpactKinds
|
|
766
|
+
/**
|
|
767
|
+
* The list of impacted data objects.
|
|
768
|
+
*/
|
|
769
|
+
impact: DomainImpactItem[]
|
|
770
|
+
/**
|
|
771
|
+
* Whether it is possible to proceed with the change.
|
|
772
|
+
* If the change is not possible, the reason will be in the impact list.
|
|
773
|
+
*/
|
|
774
|
+
canProceed: boolean
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
export interface DomainImpactItem {
|
|
778
|
+
/**
|
|
779
|
+
* The key of the impacted data object.
|
|
780
|
+
*/
|
|
781
|
+
key: string
|
|
782
|
+
/**
|
|
783
|
+
* The kind of the impacted data object.
|
|
784
|
+
*/
|
|
785
|
+
kind: string
|
|
786
|
+
/**
|
|
787
|
+
* The type of the impact.
|
|
788
|
+
*
|
|
789
|
+
* - `delete` - The data object would be deleted.
|
|
790
|
+
*/
|
|
791
|
+
type: 'delete' | 'publish'
|
|
792
|
+
/**
|
|
793
|
+
* The impact description.
|
|
794
|
+
* Explains what will happen to the impacted data object.
|
|
795
|
+
* This is a human-readable description of the impact.
|
|
796
|
+
* It should be clear and concise.
|
|
797
|
+
*/
|
|
798
|
+
impact: string
|
|
799
|
+
/**
|
|
800
|
+
* The severity of the impact.
|
|
801
|
+
*
|
|
802
|
+
* - `info` - The impact is informational.
|
|
803
|
+
* - `warning` - The impact can potentially cause problems but is not a blocker.
|
|
804
|
+
* - `error` - The impact is a blocker and needs to be resolved before proceeding.
|
|
805
|
+
*/
|
|
806
|
+
severity: 'info' | 'warning' | 'error'
|
|
807
|
+
/**
|
|
808
|
+
* The type of the relationship between two impacted objects.
|
|
809
|
+
*/
|
|
810
|
+
relationship?: 'child'
|
|
811
|
+
/**
|
|
812
|
+
* The resolution of the conflict if the change will be forced.
|
|
813
|
+
*/
|
|
814
|
+
resolution?: string
|
|
815
|
+
/**
|
|
816
|
+
* The optional parent of the impacted data object.
|
|
817
|
+
* For example, if the impacted item is a property, this will be the entity it belongs to.
|
|
818
|
+
*/
|
|
819
|
+
parent?: string
|
|
820
|
+
}
|
|
@@ -225,7 +225,7 @@ export class EntityValidation {
|
|
|
225
225
|
})
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
|
-
for (const other of this.domain.
|
|
228
|
+
for (const other of this.domain.listAllForeignEntities()) {
|
|
229
229
|
if (other.info.name?.toLowerCase() === name && other.key !== entity.key) {
|
|
230
230
|
const message = `The "${name}" entity name is already used in the foreign data domain.`
|
|
231
231
|
const help = `The name must be unique. This includes references to other data domains.`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReservedKeywords } from './postgresql.js'
|
|
2
2
|
import type { DomainProperty } from '../DomainProperty.js'
|
|
3
3
|
import type { DomainAssociation } from '../DomainAssociation.js'
|
|
4
|
-
import type { DomainImpactItem } from '../
|
|
4
|
+
import type { DomainImpactItem } from '../types.js'
|
|
5
5
|
import type { DomainEntity } from '../DomainEntity.js'
|
|
6
6
|
import { DomainPropertyKind } from '../../models/kinds.js'
|
|
7
7
|
|
|
@@ -10,11 +10,9 @@ import { DomainPropertyKind } from '../../models/kinds.js'
|
|
|
10
10
|
* - `impact` -> `message`
|
|
11
11
|
* - `resolution` -> `help`
|
|
12
12
|
* - `type` -> unused
|
|
13
|
-
* - `blocking` -> unused (deprecated)
|
|
14
13
|
* - `relationship` -> unused
|
|
15
14
|
*/
|
|
16
|
-
export interface DomainValidation
|
|
17
|
-
extends Omit<DomainImpactItem, 'type' | 'impact' | 'blocking' | 'relationship' | 'resolution'> {
|
|
15
|
+
export interface DomainValidation extends Omit<DomainImpactItem, 'type' | 'impact' | 'relationship' | 'resolution'> {
|
|
18
16
|
/**
|
|
19
17
|
* The field that did not pass validation.
|
|
20
18
|
*/
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { DomainEntityKind } from '../../models/kinds.js'
|
|
2
|
+
import type { DataDomain } from '../DataDomain.js'
|
|
3
|
+
import { SemanticType } from '../Semantics.js'
|
|
4
|
+
import type { DomainValidation } from './rules.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* SemanticValidation is a class that performs validation on semantics in a data domain.
|
|
8
|
+
* It checks for required and recommended semantics in entities, properties, and associations.
|
|
9
|
+
*/
|
|
10
|
+
export class SemanticValidation {
|
|
11
|
+
constructor(protected domain: DataDomain) {}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Performs all the semantic validation rules on the domain.
|
|
15
|
+
* @returns The list of validation messages.
|
|
16
|
+
*/
|
|
17
|
+
validate(): DomainValidation[] {
|
|
18
|
+
const results: DomainValidation[] = []
|
|
19
|
+
|
|
20
|
+
// Check for User entity semantic
|
|
21
|
+
const hasUserEntity = this.validateUserEntity()
|
|
22
|
+
results.push(...hasUserEntity)
|
|
23
|
+
|
|
24
|
+
// Check for timestamp semantics
|
|
25
|
+
const timestampSemantics = this.validateTimestampSemantics()
|
|
26
|
+
results.push(...timestampSemantics)
|
|
27
|
+
|
|
28
|
+
// Check for soft delete semantics
|
|
29
|
+
const softDeleteSemantics = this.validateSoftDeleteSemantics()
|
|
30
|
+
results.push(...softDeleteSemantics)
|
|
31
|
+
|
|
32
|
+
return results
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Validates if there is at least one entity with the User semantic.
|
|
37
|
+
* This is a recommended semantic for authentication purposes.
|
|
38
|
+
*/
|
|
39
|
+
private validateUserEntity(): DomainValidation[] {
|
|
40
|
+
const results: DomainValidation[] = []
|
|
41
|
+
let hasUserEntity = false
|
|
42
|
+
|
|
43
|
+
for (const entity of this.domain.listEntities()) {
|
|
44
|
+
if (entity.hasSemantic(SemanticType.User)) {
|
|
45
|
+
hasUserEntity = true
|
|
46
|
+
break
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!hasUserEntity) {
|
|
51
|
+
results.push({
|
|
52
|
+
field: 'semantics',
|
|
53
|
+
rule: 'recommended',
|
|
54
|
+
message: 'No entity with User taxonomy found in the domain.',
|
|
55
|
+
help: 'It is recommended to have at least one entity with the User taxonomy for authentication purposes.',
|
|
56
|
+
severity: 'warning',
|
|
57
|
+
key: 'user_semantic',
|
|
58
|
+
kind: DomainEntityKind,
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return results
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Validates if entities have the recommended timestamp semantics.
|
|
67
|
+
* This includes CreatedTimestamp and UpdatedTimestamp.
|
|
68
|
+
*/
|
|
69
|
+
private validateTimestampSemantics(): DomainValidation[] {
|
|
70
|
+
const results: DomainValidation[] = []
|
|
71
|
+
|
|
72
|
+
for (const entity of this.domain.listEntities()) {
|
|
73
|
+
let hasCreatedTimestamp = false
|
|
74
|
+
let hasUpdatedTimestamp = false
|
|
75
|
+
|
|
76
|
+
for (const property of entity.listProperties()) {
|
|
77
|
+
if (property.hasSemantic(SemanticType.CreatedTimestamp)) {
|
|
78
|
+
hasCreatedTimestamp = true
|
|
79
|
+
}
|
|
80
|
+
if (property.hasSemantic(SemanticType.UpdatedTimestamp)) {
|
|
81
|
+
hasUpdatedTimestamp = true
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!hasCreatedTimestamp) {
|
|
86
|
+
results.push({
|
|
87
|
+
field: 'semantics',
|
|
88
|
+
rule: 'recommended',
|
|
89
|
+
message: `The "${entity.info.getLabel()}" entity does not have a CreatedTimestamp taxonomy.`,
|
|
90
|
+
help: 'It is recommended to have a CreatedTimestamp property to track when the entity was created.',
|
|
91
|
+
severity: 'info',
|
|
92
|
+
key: entity.key,
|
|
93
|
+
kind: entity.kind,
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!hasUpdatedTimestamp) {
|
|
98
|
+
results.push({
|
|
99
|
+
field: 'semantics',
|
|
100
|
+
rule: 'recommended',
|
|
101
|
+
message: `The "${entity.info.getLabel()}" entity does not have an UpdatedTimestamp taxonomy.`,
|
|
102
|
+
help: 'It is recommended to have an UpdatedTimestamp property to track when the entity was last modified.',
|
|
103
|
+
severity: 'info',
|
|
104
|
+
key: entity.key,
|
|
105
|
+
kind: entity.kind,
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return results
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Validates if entities have the recommended soft delete semantics.
|
|
115
|
+
* This includes either DeletedTimestamp or DeletedFlag.
|
|
116
|
+
*/
|
|
117
|
+
private validateSoftDeleteSemantics(): DomainValidation[] {
|
|
118
|
+
const results: DomainValidation[] = []
|
|
119
|
+
|
|
120
|
+
for (const entity of this.domain.listEntities()) {
|
|
121
|
+
let hasSoftDelete = false
|
|
122
|
+
|
|
123
|
+
for (const property of entity.listProperties()) {
|
|
124
|
+
if (property.hasSemantic(SemanticType.DeletedTimestamp) || property.hasSemantic(SemanticType.DeletedFlag)) {
|
|
125
|
+
hasSoftDelete = true
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!hasSoftDelete) {
|
|
131
|
+
results.push({
|
|
132
|
+
field: 'semantics',
|
|
133
|
+
rule: 'recommended',
|
|
134
|
+
message: `The "${entity.info.getLabel()}" entity does not have soft delete taxonomy.`,
|
|
135
|
+
help: 'It is recommended to have either a DeletedTimestamp or DeletedFlag property for soft deletion.',
|
|
136
|
+
severity: 'info',
|
|
137
|
+
key: entity.key,
|
|
138
|
+
kind: entity.kind,
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return results
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The event names should be unique across all events in all modules.
|
|
2
|
+
const names: string[] = []
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
export function ensureUnique(namespace: string, src: any): void {
|
|
6
|
+
for (const [key, value] of Object.entries(src)) {
|
|
7
|
+
const typedValue = value as string
|
|
8
|
+
if (typeof typedValue !== 'string') {
|
|
9
|
+
return
|
|
10
|
+
}
|
|
11
|
+
if (names.includes(typedValue)) {
|
|
12
|
+
throw new Error(`${namespace}.${key} has duplicated event name ${typedValue}`)
|
|
13
|
+
}
|
|
14
|
+
names.push(typedValue)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
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('EventTypes.Amf', () => {
|
|
9
|
+
test('has the namespace', ({ assert }) => {
|
|
10
|
+
assert.typeOf(EventTypes.Amf, 'object')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('has frozen namespace', ({ assert }) => {
|
|
14
|
+
assert.throws(() => {
|
|
15
|
+
// @ts-expect-error Used in testing
|
|
16
|
+
EventTypes.Amf = { read: '' }
|
|
17
|
+
})
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('has "{prop}" property')
|
|
21
|
+
.with([
|
|
22
|
+
{
|
|
23
|
+
prop: 'processApiLink',
|
|
24
|
+
value: 'amfprocessapilink',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
prop: 'processBuffer',
|
|
28
|
+
value: 'amfprocessbuffer',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
prop: 'processApiFile',
|
|
32
|
+
value: 'amfprocessapifile',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
prop: 'selectApiMainFile',
|
|
36
|
+
value: 'amfselectapimainfile',
|
|
37
|
+
},
|
|
38
|
+
])
|
|
39
|
+
.run(({ assert }, { prop, value }) => {
|
|
40
|
+
// @ts-expect-error Used in testing
|
|
41
|
+
assert.equal(EventTypes.Amf[prop], value)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('has unique events on the namespace', () => {
|
|
45
|
+
ensureUnique('EventTypes.Amf', EventTypes.Amf)
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test.group('processApiLink()', () => {
|
|
50
|
+
const url = 'https://api.com'
|
|
51
|
+
const mainFile = 'api.raml'
|
|
52
|
+
const md5 = '123qwe'
|
|
53
|
+
const packaging = 'zip'
|
|
54
|
+
|
|
55
|
+
test('dispatches the event', async ({ assert }) => {
|
|
56
|
+
const spy = sinon.spy()
|
|
57
|
+
globalThis.addEventListener(EventTypes.Amf.processApiLink, spy)
|
|
58
|
+
await Events.Amf.processApiLink(url)
|
|
59
|
+
assert.isTrue(spy.calledOnce)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('sets the arguments on the detail object', async ({ assert }) => {
|
|
63
|
+
const spy = sinon.spy()
|
|
64
|
+
globalThis.addEventListener(EventTypes.Amf.processApiLink, spy)
|
|
65
|
+
await Events.Amf.processApiLink(url, mainFile, md5, packaging)
|
|
66
|
+
globalThis.removeEventListener(EventTypes.Amf.processApiLink, spy)
|
|
67
|
+
const { detail } = spy.args[0][0]
|
|
68
|
+
assert.equal(detail.url, url, 'url is set')
|
|
69
|
+
assert.equal(detail.mainFile, mainFile, 'mainFile is set')
|
|
70
|
+
assert.equal(detail.md5, md5, 'md5 is set')
|
|
71
|
+
assert.equal(detail.packaging, packaging, 'packaging is set')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('returns the result', async ({ assert }) => {
|
|
75
|
+
const parseResult = { model: '', type: { type: 'RAML 1.0' } }
|
|
76
|
+
function handler(e: CustomEvent): void {
|
|
77
|
+
globalThis.removeEventListener(EventTypes.Amf.processApiLink, handler as EventListener)
|
|
78
|
+
e.preventDefault()
|
|
79
|
+
e.detail.result = Promise.resolve(parseResult)
|
|
80
|
+
}
|
|
81
|
+
globalThis.addEventListener(EventTypes.Amf.processApiLink, handler as EventListener)
|
|
82
|
+
const result = await Events.Amf.processApiLink(url)
|
|
83
|
+
assert.equal(result, parseResult)
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test.group('processApiFile()', () => {
|
|
88
|
+
const file = new File([], 'test.txt')
|
|
89
|
+
|
|
90
|
+
test('dispatches the event', async ({ assert }) => {
|
|
91
|
+
const spy = sinon.spy()
|
|
92
|
+
globalThis.addEventListener(EventTypes.Amf.processApiFile, spy)
|
|
93
|
+
await Events.Amf.processApiFile(file)
|
|
94
|
+
globalThis.removeEventListener(EventTypes.Amf.processApiFile, spy)
|
|
95
|
+
assert.isTrue(spy.calledOnce)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('sets the arguments on the detail object', async ({ assert }) => {
|
|
99
|
+
const spy = sinon.spy()
|
|
100
|
+
globalThis.addEventListener(EventTypes.Amf.processApiFile, spy)
|
|
101
|
+
await Events.Amf.processApiFile(file)
|
|
102
|
+
globalThis.removeEventListener(EventTypes.Amf.processApiFile, spy)
|
|
103
|
+
const { detail } = spy.args[0][0]
|
|
104
|
+
assert.deepEqual(detail.file, file, 'file is set')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test('returns the result', async ({ assert }) => {
|
|
108
|
+
const parseResult = { model: '', type: { type: 'RAML 1.0' } }
|
|
109
|
+
function handler(e: CustomEvent): void {
|
|
110
|
+
globalThis.removeEventListener(EventTypes.Amf.processApiFile, handler as EventListener)
|
|
111
|
+
e.preventDefault()
|
|
112
|
+
e.detail.result = Promise.resolve(parseResult)
|
|
113
|
+
}
|
|
114
|
+
globalThis.addEventListener(EventTypes.Amf.processApiFile, handler as EventListener)
|
|
115
|
+
const result = await Events.Amf.processApiFile(file)
|
|
116
|
+
assert.equal(result, parseResult)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test.group('selectApiMainFile()', () => {
|
|
121
|
+
const candidates = ['test']
|
|
122
|
+
|
|
123
|
+
test('dispatches the event', async ({ assert }) => {
|
|
124
|
+
const spy = sinon.spy()
|
|
125
|
+
globalThis.addEventListener(EventTypes.Amf.selectApiMainFile, spy)
|
|
126
|
+
await Events.Amf.selectApiMainFile(candidates)
|
|
127
|
+
globalThis.removeEventListener(EventTypes.Amf.selectApiMainFile, spy)
|
|
128
|
+
assert.isTrue(spy.calledOnce)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
test('sets the arguments on the detail object', async ({ assert }) => {
|
|
132
|
+
const spy = sinon.spy()
|
|
133
|
+
globalThis.addEventListener(EventTypes.Amf.selectApiMainFile, spy)
|
|
134
|
+
await Events.Amf.selectApiMainFile(candidates)
|
|
135
|
+
globalThis.removeEventListener(EventTypes.Amf.selectApiMainFile, spy)
|
|
136
|
+
const { detail } = spy.args[0][0]
|
|
137
|
+
assert.deepEqual(detail.candidates, candidates, 'candidates is set')
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('returns the result', async ({ assert }) => {
|
|
141
|
+
const selected = 'test'
|
|
142
|
+
function handler(e: CustomEvent): void {
|
|
143
|
+
globalThis.removeEventListener(EventTypes.Amf.selectApiMainFile, handler as EventListener)
|
|
144
|
+
e.preventDefault()
|
|
145
|
+
e.detail.result = Promise.resolve(selected)
|
|
146
|
+
}
|
|
147
|
+
globalThis.addEventListener(EventTypes.Amf.selectApiMainFile, handler as EventListener)
|
|
148
|
+
const result = await Events.Amf.selectApiMainFile(candidates)
|
|
149
|
+
assert.equal(result, selected)
|
|
150
|
+
})
|
|
151
|
+
})
|
|
@@ -0,0 +1,150 @@
|
|
|
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 > Authorization > EventTypes.Authorization', () => {
|
|
9
|
+
test('has the namespace', ({ assert }) => {
|
|
10
|
+
assert.typeOf(EventTypes.Authorization, 'object')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('has OAuth2 namespace', ({ assert }) => {
|
|
14
|
+
assert.typeOf(EventTypes.Authorization.OAuth2, 'object')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('has frozen OAuth2 namespace', ({ assert }) => {
|
|
18
|
+
assert.throws(() => {
|
|
19
|
+
// @ts-expect-error Used in testing
|
|
20
|
+
EventTypes.Authorization.OAuth2 = { read: '' }
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('has "{prop}" property for OAuth2')
|
|
25
|
+
.with([
|
|
26
|
+
{ prop: 'authorize', value: 'oauth2authorize' },
|
|
27
|
+
{ prop: 'removeToken', value: 'oauth2removetoken' },
|
|
28
|
+
])
|
|
29
|
+
.run(({ assert }, { prop, value }) => {
|
|
30
|
+
// @ts-expect-error Used in testing
|
|
31
|
+
assert.equal(EventTypes.Authorization.OAuth2[prop], value)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('has unique events for OAuth2 namespace', () => {
|
|
35
|
+
ensureUnique('EventTypes.Authorization.OAuth2', EventTypes.Authorization.OAuth2)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('has frozen Oidc namespace', ({ assert }) => {
|
|
39
|
+
assert.throws(() => {
|
|
40
|
+
// @ts-expect-error Used in testing
|
|
41
|
+
EventTypes.Authorization.Oidc = { read: '' }
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('has "{prop}" property for Oidc')
|
|
46
|
+
.with([
|
|
47
|
+
{ prop: 'authorize', value: 'oidcauthorize' },
|
|
48
|
+
{ prop: 'removeTokens', value: 'oidcremovetokens' },
|
|
49
|
+
])
|
|
50
|
+
.run(({ assert }, { prop, value }) => {
|
|
51
|
+
// @ts-expect-error Used in testing
|
|
52
|
+
assert.equal(EventTypes.Authorization.Oidc[prop], value)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('has unique events for Oidc namespace', () => {
|
|
56
|
+
ensureUnique('EventTypes.Authorization.Oidc', EventTypes.Authorization.Oidc)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test.group('Events > Authorization > Events.Authorization > OAuth2 > authorize()', () => {
|
|
61
|
+
const config = { responseType: 'implicit' }
|
|
62
|
+
|
|
63
|
+
test('dispatches the event', async ({ assert }) => {
|
|
64
|
+
const spy = sinon.spy()
|
|
65
|
+
globalThis.addEventListener(EventTypes.Authorization.OAuth2.authorize, spy)
|
|
66
|
+
Events.Authorization.OAuth2.authorize(config)
|
|
67
|
+
globalThis.removeEventListener(EventTypes.Authorization.OAuth2.authorize, spy)
|
|
68
|
+
assert.isTrue(spy.calledOnce)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('has the configuration on the detail', async ({ assert }) => {
|
|
72
|
+
const spy = sinon.spy()
|
|
73
|
+
globalThis.addEventListener(EventTypes.Authorization.OAuth2.authorize, spy)
|
|
74
|
+
Events.Authorization.OAuth2.authorize(config)
|
|
75
|
+
globalThis.removeEventListener(EventTypes.Authorization.OAuth2.authorize, spy)
|
|
76
|
+
const e = spy.args[0][0]
|
|
77
|
+
const cnf = e.detail
|
|
78
|
+
delete cnf.result
|
|
79
|
+
assert.deepEqual(cnf, config)
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test.group('Events > Authorization > Events.Authorization > OAuth2 > removeToken()', () => {
|
|
84
|
+
const config = { clientId: 'id', authorizationUri: 'test' }
|
|
85
|
+
|
|
86
|
+
test('dispatches the event', async ({ assert }) => {
|
|
87
|
+
const spy = sinon.spy()
|
|
88
|
+
globalThis.addEventListener(EventTypes.Authorization.OAuth2.removeToken, spy)
|
|
89
|
+
Events.Authorization.OAuth2.removeToken(config)
|
|
90
|
+
globalThis.removeEventListener(EventTypes.Authorization.OAuth2.removeToken, spy)
|
|
91
|
+
assert.isTrue(spy.calledOnce)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('has the configuration on the detail', async ({ assert }) => {
|
|
95
|
+
const spy = sinon.spy()
|
|
96
|
+
globalThis.addEventListener(EventTypes.Authorization.OAuth2.removeToken, spy)
|
|
97
|
+
Events.Authorization.OAuth2.removeToken(config)
|
|
98
|
+
globalThis.removeEventListener(EventTypes.Authorization.OAuth2.removeToken, spy)
|
|
99
|
+
const e = spy.args[0][0]
|
|
100
|
+
const cnf = e.detail
|
|
101
|
+
delete cnf.result
|
|
102
|
+
assert.deepEqual(cnf, config)
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test.group('Events > Authorization > Events.Authorization > Oidc > authorize()', () => {
|
|
107
|
+
const config = { responseType: 'implicit' }
|
|
108
|
+
|
|
109
|
+
test('dispatches the event', async ({ assert }) => {
|
|
110
|
+
const spy = sinon.spy()
|
|
111
|
+
globalThis.addEventListener(EventTypes.Authorization.Oidc.authorize, spy)
|
|
112
|
+
Events.Authorization.Oidc.authorize(config)
|
|
113
|
+
globalThis.removeEventListener(EventTypes.Authorization.Oidc.authorize, spy)
|
|
114
|
+
assert.isTrue(spy.calledOnce)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('has the configuration on the detail', async ({ assert }) => {
|
|
118
|
+
const spy = sinon.spy()
|
|
119
|
+
globalThis.addEventListener(EventTypes.Authorization.Oidc.authorize, spy)
|
|
120
|
+
Events.Authorization.Oidc.authorize(config)
|
|
121
|
+
globalThis.removeEventListener(EventTypes.Authorization.Oidc.authorize, spy)
|
|
122
|
+
const e = spy.args[0][0]
|
|
123
|
+
const cnf = e.detail
|
|
124
|
+
delete cnf.result
|
|
125
|
+
assert.deepEqual(cnf, config)
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test.group('Events > Authorization > Events.Authorization > Oidc > removeToken()', () => {
|
|
130
|
+
const config = { clientId: 'id', authorizationUri: 'test' }
|
|
131
|
+
|
|
132
|
+
test('dispatches the event', async ({ assert }) => {
|
|
133
|
+
const spy = sinon.spy()
|
|
134
|
+
globalThis.addEventListener(EventTypes.Authorization.Oidc.removeTokens, spy)
|
|
135
|
+
Events.Authorization.Oidc.removeTokens(config)
|
|
136
|
+
globalThis.removeEventListener(EventTypes.Authorization.Oidc.removeTokens, spy)
|
|
137
|
+
assert.isTrue(spy.calledOnce)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('has the configuration on the detail', async ({ assert }) => {
|
|
141
|
+
const spy = sinon.spy()
|
|
142
|
+
globalThis.addEventListener(EventTypes.Authorization.Oidc.removeTokens, spy)
|
|
143
|
+
Events.Authorization.Oidc.removeTokens(config) // Calling removeToken
|
|
144
|
+
globalThis.removeEventListener(EventTypes.Authorization.Oidc.removeTokens, spy)
|
|
145
|
+
const e = spy.args[0][0]
|
|
146
|
+
const cnf = e.detail
|
|
147
|
+
delete cnf.result
|
|
148
|
+
assert.deepEqual(cnf, config)
|
|
149
|
+
})
|
|
150
|
+
})
|