-
Notifications
You must be signed in to change notification settings - Fork 243
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add CustomObject2 action to support SyncMode (#2259)
- Loading branch information
Showing
4 changed files
with
487 additions
and
0 deletions.
There are no files selected for viewing
318 changes: 318 additions & 0 deletions
318
packages/destination-actions/src/destinations/salesforce/__tests__/customObject2.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,318 @@ | ||
import nock from 'nock' | ||
import { createTestEvent, createTestIntegration } from '@segment/actions-core' | ||
import Destination from '../index' | ||
import { API_VERSION } from '../sf-operations' | ||
import { DynamicFieldResponse } from '@segment/actions-core' | ||
|
||
const testDestination = createTestIntegration(Destination) | ||
|
||
const settings = { | ||
instanceUrl: 'https://test.salesforce.com' | ||
} | ||
const auth = { | ||
refreshToken: 'xyz321', | ||
accessToken: 'abc123' | ||
} | ||
|
||
describe('Salesforce', () => { | ||
describe('Custom Object Tests', () => { | ||
it('should create a custom object record', async () => { | ||
const event = createTestEvent({ | ||
type: 'track', | ||
event: 'Create Custom Object', | ||
properties: { | ||
email: '[email protected]', | ||
company: 'Krusty Krab', | ||
last_name: 'Squarepants' | ||
} | ||
}) | ||
|
||
nock(`${settings.instanceUrl}/services/data/${API_VERSION}/sobjects`).post('/TestCustom__c').reply(201, {}) | ||
|
||
const responses = await testDestination.testAction('customObject2', { | ||
event, | ||
settings, | ||
mapping: { | ||
__segment_internal_sync_mode: 'add', | ||
customObjectName: 'TestCustom__c', | ||
customFields: { | ||
'@path': '$.properties' | ||
} | ||
}, | ||
auth | ||
}) | ||
|
||
expect(responses.length).toBe(1) | ||
expect(responses[0].status).toBe(201) | ||
|
||
expect(responses[0].request.headers).toMatchInlineSnapshot(` | ||
Headers { | ||
Symbol(map): Object { | ||
"authorization": Array [ | ||
"Bearer abc123", | ||
], | ||
"content-type": Array [ | ||
"application/json", | ||
], | ||
"user-agent": Array [ | ||
"Segment (Actions)", | ||
], | ||
}, | ||
} | ||
`) | ||
|
||
expect(responses[0].options.body).toMatchInlineSnapshot( | ||
`"{\\"email\\":\\"[email protected]\\",\\"company\\":\\"Krusty Krab\\",\\"last_name\\":\\"Squarepants\\"}"` | ||
) | ||
}) | ||
|
||
it('should error out when custom fields are not passed for create operation', async () => { | ||
const event = createTestEvent({ | ||
type: 'track', | ||
event: 'Create Custom Object', | ||
properties: { | ||
email: '[email protected]', | ||
company: 'Krusty Krab', | ||
last_name: 'Squarepants' | ||
} | ||
}) | ||
|
||
await expect( | ||
testDestination.testAction('customObject2', { | ||
event, | ||
settings, | ||
auth, | ||
mapping: { | ||
__segment_internal_sync_mode: 'add', | ||
customObjectName: 'TestCustom__c', | ||
traits: { | ||
Id: { '@path': '$.userId' } | ||
} | ||
} | ||
}) | ||
).rejects.toThrow('Custom fields are required for this operation.') | ||
}) | ||
|
||
it('should error out when custom fields are not passed for update operation', async () => { | ||
const event = createTestEvent({ | ||
type: 'track', | ||
event: 'Create Custom Object', | ||
properties: { | ||
email: '[email protected]', | ||
company: 'Krusty Krab', | ||
last_name: 'Squarepants' | ||
} | ||
}) | ||
|
||
await expect( | ||
testDestination.testAction('customObject2', { | ||
event, | ||
settings, | ||
auth, | ||
mapping: { | ||
__segment_internal_sync_mode: 'update', | ||
customObjectName: 'TestCustom__c', | ||
traits: { | ||
Id: { '@path': '$.userId' } | ||
} | ||
} | ||
}) | ||
).rejects.toThrow('Custom fields are required for this operation.') | ||
}) | ||
|
||
it('should error out when custom fields are not passed for upsert operation', async () => { | ||
const event = createTestEvent({ | ||
type: 'track', | ||
event: 'Create Custom Object', | ||
properties: { | ||
email: '[email protected]', | ||
company: 'Krusty Krab', | ||
last_name: 'Squarepants' | ||
} | ||
}) | ||
|
||
await expect( | ||
testDestination.testAction('customObject2', { | ||
event, | ||
settings, | ||
auth, | ||
mapping: { | ||
__segment_internal_sync_mode: 'upsert', | ||
customObjectName: 'TestCustom__c', | ||
traits: { | ||
Id: { '@path': '$.userId' } | ||
} | ||
} | ||
}) | ||
).rejects.toThrow('Custom fields are required for this operation.') | ||
}) | ||
|
||
it('should delete a custom record given an Id', async () => { | ||
nock(`${settings.instanceUrl}/services/data/${API_VERSION}/sobjects`).delete('/TestCustom__c/123').reply(201, {}) | ||
|
||
const event = createTestEvent({ | ||
type: 'track', | ||
event: 'Delete', | ||
userId: '123' | ||
}) | ||
|
||
const responses = await testDestination.testAction('customObject2', { | ||
event, | ||
settings, | ||
auth, | ||
mapping: { | ||
__segment_internal_sync_mode: 'delete', | ||
customObjectName: 'TestCustom__c', | ||
traits: { | ||
Id: { '@path': '$.userId' } | ||
} | ||
} | ||
}) | ||
|
||
expect(responses.length).toBe(1) | ||
expect(responses[0].status).toBe(201) | ||
}) | ||
|
||
it('should dynamically fetch customObjectName', async () => { | ||
nock(`${settings.instanceUrl}/services/data/${API_VERSION}`) | ||
.get('/sobjects') | ||
.reply(200, { | ||
sobjects: [ | ||
{ | ||
label: 'Accounts', | ||
name: 'Account', | ||
createable: true, | ||
queryable: true | ||
}, | ||
{ | ||
label: 'Contacts', | ||
name: 'Contact', | ||
createable: true, | ||
queryable: true | ||
}, | ||
{ | ||
label: 'Test Custom Object', | ||
name: 'TestCustom__c', | ||
createable: true, | ||
queryable: true | ||
}, | ||
{ | ||
label: 'Hidden Object', | ||
name: 'HiddenObject__c', | ||
createable: false, | ||
queryable: false | ||
} | ||
] | ||
}) | ||
|
||
const payload = {} | ||
const responses = (await testDestination.testDynamicField('customObject', 'customObjectName', { | ||
payload, | ||
settings, | ||
auth | ||
})) as DynamicFieldResponse | ||
|
||
expect(responses.choices.length).toBe(3) | ||
expect(responses.choices).toEqual( | ||
expect.arrayContaining([ | ||
expect.objectContaining({ | ||
label: 'Accounts', | ||
value: 'Account' | ||
}), | ||
expect.objectContaining({ | ||
label: 'Contacts', | ||
value: 'Contact' | ||
}), | ||
expect.objectContaining({ | ||
label: 'Test Custom Object', | ||
value: 'TestCustom__c' | ||
}) | ||
]) | ||
) | ||
}) | ||
|
||
describe('batching', () => { | ||
it('should fail if delete is set as syncMode', async () => { | ||
const event = createTestEvent({ | ||
type: 'track', | ||
event: 'Create Custom Object', | ||
properties: { | ||
email: '[email protected]', | ||
company: 'Krusty Krab', | ||
last_name: 'Squarepants' | ||
} | ||
}) | ||
|
||
await expect(async () => { | ||
await testDestination.testBatchAction('customObject2', { | ||
events: [event], | ||
settings, | ||
mapping: { | ||
enable_batching: true, | ||
__segment_internal_sync_mode: 'delete', | ||
customObjectName: 'TestCustom__c', | ||
customFields: { | ||
'@path': '$.properties' | ||
} | ||
}, | ||
auth | ||
}) | ||
}).rejects.toThrowErrorMatchingInlineSnapshot( | ||
`"Unsupported operation: Bulk API does not support the delete operation"` | ||
) | ||
}) | ||
}) | ||
|
||
it('should fail if syncMode is undefined', async () => { | ||
const event = createTestEvent({ | ||
type: 'track', | ||
event: 'Create Custom Object', | ||
properties: { | ||
email: '[email protected]', | ||
company: 'Krusty Krab', | ||
last_name: 'Squarepants' | ||
} | ||
}) | ||
|
||
await expect(async () => { | ||
await testDestination.testBatchAction('customObject2', { | ||
events: [event], | ||
settings, | ||
mapping: { | ||
enable_batching: true, | ||
customObjectName: 'TestCustom__c', | ||
customFields: { | ||
'@path': '$.properties' | ||
} | ||
}, | ||
auth | ||
}) | ||
}).rejects.toThrowErrorMatchingInlineSnapshot(`"syncMode is required"`) | ||
}) | ||
|
||
it('should fail if the operation does not have custom fields', async () => { | ||
const event = createTestEvent({ | ||
type: 'track', | ||
event: 'Create Custom Object', | ||
properties: { | ||
email: '[email protected]', | ||
company: 'Krusty Krab', | ||
last_name: 'Squarepants' | ||
} | ||
}) | ||
|
||
await expect(async () => { | ||
await testDestination.testBatchAction('customObject2', { | ||
events: [event], | ||
settings, | ||
mapping: { | ||
enable_batching: true, | ||
customObjectName: 'TestCustom__c', | ||
__segment_internal_sync_mode: 'add' | ||
}, | ||
auth | ||
}) | ||
}).rejects.toThrowErrorMatchingInlineSnapshot(`"Custom fields are required for this operation."`) | ||
}) | ||
}) | ||
}) |
64 changes: 64 additions & 0 deletions
64
packages/destination-actions/src/destinations/salesforce/customObject2/generated-types.ts
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.