Skip to content

Commit

Permalink
test: add generic event test
Browse files Browse the repository at this point in the history
  • Loading branch information
danbillson committed Dec 2, 2024
1 parent 30b3034 commit 7ea3193
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 2 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@
"import": "./dist/esm/index.esm.node.js",
"require": "./dist/cjs/index.cjs.node.js"
}
}
},
"dependencies": {}
}
165 changes: 165 additions & 0 deletions src/__tests__/mocks/notifications/invoice-paid.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// Invoice paid is a legacy/unsupported event which is implicitly handled through GenericEvent

import { IEventsResponse } from '../../../types/index.js';

export const InvoicePaidMock: IEventsResponse<object> = {
event_id: 'evt_01jdw4vq5a26w8mpfc59mez047',
event_type: 'invoice.paid',
occurred_at: '2024-11-29T14:23:08.971054Z',
notification_id: 'ntf_01h90nmerv7vrn93f97j5v72p7',
data: {
id: 'inv_01jdw4vk9fr1n6smpbhykm6ha9',
items: [
{
price: {
product_id: 'pro_01gv5dvjjx0nmydxa2pb9trdcq',
unit_price: {
amount: '1000',
currency_code: 'GBP',
},
},
quantity: 1,
},
],
due_at: '2024-11-30T14:23:07.865592Z',
status: 'paid',
details: {
totals: {
tax: '167',
total: '1000',
subtotal: '833',
},
line_items: [
{
totals: {
tax: '0',
total: '1000',
subtotal: '1000',
},
product: {
id: 'pro_01gv5dvjjx0nmydxa2pb9trdcq',
name: 'AT Test Product',
status: 'active',
image_url: null,
description: 'Exmaple',
tax_category: 'standard',
},
quantity: 1,
tax_rate: '0',
unit_totals: {
tax: '0',
total: '1000',
subtotal: '1000',
},
},
],
},
paid_at: '2024-11-29T14:23:05.561011761Z',
checkout: null,
issued_at: '2024-11-29T14:23:07.865592Z',
address_id: 'add_01jaav7fx9ew7w6293cxjdkrp7',
created_at: '2024-11-29T14:23:05.007735Z',
updated_at: '2024-11-29T14:23:05.007735Z',
business_id: 'biz_01jaav8zw7anv2egarn5vz7xhr',
custom_data: [],
customer_id: 'ctm_01gv5gb258na82skxd7ng7ha3r',
currency_code: 'GBP',
billing_period: {
type: 'billing',
ends_at: '2024-11-30',
starts_at: '2024-11-29',
},
invoice_number: '296-844420',
transaction_id: 'txn_01jdw4vgdq62e0b6x8dqsm4ycn',
billing_details: {
payment_terms: {
interval: 'day',
frequency: 1,
},
enable_checkout: true,
purchase_order_number: null,
additional_information: null,
},
},
};

export const InvoicePaidMockExpectation = {
data: {
addressId: 'add_01jaav7fx9ew7w6293cxjdkrp7',
billingDetails: {
additionalInformation: null,
enableCheckout: true,
paymentTerms: {
frequency: 1,
interval: 'day',
},
purchaseOrderNumber: null,
},
billingPeriod: {
endsAt: '2024-11-30',
startsAt: '2024-11-29',
type: 'billing',
},
businessId: 'biz_01jaav8zw7anv2egarn5vz7xhr',
checkout: null,
createdAt: '2024-11-29T14:23:05.007735Z',
currencyCode: 'GBP',
customData: [],
customerId: 'ctm_01gv5gb258na82skxd7ng7ha3r',
details: {
lineItems: [
{
product: {
description: 'Exmaple',
id: 'pro_01gv5dvjjx0nmydxa2pb9trdcq',
imageUrl: null,
name: 'AT Test Product',
status: 'active',
taxCategory: 'standard',
},
quantity: 1,
taxRate: '0',
totals: {
subtotal: '1000',
tax: '0',
total: '1000',
},
unitTotals: {
subtotal: '1000',
tax: '0',
total: '1000',
},
},
],
totals: {
subtotal: '833',
tax: '167',
total: '1000',
},
},
dueAt: '2024-11-30T14:23:07.865592Z',
id: 'inv_01jdw4vk9fr1n6smpbhykm6ha9',
invoiceNumber: '296-844420',
issuedAt: '2024-11-29T14:23:07.865592Z',
items: [
{
price: {
productId: 'pro_01gv5dvjjx0nmydxa2pb9trdcq',
unitPrice: {
amount: '1000',
currencyCode: 'GBP',
},
},
quantity: 1,
},
],
paidAt: '2024-11-29T14:23:05.561011761Z',
status: 'paid',
transactionId: 'txn_01jdw4vgdq62e0b6x8dqsm4ycn',
updatedAt: '2024-11-29T14:23:05.007735Z',
},
eventId: 'evt_01jdw4vq5a26w8mpfc59mez047',
eventType: 'invoice.paid',
notificationId: 'ntf_01h90nmerv7vrn93f97j5v72p7',
occurredAt: '2024-11-29T14:23:08.971054Z',
};
3 changes: 3 additions & 0 deletions src/__tests__/notifications/notifications-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ import {
TransactionUpdatedMock,
TransactionUpdatedMockExpectation,
} from '../mocks/notifications/transaction-updated.mock.js';
import { InvoicePaidMock, InvoicePaidMockExpectation } from '../mocks/notifications/invoice-paid.mock.js';
import { IEvents, IEventsResponse } from '../../types/index.js';
import { Webhooks } from '../../notifications/index.js';

