Skip to content

Commit

Permalink
[Hyperengage] Destination (#1621)
Browse files Browse the repository at this point in the history
* Add unit and integration tests

* Updated field descriptions for group, identify and track

* Updated common fields

* Fix identify function error

* Added authentication endpoint

* Revise tests to enable auth

* Update default paths for groupId.

* Implement recommended changes from PR #1621

* Add url field

* Resolve pathing issues and add tests/checks for first and last name fields

* Resolve test issues, payload validation error, and correct context default

---------

Co-authored-by: saadhypng <[email protected]>
Co-authored-by: Saad Ali <[email protected]>
  • Loading branch information
3 people authored Oct 3, 2023
1 parent 08e75ef commit dc0f000
Show file tree
Hide file tree
Showing 16 changed files with 1,551 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createTestIntegration } from '@segment/actions-core'
import Definition from '../index'
import nock from 'nock'

export const apiKey = 'testApiKey'
export const workspaceIdentifier = 'testApiIdentifier'

const testDestination = createTestIntegration(Definition)
beforeAll(() => {
nock.disableNetConnect()
})

afterAll(() => {
nock.enableNetConnect()
nock.cleanAll()
})

describe('Hyperengage', () => {
describe('testAuthentication', () => {
test('should validate workspaceIdentifier and apiKey', async () => {
nock('https://api.hyperengage.io/api/v1/verify_api_key')
.post(/.*/, {
api_key: apiKey,
workspace_identifier: workspaceIdentifier
})
.reply(200, { message: 'Mocked response' })
await expect(testDestination.testAuthentication({ apiKey, workspaceIdentifier })).resolves.not.toThrowError()
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { validateInput } from '../validateInput'

const fakeTrackData = {
event_id: 'test-message-cz380xxe9kn',
page_title: 'Title',
event_name: 'test',
event_type: 'track',
properties: {
required: 'false'
},
timestamp: '2023-09-11T08:06:11.192Z',
user_id: 'test',
account_id: 'testAccount'
}

const fakeIdentifyData = {
event_id: 'test-message-cz380xxe9kn',
page_title: 'Title',
event_name: 'test',
event_type: 'identify',
name: 'testUser',
email: 'testEmail',
traits: {
required: 'false'
},
timestamp: '2023-09-11T08:06:11.192Z',
user_id: 'test',
account_id: 'testAccount'
}

const fakeGroupData = {
event_id: 'test-message-cz380xxe9kn',
page_title: 'Title',
event_name: 'test',
event_type: 'group',
name: 'Test account',
plan: 'temporary',
industry: 'test industry',
website: 'test website',
traits: {
required: 'false'
},
timestamp: '2023-09-11T08:06:11.192Z',
user_id: 'test',
account_id: 'testAccount'
}

const settings = {
workspaceIdentifier: 'testWorkspaceId',
apiKey: 'testApiKey'
}

describe('validateInput', () => {
describe('test common payload', () => {
it('should return converted payload', () => {
const payload = validateInput(settings, fakeIdentifyData, 'user_identify')
expect(payload.api_key).toBe(settings.apiKey)
expect(payload.workspace_key).toBe(settings.workspaceIdentifier)
expect(payload.doc_encoding).toBe('UTF-8')
expect(payload.src).toBe('segment_api')
})
})

describe('test identify payload', () => {
it('should return converted payload', async () => {
const payload = validateInput(settings, fakeIdentifyData, 'user_identify')
expect(payload.user_id).toEqual(fakeIdentifyData.user_id)
expect(payload.traits.email).toEqual(fakeIdentifyData.email)
expect(payload.traits.name).toEqual(fakeIdentifyData.name)
expect(payload.traits).toHaveProperty('required')
})
})

describe('test group payload', () => {
it('should return converted payload', async () => {
const payload = validateInput(settings, fakeGroupData, 'account_identify')
expect(payload.account_id).toEqual(fakeGroupData.account_id)
expect(payload.traits.plan_name).toEqual(fakeGroupData.plan)
expect(payload.traits.industry).toEqual(fakeGroupData.industry)
expect(payload.traits.website).toEqual(fakeGroupData.website)
expect(payload.traits).toHaveProperty('required')
})
})

describe('test track payload', () => {
it('should return converted payload', async () => {
let payload = validateInput(settings, fakeGroupData, 'account_identify')
expect(payload.event_type).toEqual('account_identify')
payload = validateInput(settings, fakeTrackData, 'track')
expect(payload.event_type).toEqual('test')
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { ActionDefinition } from '@segment/actions-core'
import { Settings } from '../encharge/generated-types'

export const commonFields: ActionDefinition<Settings>['fields'] = {
anonymous_id: {
type: 'string',
allowNull: true,
required: false,
description: 'User Anonymous id',
label: 'Anonymous ID',
default: { '@path': '$.anonymousId' }
},
event_id: {
type: 'string',
required: false,
description: 'The ID of the event.',
label: 'Event ID',
default: { '@path': '$.messageId' }
},
doc_path: {
type: 'string',
required: false,
description: 'The path of the document.',
label: 'Document Path',
default: { '@path': '$.context.page.path' }
},
doc_search: {
type: 'string',
required: false,
description: 'The search query of the document.',
label: 'Document Search',
default: { '@path': '$.context.page.search' }
},
doc_title: {
type: 'string',
required: false,
description: 'The title of the page where the event occurred.',
label: 'Page Title',
default: { '@path': '$.context.page.title' }
},
url: {
type: 'string',
required: false,
description: 'The URL of the page where the event occurred.',
label: 'URL',
default: { '@path': '$.context.page.url' }
},
referer: {
type: 'string',
required: false,
description: 'The referrer of the page where the event occurred.',
label: 'Referrer',
default: { '@path': '$.context.page.referrer' }
},
user_agent: {
type: 'string',
required: false,
description: 'The user agent of the browser.',
label: 'User Agent',
default: { '@path': '$.context.userAgent' }
},
user_language: {
type: 'string',
required: false,
description: 'The language of the browser.',
label: 'User Language',
default: { '@path': '$.context.locale' }
},
utc_time: {
type: 'string',
required: false,
description: 'The time of the event in UTC.',
label: 'UTC Time',
default: { '@path': '$.timestamp' }
},
utm: {
type: 'object',
required: false,
description: 'Information about the UTM parameters.',
label: 'UTM',
properties: {
source: {
label: 'Source',
description: 'The source of the campaign.',
type: 'string'
},
medium: {
label: 'Medium',
description: 'The medium of the campaign.',
type: 'string'
},
name: {
label: 'Name',
description: 'The name of the campaign.',
type: 'string'
},
term: {
label: 'Term',
description: 'The term of the campaign.',
type: 'string'
},
content: {
label: 'Content',
description: 'The content of the campaign.',
type: 'string'
}
},
default: {
source: { '@path': '$.context.campaign.source' },
medium: { '@path': '$.context.campaign.medium' },
name: { '@path': '$.context.campaign.name' },
term: { '@path': '$.context.campaign.term' },
content: { '@path': '$.context.campaign.content' }
}
},
screen: {
type: 'object',
required: false,
description: 'Information about the screen.',
label: 'Screen',
properties: {
height: {
label: 'Height',
description: 'The height of the screen.',
type: 'integer'
},
width: {
label: 'Width',
description: 'The width of the screen.',
type: 'integer'
},
density: {
label: 'Density',
description: 'The density of the screen.',
type: 'number'
}
},
default: {
height: { '@path': '$.context.screen.height' },
width: { '@path': '$.context.screen.width' },
density: { '@path': '$.context.screen.density' }
}
},
timezone: {
type: 'string',
required: false,
description: 'The timezone of the browser.',
label: 'Timezone',
default: {
'@if': {
exists: { '@path': '$.context.timezone' },
then: { '@path': '$.context.timezone' },
else: { '@path': '$.properties.timezone' }
}
}
},
source_ip: {
type: 'string',
required: false,
description: 'The IP address of the user.',
label: 'IP Address',
default: { '@path': '$.context.ip' }
}
}

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

Loading

0 comments on commit dc0f000

Please sign in to comment.