Skip to content

Commit

Permalink
DOTORG-849 Create Constituent Action (#10)
Browse files Browse the repository at this point in the history
* Added blackbaud createConstituentAction

* Remove constituent_id since it is provided by constituent fields

* Add augmentFieldsWithConstituentFields

* Cleaned up and updated fields

* Removed comment

---------

Co-authored-by: Noah Cooper <[email protected]>
  • Loading branch information
twilio-hwong and noahcooper authored Mar 7, 2023
1 parent a973f4a commit e3dde0c
Show file tree
Hide file tree
Showing 12 changed files with 630 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Testing snapshot for actions-blackbaud-raisers-edge-nxt destination: createConstituentAction action - all fields 1`] = `
Object {
"birthdate": Object {
"d": "1",
"m": "2",
"y": "2021",
},
"first": "x3tNm3W0",
"gender": "x3tNm3W0",
"income": "x3tNm3W0",
"last": "x3tNm3W0",
"lookup_id": "x3tNm3W0",
}
`;

exports[`Testing snapshot for actions-blackbaud-raisers-edge-nxt destination: createConstituentAction action - required fields 1`] = `
Object {
"lookup_id": "x3tNm3W0",
}
`;

exports[`Testing snapshot for actions-blackbaud-raisers-edge-nxt destination: createGift action - all fields 1`] = `
Object {
"birthdate": Object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SKY_API_CONSTITUENT_URL, SKY_API_GIFTS_URL } from '../constants'
import {
Address,
Constituent,
ConstituentAction,
CreateConstituentResult,
Email,
ExistingAddress,
Expand Down Expand Up @@ -553,4 +554,11 @@ export class BlackbaudSkyApi {
json: giftData
})
}

async createConstituentAction(constituentActionData: ConstituentAction): Promise<ModifiedResponse> {
return this.request(`${SKY_API_CONSTITUENT_URL}/actions`, {
method: 'post',
json: constituentActionData
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Testing snapshot for BlackbaudRaisersEdgeNxt's createConstituentAction destination action: all fields 1`] = `
Object {
"birthdate": Object {
"d": "1",
"m": "2",
"y": "2021",
},
"first": "bUa9Yg9hQ",
"gender": "bUa9Yg9hQ",
"income": "bUa9Yg9hQ",
"last": "bUa9Yg9hQ",
"lookup_id": "bUa9Yg9hQ",
}
`;

exports[`Testing snapshot for BlackbaudRaisersEdgeNxt's createConstituentAction destination action: required fields 1`] = `
Object {
"lookup_id": "bUa9Yg9hQ",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import nock from 'nock'
import { createTestEvent, createTestIntegration, IntegrationError } from '@segment/actions-core'
import Destination from '../../index'
import { SKY_API_CONSTITUENT_URL } from '../../constants'
import { trackEventData, trackEventDataNewConstituent, trackEventDataNoConstituent } from '../fixtures'

const testDestination = createTestIntegration(Destination)

const mapping = {
constituent_email: {
address: {
'@path': '$.properties.email'
},
type: {
'@path': '$.properties.emailType'
}
},
constituent_id: {
'@path': '$.properties.constituentId'
},
date: {
'@path': '$.timestamp'
},
category: {
'@path': '$.properties.category'
}
}

describe('BlackbaudRaisersEdgeNxt.createConstituentAction', () => {
test('should create a new constituent action successfully', async () => {
const event = createTestEvent(trackEventData)

nock(SKY_API_CONSTITUENT_URL).post('/actions').reply(200, {
id: '1000'
})

await expect(
testDestination.testAction('createConstituentAction', {
event,
mapping,
useDefaultMappings: true
})
).resolves.not.toThrowError()
})

test('should create a new constituent and associate action with it', async () => {
const event = createTestEvent(trackEventDataNewConstituent)

nock(SKY_API_CONSTITUENT_URL)
.get('/constituents/search?search_field=email_address&[email protected]')
.reply(200, {
count: 0,
value: []
})

nock(SKY_API_CONSTITUENT_URL).post('/constituents').reply(200, {
id: '456'
})

nock(SKY_API_CONSTITUENT_URL).post('/actions').reply(200, {
id: '1001'
})

await expect(
testDestination.testAction('createConstituentAction', {
event,
mapping,
useDefaultMappings: true
})
).resolves.not.toThrowError()
})

test('should throw an IntegrationError if no constituent provided', async () => {
const event = createTestEvent(trackEventDataNoConstituent)

await expect(
testDestination.testAction('createConstituentAction', {
event,
mapping,
useDefaultMappings: true
})
).rejects.toThrowError(new IntegrationError('Missing constituent_id value', 'MISSING_REQUIRED_FIELD', 400))
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
import { generateTestData } from '../../../../lib/test-data'
import destination from '../../index'
import nock from 'nock'

const testDestination = createTestIntegration(destination)
const actionSlug = 'createConstituentAction'
const destinationSlug = 'BlackbaudRaisersEdgeNxt'
const seedName = `${destinationSlug}#${actionSlug}`

describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
it('required fields', async () => {
const action = destination.actions[actionSlug]
const [eventData, settingsData] = generateTestData(seedName, destination, action, true)

nock(/.*/).persist().get(/.*/).reply(200, {})
nock(/.*/).persist().patch(/.*/).reply(200, {})
nock(/.*/).persist().post(/.*/).reply(200, {})
nock(/.*/).persist().put(/.*/).reply(200, {})

const event = createTestEvent({
properties: eventData
})

const responses = await testDestination.testAction(actionSlug, {
event: event,
mapping: event.properties,
settings: settingsData,
auth: undefined
})

const request = responses[0].request
const rawBody = await request.text()

try {
const json = JSON.parse(rawBody)
expect(json).toMatchSnapshot()
return
} catch (err) {
expect(rawBody).toMatchSnapshot()
}

expect(request.headers).toMatchSnapshot()
})

it('all fields', async () => {
const action = destination.actions[actionSlug]
const [eventData, settingsData] = generateTestData(seedName, destination, action, false)

nock(/.*/).persist().get(/.*/).reply(200, {})
nock(/.*/).persist().patch(/.*/).reply(200, {})
nock(/.*/).persist().post(/.*/).reply(200, {})
nock(/.*/).persist().put(/.*/).reply(200, {})

const event = createTestEvent({
properties: eventData
})

const responses = await testDestination.testAction(actionSlug, {
event: event,
mapping: event.properties,
settings: settingsData,
auth: undefined
})

const request = responses[0].request
const rawBody = await request.text()

try {
const json = JSON.parse(rawBody)
expect(json).toMatchSnapshot()
return
} catch (err) {
expect(rawBody).toMatchSnapshot()
}
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { SegmentEvent } from '@segment/actions-core'

// track events
export const trackEventData: Partial<SegmentEvent> = {
type: 'track',
properties: {
constituentId: '123',
category: 'Task/Other'
},
timestamp: '2022-12-12T19:11:01.249Z'
}

export const trackEventDataNewConstituent: Partial<SegmentEvent> = {
type: 'track',
properties: {
email: '[email protected]',
emailType: 'Personal',
firstName: 'John',
lastName: 'Doe',
category: 'Task/Other'
},
timestamp: '2022-12-12T19:11:01.249Z'
}

export const trackEventDataNoConstituent: Partial<SegmentEvent> = {
type: 'track',
properties: {
category: 'Task/Other'
},
timestamp: '2022-12-12T19:11:01.249Z'
}
Loading

0 comments on commit e3dde0c

Please sign in to comment.