Expand Down Expand Up @@ -163,6 +164,8 @@ describe('Notifications Parser', () => {
[TransactionPaymentFailedMock.event_type, TransactionPaymentFailedMock, TransactionPaymentFailedMockExpectation],
[TransactionReadyMock.event_type, TransactionReadyMock, TransactionReadyMockExpectation],
[TransactionUpdatedMock.event_type, TransactionUpdatedMock, TransactionUpdatedMockExpectation],
// Generic Event
[InvoicePaidMock.event_type, InvoicePaidMock, InvoicePaidMockExpectation],
])('validate %s ', (_eventType: string, eventMock: IEventsResponse, expectedValue: any = {}) => {
expect(Webhooks.fromJson(eventMock as IEvents)).toEqual(expectedValue);
});
Expand Down
1 change: 1 addition & 0 deletions src/internal/base/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './base-resource.js';
export * from './query-parameters.js';
export * from './path-parameters.js';
export * from './collection.js';
export * from './transform.js';
27 changes: 27 additions & 0 deletions src/internal/base/transform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
function toCamelCase(str: string) {
return str.toLowerCase().replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
}

export function convertKeysToCamelCase(obj: object) {

Check failure on line 5 in src/internal/base/transform.ts

View workflow job for this annotation

GitHub Actions / Run Build & test (18)

'convertKeysToCamelCase' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.

Check failure on line 5 in src/internal/base/transform.ts

View workflow job for this annotation

GitHub Actions / Run Build & test (20)

'convertKeysToCamelCase' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.

Check failure on line 5 in src/internal/base/transform.ts

View workflow job for this annotation

GitHub Actions / Run Build & test (22)

'convertKeysToCamelCase' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
// Handle null or primitive values
if (obj === null || typeof obj !== 'object') {
return obj;
}

// Handle arrays
if (Array.isArray(obj)) {
return obj.map(convertKeysToCamelCase);
}

// Handle objects
const converted = {};
for (const [key, value] of Object.entries(obj)) {
// Convert the key to camelCase
const camelCaseKey = toCamelCase(key);

// Recursively convert nested objects and arrays
converted[camelCaseKey] = convertKeysToCamelCase(value);

Check failure on line 23 in src/internal/base/transform.ts

View workflow job for this annotation

GitHub Actions / Run Build & test (18)

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.

Check failure on line 23 in src/internal/base/transform.ts

View workflow job for this annotation

GitHub Actions / Run Build & test (20)

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.

Check failure on line 23 in src/internal/base/transform.ts

View workflow job for this annotation

GitHub Actions / Run Build & test (22)

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
}

return converted;
}
3 changes: 2 additions & 1 deletion src/notifications/events/generic/generic-event.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Event } from '../../../entities/events/event.js';
import { convertKeysToCamelCase } from '../../../internal/base/index.js';
import { type IEventsResponse } from '../../../types/index.js';

export class GenericEvent extends Event {
public override readonly data: object;

constructor(response: IEventsResponse<object>) {
super(response);
this.data = response.data;
this.data = convertKeysToCamelCase(response.data);
}
}

0 comments on commit 7ea3193

Please sign in to comment.