@orbit-love/activities
Version:
Orbit API client for Node.js. API support for activity and note operations.
734 lines (593 loc) • 20.8 kB
JavaScript
const OrbitActivities = require('../src/index.js')
const axios = require('axios')
const url = require('url')
jest.mock('axios')
describe('OrbitActivities constructor', () => {
it('given all credentials, does not throw', () => {
const sut = new OrbitActivities('1', '2')
expect(sut).not.toBeNull()
})
it('given missing configuration values, throws', () => {
delete process.env.ORBIT_WORKSPACE_ID
delete process.env.ORBIT_API_KEY
expect(() => {
new OrbitActivities(null, null)
}).toThrow()
})
it('configuration read from env variables when not directly provided', () => {
process.env.ORBIT_WORKSPACE_ID = '1'
process.env.ORBIT_API_KEY = '2'
const sut = new OrbitActivities(null, null)
expect(sut.credentials.orbitWorkspaceId).toBe('1')
expect(sut.credentials.orbitApiKey).toBe('2')
})
it('given no user agent, the default is set correctly', () => {
const sut = new OrbitActivities('1', '2')
expect(sut.credentials.userAgent).toContain('js-orbit-activities/')
})
it('given a user agent, it is set correctly', () => {
const sut = new OrbitActivities('1', '2', '3')
expect(sut.credentials.userAgent).toBe('3')
})
})
describe('OrbitActivities api', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('missing all required parameters, throws', async () => {
await expect(sut.api()).rejects.toThrow(
'You must pass a client, method, and endpoint'
)
})
it('missing some required parameters, throws', async () => {
await expect(sut.api('1', '2')).rejects.toThrow(
'You must pass a client, method, and endpoint'
)
})
it('calls axios correctly based on params', async () => {
const toReturn = { data: [{ key: 'value' }] }
axios.mockResolvedValueOnce(toReturn)
await sut.api(
sut.credentials,
'3',
'/4',
{ queryKey: 'queryValue' },
{ dataKey: 'dataValue' }
)
const firstCall = axios.mock.calls[0][0]
expect(axios).toHaveBeenCalledTimes(1)
expect(firstCall.headers.Authorization).toBe('Bearer 2')
expect(firstCall.method).toBe('3')
expect(firstCall.data.dataKey).toBe('dataValue')
expect(url.parse(firstCall.url, true).query.queryKey).toBe('queryValue')
})
})
describe('OrbitActivities listWorkspaceActivities', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('returns data in correct format', async () => {
const toReturn = setActivitiesResponse({ nextPage: 3 })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listWorkspaceActivities()
expect(response.data.length).toBe(2)
expect(response.data.included).not.toBeNull()
expect(response.items).toBe(2)
expect(response.nextPage).toBe(3)
})
it('given nextPageUrl, provides nextPage integer, ', async () => {
const toReturn = setActivitiesResponse({ nextPage: 3 })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listWorkspaceActivities()
expect(response.nextPage).toBe(3)
})
it('given no nextPageUrl, sets nextPage to null, ', async () => {
const toReturn = setActivitiesResponse({ nextPage: null })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listWorkspaceActivities()
expect(response.nextPage).toBeNull()
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.listWorkspaceActivities()).rejects.toThrow(errorMessage)
})
})
describe('OrbitActivities listMemberActivities', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if memberId is not provided, throws', async () => {
await expect(sut.listMemberActivities()).rejects.toThrow(
'You must provide a memberId'
)
})
it('if memberId is not a string, throws', async () => {
const errorText = 'memberId must be a string'
await expect(sut.listMemberActivities(123)).rejects.toThrow(errorText)
await expect(sut.listMemberActivities(true)).rejects.toThrow(errorText)
await expect(sut.listMemberActivities({})).rejects.toThrow(errorText)
})
it('returns data in correct format', async () => {
const toReturn = setActivitiesResponse({ nextPage: 3 })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listMemberActivities('123')
expect(response.data.length).toBe(2)
expect(response.data.included).not.toBeNull()
expect(response.items).toBe(2)
expect(response.nextPage).toBe(3)
})
it('given nextPageUrl, provides nextPage integer', async () => {
const toReturn = setActivitiesResponse({ nextPage: 4 })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listMemberActivities('123')
expect(response.nextPage).toBe(4)
})
it('given no nextPageUrl, sets nextPage to null', async () => {
const toReturn = setActivitiesResponse({ nextPage: null })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listMemberActivities('123')
expect(response.nextPage).toBeNull()
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.listMemberActivities('123')).rejects.toThrow(errorMessage)
})
})
describe('OrbitActivities getActivity', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if activityId is missing, throws', async () => {
await expect(sut.getActivity()).rejects.toThrow(
'You must provide an activityId'
)
})
it('returns data in correct format', async () => {
const toReturn = { data: { data: { id: 'id-val' }, included: [] } }
axios.mockResolvedValueOnce(toReturn)
const response = await sut.getActivity('123')
expect(response.data.id).toBe('id-val')
expect(response.included).not.toBeNull()
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.getActivity('123')).rejects.toThrow(errorMessage)
})
})
describe('OrbitActivities getLatestActivityTimestamp', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
it('given type is missing, throws', async () => {
await expect(sut.getLatestActivityTimestamp()).rejects.toThrow(
'You must provide a type'
)
})
it('given type is not a string, throws', async () => {
await expect(sut.getLatestActivityTimestamp(123)).rejects.toThrow(
'type must be a string'
)
})
it('given correct parameters, calls listMemberActivities', async () => {
const toReturn = {
data: {
data: [
{ attributes: { created_at: '2021-07-07T12:00:00.000Z' } },
{ attributes: { created_at: '2021-07-07T11:00:00.000Z' } }
]
}
}
axios.mockResolvedValueOnce(toReturn)
const spy = jest.spyOn(sut, 'listWorkspaceActivities')
sut.getLatestActivityTimestamp('type')
expect(spy).toHaveBeenCalledTimes(1)
})
it('given existing activities, return first created_at', async () => {
const toReturn = {
data: {
data: [
{ attributes: { created_at: '2021-07-07T12:00:00.000Z' } },
{ attributes: { created_at: '2021-07-07T11:00:00.000Z' } }
]
}
}
axios.mockResolvedValueOnce(toReturn)
const response = await sut.getLatestActivityTimestamp('123')
expect(response).toBe('2021-07-07T12:00:00.000Z')
})
it('given no existing activities, return null', async () => {
const toReturn = {
data: {
data: []
}
}
axios.mockResolvedValueOnce(toReturn)
const response = await sut.getLatestActivityTimestamp('123')
expect(response).toBeNull()
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.getLatestActivityTimestamp('123')).rejects.toThrow(
errorMessage
)
})
})
describe('OrbitActivities createActivity', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
it('given one argument which is an object, call createActivityForUnknownMember', () => {
const spy = jest.spyOn(sut, 'createActivityForUnknownMember')
sut.createActivity({})
expect(spy).toHaveBeenCalledTimes(1)
})
it('given a memberId and an object, call createActivityByMemberId', () => {
const spy = jest.spyOn(sut, 'createActivityByMemberId')
sut.createActivity('123', {})
expect(spy).toHaveBeenCalledTimes(1)
})
})
describe('OrbitActivities createActivityByMemberId', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if memberId or data is not provided, throws', async () => {
await expect(sut.createActivityByMemberId()).rejects.toThrow(
'You must provide a memberId and data'
)
await expect(sut.createActivityByMemberId(null, {})).rejects.toThrow(
'You must provide a memberId and data'
)
await expect(sut.createActivityByMemberId('123', null)).rejects.toThrow(
'You must provide a memberId and data'
)
})
it('if parameters are the wrong type, throws', async () => {
const stringError = 'memberId must be a string'
const objectError = 'data must be an object'
await expect(sut.createActivityByMemberId(123, {})).rejects.toThrow(
stringError
)
await expect(sut.createActivityByMemberId(true, {})).rejects.toThrow(
stringError
)
await expect(sut.createActivityByMemberId({}, {})).rejects.toThrow(
stringError
)
await expect(sut.createActivityByMemberId('string', 123)).rejects.toThrow(
objectError
)
await expect(sut.createActivityByMemberId('string', true)).rejects.toThrow(
objectError
)
await expect(
sut.createActivityByMemberId('string', 'string')
).rejects.toThrow(objectError)
})
it('returns data in the correct format', async () => {
const toReturn = setActivitiesResponse()
axios.mockResolvedValueOnce(toReturn)
const response = await sut.createActivityByMemberId('123', {})
expect(response).toMatchObject(toReturn.data)
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.createActivityByMemberId('123', {})).rejects.toThrow(
errorMessage
)
})
})
describe('OrbitActivities createActivityForUnknownMember', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if data is not provided, throws', async () => {
await expect(sut.createActivityForUnknownMember()).rejects.toThrow(
'You must provide data'
)
})
it('if data is not an object', async () => {
const errorText = 'data must be an object'
await expect(sut.createActivityForUnknownMember(123)).rejects.toThrow(
errorText
)
await expect(sut.createActivityForUnknownMember(true)).rejects.toThrow(
errorText
)
await expect(sut.createActivityForUnknownMember('string')).rejects.toThrow(
errorText
)
})
it('returns data in the correct format', async () => {
const toReturn = setActivitiesResponse()
axios.mockResolvedValueOnce(toReturn)
const response = await sut.createActivityForUnknownMember({})
expect(response).toMatchObject(toReturn.data)
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.createActivityForUnknownMember({})).rejects.toThrow(
errorMessage
)
})
})
describe('orbitActivities updateActivity', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if parameters are missing, throws', async () => {
await expect(sut.updateActivity()).rejects.toThrow(
'You must provide a memberId as the first parameter'
)
await expect(sut.updateActivity('1')).rejects.toThrow(
'You must provide an activityId as the second parameter'
)
await expect(sut.updateActivity('1', '2')).rejects.toThrow(
'You must provide a data object as the third parameter'
)
})
it('calls axios correctly', async () => {
axios.mockResolvedValueOnce({})
await sut.updateActivity('123', '456', { dataKey: 'dataValue' })
const firstCall = axios.mock.calls[0][0]
const path = url
.parse(firstCall.url, true)
.path.split('v1')[1]
.split('?')[0]
const memberId = path.split('/')[3]
const activityId = path.split('/')[5]
expect(memberId).toBe('123')
expect(activityId).toBe('456')
})
it('returns success message correctly', async () => {
axios.mockResolvedValueOnce({})
const response = await sut.updateActivity('123', '456', {
dataKey: 'dataValue'
})
expect(response).toBe('activity 456 on member 123 updated')
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.updateActivity('1', '2', {})).rejects.toThrow(errorMessage)
})
})
describe('orbitActivities deleteActivity', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if parameters are missing, throws', async () => {
await expect(sut.deleteActivity()).rejects.toThrow(
'You must provide a memberId as the first parameter'
)
await expect(sut.deleteActivity('1')).rejects.toThrow(
'You must provide an activityId as the second parameter'
)
})
it('calls axios correctly', async () => {
axios.mockResolvedValueOnce({})
await sut.deleteActivity('123', '456')
const firstCall = axios.mock.calls[0][0]
const path = url
.parse(firstCall.url, true)
.path.split('v1')[1]
.split('?')[0]
const memberId = path.split('/')[3]
const activityId = path.split('/')[5]
expect(memberId).toBe('123')
expect(activityId).toBe('456')
})
it('returns success message correctly', async () => {
axios.mockResolvedValueOnce({})
const response = await sut.deleteActivity('123', '456')
expect(response).toBe('activity 456 on member 123 deleted')
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.deleteActivity('1', '2')).rejects.toThrow(errorMessage)
})
})
describe('OrbitActivities createNote', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if memberId or body is not provided, throws', async () => {
await expect(sut.createNote()).rejects.toThrow(
'You must provide a memberId and body'
)
await expect(sut.createNote('1')).rejects.toThrow(
'You must provide a memberId and body'
)
})
it('if parameters are the wrong type, throws', async () => {
const stringError = 'parameters must be strings'
await expect(sut.createNote(123, 'string')).rejects.toThrow(stringError)
await expect(sut.createNote('string', {})).rejects.toThrow(stringError)
})
it('returns data in the correct format', async () => {
axios.mockResolvedValueOnce({ data: {} })
const response = await sut.createNote('123', '456')
expect(response).toMatchObject({})
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.createNote('123', '456')).rejects.toThrow(errorMessage)
})
})
describe('OrbitActivities listMemberNotes', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if memberId is not provided, throws', async () => {
await expect(sut.listMemberNotes()).rejects.toThrow(
'You must provide a memberId'
)
})
it('if memberId is not a string, throws', async () => {
const errorText = 'memberId must be a string'
await expect(sut.listMemberNotes(123)).rejects.toThrow(errorText)
await expect(sut.listMemberNotes(true)).rejects.toThrow(errorText)
await expect(sut.listMemberNotes({})).rejects.toThrow(errorText)
})
it('returns data in correct format', async () => {
const toReturn = setActivitiesResponse({ nextPage: 3 })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listMemberNotes('123')
expect(response.data.length).toBe(2)
expect(response.data.included).not.toBeNull()
expect(response.items).toBe(2)
expect(response.nextPage).toBe(3)
})
it('given nextPageUrl, provides nextPage integer', async () => {
const toReturn = setActivitiesResponse({ nextPage: 4 })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listMemberNotes('123')
expect(response.nextPage).toBe(4)
})
it('given no nextPageUrl, sets nextPage to null', async () => {
const toReturn = setActivitiesResponse({ nextPage: null })
axios.mockResolvedValueOnce(toReturn)
const response = await sut.listMemberNotes('123')
expect(response.nextPage).toBeNull()
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.listMemberNotes('123')).rejects.toThrow(errorMessage)
})
})
describe('orbitActivities updateNote', () => {
let sut
beforeEach(() => {
sut = new OrbitActivities('1', '2')
})
afterEach(() => {
jest.resetAllMocks()
})
it('if parameters are missing, throws', async () => {
await expect(sut.updateNote()).rejects.toThrow(
'You must provide a memberId as the first parameter'
)
await expect(sut.updateNote('1')).rejects.toThrow(
'You must provide a noteId as the second parameter'
)
await expect(sut.updateNote('1', '2')).rejects.toThrow(
'You must provide a body as the third parameter'
)
})
it('if body is not a string, throws', async () => {
await expect(sut.updateNote('123', '456', 1)).rejects.toThrow(
'body must be a string'
)
})
it('calls axios correctly', async () => {
axios.mockResolvedValueOnce({})
await sut.updateNote('123', '456', 'new value')
const firstCall = axios.mock.calls[0][0]
const path = url
.parse(firstCall.url, true)
.path.split('v1')[1]
.split('?')[0]
const memberId = path.split('/')[3]
const activityId = path.split('/')[5]
expect(memberId).toBe('123')
expect(activityId).toBe('456')
expect(firstCall.data.body).toBe('new value')
})
it('returns success message correctly', async () => {
axios.mockResolvedValueOnce({})
const response = await sut.updateNote('123', '456', '567')
expect(response).toBe('note 456 on member 123 updated')
})
it('when there is an error, return error', async () => {
const errorMessage = 'Network Error'
axios.mockImplementationOnce(() => {
return Promise.reject(new Error(errorMessage))
})
await expect(sut.updateNote('1', '2', '3')).rejects.toThrow(errorMessage)
})
})
function setActivitiesResponse(params) {
const next = params?.nextPage
? `https://app.orbit.love/api/v1/workspaceid/activities?filters=true&items=25&page=${params.nextPage}&sort=occurred_at`
: null
return {
data: {
data: [{}, {}],
included: [],
links: {
next
}
}
}
}