mirror of
https://github.com/hcengineering/platform.git
synced 2026-10-01 22:15:04 +02:00
* UBERF-11414: Use common integration kind Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Allow multiple gmail Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Merge with develop Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Refactor integration kinds Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Add integrations package Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Integrations Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Integration state and config Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Add integration events Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Refresh integration states Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Rename to integration-client Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Add filter button Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Add translations for filters Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Synced channels count Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Actions Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Add isLoading for connect Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Create connection and integration Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Use social id from hulygram Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Remove old integrations Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Gmail state Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Gmail state and disconnect all handler Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Add tests Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Formatting Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Gmail sync state Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Fix rush check Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Fix gmail tests Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Fix calendar actions and config Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Calendar state Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Access config Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Github integration state Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Fix svelte errors Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Fix formatting Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Fix typos Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Fix validate Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Fix translations Signed-off-by: Artem Savchenko <armisav@gmail.com> * UBERF-11414: Retry on network issues Signed-off-by: Artem Savchenko <armisav@gmail.com> --------- Signed-off-by: Artem Savchenko <armisav@gmail.com>
141 lines
4.7 KiB
TypeScript
141 lines
4.7 KiB
TypeScript
import { AccountUuid, PersonId, WorkspaceUuid, type MeasureContext } from '@hcengineering/core'
|
|
import { AccountClient, IntegrationSecret } from '@hcengineering/account-client'
|
|
import { getAccountClient } from '@hcengineering/server-client'
|
|
import { gmailIntegrationKind } from '@hcengineering/gmail'
|
|
|
|
import { TokenStorage } from '../tokens'
|
|
import { SecretType, Token } from '../types'
|
|
|
|
// Mock the getAccountClient function
|
|
jest.mock('@hcengineering/server-client', () => ({
|
|
getAccountClient: jest.fn()
|
|
}))
|
|
|
|
describe('TokenStorage', () => {
|
|
const mockSocialId = 'test-social-id' as PersonId
|
|
const mockWorkspace = 'test-workspace' as WorkspaceUuid
|
|
const mockPlatformToken = 'test-platform-token'
|
|
const mockUserId = 'test-user' as AccountUuid
|
|
const mockToken: Token = {
|
|
userId: mockUserId,
|
|
socialId: { _id: '123' } as any,
|
|
workspace: mockWorkspace,
|
|
token: 'test-token',
|
|
access_token: 'test-access-token',
|
|
refresh_token: 'test-refresh-token',
|
|
scope: 'test-scope',
|
|
token_type: 'Bearer',
|
|
expiry_date: 123456789
|
|
}
|
|
|
|
let tokenStorage: TokenStorage
|
|
let mockAccountClient: jest.Mocked<AccountClient>
|
|
// Add mock MeasureContext
|
|
const mockMeasureContext: MeasureContext = {
|
|
info: jest.fn(),
|
|
error: jest.fn()
|
|
} as any
|
|
|
|
beforeEach(() => {
|
|
// Create mock AccountClient
|
|
mockAccountClient = {
|
|
getIntegrationSecret: jest.fn(),
|
|
addIntegrationSecret: jest.fn(),
|
|
updateIntegrationSecret: jest.fn(),
|
|
deleteIntegrationSecret: jest.fn()
|
|
} as any
|
|
|
|
// Set up getAccountClient mock
|
|
;(getAccountClient as jest.Mock).mockReturnValue(mockAccountClient)
|
|
|
|
// Create TokenStorage instance with MeasureContext
|
|
tokenStorage = new TokenStorage(mockMeasureContext, mockWorkspace, mockPlatformToken)
|
|
})
|
|
|
|
afterEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
describe('getToken', () => {
|
|
it('should return null when no token exists', async () => {
|
|
mockAccountClient.getIntegrationSecret.mockResolvedValue(null)
|
|
const result = await tokenStorage.getToken(mockSocialId)
|
|
expect(result).toBeNull()
|
|
expect(mockAccountClient.getIntegrationSecret).toHaveBeenCalledWith({
|
|
key: SecretType.TOKEN,
|
|
kind: gmailIntegrationKind,
|
|
socialId: mockSocialId,
|
|
workspaceUuid: mockWorkspace
|
|
})
|
|
})
|
|
|
|
it('should return parsed token when token exists', async () => {
|
|
const mockSecret: IntegrationSecret = {
|
|
socialId: mockSocialId,
|
|
kind: gmailIntegrationKind,
|
|
workspaceUuid: mockWorkspace,
|
|
key: SecretType.TOKEN,
|
|
secret: JSON.stringify(mockToken)
|
|
}
|
|
mockAccountClient.getIntegrationSecret.mockResolvedValue(mockSecret)
|
|
const result = await tokenStorage.getToken(mockSocialId)
|
|
expect(result).toEqual(mockToken)
|
|
})
|
|
})
|
|
|
|
describe('saveToken', () => {
|
|
it('should update token when it exists', async () => {
|
|
const existingToken = { existing: 'token' }
|
|
const mockSecret: IntegrationSecret = {
|
|
socialId: mockSocialId,
|
|
kind: gmailIntegrationKind,
|
|
workspaceUuid: mockWorkspace,
|
|
key: SecretType.TOKEN,
|
|
secret: JSON.stringify(existingToken)
|
|
}
|
|
mockAccountClient.getIntegrationSecret.mockResolvedValue(mockSecret)
|
|
await tokenStorage.saveToken(mockSocialId, mockToken)
|
|
|
|
// Expect merged token (existing token properties + new token properties)
|
|
const expectedMergedToken = {
|
|
...existingToken,
|
|
...mockToken
|
|
}
|
|
|
|
expect(mockAccountClient.updateIntegrationSecret).toHaveBeenCalledWith({
|
|
key: SecretType.TOKEN,
|
|
kind: gmailIntegrationKind,
|
|
socialId: mockSocialId,
|
|
secret: JSON.stringify(expectedMergedToken),
|
|
workspaceUuid: mockWorkspace
|
|
})
|
|
expect(mockAccountClient.addIntegrationSecret).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('should add new token when it does not exist', async () => {
|
|
mockAccountClient.getIntegrationSecret.mockResolvedValue(null)
|
|
await tokenStorage.saveToken(mockSocialId, mockToken)
|
|
expect(mockAccountClient.addIntegrationSecret).toHaveBeenCalledWith({
|
|
key: SecretType.TOKEN,
|
|
kind: gmailIntegrationKind,
|
|
socialId: mockSocialId,
|
|
secret: JSON.stringify(mockToken),
|
|
workspaceUuid: mockWorkspace
|
|
})
|
|
expect(mockAccountClient.updateIntegrationSecret).not.toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('deleteToken', () => {
|
|
it('should delete the token', async () => {
|
|
await tokenStorage.deleteToken(mockSocialId)
|
|
expect(mockAccountClient.deleteIntegrationSecret).toHaveBeenCalledWith({
|
|
key: SecretType.TOKEN,
|
|
kind: gmailIntegrationKind,
|
|
socialId: mockSocialId,
|
|
workspaceUuid: mockWorkspace
|
|
})
|
|
})
|
|
})
|
|
})
|