515 lines
14 KiB
TypeScript
515 lines
14 KiB
TypeScript
import { setupAndTeardown } from "@calcom/web/test/utils/bookingScenario/setupAndTeardown";
|
|
|
|
import { describe, expect, it, beforeEach, vi } from "vitest";
|
|
import type { z } from "zod";
|
|
|
|
import type { CredentialPayload } from "@calcom/types/Credential";
|
|
|
|
import type { appDataSchema } from "../zod";
|
|
import SalesforceCRMService from "./CrmService";
|
|
import { SalesforceRecordEnum } from "./enums";
|
|
|
|
type AppOptions = z.infer<typeof appDataSchema>;
|
|
|
|
const contactQueryResponse = {
|
|
records: [
|
|
{
|
|
Id: "001",
|
|
Email: "test@example.com",
|
|
OwnerId: "owner001",
|
|
attributes: { type: "Contact" },
|
|
Owner: {
|
|
Email: "owner@example.com",
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const contactUnderAccountQueryResponse = {
|
|
records: [
|
|
{
|
|
Id: "001",
|
|
Email: "test@example.com",
|
|
OwnerId: "owner001",
|
|
AccountId: "acc001",
|
|
attributes: { type: "Contact" },
|
|
Account: {
|
|
attributes: { type: "Account" },
|
|
Owner: {
|
|
Email: "owner@example.com",
|
|
},
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const leadQueryResponse = {
|
|
records: [
|
|
{
|
|
Id: "001",
|
|
Email: "test@example.com",
|
|
OwnerId: "owner001",
|
|
attributes: { type: "Lead" },
|
|
Owner: {
|
|
Email: "owner@example.com",
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const ownerQueryResponse = {
|
|
records: [
|
|
{
|
|
Id: "owner001",
|
|
Email: "owner@example.com",
|
|
Name: "Test Owner",
|
|
},
|
|
],
|
|
};
|
|
|
|
const accountQueryResponse = {
|
|
records: [
|
|
{
|
|
Id: "acc001",
|
|
OwnerId: "owner001",
|
|
Email: "test@example.com",
|
|
attributes: { type: "Account" },
|
|
},
|
|
],
|
|
};
|
|
|
|
describe("SalesforceCRMService", () => {
|
|
let service: SalesforceCRMService;
|
|
let mockConnection: { query: any };
|
|
|
|
setupAndTeardown();
|
|
|
|
beforeEach(() => {
|
|
mockConnection = {
|
|
query: vi.fn(),
|
|
};
|
|
|
|
const mockCredential: CredentialPayload = {
|
|
id: 1,
|
|
type: "salesforce_crm",
|
|
key: {
|
|
access_token: "mock_token",
|
|
refresh_token: "mock_refresh",
|
|
instance_url: "https://mock.salesforce.com",
|
|
},
|
|
userId: 1,
|
|
appId: "salesforce",
|
|
teamId: null,
|
|
invalid: false,
|
|
user: {
|
|
email: "test-user@example.com",
|
|
},
|
|
};
|
|
|
|
service = new SalesforceCRMService(mockCredential, {}, true);
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
service.conn = Promise.resolve(mockConnection);
|
|
});
|
|
|
|
const mockAppOptions = (appOptions: AppOptions) => {
|
|
const appOptionsSpy = vi.spyOn(service, "getAppOptions");
|
|
appOptionsSpy.mockReturnValue(appOptions);
|
|
};
|
|
|
|
describe("getContacts", () => {
|
|
it("should return empty array when no records found", async () => {
|
|
// Setup mock response
|
|
mockConnection.query.mockResolvedValueOnce({ records: [] });
|
|
|
|
const result = await service.getContacts({ emails: "test@example.com" });
|
|
|
|
expect(result).toEqual([]);
|
|
expect(mockConnection.query).toHaveBeenCalledWith(
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Contact WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
|
|
it("should handle single email string input", async () => {
|
|
// Setup mock response with descriptive name
|
|
const contactQueryResponse = {
|
|
records: [
|
|
{
|
|
Id: "001",
|
|
Email: "test@example.com",
|
|
OwnerId: "owner001",
|
|
attributes: { type: "Contact" },
|
|
},
|
|
],
|
|
};
|
|
|
|
// Setup query spy
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(contactQueryResponse);
|
|
|
|
const result = await service.getContacts({ emails: "test@example.com" });
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
]);
|
|
|
|
// Verify the exact query made
|
|
expect(querySpy).toHaveBeenCalledWith(
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Contact WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
|
|
it("should handle array of emails input", async () => {
|
|
const contactsQueryResponse = {
|
|
records: [
|
|
{
|
|
Id: "001",
|
|
Email: "test1@example.com",
|
|
OwnerId: "owner001",
|
|
attributes: { type: "Contact" },
|
|
},
|
|
{
|
|
Id: "002",
|
|
Email: "test2@example.com",
|
|
OwnerId: "owner002",
|
|
attributes: { type: "Contact" },
|
|
},
|
|
],
|
|
};
|
|
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(contactsQueryResponse);
|
|
|
|
const result = await service.getContacts({
|
|
emails: ["test1@example.com", "test2@example.com"],
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test1@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
{
|
|
id: "002",
|
|
email: "test2@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenCalledWith(
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Contact WHERE Email IN ('test1@example.com','test2@example.com')"
|
|
);
|
|
});
|
|
|
|
it("should return contacts when includeOwner is true but no owner is found", async () => {
|
|
mockAppOptions({
|
|
roundRobinSkipCheckRecordOn: SalesforceRecordEnum.CONTACT,
|
|
createEventOn: SalesforceRecordEnum.CONTACT,
|
|
});
|
|
|
|
const contactQueryResponse = {
|
|
records: [
|
|
{
|
|
Id: "001",
|
|
Email: "test@example.com",
|
|
// OwnerId: "owner001",
|
|
attributes: { type: "Contact" },
|
|
Owner: {
|
|
Email: "owner@example.com",
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
// Setup query spy with specific responses
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(contactQueryResponse); // Contact query
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
includeOwner: true,
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
ownerId: undefined,
|
|
ownerEmail: "owner@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Contact WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
|
|
describe("no additional params are passed", () => {
|
|
it("when createEventOn is contact", async () => {
|
|
mockAppOptions({
|
|
createEventOn: SalesforceRecordEnum.CONTACT,
|
|
});
|
|
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(contactQueryResponse);
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Contact WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
it("when createEventOn is lead", async () => {
|
|
mockAppOptions({
|
|
createEventOn: SalesforceRecordEnum.LEAD,
|
|
});
|
|
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(leadQueryResponse);
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
recordType: "Lead",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Lead WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
it("when createEventOn is contact under an account", async () => {
|
|
mockAppOptions({
|
|
createEventOn: SalesforceRecordEnum.ACCOUNT,
|
|
});
|
|
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(contactUnderAccountQueryResponse);
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, AccountId, Account.Owner.Email, Account.Website FROM Contact WHERE Email = 'test@example.com' AND AccountId != null"
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("includeOwner param is passed", () => {
|
|
it("when createEventOn is contact", async () => {
|
|
mockAppOptions({
|
|
createEventOn: SalesforceRecordEnum.CONTACT,
|
|
});
|
|
|
|
// Setup query spy with specific responses
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(contactQueryResponse); // Contact query
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
includeOwner: true,
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
ownerId: "owner001",
|
|
ownerEmail: "owner@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Contact WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
it("when createEventOn is lead", async () => {
|
|
mockAppOptions({
|
|
createEventOn: SalesforceRecordEnum.LEAD,
|
|
});
|
|
|
|
// Setup query spy with specific responses
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(leadQueryResponse);
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
includeOwner: true,
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
ownerId: "owner001",
|
|
ownerEmail: "owner@example.com",
|
|
recordType: "Lead",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Lead WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
it("when createEventOn is contact under an account", async () => {
|
|
mockAppOptions({
|
|
createEventOn: SalesforceRecordEnum.ACCOUNT,
|
|
});
|
|
|
|
// Setup query spy with specific responses
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(contactUnderAccountQueryResponse);
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
includeOwner: true,
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
ownerId: "owner001",
|
|
ownerEmail: "owner@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, AccountId, Account.Owner.Email, Account.Website FROM Contact WHERE Email = 'test@example.com' AND AccountId != null"
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("forRoundRobinSkip param is passed", () => {
|
|
it("checking against contacts", async () => {
|
|
mockAppOptions({
|
|
roundRobinSkipCheckRecordOn: SalesforceRecordEnum.CONTACT,
|
|
createEventOn: SalesforceRecordEnum.CONTACT,
|
|
});
|
|
|
|
// Setup query spy with specific responses
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(contactQueryResponse); // Contact query
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
forRoundRobinSkip: true,
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
ownerId: "owner001",
|
|
ownerEmail: "owner@example.com",
|
|
recordType: "Contact",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Contact WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
it("checking against leads", async () => {
|
|
mockAppOptions({
|
|
roundRobinSkipCheckRecordOn: SalesforceRecordEnum.LEAD,
|
|
});
|
|
|
|
// Setup query spy with specific responses
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy.mockResolvedValueOnce(leadQueryResponse);
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
forRoundRobinSkip: true,
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "001",
|
|
email: "test@example.com",
|
|
ownerId: "owner001",
|
|
ownerEmail: "owner@example.com",
|
|
recordType: "Lead",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, Owner.Email FROM Lead WHERE Email IN ('test@example.com')"
|
|
);
|
|
});
|
|
it("checking against contacts under an account", async () => {
|
|
mockAppOptions({
|
|
roundRobinSkipCheckRecordOn: SalesforceRecordEnum.ACCOUNT,
|
|
});
|
|
const querySpy = vi.spyOn(mockConnection, "query");
|
|
querySpy
|
|
.mockResolvedValueOnce(contactUnderAccountQueryResponse)
|
|
.mockResolvedValueOnce(accountQueryResponse)
|
|
.mockResolvedValueOnce(ownerQueryResponse);
|
|
|
|
const result = await service.getContacts({
|
|
emails: "test@example.com",
|
|
forRoundRobinSkip: true,
|
|
});
|
|
|
|
expect(result).toEqual([
|
|
{
|
|
id: "acc001",
|
|
email: "test@example.com",
|
|
ownerId: "owner001",
|
|
ownerEmail: "owner@example.com",
|
|
recordType: "Account",
|
|
},
|
|
]);
|
|
|
|
expect(querySpy).toHaveBeenNthCalledWith(
|
|
1,
|
|
"SELECT Id, Email, OwnerId, AccountId, Account.Owner.Email, Account.Website FROM Contact WHERE Email = 'test@example.com' AND AccountId != null"
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|