From 1d2971d91540180ff326aa736bbae67c218788ab Mon Sep 17 00:00:00 2001 From: Ivan Garcia Sainz-Aja Date: Thu, 2 Jul 2026 09:24:54 +0200 Subject: [PATCH] feat: add traits field to channel object asyncapi/spec#1220 --- .../src/custom-operations/apply-traits.ts | 5 +- packages/parser/src/models/channel-trait.ts | 10 ++ packages/parser/src/models/channel-traits.ts | 4 + packages/parser/src/models/channel.ts | 2 + packages/parser/src/models/components.ts | 2 + packages/parser/src/models/index.ts | 2 + .../parser/src/models/v2/channel-traits.ts | 10 ++ packages/parser/src/models/v2/channel.ts | 6 ++ packages/parser/src/models/v2/components.ts | 6 ++ packages/parser/src/models/v2/index.ts | 3 +- .../parser/src/models/v3/channel-trait.ts | 39 ++++++++ .../parser/src/models/v3/channel-traits.ts | 10 ++ packages/parser/src/models/v3/channel.ts | 14 +++ packages/parser/src/models/v3/components.ts | 7 ++ packages/parser/src/models/v3/index.ts | 2 + packages/parser/src/spec-types/v3.ts | 7 +- .../custom-operations/apply-traits-v3.spec.ts | 95 +++++++++++++++++++ .../test/models/v3/channel-trait.spec.ts | 62 ++++++++++++ .../test/models/v3/channel-traits.spec.ts | 13 +++ .../parser/test/models/v3/channel.spec.ts | 27 ++++++ .../parser/test/models/v3/components.spec.ts | 18 ++++ 21 files changed, 341 insertions(+), 3 deletions(-) create mode 100644 packages/parser/src/models/channel-trait.ts create mode 100644 packages/parser/src/models/channel-traits.ts create mode 100644 packages/parser/src/models/v2/channel-traits.ts create mode 100644 packages/parser/src/models/v3/channel-trait.ts create mode 100644 packages/parser/src/models/v3/channel-traits.ts create mode 100644 packages/parser/test/models/v3/channel-trait.spec.ts create mode 100644 packages/parser/test/models/v3/channel-traits.spec.ts diff --git a/packages/parser/src/custom-operations/apply-traits.ts b/packages/parser/src/custom-operations/apply-traits.ts index 1c2ff7ef0..4617377f1 100644 --- a/packages/parser/src/custom-operations/apply-traits.ts +++ b/packages/parser/src/custom-operations/apply-traits.ts @@ -49,6 +49,9 @@ function applyTraitsToObjectV2(value: Record) { } const v3TraitPaths = [ + // channels + '$.channels.*', + '$.components.channels.*', // operations '$.operations.*', '$.operations.*.channel.messages.*', @@ -56,7 +59,7 @@ const v3TraitPaths = [ '$.components.operations.*', '$.components.operations.*.channel.messages.*', '$.components.operations.*.messages.*', - // Channels + // messages inside channels '$.channels.*.messages.*', '$.components.channels.*.messages.*', // messages diff --git a/packages/parser/src/models/channel-trait.ts b/packages/parser/src/models/channel-trait.ts new file mode 100644 index 000000000..41612db59 --- /dev/null +++ b/packages/parser/src/models/channel-trait.ts @@ -0,0 +1,10 @@ +import type { BaseModel } from './base'; +import type { ChannelParametersInterface } from './channel-parameters'; +import type { CoreMixinInterface } from './mixins'; +import type { ServersInterface } from './servers'; + +export interface ChannelTraitInterface extends BaseModel, CoreMixinInterface { + id(): string; + servers(): ServersInterface; + parameters(): ChannelParametersInterface; +} diff --git a/packages/parser/src/models/channel-traits.ts b/packages/parser/src/models/channel-traits.ts new file mode 100644 index 000000000..c64e8cbae --- /dev/null +++ b/packages/parser/src/models/channel-traits.ts @@ -0,0 +1,4 @@ +import type { Collection } from './collection'; +import type { ChannelTraitInterface } from './channel-trait'; + +export type ChannelTraitsInterface = Collection; diff --git a/packages/parser/src/models/channel.ts b/packages/parser/src/models/channel.ts index 57f07ff35..4e405fe5e 100644 --- a/packages/parser/src/models/channel.ts +++ b/packages/parser/src/models/channel.ts @@ -1,5 +1,6 @@ import type { BaseModel } from './base'; import type { ChannelParametersInterface } from './channel-parameters'; +import type { ChannelTraitsInterface } from './channel-traits'; import type { MessagesInterface } from './messages'; import type { BindingsMixinInterface, DescriptionMixinInterface, ExtensionsMixinInterface } from './mixins'; import type { OperationsInterface } from './operations'; @@ -12,4 +13,5 @@ export interface ChannelInterface extends BaseModel, BindingsMixinInterface, Des operations(): OperationsInterface; messages(): MessagesInterface; parameters(): ChannelParametersInterface; + traits(): ChannelTraitsInterface; } diff --git a/packages/parser/src/models/components.ts b/packages/parser/src/models/components.ts index f96524f1e..7fd7466c4 100644 --- a/packages/parser/src/models/components.ts +++ b/packages/parser/src/models/components.ts @@ -6,6 +6,7 @@ import type { ChannelsInterface } from './channels'; import type { MessagesInterface } from './messages'; import type { SchemasInterface } from './schemas'; import type { ChannelParametersInterface } from './channel-parameters'; +import type { ChannelTraitsInterface } from './channel-traits'; import type { ServerVariablesInterface } from './server-variables'; import type { OperationTraitsInterface } from './operation-traits'; import type { MessageTraitsInterface } from './message-traits'; @@ -21,6 +22,7 @@ export interface ComponentsInterface extends BaseModel, ExtensionsMixinInterface channelParameters(): ChannelParametersInterface; serverVariables(): ServerVariablesInterface; operations(): OperationsInterface; + channelTraits(): ChannelTraitsInterface; operationTraits(): OperationTraitsInterface; messageTraits(): MessageTraitsInterface; correlationIds(): CorrelationIdsInterface; diff --git a/packages/parser/src/models/index.ts b/packages/parser/src/models/index.ts index 1d094f79e..5189de3c1 100644 --- a/packages/parser/src/models/index.ts +++ b/packages/parser/src/models/index.ts @@ -9,6 +9,8 @@ export * from './channel-parameter'; export * from './channel-parameters'; export * from './channel'; export * from './channels'; +export * from './channel-trait'; +export * from './channel-traits'; export * from './collection'; export * from './components'; export * from './contact'; diff --git a/packages/parser/src/models/v2/channel-traits.ts b/packages/parser/src/models/v2/channel-traits.ts new file mode 100644 index 000000000..e389c8671 --- /dev/null +++ b/packages/parser/src/models/v2/channel-traits.ts @@ -0,0 +1,10 @@ +import { Collection } from '../collection'; + +import type { ChannelTraitsInterface } from '../channel-traits'; +import type { ChannelTraitInterface } from '../channel-trait'; + +export class ChannelTraits extends Collection implements ChannelTraitsInterface { + override get(id: string): ChannelTraitInterface | undefined { + return this.collections.find(trait => trait.id() === id); + } +} diff --git a/packages/parser/src/models/v2/channel.ts b/packages/parser/src/models/v2/channel.ts index 8e994a4f3..023761dc3 100644 --- a/packages/parser/src/models/v2/channel.ts +++ b/packages/parser/src/models/v2/channel.ts @@ -1,4 +1,5 @@ import { BaseModel } from '../base'; +import { ChannelTraits } from './channel-traits'; import { ChannelParameters } from './channel-parameters'; import { ChannelParameter } from './channel-parameter'; import { Messages } from './messages'; @@ -12,6 +13,7 @@ import { bindings, hasDescription, description, extensions } from './mixins'; import type { BindingsInterface } from '../bindings'; import type { ChannelInterface } from '../channel'; import type { ChannelParametersInterface } from '../channel-parameters'; +import type { ChannelTraitsInterface } from '../channel-traits'; import type { ExtensionsInterface } from '../extensions'; import type { MessagesInterface } from '../messages'; import type { MessageInterface } from '../message'; @@ -81,6 +83,10 @@ export class Channel extends BaseModel implements Compon return this.createCollection('parameters', ChannelParameters, ChannelParameter); } + channelTraits(): ChannelTraitsInterface { + return new ChannelTraits([]); + } + serverVariables(): ServerVariablesInterface { return this.createCollection('serverVariables', ServerVariables, ServerVariable); } diff --git a/packages/parser/src/models/v2/index.ts b/packages/parser/src/models/v2/index.ts index 69b94f651..43254be9a 100644 --- a/packages/parser/src/models/v2/index.ts +++ b/packages/parser/src/models/v2/index.ts @@ -5,6 +5,7 @@ export { ChannelParameter as ChannelParameterV2 } from './channel-parameter'; export { ChannelParameters as ChannelParametersV2 } from './channel-parameters'; export { Channel as ChannelV2 } from './channel'; export { Channels as ChannelsV2 } from './channels'; +export { ChannelTraits as ChannelTraitsV2 } from './channel-traits'; export { Components as ComponentsV2 } from './components'; export { Contact as ContactV2 } from './contact'; export { CorrelationId as CorrelationIdV2 } from './correlation-id'; @@ -34,4 +35,4 @@ export { ServerVariables as ServerVariablesV2 } from './server-variables'; export { Server as ServerV2 } from './server'; export { Servers as ServersV2 } from './servers'; export { Tag as TagV2 } from './tag'; -export { Tags as TagsV2 } from './tags'; \ No newline at end of file +export { Tags as TagsV2 } from './tags'; diff --git a/packages/parser/src/models/v3/channel-trait.ts b/packages/parser/src/models/v3/channel-trait.ts new file mode 100644 index 000000000..08feadc1c --- /dev/null +++ b/packages/parser/src/models/v3/channel-trait.ts @@ -0,0 +1,39 @@ +import { ChannelParameters } from './channel-parameters'; +import { ChannelParameter } from './channel-parameter'; +import { Servers } from './servers'; +import { Server } from './server'; +import { CoreModel } from './mixins'; + +import type { ChannelTraitInterface } from '../channel-trait'; +import type { ChannelParametersInterface } from '../channel-parameters'; +import type { ServersInterface } from '../servers'; +import type { ServerInterface } from '../server'; +import type { v3 } from '../../spec-types'; + +export class ChannelTrait extends CoreModel implements ChannelTraitInterface { + id(): string { + return this._meta.id; + } + + servers(): ServersInterface { + const servers: ServerInterface[] = []; + const allowedServers = this._json.servers ?? []; + Object.entries(this._meta.asyncapi?.parsed.servers ?? {}).forEach(([serverName, server]) => { + if (allowedServers.length === 0 || allowedServers.includes(server)) { + servers.push(this.createModel(Server, server, { id: serverName, pointer: `/servers/${serverName}` })); + } + }); + return new Servers(servers); + } + + parameters(): ChannelParametersInterface { + return new ChannelParameters( + Object.entries(this._json.parameters ?? {}).map(([channelParameterName, channelParameter]) => { + return this.createModel(ChannelParameter, channelParameter as v3.ParameterObject, { + id: channelParameterName, + pointer: this.jsonPath(`parameters/${channelParameterName}`), + }); + }) + ); + } +} diff --git a/packages/parser/src/models/v3/channel-traits.ts b/packages/parser/src/models/v3/channel-traits.ts new file mode 100644 index 000000000..e389c8671 --- /dev/null +++ b/packages/parser/src/models/v3/channel-traits.ts @@ -0,0 +1,10 @@ +import { Collection } from '../collection'; + +import type { ChannelTraitsInterface } from '../channel-traits'; +import type { ChannelTraitInterface } from '../channel-trait'; + +export class ChannelTraits extends Collection implements ChannelTraitsInterface { + override get(id: string): ChannelTraitInterface | undefined { + return this.collections.find(trait => trait.id() === id); + } +} diff --git a/packages/parser/src/models/v3/channel.ts b/packages/parser/src/models/v3/channel.ts index 9c9c14749..524a5192a 100644 --- a/packages/parser/src/models/v3/channel.ts +++ b/packages/parser/src/models/v3/channel.ts @@ -1,5 +1,7 @@ import { ChannelParameters } from './channel-parameters'; import { ChannelParameter } from './channel-parameter'; +import { ChannelTrait } from './channel-trait'; +import { ChannelTraits } from './channel-traits'; import { Messages } from './messages'; import { Message } from './message'; import { Operations } from './operations'; @@ -10,6 +12,7 @@ import { xParserObjectUniqueId } from '../../constants'; import { CoreModel } from './mixins'; import type { ChannelInterface } from '../channel'; import type { ChannelParametersInterface } from '../channel-parameters'; +import type { ChannelTraitsInterface } from '../channel-traits'; import type { MessagesInterface } from '../messages'; import type { OperationsInterface } from '../operations'; import type { OperationInterface } from '../operation'; @@ -69,4 +72,15 @@ export class Channel extends CoreModel impleme }) ); } + + traits(): ChannelTraitsInterface { + return new ChannelTraits( + (this._json.traits ?? []).map((trait, index) => { + return this.createModel(ChannelTrait, trait as v3.ChannelTraitObject, { + id: '', + pointer: this.jsonPath(`traits/${index}`), + }); + }) + ); + } } diff --git a/packages/parser/src/models/v3/components.ts b/packages/parser/src/models/v3/components.ts index 9931b0b70..d2f77b2ec 100644 --- a/packages/parser/src/models/v3/components.ts +++ b/packages/parser/src/models/v3/components.ts @@ -4,6 +4,7 @@ import { Collection } from '../collection'; import { Bindings } from './bindings'; import { Binding } from './binding'; import { Channel } from './channel'; +import { ChannelTrait } from './channel-trait'; import { ChannelParameter } from './channel-parameter'; import { CorrelationId } from './correlation-id'; import { MessageTrait } from './message-trait'; @@ -17,6 +18,7 @@ import { ServerVariable } from './server-variable'; import { extensions } from './mixins'; import { Servers } from './servers'; import { Channels } from './channels'; +import { ChannelTraits } from './channel-traits'; import { Messages } from './messages'; import { Schemas } from './schemas'; import { ChannelParameters } from './channel-parameters'; @@ -46,6 +48,7 @@ import type { ChannelsInterface } from '../channels'; import type { MessagesInterface } from '../messages'; import type { SchemasInterface } from '../schemas'; import type { ChannelParametersInterface } from '../channel-parameters'; +import type { ChannelTraitsInterface } from '../channel-traits'; import type { ServerVariablesInterface } from '../server-variables'; import type { OperationTraitsInterface } from '../operation-traits'; import type { SecuritySchemesInterface } from '../security-schemes'; @@ -83,6 +86,10 @@ export class Components extends BaseModel implements Compon return this.createCollection('parameters', ChannelParameters, ChannelParameter); } + channelTraits(): ChannelTraitsInterface { + return this.createCollection('channelTraits', ChannelTraits, ChannelTrait); + } + serverVariables(): ServerVariablesInterface { return this.createCollection('serverVariables', ServerVariables, ServerVariable); } diff --git a/packages/parser/src/models/v3/index.ts b/packages/parser/src/models/v3/index.ts index fb3848508..dcde80870 100644 --- a/packages/parser/src/models/v3/index.ts +++ b/packages/parser/src/models/v3/index.ts @@ -5,6 +5,8 @@ export { ChannelParameter as ChannelParameterV3 } from './channel-parameter'; export { ChannelParameters as ChannelParametersV3 } from './channel-parameters'; export { Channel as ChannelV3 } from './channel'; export { Channels as ChannelsV3 } from './channels'; +export { ChannelTrait as ChannelTraitV3 } from './channel-trait'; +export { ChannelTraits as ChannelTraitsV3 } from './channel-traits'; export { Components as ComponentsV3 } from './components'; export { Contact as ContactV3 } from './contact'; export { CorrelationId as CorrelationIdV3 } from './correlation-id'; diff --git a/packages/parser/src/spec-types/v3.ts b/packages/parser/src/spec-types/v3.ts index 766df3bf9..e262feb6e 100644 --- a/packages/parser/src/spec-types/v3.ts +++ b/packages/parser/src/spec-types/v3.ts @@ -81,9 +81,13 @@ export interface ServerBindingsObject extends SpecificationExtensions { export type ChannelsObject = Record; -export interface ChannelObject extends SpecificationExtensions { +export interface ChannelObject extends ChannelTraitObject, SpecificationExtensions { address?: string | null; messages?: MessagesObject; + traits?: Array; +} + +export interface ChannelTraitObject extends SpecificationExtensions { title?: string; summary?: string; description?: string; @@ -255,6 +259,7 @@ export interface ComponentsObject extends SpecificationExtensions { replies?: Record; replyAddresses?: Record; correlationIds?: Record; + channelTraits?: Record; operationTraits?: Record; messageTraits?: Record; tags?: Record; diff --git a/packages/parser/test/custom-operations/apply-traits-v3.spec.ts b/packages/parser/test/custom-operations/apply-traits-v3.spec.ts index e89ad7f4c..9c1d102c0 100644 --- a/packages/parser/test/custom-operations/apply-traits-v3.spec.ts +++ b/packages/parser/test/custom-operations/apply-traits-v3.spec.ts @@ -1,4 +1,5 @@ import { xParserObjectUniqueId } from '../../src/constants'; +import { applyTraitsV3 } from '../../src/custom-operations/apply-traits'; import { AsyncAPIDocumentV3 } from '../../src/models'; import { Parser } from '../../src/parser'; import { filterLastVersionDiagnostics } from '../utils'; @@ -171,6 +172,100 @@ describe('custom operations - apply traits v3', function() { expect(message2).toEqual({ summary: 'root summary', description: 'root description', 'x-parser-message-name': 'someMessage2', 'x-parser-unique-object-id': 'someMessage2' }); }); + it('should apply traits to channels', function() { + const documentRaw: v3.AsyncAPIObject = { + asyncapi: '3.2.0', + info: { + title: 'Valid AsyncApi document', + version: '1.0', + }, + channels: { + someChannel1: { + traits: [ + { + description: 'some description', + bindings: { kafka: { partitions: 5 } } + }, + { + description: 'another description', + bindings: { kafka: { replicas: 3 } } + } + ] + }, + someChannel2: { + description: 'root description', + bindings: { kafka: { partitions: 10 } }, + traits: [ + { + description: 'some description', + bindings: { kafka: { partitions: 5, replicas: 3 } } + } + ] + } + } + }; + applyTraitsV3(documentRaw); + + const channel1 = documentRaw.channels?.someChannel1 as v3.ChannelObject; + delete (channel1 as any)?.traits; + expect(channel1.description).toEqual('another description'); + expect((channel1 as any).bindings).toEqual({ kafka: { partitions: 5, replicas: 3 } }); + + const channel2 = documentRaw.channels?.someChannel2 as v3.ChannelObject; + delete (channel2 as any)?.traits; + // root object wins over traits + expect(channel2.description).toEqual('root description'); + expect((channel2 as any).bindings).toEqual({ kafka: { partitions: 10, replicas: 3 } }); + }); + + it('should apply traits to channels (components)', function() { + const documentRaw: v3.AsyncAPIObject = { + asyncapi: '3.2.0', + info: { + title: 'Valid AsyncApi document', + version: '1.0', + }, + components: { + channels: { + someChannel1: { + traits: [ + { + description: 'some description', + bindings: { kafka: { partitions: 5 } } + }, + { + description: 'another description', + bindings: { kafka: { replicas: 3 } } + } + ] + }, + someChannel2: { + description: 'root description', + bindings: { kafka: { partitions: 10 } }, + traits: [ + { + description: 'some description', + bindings: { kafka: { partitions: 5, replicas: 3 } } + } + ] + } + } + } + }; + applyTraitsV3(documentRaw); + + const channel1 = documentRaw.components?.channels?.someChannel1 as v3.ChannelObject; + delete (channel1 as any)?.traits; + expect(channel1.description).toEqual('another description'); + expect((channel1 as any).bindings).toEqual({ kafka: { partitions: 5, replicas: 3 } }); + + const channel2 = documentRaw.components?.channels?.someChannel2 as v3.ChannelObject; + delete (channel2 as any)?.traits; + // root object wins over traits + expect(channel2.description).toEqual('root description'); + expect((channel2 as any).bindings).toEqual({ kafka: { partitions: 10, replicas: 3 } }); + }); + describe('iterative functions should still work after traits have been applied', function() { const documentRaw = { asyncapi: '3.0.0', diff --git a/packages/parser/test/models/v3/channel-trait.spec.ts b/packages/parser/test/models/v3/channel-trait.spec.ts new file mode 100644 index 000000000..2ceb793af --- /dev/null +++ b/packages/parser/test/models/v3/channel-trait.spec.ts @@ -0,0 +1,62 @@ +import { ChannelTrait } from '../../../src/models/v3/channel-trait'; +import { ChannelParameters } from '../../../src/models/v3/channel-parameters'; +import { ChannelParameter } from '../../../src/models/v3/channel-parameter'; +import { Servers } from '../../../src/models/v3/servers'; +import { Server } from '../../../src/models/v3/server'; + +import { assertCoreModel, serializeInput } from './utils'; + +import type { v3 } from '../../../src/spec-types'; + +describe('ChannelTrait model', function() { + describe('.id()', function() { + it('should return id of model', function() { + const d = new ChannelTrait({}, { asyncapi: {} as any, pointer: '', id: 'trait' }); + expect(d.id()).toEqual('trait'); + }); + }); + + describe('.servers()', function() { + it('should return the servers selected by the trait', function() { + const selectedServer = {}; + const doc = serializeInput({ servers: [selectedServer] }); + const d = new ChannelTrait(doc, { + asyncapi: { + parsed: { + servers: { + first: {}, + selected: selectedServer + } + } + } as any, + pointer: '', + id: 'trait' + }); + + expect(d.servers()).toBeInstanceOf(Servers); + expect(d.servers().all()).toHaveLength(1); + expect(d.servers().all()[0]).toBeInstanceOf(Server); + expect(d.servers().all()[0].id()).toEqual('selected'); + }); + }); + + describe('.parameters()', function() { + it('should return the parameters defined by the trait', function() { + const doc = serializeInput({ + parameters: { + parameter: {} + } + }); + const d = new ChannelTrait(doc); + + expect(d.parameters()).toBeInstanceOf(ChannelParameters); + expect(d.parameters().all()).toHaveLength(1); + expect(d.parameters().all()[0]).toBeInstanceOf(ChannelParameter); + expect(d.parameters().all()[0].id()).toEqual('parameter'); + }); + }); + + describe('mixins', function() { + assertCoreModel(ChannelTrait); + }); +}); diff --git a/packages/parser/test/models/v3/channel-traits.spec.ts b/packages/parser/test/models/v3/channel-traits.spec.ts new file mode 100644 index 000000000..bf3ed07b1 --- /dev/null +++ b/packages/parser/test/models/v3/channel-traits.spec.ts @@ -0,0 +1,13 @@ +import { ChannelTrait } from '../../../src/models/v3/channel-trait'; +import { ChannelTraits } from '../../../src/models/v3/channel-traits'; + +describe('ChannelTraits model', function() { + it('should return a channel trait by id', function() { + const first = new ChannelTrait({}, { id: 'first' }); + const second = new ChannelTrait({}, { id: 'second' }); + const traits = new ChannelTraits([first, second]); + + expect(traits.get('second')).toBe(second); + expect(traits.get('missing')).toBeUndefined(); + }); +}); diff --git a/packages/parser/test/models/v3/channel.spec.ts b/packages/parser/test/models/v3/channel.spec.ts index a444b1c62..dfbfc2f63 100644 --- a/packages/parser/test/models/v3/channel.spec.ts +++ b/packages/parser/test/models/v3/channel.spec.ts @@ -1,4 +1,6 @@ import { Channel } from '../../../src/models/v3/channel'; +import { ChannelTrait } from '../../../src/models/v3/channel-trait'; +import { ChannelTraits } from '../../../src/models/v3/channel-traits'; import { ChannelParameters } from '../../../src/models/v3/channel-parameters'; import { ChannelParameter } from '../../../src/models/v3/channel-parameter'; import { Operations } from '../../../src/models/v3/operations'; @@ -134,6 +136,31 @@ describe('Channel model', function() { }); }); + describe('.traits()', function() { + it('should return collection of channel traits', function() { + const doc = serializeInput({ + traits: [ + { title: 'First trait' }, + { description: 'Second trait' } + ] + }); + const d = new Channel(doc); + + expect(d.traits()).toBeInstanceOf(ChannelTraits); + expect(d.traits().all()).toHaveLength(2); + expect(d.traits().all()[0]).toBeInstanceOf(ChannelTrait); + expect(d.traits().all()[0].title()).toEqual('First trait'); + expect(d.traits().all()[1].description()).toEqual('Second trait'); + }); + + it('should return an empty collection when traits are not defined', function() { + const d = new Channel(serializeInput({})); + + expect(d.traits()).toBeInstanceOf(ChannelTraits); + expect(d.traits().all()).toHaveLength(0); + }); + }); + describe('mixins', function() { assertCoreModel(Channel); }); diff --git a/packages/parser/test/models/v3/components.spec.ts b/packages/parser/test/models/v3/components.spec.ts index 623b9b2a9..3c06c6234 100644 --- a/packages/parser/test/models/v3/components.spec.ts +++ b/packages/parser/test/models/v3/components.spec.ts @@ -1,6 +1,7 @@ import { Components } from '../../../src/models/v3/components'; import { Bindings } from '../../../src/models/v3/bindings'; import { Channel } from '../../../src/models/v3/channel'; +import { ChannelTrait } from '../../../src/models/v3/channel-trait'; import { ChannelParameter } from '../../../src/models/v3/channel-parameter'; import { CorrelationId } from '../../../src/models/v3/correlation-id'; import { OperationTrait } from '../../../src/models/v3/operation-trait'; @@ -15,6 +16,7 @@ import { SecurityScheme } from '../../../src/models/v3/security-scheme'; import { BaseModel, ModelMetadata } from '../../../src/models'; import { Servers } from '../../../src/models/v3/servers'; import { Channels } from '../../../src/models/v3/channels'; +import { ChannelTraits } from '../../../src/models/v3/channel-traits'; import { Messages } from '../../../src/models/v3/messages'; import { Collection } from '../../../src/models/collection'; import { Constructor } from '../../../src/models/utils'; @@ -171,6 +173,22 @@ describe('Components model', function() { }); }); + describe('.channelTraits()', function() { + it('should return ChannelTraits with ChannelTrait Object', function() { + const doc = serializeInput({ channelTraits: { trait: {} } }); + const d = new Components(doc); + testCollection(doc, d.channelTraits(), 'channelTraits', ChannelTraits, ChannelTrait); + }); + + it('should return ChannelTraits with empty channel trait objects when channelTraits are not defined', function() { + const doc = serializeInput({}); + const d = new Components(doc); + const items = d.channelTraits(); + expect(items).toBeInstanceOf(ChannelTraits); + expect(items.all()).toHaveLength(0); + }); + }); + describe('.messageTraits()', function() { it('should return MessageTraits with MessageTrait Object', function() { const doc = serializeInput({ messageTraits: { trait: {} } });