UNPKG

@rudderstack/integrations-lib

Version:
751 lines 117 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const axios_1 = __importDefault(require("axios")); const axios_mock_adapter_1 = __importDefault(require("axios-mock-adapter")); const _1 = __importDefault(require(".")); const utils = __importStar(require("./utils")); describe('sfmc', () => { describe('getAccessToken', () => { it('should return existing authObject when token is not expired', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); sfmcClient.authObject = validAuthObject; jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const result = await sfmcClient.getAccessToken(); expect(result).toBe(validAuthObject); expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); }); // Handles case when authObject is initially empty or null it('should request new token when authObject is empty', async () => { const emptyAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', }; const newAuthObject = { ...emptyAuthObject, access_token: 'new-token', expires_in: 12345, }; const sfmcClient = new _1.default(emptyAuthObject); sfmcClient.authObject = emptyAuthObject; jest.spyOn(utils, 'isExpired').mockReturnValue(true); // jest.spyOn(axios, 'getToken').mockResolvedValue(newAuthObject); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.auth.marketingcloudapis.com/v2/token') .reply(200, newAuthObject); jest.spyOn(process, 'hrtime').mockImplementation(() => [0, 0]); const result = await sfmcClient.getAccessToken(); expect(result).toEqual({ ...newAuthObject, expiration: 12345 }); expect(utils.isExpired).toHaveBeenCalledWith(emptyAuthObject); expect(utils.getToken).toHaveBeenCalledWith(emptyAuthObject); }); it('should throw error when authObject has invalid clientId', () => { const invalidAuthObject = { clientId: null, clientSecret: 'test-secret', subDomain: 'test', }; try { const sfmcInstance = new _1.default(invalidAuthObject); sfmcInstance.getAccessToken(); } catch (e) { expect(e).toEqual(new Error('clientId is missing or invalid')); } }); it('should handle concurrent token refresh requests correctly', async () => { const emptyAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', }; const newAuthObject = { ...emptyAuthObject, access_token: 'new-token', expires_in: 12345, }; const sfmcClient = new _1.default(emptyAuthObject); sfmcClient.authObject = emptyAuthObject; jest.spyOn(utils, 'isExpired').mockReturnValue(true); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.auth.marketingcloudapis.com/v2/token') .reply(200, newAuthObject); jest.spyOn(process, 'hrtime').mockImplementation(() => [0, 0]); let result = await sfmcClient.getAccessToken(); jest.spyOn(utils, 'isExpired').mockReturnValue(false); result = await sfmcClient.getAccessToken(); expect(result).toEqual({ ...newAuthObject, expiration: 12345 }); expect(utils.isExpired).toHaveBeenCalledWith(emptyAuthObject); expect(utils.isExpired).toHaveBeenCalledWith(emptyAuthObject); }); it('should throw error with original message when token request fails', async () => { const emptyAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', }; const sfmcClient = new _1.default(emptyAuthObject); sfmcClient.authObject = emptyAuthObject; jest.spyOn(utils, 'isExpired').mockReturnValue(true); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.auth.marketingcloudapis.com/v2/token') .reply(400, new Error('Bad Request')); try { await sfmcClient.getAccessToken(); } catch (e) { expect(e).toEqual(new Error('Unable to generate token, with error:Error: Request failed with status code 400')); } }); }); describe('getDestinationFields', () => { it('should return data extension fields', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); const validResponse = { name: 'Test DE', categoryID: '12345', fields: [ { name: 'field1', type: 'Text', }, ], }; mockAdapter .onGet('https://abcdefghijklmnopqrstuvwxyz01.rest.marketingcloudapis.com/data/v1/customobjects/test-de-id/fields') .reply(200, validResponse); const result = await sfmcClient.getDestinationFields('test-de-id'); expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); expect(result).toStrictEqual(validResponse); }); it('should handle failure scenario', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onGet('https://abcdefghijklmnopqrstuvwxyz01.rest.marketingcloudapis.com/data/v1/customobjects/test-de-id/fields') .reply(401, { documentation: 'https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/error-handling.htm', errorcode: 0, message: 'Not Authorized', }); try { await sfmcClient.getDestinationFields('test-de-id'); } catch (e) { expect(e).toEqual(new Error('Not Authorized')); } expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); }); }); describe('getContactAttributes', () => { it('should return contact attributes', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); const validResponse = { data: { items: [ { isReadOnly: true, attributes: [ { isReadOnly: true, fullyQualifiedName: 'test.name', dataType: 'string', }, ], }, ], }, }; mockAdapter .onGet('https://abcdefghijklmnopqrstuvwxyz01.rest.marketingcloudapis.com/contacts/v1/attributeSetDefinitions') .reply(200, validResponse); const result = await sfmcClient.getContactAttributes(); expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); expect(result).toStrictEqual(validResponse); }); it('should handle failure scenario', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onGet('https://abcdefghijklmnopqrstuvwxyz01.rest.marketingcloudapis.com/contacts/v1/attributeSetDefinitions') .reply(401, { documentation: 'https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/error-handling.htm', errorcode: 0, message: 'Not Authorized', }); try { await sfmcClient.getContactAttributes(); } catch (e) { expect(e).toEqual(new Error('Not Authorized')); } expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); }); }); describe('createDataExtension', () => { it('should create new data extension', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); const validResponse = { id: '4baf4cf1-8cc9-ef11-ba6e-f40343d380c8', name: 'rudderstackTesting0295', key: 'rudderstackTesting0295', isActive: true, isSendable: false, isTestable: false, status: 0, categoryId: 12345, ownerId: 735444531, isObjectDeletable: true, isFieldAdditionAllowed: true, isFieldModificationAllowed: true, createdDate: '2025-01-02T22:41:12.5018415-06:00', createdById: 735444531, modifiedDate: '2025-01-02T22:41:12.5018415-06:00', modifiedById: 735444531, ownerName: 'RudderstackIntegration app user', rowCount: 0, dataRetentionProperties: { isDeleteAtEndOfRetentionPeriod: true, isRowBasedRetention: false, isResetRetentionPeriodOnImport: false, rowBasedThreshold: 1000000000, }, fields: [ { name: 'key1', id: '300ba233-b7e0-4732-ba85-1bc01208fc1b', type: 'Text', maskType: 'None', storageType: 'Plain', length: 254, ordinal: 0, isNullable: false, isPrimaryKey: true, isTemplateField: false, isInheritable: false, isOverridable: true, isHidden: false, isReadOnly: false, mustOverride: false, }, { name: 'key2', id: '75a38f98-e865-43ce-9702-5b317ba29d92', type: 'EmailAddress', maskType: 'None', storageType: 'Plain', length: 254, ordinal: 0, isNullable: true, isPrimaryKey: false, isTemplateField: false, isInheritable: false, isOverridable: true, isHidden: false, isReadOnly: false, mustOverride: false, }, ], fieldCount: 2, }; mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.rest.marketingcloudapis.com/data/v1/customobjects') .reply(200, validResponse); const result = await sfmcClient.createDataExtension({ name: 'test-de', categoryID: '12345', dataRetentionProperties: { isDeleteAtEndOfRetentionPeriod: true, isRowBasedRetention: false, isResetRetentionPeriodOnImport: false, }, fields: [ { name: 'key1', type: 'Text', length: 254, isNullable: false, isPrimaryKey: true, isHidden: false, isReadOnly: false, isOverridable: true, isTemplateField: false, isInheritable: false, mustOverride: false, ordinal: 0, }, { name: 'key2', type: 'EmailAddress', length: 254, isNullable: true, isPrimaryKey: false, isHidden: false, isReadOnly: false, isOverridable: true, isTemplateField: false, isInheritable: false, mustOverride: false, ordinal: 0, }, ], }); expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); expect(result).toStrictEqual(validResponse); }); it('should handle failure scenario', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.rest.marketingcloudapis.com/data/v1/customobjects') .reply(401, { documentation: 'https://developer.salesforce.com/docs/atlas.en-us.mc-apis.meta/mc-apis/error-handling.htm', errorcode: 0, message: 'Not Authorized', }); try { await sfmcClient.createDataExtension({ name: 'test-de', categoryID: '12345', fields: [ { name: 'key1', type: 'Text', length: 254, isNullable: false, isPrimaryKey: true, isHidden: false, isReadOnly: false, isOverridable: true, isTemplateField: false, isInheritable: false, mustOverride: false, ordinal: 0, }, ], }); } catch (e) { expect(e).toEqual(new Error('Not Authorized')); } expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); }); }); describe('getBusinessUnits', () => { it('should get all the business units', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); const validResponse = `<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><soap:Header><wsa:Action>RetrieveResponse</wsa:Action><wsa:MessageID>urn:uuid:0bed602b-63c4-4bb4-9582-2b27c8f2b1da</wsa:MessageID><wsa:RelatesTo>urn:uuid:45dcc251-a037-4172-99ce-666a6b3b872c</wsa:RelatesTo><wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To><wsse:Security><wsu:Timestamp wsu:Id="Timestamp-d0308ae2-4adf-4578-8d85-faa720a966ce"><wsu:Created>2025-01-09T05:50:10Z</wsu:Created><wsu:Expires>2025-01-09T05:55:10Z</wsu:Expires></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI"><OverallStatus>OK</OverallStatus><RequestID>ab947caa-34bd-4e5b-84c1-54ab1e633a6f</RequestID><Results xsi:type="BusinessUnit"><PartnerKey xsi:nil="true" /><PartnerProperties><Name>id</Name><Value>534003210</Value></PartnerProperties><PartnerProperties><Name>name</Name><Value>Lansdowne Stadium LP</Value></PartnerProperties><ObjectID xsi:nil="true" /><AccountType>None</AccountType><Subscription xsi:nil="true" /></Results><Results xsi:type="BusinessUnit"><PartnerKey xsi:nil="true" /><PartnerProperties><Name>id</Name><Value>534003210</Value></PartnerProperties><PartnerProperties><Name>name</Name><Value>Lansdowne Stadium LP</Value></PartnerProperties><ObjectID xsi:nil="true" /><AccountType>None</AccountType><Subscription xsi:nil="true" /></Results></RetrieveResponseMsg></soap:Body></soap:Envelope>`; mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.soap.marketingcloudapis.com/Service.asmx') .reply(200, validResponse); const result = await sfmcClient.getBusinessUnits(); expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); expect(result).toStrictEqual([ { Name: 'Lansdowne Stadium LP', ID: 534003210 }, { Name: 'Lansdowne Stadium LP', ID: 534003210 }, ]); }); it('should handle failure scenario', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.soap.marketingcloudapis.com/Service.asmx') .reply(500, `<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <soap:Header> <wsa:Action>http://schemas.xmlsoap.org/ws/2004/08/addressing/fault</wsa:Action> <wsa:MessageID>urn:uuid:15d3e286-97f5-4f5c-b0fa-d58673621568</wsa:MessageID> <wsa:RelatesTo>urn:uuid:b38ee85b-8f6b-4edc-9ab9-23ab6e5a51e3</wsa:RelatesTo> <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To> <wsse:Security> <wsu:Timestamp wsu:Id="Timestamp-dc02f8e8-af74-4799-b5e9-9e9c0299278f"> <wsu:Created>2025-01-03T04:59:45Z</wsu:Created> <wsu:Expires>2025-01-03T05:04:45Z</wsu:Expires> </wsu:Timestamp> </wsse:Security> </soap:Header> <soap:Body> <soap:Fault> <faultcode xmlns:q0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">q0:Security</faultcode> <faultstring>Login Failed</faultstring> <faultactor>https://mcvgkqz3c1chrbsz586k90s41hp8.soap.marketingcloudapis.com/Service.asmx</faultactor> </soap:Fault> </soap:Body> </soap:Envelope>`); try { await sfmcClient.getBusinessUnits(); } catch (e) { expect(e).toEqual(new Error('Request failed with status code 500')); } expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); }); }); describe('getDataFolders', () => { it('should get all the data folders', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); const validResponse = `<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <soap:Header> <wsa:Action>RetrieveResponse</wsa:Action> <wsa:MessageID>urn:uuid:1cf4fd72-93a9-4360-a75c-988dc708eb7c</wsa:MessageID> <wsa:RelatesTo>urn:uuid:527a13a5-a798-4438-b23d-b7fd084ac953</wsa:RelatesTo> <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To> <wsse:Security> <wsu:Timestamp wsu:Id="Timestamp-9d7c5707-e8ec-4db8-b55e-7cbd2ce22fa3"> <wsu:Created>2025-01-03T05:54:16Z</wsu:Created> <wsu:Expires>2025-01-03T05:59:16Z</wsu:Expires> </wsu:Timestamp> </wsse:Security> </soap:Header> <soap:Body> <RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI"> <OverallStatus>OK</OverallStatus> <RequestID>5d91708b-25d1-4b27-80a0-dc84ef0aac0c</RequestID> <Results xsi:type="DataFolder"> <Client> <ID>534003210</ID> </Client> <PartnerKey xsi:nil="true" /> <ID>11546</ID> <ObjectID>4f591ca1-8236-47b8-92fe-cf0dcf7cffb5</ObjectID> <Name>my emails</Name> <Description /> <ContentType>email</ContentType> </Results> <Results xsi:type="DataFolder"> <Client> <ID>534003210</ID> </Client> <PartnerKey xsi:nil="true" /> <ID>11547</ID> <ObjectID>695dd7c6-d764-479d-9e77-36d141cdd342</ObjectID> <Name>simple automated emails</Name> <Description /> <ContentType>automated_email</ContentType> </Results> </RetrieveResponseMsg> </soap:Body> </soap:Envelope>`; mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.soap.marketingcloudapis.com/Service.asmx') .reply(200, validResponse); const result = await sfmcClient.getDataFolders(); expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); expect(result).toStrictEqual([ { Client: { ID: 534003210, }, ContentType: 'email', Description: '', ID: 11546, Name: 'my emails', ObjectID: '4f591ca1-8236-47b8-92fe-cf0dcf7cffb5', PartnerKey: '', }, { Client: { ID: 534003210, }, ContentType: 'automated_email', Description: '', ID: 11547, Name: 'simple automated emails', ObjectID: '695dd7c6-d764-479d-9e77-36d141cdd342', PartnerKey: '', }, ]); }); it('should handle failure scenario', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.soap.marketingcloudapis.com/Service.asmx') .reply(500, `<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <soap:Header> <wsa:Action>http://schemas.xmlsoap.org/ws/2004/08/addressing/fault</wsa:Action> <wsa:MessageID>urn:uuid:15d3e286-97f5-4f5c-b0fa-d58673621568</wsa:MessageID> <wsa:RelatesTo>urn:uuid:b38ee85b-8f6b-4edc-9ab9-23ab6e5a51e3</wsa:RelatesTo> <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To> <wsse:Security> <wsu:Timestamp wsu:Id="Timestamp-dc02f8e8-af74-4799-b5e9-9e9c0299278f"> <wsu:Created>2025-01-03T04:59:45Z</wsu:Created> <wsu:Expires>2025-01-03T05:04:45Z</wsu:Expires> </wsu:Timestamp> </wsse:Security> </soap:Header> <soap:Body> <soap:Fault> <faultcode xmlns:q0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">q0:Security</faultcode> <faultstring>Login Failed</faultstring> <faultactor>https://mcvgkqz3c1chrbsz586k90s41hp8.soap.marketingcloudapis.com/Service.asmx</faultactor> </soap:Fault> </soap:Body> </soap:Envelope>`); try { await sfmcClient.getDataFolders(); } catch (e) { expect(e).toEqual(new Error('Request failed with status code 500')); } expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); }); }); describe('getDataExtensions', () => { it('should get all the data extensions', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); const validResponse = `<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><soap:Header><wsa:Action>RetrieveResponse</wsa:Action><wsa:MessageID>urn:uuid:0214d595-39f2-42bb-b18f-782e3aec9125</wsa:MessageID><wsa:RelatesTo>urn:uuid:8c9f1fe6-584a-492f-ad1e-b62887e6b27d</wsa:RelatesTo><wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To><wsse:Security><wsu:Timestamp wsu:Id="Timestamp-749c5b90-7c3e-405e-a891-4cab9aa319d5"><wsu:Created>2025-01-09T10:01:15Z</wsu:Created><wsu:Expires>2025-01-09T10:06:15Z</wsu:Expires></wsu:Timestamp></wsse:Security></soap:Header><soap:Body><RetrieveResponseMsg xmlns="http://exacttarget.com/wsdl/partnerAPI"><OverallStatus>OK</OverallStatus><RequestID>26123846-4046-430b-89dc-9e5c2eb587fd</RequestID><Results xsi:type="DataExtension"><PartnerKey xsi:nil="true" /><PartnerProperties><Name>ObjectId</Name><Value>b30e26db-5e59-ef11-ba6d-f40343ce89d8</Value></PartnerProperties><PartnerProperties><Name>NAME</Name><Value>rudderstackTesting13342</Value></PartnerProperties><PartnerProperties><Name>CategoryId</Name><Value>12345</Value></PartnerProperties><ObjectID xsi:nil="true" /></Results><Results xsi:type="DataExtension"><PartnerKey xsi:nil="true" /><PartnerProperties><Name>ObjectId</Name><Value>191c5b2a-57b8-ef11-ba6e-f40343d380c8</Value></PartnerProperties><PartnerProperties><Name>NAME</Name><Value>TestFromSDK1234</Value></PartnerProperties><PartnerProperties><Name>CategoryId</Name><Value>12345</Value></PartnerProperties><ObjectID xsi:nil="true" /></Results><Results xsi:type="DataExtension"><PartnerKey xsi:nil="true" /><PartnerProperties><Name>ObjectId</Name><Value>503856e3-5ab8-ef11-ba6e-f40343d380c8</Value></PartnerProperties><PartnerProperties><Name>NAME</Name><Value>rudderstackTesting121120</Value></PartnerProperties><PartnerProperties><Name>CategoryId</Name><Value>12345</Value></PartnerProperties><ObjectID xsi:nil="true" /></Results><Results xsi:type="DataExtension"><PartnerKey xsi:nil="true" /><PartnerProperties><Name>ObjectId</Name><Value>1742f6f1-79b8-ef11-ba6e-f40343d380c8</Value></PartnerProperties><PartnerProperties><Name>NAME</Name><Value>rudderstackTesting12442</Value></PartnerProperties><PartnerProperties><Name>CategoryId</Name><Value>12345</Value></PartnerProperties><ObjectID xsi:nil="true" /></Results><Results xsi:type="DataExtension"><PartnerKey xsi:nil="true" /><PartnerProperties><Name>ObjectId</Name><Value>4baf4cf1-8cc9-ef11-ba6e-f40343d380c8</Value></PartnerProperties><PartnerProperties><Name>NAME</Name><Value>rudderstackTesting0295</Value></PartnerProperties><PartnerProperties><Name>CategoryId</Name><Value>12345</Value></PartnerProperties><ObjectID xsi:nil="true" /></Results></RetrieveResponseMsg></soap:Body></soap:Envelope>`; mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.soap.marketingcloudapis.com/Service.asmx') .reply(200, validResponse); const result = await sfmcClient.getDataExtensions('valid-folder-id'); expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); expect(result).toStrictEqual([ { CategoryId: 12345, Name: 'rudderstackTesting13342', ObjectId: 'b30e26db-5e59-ef11-ba6d-f40343ce89d8', }, { CategoryId: 12345, Name: 'TestFromSDK1234', ObjectId: '191c5b2a-57b8-ef11-ba6e-f40343d380c8', }, { CategoryId: 12345, Name: 'rudderstackTesting121120', ObjectId: '503856e3-5ab8-ef11-ba6e-f40343d380c8', }, { CategoryId: 12345, Name: 'rudderstackTesting12442', ObjectId: '1742f6f1-79b8-ef11-ba6e-f40343d380c8', }, { CategoryId: 12345, Name: 'rudderstackTesting0295', ObjectId: '4baf4cf1-8cc9-ef11-ba6e-f40343d380c8', }, ]); }); it('should handle failure scenario', async () => { const validAuthObject = { clientId: 'test-client', clientSecret: 'test-secret', subDomain: 'abcdefghijklmnopqrstuvwxyz01', access_token: 'valid-token', expiration: process.hrtime()[0] + 3600, }; const sfmcClient = new _1.default(validAuthObject); jest.spyOn(utils, 'isExpired').mockReturnValue(false); const requestTokenSpy = jest.spyOn(utils, 'getToken'); const mockAdapter = new axios_mock_adapter_1.default(axios_1.default, { onNoMatch: 'throwException' }); mockAdapter .onPost('https://abcdefghijklmnopqrstuvwxyz01.soap.marketingcloudapis.com/Service.asmx') .reply(500, `<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <soap:Header> <wsa:Action>http://schemas.xmlsoap.org/ws/2004/08/addressing/fault</wsa:Action> <wsa:MessageID>urn:uuid:15d3e286-97f5-4f5c-b0fa-d58673621568</wsa:MessageID> <wsa:RelatesTo>urn:uuid:b38ee85b-8f6b-4edc-9ab9-23ab6e5a51e3</wsa:RelatesTo> <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To> <wsse:Security> <wsu:Timestamp wsu:Id="Timestamp-dc02f8e8-af74-4799-b5e9-9e9c0299278f"> <wsu:Created>2025-01-03T04:59:45Z</wsu:Created> <wsu:Expires>2025-01-03T05:04:45Z</wsu:Expires> </wsu:Timestamp> </wsse:Security> </soap:Header> <soap:Body> <soap:Fault> <faultcode xmlns:q0="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">q0:Security</faultcode> <faultstring>Login Failed</faultstring> <faultactor>https://mcvgkqz3c1chrbsz586k90s41hp8.soap.marketingcloudapis.com/Service.asmx</faultactor> </soap:Fault> </soap:Body> </soap:Envelope>`); try { await sfmcClient.getDataExtensions(); } catch (e) { expect(e).toEqual(new Error('Request failed with status code 500')); } expect(utils.isExpired).toHaveBeenCalledWith(validAuthObject); expect(requestTokenSpy).not.toHaveBeenCalled(); }); }); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZGtzL3NmbWMvaW5kZXgudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGtEQUEwQjtBQUMxQiw0RUFBa0Q7QUFDbEQseUNBQXFCO0FBQ3JCLCtDQUFpQztBQUVqQyxRQUFRLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRTtJQUNwQixRQUFRLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxFQUFFO1FBQzlCLEVBQUUsQ0FBQyw2REFBNkQsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMzRSxNQUFNLGVBQWUsR0FBRztnQkFDdEIsUUFBUSxFQUFFLGFBQWE7Z0JBQ3ZCLFlBQVksRUFBRSxhQUFhO2dCQUMzQixTQUFTLEVBQUUsOEJBQThCO2dCQUN6QyxZQUFZLEVBQUUsYUFBYTtnQkFDM0IsVUFBVSxFQUFFLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJO2FBQ3ZDLENBQUM7WUFFRixNQUFNLFVBQVUsR0FBRyxJQUFJLFVBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUM3QyxVQUFVLENBQUMsVUFBVSxHQUFHLGVBQWUsQ0FBQztZQUV4QyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDdEQsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDdEQsTUFBTSxNQUFNLEdBQUcsTUFBTSxVQUFVLENBQUMsY0FBYyxFQUFFLENBQUM7WUFFakQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUNyQyxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLG9CQUFvQixD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