Skip to content

Commit

Permalink
DEVEXP-516: E2E SMS/Delivery Reports (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
asein-sinch authored Aug 20, 2024
1 parent cf9789a commit 6fa8d48
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import { Sms } from '@sinch/sdk-core';

const requestData: Sms.GetDeliveryReportByPhoneNumberRequestData = {
batch_id: batchId,
recipient_msisdn: recipientPhoneNumber,
phone_number: recipientPhoneNumber,
};

const smsService = initSmsServiceWithServicePlanId();
let response;
try {
response = await smsService.deliveryReports.getForNumber(requestData);
} catch (error) {
console.error(`ERROR: Impossible to retrieve the delivery report by batch ID ${requestData.batch_id} for the recipient ${requestData.recipient_msisdn}`);
console.error(`ERROR: Impossible to retrieve the delivery report by batch ID ${requestData.batch_id} for the recipient ${requestData.phone_number}`);
throw error;
}

Expand Down
2 changes: 1 addition & 1 deletion examples/webhooks/src/services/sms-event.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class SmsEventService {
}

private handleDeliveryReportEvent(event: Sms.DeliveryReport): void {
console.log(`The batch ${event.batch_id} has the following statuses:\n${event.statuses.map((status) => ' - \'' + status.status + '\' for the recipients: ' + status.recipients.join(', ')).join('\n')} `);
console.log(`The batch ${event.batch_id} has the following statuses:\n${event.statuses.map((status) => ' - \'' + status.status + '\' for the recipients: ' + status.recipients?.join(', ')).join('\n')} `);
}

private handleSmsEvent(event: Sms.MOText): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface MessageDeliveryStatus {
/** The number of messages that currently has this code. */
count: number;
/** Only for `full` report. A list of the phone number recipients which messages has this status code. */
recipients: string[];
recipients?: string[];
/** The simplified status as described in _Delivery Report Statuses_. */
status: DeliveryReportStatusEnum;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ export interface GetDeliveryReportByBatchIdRequestData {
/** Comma separated list of delivery_report_statuses to include */
'status'?: DeliveryReportStatusEnum[];
/** Comma separated list of delivery_receipt_error_codes to include */
'code'?: string;
'code'?: string | number | number[];
}
export interface GetDeliveryReportByPhoneNumberRequestData {
/** The batch ID you received from sending a message. */
'batch_id': string;
/** Phone number for which you to want to search. */
'recipient_msisdn': string;
'phone_number': string;
}
export interface ListDeliveryReportsRequestData {
/** The page number starting from 0. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export class DeliveryReportsApi extends SmsDomainApi {
*/
public async get(data: GetDeliveryReportByBatchIdRequestData): Promise<DeliveryReport> {
this.client = this.getSinchClient();
data['type'] = data['type'] !== undefined ? data['type'] : 'summary';
const getParams = this.client.extractQueryParams<GetDeliveryReportByBatchIdRequestData>(
data,
['type', 'status', 'code'],
Expand Down Expand Up @@ -73,7 +72,7 @@ export class DeliveryReportsApi extends SmsDomainApi {
};

const body: RequestBody = '';
const basePathUrl = `${this.client.apiClientOptions.hostname}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}/delivery_report/${data['recipient_msisdn']}`;
const basePathUrl = `${this.client.apiClientOptions.hostname}/xms/v1/${this.client.apiClientOptions.projectId}/batches/${data['batch_id']}/delivery_report/${data['phone_number']}`;

const requestOptions
= await this.client.prepareOptions(basePathUrl, 'GET', getParams, headers, body || undefined);
Expand All @@ -95,8 +94,6 @@ export class DeliveryReportsApi extends SmsDomainApi {
*/
public list(data: ListDeliveryReportsRequestData): ApiListPromise<RecipientDeliveryReport> {
this.client = this.getSinchClient();
data['page'] = data['page'] !== undefined ? data['page'] : 0;
data['page_size'] = data['page_size'] !== undefined ? data['page_size'] : 30;
const getParams = this.client.extractQueryParams<ListDeliveryReportsRequestData>(
data,
['page', 'page_size', 'start_date', 'end_date', 'status', 'code', 'client_reference'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('DeliveryReportsApi', () => {
// Given
const requestData: Sms.GetDeliveryReportByPhoneNumberRequestData = {
batch_id: '01HF28S9AAGRKWP2CY92BJB569',
recipient_msisdn: '+33444555666',
phone_number: '+33444555666',
};
const expectedResponse: Sms.RecipientDeliveryReport = {
batch_id: '01HF28S9AAGRKWP2CY92BJB569',
Expand Down
140 changes: 140 additions & 0 deletions packages/sms/tests/rest/v1/delivery-reports/delivery-reports.steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { DeliveryReportsApi, SmsService, Sms } from '../../../../src';
import { Given, When, Then } from '@cucumber/cucumber';
import * as assert from 'assert';
import { PageResult } from '@sinch/sdk-client';

let deliveryReportsApi: DeliveryReportsApi;
let deliveryReport: Sms.DeliveryReport;
let recipientDeliveryReport: Sms.RecipientDeliveryReport;
let listResponse: PageResult<Sms.RecipientDeliveryReport>;
let recipientDeliveryReportList: Sms.RecipientDeliveryReport[];
let pagesIteration: number;

Given('the SMS service "Delivery Reports" is available', () => {
const smsService = new SmsService({
projectId: 'tinyfrog-jump-high-over-lilypadbasin',
keyId: 'keyId',
keySecret: 'keySecret',
authHostname: 'http://localhost:3011',
smsHostname: 'http://localhost:3017',
});
deliveryReportsApi = smsService.deliveryReports;
});

When('I send a request to retrieve a summary SMS delivery report', async () => {
const requestData: Sms.GetDeliveryReportByBatchIdRequestData = {
batch_id: '01W4FFL35P4NC4K35SMSBATCH1',
status: [
'Delivered',
'Failed',
],
code: [15, 0],
};
deliveryReport = await deliveryReportsApi.get(requestData);
});

Then('the response contains a summary SMS delivery report', () => {
assert.equal(deliveryReport.batch_id, '01W4FFL35P4NC4K35SMSBATCH1');
assert.equal(deliveryReport.client_reference, 'reference_e2e');
assert.ok(deliveryReport.statuses);
let status = deliveryReport.statuses[0];
assert.equal(status.code, 15);
assert.equal(status.count, 1);
assert.equal(status.recipients, undefined);
const failedStatus: Sms.DeliveryReportStatusEnum = 'Failed';
assert.equal(status.status, failedStatus);
status = deliveryReport.statuses[1];
assert.equal(status.code, 0);
assert.equal(status.count, 1);
assert.equal(status.recipients, undefined);
const deliveredStatus: Sms.DeliveryReportStatusEnum = 'Delivered';
assert.equal(status.status, deliveredStatus);
assert.equal(deliveryReport.total_message_count, 2);
assert.equal(deliveryReport.type, 'delivery_report_sms');
});

When('I send a request to retrieve a full SMS delivery report', async () => {
const requestData: Sms.GetDeliveryReportByBatchIdRequestData = {
batch_id: '01W4FFL35P4NC4K35SMSBATCH1',
type: 'full',
};
deliveryReport = await deliveryReportsApi.get(requestData);
});

Then('the response contains a full SMS delivery report', () => {
assert.equal(deliveryReport.batch_id, '01W4FFL35P4NC4K35SMSBATCH1');
assert.ok(deliveryReport.statuses);
const status = deliveryReport.statuses[0];
assert.ok(status.recipients);
assert.equal(status.code, 0);
assert.equal(status.count, 1);
assert.equal(status.recipients[0], '12017777777');
const deliveredStatus: Sms.DeliveryReportStatusEnum = 'Delivered';
assert.equal(status.status, deliveredStatus);
});

When('I send a request to retrieve a recipient\'s delivery report', async () => {
const requestData: Sms.GetDeliveryReportByPhoneNumberRequestData = {
batch_id: '01W4FFL35P4NC4K35SMSBATCH1',
phone_number: '12017777777',
};
recipientDeliveryReport = await deliveryReportsApi.getForNumber(requestData);
});

Then('the response contains the recipient\'s delivery report details', () => {
assert.equal(recipientDeliveryReport.batch_id, '01W4FFL35P4NC4K35SMSBATCH1');
assert.equal(recipientDeliveryReport.recipient, '12017777777');
assert.equal(recipientDeliveryReport.client_reference, 'reference_e2e');
const deliveredStatus: Sms.DeliveryReportStatusEnum = 'Delivered';
assert.equal(recipientDeliveryReport.status, deliveredStatus);
assert.equal(recipientDeliveryReport.type, 'recipient_delivery_report_sms');
assert.equal(recipientDeliveryReport.code, 0);
assert.deepEqual(recipientDeliveryReport.at, new Date('2024-06-06T13:06:27.833Z'));
assert.deepEqual(recipientDeliveryReport.operator_status_at, new Date('2024-06-06T13:06:00Z'));
});

When('I send a request to list the SMS delivery reports', async () => {
const requestData: Sms.ListDeliveryReportsRequestData = {};
listResponse = await deliveryReportsApi.list(requestData);
});

Then('the response contains {string} SMS delivery reports', (expectedAnswer: string) => {
const expectedDeliveryReportsCount = parseInt(expectedAnswer, 10);
assert.equal(listResponse.data.length, expectedDeliveryReportsCount);
});

When('I send a request to list all the SMS delivery reports', async () => {
recipientDeliveryReportList = [];
for await (const deliveryReport of deliveryReportsApi.list({ page_size: 2 })) {
recipientDeliveryReportList.push(deliveryReport);
}
});

When('I iterate manually over the SMS delivery reports pages', async () => {
recipientDeliveryReportList = [];
listResponse = await deliveryReportsApi.list({
page_size: 2,
});
recipientDeliveryReportList.push(...listResponse.data);
pagesIteration = 1;
let reachedEndOfPages = false;
while (!reachedEndOfPages) {
if (listResponse.hasNextPage) {
listResponse = await listResponse.nextPage();
recipientDeliveryReportList.push(...listResponse.data);
pagesIteration++;
} else {
reachedEndOfPages = true;
}
}
});

Then('the SMS delivery reports list contains {string} SMS delivery reports', (expectedAnswer: string) => {
const expectedDeliveryReportsCount = parseInt(expectedAnswer, 10);
assert.equal(recipientDeliveryReportList.length, expectedDeliveryReportsCount);
});

Then('the SMS delivery reports iteration result contains the data from {string} pages', (expectedAnswer: string) => {
const expectedPagesCount = parseInt(expectedAnswer, 10);
assert.equal(pagesIteration, expectedPagesCount);
});

0 comments on commit 6fa8d48

Please sign in to comment.