Skip to content

Commit 1bf1a2a

Browse files
smoghe-bwclaude
andcommitted
Address PR review feedback for BRTC endpoints
- Add Connect and Endpoint BXML verb implementations and tests - Export new verbs from bxml/verbs/index.ts - Combine model tests into single comprehensive tests per model - Add Object.values assertions to all enum tests - Improve date assertions to verify year and specific ISO timestamps - Use request body variable with CreateWebRtcConnectionRequest type in unit API tests - Remove toContainKeys assertions from unit API tests - Rename test descriptions to "should create/list/get/delete endpoint" - Add missing delete endpoint unit test - Remove unnecessary filtered-by-type test from smoke tests - Rename smoke test descriptions for consistency Generated from Claude9 with Claude Code Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 92ee0d9 commit 1bf1a2a

19 files changed

Lines changed: 260 additions & 198 deletions

models/bxml/verbs/Connect.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { NestableVerb } from '../NestableVerb';
2+
import { Endpoint } from './Endpoint';
3+
4+
export interface ConnectAttributes {
5+
connectCompleteUrl?: string;
6+
connectCompleteMethod?: string;
7+
connectCompleteFallbackUrl?: string;
8+
connectCompleteFallbackMethod?: string;
9+
username?: string;
10+
password?: string;
11+
fallbackUsername?: string;
12+
fallbackPassword?: string;
13+
tag?: string;
14+
}
15+
16+
/**
17+
* @export
18+
* @class Connect
19+
* @extends {NestableVerb}
20+
* Represents a Connect verb
21+
*/
22+
export class Connect extends NestableVerb {
23+
attributes: ConnectAttributes;
24+
25+
/**
26+
* Creates an instance of Connect
27+
* @param {ConnectAttributes} attributes The attributes to add to the element
28+
* @param {Endpoint | Endpoint[]} endpoints The endpoint or endpoints to connect to
29+
*/
30+
constructor(attributes?: ConnectAttributes, endpoints?: Endpoint | Endpoint[]) {
31+
super('Connect', undefined, attributes, endpoints);
32+
}
33+
34+
/**
35+
* Add an endpoint or endpoints to the connect
36+
* @param {Endpoint | Endpoint[]} endpoints The endpoint or endpoints to add
37+
*/
38+
addEndpoints(endpoints: Endpoint | Endpoint[]): void {
39+
this.nestedVerbs = this.nestedVerbs.concat(endpoints);
40+
}
41+
}

models/bxml/verbs/Endpoint.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Verb } from '../Verb';
2+
3+
export interface EndpointAttributes {
4+
endpointId?: string;
5+
}
6+
7+
/**
8+
* @export
9+
* @class Endpoint
10+
* @extends {Verb}
11+
* Represents an Endpoint verb
12+
*/
13+
export class Endpoint extends Verb {
14+
attributes: EndpointAttributes;
15+
16+
/**
17+
* Creates an instance of Endpoint
18+
* @param {string} endpointId The endpoint ID to connect to
19+
* @param {EndpointAttributes} attributes The attributes to add to the element
20+
*/
21+
constructor(endpointId: string, attributes?: EndpointAttributes) {
22+
super('Endpoint', endpointId, attributes);
23+
}
24+
}

models/bxml/verbs/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
export * from './Bridge';
22
export * from './Conference';
3+
export * from './Connect';
34
export * from './CustomParam';
5+
export * from './Endpoint';
46
export * from './Forward';
57
export * from './Gather';
68
export * from './Hangup';

