Skip to content

Commit

Permalink
Add CustomObject2 action to support SyncMode (#2259)
Browse files Browse the repository at this point in the history
  • Loading branch information
marinhero authored Sep 17, 2024
1 parent a2ea39f commit 54cbe9e
Show file tree
Hide file tree
Showing 4 changed files with 487 additions and 0 deletions.
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."`)
})
})
})

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 54cbe9e

Please sign in to comment.