tests/smoke/endpoints-api.test.ts

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('EndpointsApi', () => {
1313
let endpointId: string;
1414

1515
describe('endpoint lifecycle', () => {
16-
test('should create a new endpoint', async () => {
16+
test('should create endpoint', async () => {
1717
const endpointBody: CreateWebRtcConnectionRequest = {
1818
type: EndpointTypeEnum.Webrtc,
1919
direction: EndpointDirectionEnum.Bidirectional
@@ -42,7 +42,7 @@ describe('EndpointsApi', () => {
4242
endpointId = data.data.endpointId;
4343
});
4444

45-
test('should list endpoints for the account', async () => {
45+
test('should list endpoints', async () => {
4646
const { status, data } = await endpointsApi.listEndpoints(BW_ACCOUNT_ID);
4747

4848
expect(status).toEqual(200);
@@ -61,18 +61,7 @@ describe('EndpointsApi', () => {
6161
expect(createdEndpoint!.expirationTimestamp).toBeDateString();
6262
});
6363

64-
test('should list endpoints filtered by type', async () => {
65-
const { status, data } = await endpointsApi.listEndpoints(BW_ACCOUNT_ID, EndpointTypeEnum.Webrtc);
66-
67-
expect(status).toEqual(200);
68-
expect(data.data).toBeInstanceOf(Array);
69-
expect(data.errors).toBeInstanceOf(Array);
70-
if (data.data.length > 0) {
71-
expect(data.data.every((item) => item.type === EndpointTypeEnum.Webrtc)).toEqual(true);
72-
}
73-
});
74-
75-
test('should retrieve details of a specific endpoint', async () => {
64+
test('should get endpoint', async () => {
7665
const { status, data } = await endpointsApi.getEndpoint(BW_ACCOUNT_ID, endpointId);
7766

7867
expect(status).toEqual(200);
Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@ts-nocheck
22
import { EndpointsApi } from '../../../api';
33
import { Configuration } from '../../../configuration';
4-
import { EndpointDirectionEnum, EndpointStatusEnum, EndpointTypeEnum } from '../../../models';
4+
import { CreateWebRtcConnectionRequest, EndpointDirectionEnum, EndpointStatusEnum, EndpointTypeEnum } from '../../../models';
55

66
describe('EndpointsApi', () => {
77
const config = new Configuration({
@@ -15,27 +15,20 @@ describe('EndpointsApi', () => {
1515
const endpointId = 'ep-123456';
1616

1717
describe('createEndpoint', () => {
18-
test('should create endpoint and return full response shape', async () => {
19-
const { status, data } = await endpointsApi.createEndpoint(accountId, {
18+
test('should create endpoint', async () => {
19+
const createEndpointBody: CreateWebRtcConnectionRequest = {
2020
type: EndpointTypeEnum.Webrtc,
2121
direction: EndpointDirectionEnum.Bidirectional
22-
});
22+
};
23+
24+
const { status, data } = await endpointsApi.createEndpoint(accountId, createEndpointBody);
2325

2426
expect(status).toEqual(201);
2527
expect(data.links).toBeInstanceOf(Array);
2628
expect(data.links.length).toBeGreaterThan(0);
27-
expect(data.links[0]).toContainKeys(['rel', 'href']);
2829
expect(data.links[0].rel).toBeString();
2930
expect(data.links[0].href).toBeString();
3031

31-
expect(data.data).toContainKeys([
32-
'endpointId',
33-
'type',
34-
'status',
35-
'creationTimestamp',
36-
'expirationTimestamp',
37-
'token'
38-
]);
3932
expect(data.data.endpointId).toBeString();
4033
expect(data.data.type).toBeOneOf(Object.values(EndpointTypeEnum));
4134
expect(data.data.status).toBeOneOf(Object.values(EndpointStatusEnum));
@@ -49,30 +42,23 @@ describe('EndpointsApi', () => {
4942
});
5043

5144
describe('listEndpoints', () => {
52-
test('should list endpoints and include links, page, data, and errors', async () => {
45+
test('should list endpoints', async () => {
5346
const { status, data } = await endpointsApi.listEndpoints(accountId, EndpointTypeEnum.Webrtc, EndpointStatusEnum.Connected, undefined, 10);
5447

5548
expect(status).toEqual(200);
5649
expect(data.links).toBeInstanceOf(Array);
5750
expect(data.links.length).toBeGreaterThan(0);
58-
expect(data.links[0]).toContainKeys(['rel', 'href']);
51+
expect(data.links[0].rel).toBeString();
52+
expect(data.links[0].href).toBeString();
5953
expect(data.data).toBeInstanceOf(Array);
6054
expect(data.page).toBeDefined();
61-
expect(data.page).toContainKeys(['pageSize', 'pageNumber', 'totalPages', 'totalElements']);
6255
expect(data.page.pageSize).toBeNumber();
6356
expect(data.page.pageNumber).toBeNumber();
6457
expect(data.page.totalPages).toBeNumber();
6558
expect(data.page.totalElements).toBeNumber();
6659
expect(data.errors).toBeInstanceOf(Array);
6760

6861
if (data.data.length > 0) {
69-
expect(data.data[0]).toContainKeys([
70-
'endpointId',
71-
'type',
72-
'status',
73-
'creationTimestamp',
74-
'expirationTimestamp'
75-
]);
7662
expect(data.data[0].endpointId).toBeString();
7763
expect(data.data[0].type).toBeOneOf(Object.values(EndpointTypeEnum));
7864
expect(data.data[0].status).toBeOneOf(Object.values(EndpointStatusEnum));
@@ -83,21 +69,15 @@ describe('EndpointsApi', () => {
8369
});
8470

8571
describe('getEndpoint', () => {
86-
test('should get endpoint and return full response shape', async () => {
72+
test('should get endpoint', async () => {
8773
const { status, data } = await endpointsApi.getEndpoint(accountId, endpointId);
8874

8975
expect(status).toEqual(200);
9076
expect(data.links).toBeInstanceOf(Array);
9177
expect(data.links.length).toBeGreaterThan(0);
92-
expect(data.links[0]).toContainKeys(['rel', 'href']);
93-
94-
expect(data.data).toContainKeys([
95-
'endpointId',
96-
'type',
97-
'status',
98-
'creationTimestamp',
99-
'expirationTimestamp'
100-
]);
78+
expect(data.links[0].rel).toBeString();
79+
expect(data.links[0].href).toBeString();
80+
10181
expect(data.data.endpointId).toBeString();
10282
expect(data.data.type).toBeOneOf(Object.values(EndpointTypeEnum));
10383
expect(data.data.status).toBeOneOf(Object.values(EndpointStatusEnum));
@@ -108,4 +88,12 @@ describe('EndpointsApi', () => {
10888
expect(data.errors).toHaveLength(0);
10989
});
11090
});
91+
92+
describe('deleteEndpoint', () => {
93+
test('should delete endpoint', async () => {
94+
const { status } = await endpointsApi.deleteEndpoint(accountId, endpointId);
95+
96+
expect(status).toEqual(204);
97+
});
98+
});
11199
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { Verb } from '../../../../../models/bxml/Verb';
2+
import { Connect, ConnectAttributes } from '../../../../../models/bxml/verbs/Connect';
3+
import { Endpoint } from '../../../../../models/bxml/verbs/Endpoint';
4+
5+
describe('Connect', () => {
6+
const attributes: ConnectAttributes = {
7+
connectCompleteUrl: 'https://initial.com',
8+
connectCompleteMethod: 'POST',
9+
connectCompleteFallbackUrl: 'https://initial.com',
10+
connectCompleteFallbackMethod: 'POST',
11+
username: 'initialUsername',
12+
password: 'initialPassword',
13+
fallbackUsername: 'initialFallbackUsername',
14+
fallbackPassword: 'initialFallbackPassword',
15+
tag: 'initialTag'
16+
};
17+
18+
const endpoint = new Endpoint('ep-123456');
19+
20+
test('should create a Connect Verb', () => {
21+
const connect = new Connect(attributes);
22+
const expected = '<Connect connectCompleteUrl="https://initial.com" connectCompleteMethod="POST" connectCompleteFallbackUrl="https://initial.com" connectCompleteFallbackMethod="POST" username="initialUsername" password="initialPassword" fallbackUsername="initialFallbackUsername" fallbackPassword="initialFallbackPassword" tag="initialTag"/>';
23+
24+
expect(connect).toBeInstanceOf(Connect);
25+
expect(connect).toBeInstanceOf(Verb);
26+
expect(connect.toBxml()).toBe(expected);
27+
});
28+
29+
test('should create a Connect Verb with nested Endpoint', () => {
30+
const connect = new Connect(attributes, endpoint);
31+
const expected = '<Connect connectCompleteUrl="https://initial.com" connectCompleteMethod="POST" connectCompleteFallbackUrl="https://initial.com" connectCompleteFallbackMethod="POST" username="initialUsername" password="initialPassword" fallbackUsername="initialFallbackUsername" fallbackPassword="initialFallbackPassword" tag="initialTag"><Endpoint>ep-123456</Endpoint></Connect>';
32+
33+
expect(connect).toBeInstanceOf(Connect);
34+
expect(connect).toBeInstanceOf(Verb);
35+
expect(connect.toBxml()).toBe(expected);
36+
});
37+
38+
test('should create a Connect Verb with multiple nested Endpoints', () => {
39+
const endpoint2 = new Endpoint('ep-789012');
40+
const connect = new Connect(attributes, [endpoint, endpoint2]);
41+
const expected = '<Connect connectCompleteUrl="https://initial.com" connectCompleteMethod="POST" connectCompleteFallbackUrl="https://initial.com" connectCompleteFallbackMethod="POST" username="initialUsername" password="initialPassword" fallbackUsername="initialFallbackUsername" fallbackPassword="initialFallbackPassword" tag="initialTag"><Endpoint>ep-123456</Endpoint><Endpoint>ep-789012</Endpoint></Connect>';
42+
43+
expect(connect).toBeInstanceOf(Connect);
44+
expect(connect).toBeInstanceOf(Verb);
45+
expect(connect.toBxml()).toBe(expected);
46+
});
47+
48+
test('should test the addEndpoints method when no verbs are initially nested', () => {
49+
const connect = new Connect(attributes);
50+
const expected = '<Connect connectCompleteUrl="https://initial.com" connectCompleteMethod="POST" connectCompleteFallbackUrl="https://initial.com" connectCompleteFallbackMethod="POST" username="initialUsername" password="initialPassword" fallbackUsername="initialFallbackUsername" fallbackPassword="initialFallbackPassword" tag="initialTag"><Endpoint>ep-123456</Endpoint></Connect>';
51+
52+
connect.addEndpoints(endpoint);
53+
expect(connect.toBxml()).toBe(expected);
54+
});
55+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Verb } from '../../../../../models/bxml/Verb';
2+
import { Endpoint, EndpointAttributes } from '../../../../../models/bxml/verbs/Endpoint';
3+
4+
describe('Endpoint', () => {
5+
const attributes: EndpointAttributes = {
6+
endpointId: 'ep-123456'
7+
};
8+
9+
const expected = '<Endpoint endpointId="ep-123456">ep-123456</Endpoint>';
10+
const expectedNoAttributes = '<Endpoint>ep-123456</Endpoint>';
11+
12+
test('should create an Endpoint Verb with attributes', () => {
13+
const endpoint = new Endpoint('ep-123456', attributes);
14+
15+
expect(endpoint).toBeInstanceOf(Endpoint);
16+
expect(endpoint).toBeInstanceOf(Verb);
17+
expect(endpoint.toBxml()).toBe(expected);
18+
});
19+
20+
test('should create an Endpoint Verb without attributes', () => {
21+
const endpoint = new Endpoint('ep-123456');
22+
23+
expect(endpoint).toBeInstanceOf(Endpoint);
24+
expect(endpoint).toBeInstanceOf(Verb);
25+
expect(endpoint.toBxml()).toBe(expectedNoAttributes);
26+
});
27+
});

tests/unit/models/create-endpoint-response-data.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { EndpointStatusEnum } from '../../../models/endpoint-status-enum';
33
import { EndpointTypeEnum } from '../../../models/endpoint-type-enum';
44

55
describe('CreateEndpointResponseData', () => {
6-
test('should include endpoint fields and token', () => {
6+
test('should include all endpoint fields and token', () => {
77
const responseData: CreateEndpointResponseData = {
88
endpointId: 'ep-123456',
99
type: EndpointTypeEnum.Webrtc,
@@ -17,8 +17,10 @@ describe('CreateEndpointResponseData', () => {
1717
expect(responseData.endpointId).toBe('ep-123456');
1818
expect(responseData.type).toBe(EndpointTypeEnum.Webrtc);
1919
expect(responseData.status).toBe(EndpointStatusEnum.Connected);
20-
expect(new Date(responseData.creationTimestamp).toString()).not.toBe('Invalid Date');
21-
expect(new Date(responseData.expirationTimestamp).toString()).not.toBe('Invalid Date');
20+
expect(new Date(responseData.creationTimestamp).getFullYear()).toBe(2024);
21+
expect(new Date(responseData.creationTimestamp).toISOString()).toBe('2024-02-18T10:30:00.000Z');
22+
expect(new Date(responseData.expirationTimestamp).getFullYear()).toBe(2024);
23+
expect(new Date(responseData.expirationTimestamp).toISOString()).toBe('2024-02-19T10:30:00.000Z');
2224
expect(responseData.token).toBe('xxxxx.yyyyy.zzzzz');
2325
expect(responseData.tag).toBe('endpoint-tag');
2426
});

tests/unit/models/create-endpoint-response.test.ts

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Link } from '../../../models/link';
66
import { ModelError } from '../../../models/model-error';
77

88
describe('CreateEndpointResponse', () => {
9-
test('should create an endpoint response with successful data', () => {
9+
test('should create an endpoint response with all fields', () => {
1010
const link: Link = {
1111
rel: 'self',
1212
href: 'http://api.example.com/endpoints/ep-123456'
@@ -22,35 +22,6 @@ describe('CreateEndpointResponse', () => {
2222
tag: 'webrtc-endpoint'
2323
};
2424

25-
const response: CreateEndpointResponse = {
26-
links: [link],
27-
data: responseData,
28-
errors: []
29-
};
30-
31-
expect(response.links).toHaveLength(1);
32-
expect(response.data.endpointId).toBe('ep-123456');
33-
expect(response.data.type).toBe('WEBRTC');
34-
expect(response.data.status).toBe('CONNECTED');
35-
expect(response.data.token).toBe('xxxxx.yyyyy.zzzzz');
36-
expect(response.errors).toHaveLength(0);
37-
});
38-
39-
test('should create an endpoint response with error', () => {
40-
const link: Link = {
41-
rel: 'documentation',
42-
href: 'http://api.example.com/docs/endpoints'
43-
};
44-
45-
const responseData: CreateEndpointResponseData = {
46-
endpointId: '',
47-
type: EndpointTypeEnum.Webrtc,
48-
status: EndpointStatusEnum.Disconnected,
49-
creationTimestamp: '2024-02-18T10:30:00Z',
50-
expirationTimestamp: '2024-02-19T10:30:00Z',
51-
token: 'invalid.token.value'
52-
};
53-
5425
const error: ModelError = {
5526
code: 400,
5627
description: 'Missing required field: endpointId'
@@ -62,7 +33,18 @@ describe('CreateEndpointResponse', () => {
6233
errors: [error]
6334
};
6435

36+
expect(response.links).toHaveLength(1);
37+
expect(response.links[0].rel).toBe('self');
38+
expect(response.links[0].href).toBe('http://api.example.com/endpoints/ep-123456');
39+
expect(response.data.endpointId).toBe('ep-123456');
40+
expect(response.data.type).toBe('WEBRTC');
41+
expect(response.data.status).toBe('CONNECTED');
42+
expect(response.data.token).toBe('xxxxx.yyyyy.zzzzz');
43+
expect(response.data.tag).toBe('webrtc-endpoint');
44+
expect(new Date(response.data.creationTimestamp).getFullYear()).toBe(2024);
45+
expect(new Date(response.data.expirationTimestamp).getFullYear()).toBe(2024);
6546
expect(response.errors).toHaveLength(1);
47+
expect(response.errors[0].code).toBe(400);
6648
expect(response.errors[0].description).toContain('endpointId');
6749
});
6850
});

0 commit comments

Comments
 (0)