chore: Add Salesforce tests to getContacts method (#18225)

This commit is contained in:
Joe Au-Yeung
2025-01-07 14:14:34 -07:00
committed by GitHub
parent 53a846d10c
commit 79d51a4989
2 changed files with 366 additions and 107 deletions
@@ -1,12 +1,71 @@
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" },
},
],
};
const contactUnderAccountQueryResponse = {
records: [
{
Id: "001",
Email: "test@example.com",
OwnerId: "owner001",
AccountId: "acc001",
attributes: { type: "Contact" },
},
],
};
const leadQueryResponse = {
records: [
{
Id: "001",
Email: "test@example.com",
OwnerId: "owner001",
attributes: { type: "Lead" },
},
],
};
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 };
@@ -41,6 +100,11 @@ describe("SalesforceCRMService", () => {
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
@@ -130,26 +194,25 @@ describe("SalesforceCRMService", () => {
);
});
it("should include owner information when includeOwner is true", async () => {
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",
// OwnerId: "owner001",
attributes: { type: "Contact" },
},
],
};
const ownerQueryResponse = {
records: [
{
Id: "owner001",
Email: "owner@example.com",
Name: "Test Owner",
},
],
records: [],
};
// Setup query spy with specific responses
@@ -167,8 +230,8 @@ describe("SalesforceCRMService", () => {
{
id: "001",
email: "test@example.com",
ownerId: "owner001",
ownerEmail: "owner@example.com",
ownerId: undefined,
ownerEmail: undefined,
recordType: "Contact",
},
]);
@@ -177,89 +240,297 @@ describe("SalesforceCRMService", () => {
1,
"SELECT Id, Email, OwnerId FROM Contact WHERE Email IN ('test@example.com')"
);
expect(querySpy).toHaveBeenNthCalledWith(
2,
expect.stringContaining("SELECT Id, Email, Name FROM User WHERE Id = 'owner001'")
);
});
it("should handle account record type with round robin skip", async () => {
service = new SalesforceCRMService(
{} as CredentialPayload,
{
createEventOn: SalesforceRecordEnum.ACCOUNT,
roundRobinSkipCheckRecordOn: SalesforceRecordEnum.ACCOUNT,
},
true
);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
service.conn = Promise.resolve(mockConnection);
describe("no additional params are passed", () => {
it("when createEventOn is contact", async () => {
mockAppOptions({
createEventOn: SalesforceRecordEnum.CONTACT,
});
const initialContactQueryResponse = {
records: [
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",
AccountId: "acc001",
OwnerId: "owner001",
attributes: { type: "Contact" },
id: "001",
email: "test@example.com",
recordType: "Contact",
},
],
};
]);
const accountQueryResponse = {
records: [
{
Id: "acc001",
OwnerId: "owner001",
Email: "test@example.com",
attributes: { type: "Account" },
},
],
};
const ownerQueryResponse = {
records: [
{
Id: "owner001",
Email: "owner@example.com",
Name: "Test Owner",
},
],
};
const querySpy = vi.spyOn(mockConnection, "query");
querySpy
.mockResolvedValueOnce(initialContactQueryResponse)
.mockResolvedValueOnce(accountQueryResponse)
.mockResolvedValueOnce(ownerQueryResponse);
const result = await service.getContacts({
emails: "test@example.com",
forRoundRobinSkip: true,
includeOwner: true,
expect(querySpy).toHaveBeenNthCalledWith(
1,
"SELECT Id, Email, OwnerId FROM Contact WHERE Email IN ('test@example.com')"
);
});
it("when createEventOn is lead", async () => {
mockAppOptions({
createEventOn: SalesforceRecordEnum.LEAD,
});
expect(result).toEqual([
{
id: "acc001",
email: "test@example.com",
ownerId: "owner001",
ownerEmail: "owner@example.com",
recordType: "Account",
},
]);
const querySpy = vi.spyOn(mockConnection, "query");
querySpy.mockResolvedValueOnce(leadQueryResponse);
expect(querySpy).toHaveBeenNthCalledWith(
1,
"SELECT Id, Email, OwnerId, AccountId FROM Contact WHERE Email = 'test@example.com' AND AccountId != null"
);
expect(querySpy).toHaveBeenNthCalledWith(2, "SELECT Id, OwnerId FROM Account WHERE Id = 'acc001'");
expect(querySpy).toHaveBeenNthCalledWith(
3,
expect.stringContaining("SELECT Id, Email, Name FROM User WHERE Id = 'owner001'")
);
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 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 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
.mockResolvedValueOnce(ownerQueryResponse); // Owner 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 FROM Contact WHERE Email IN ('test@example.com')"
);
expect(querySpy).toHaveBeenNthCalledWith(
2,
expect.stringContaining("SELECT Id, Email, Name FROM User WHERE Id = 'owner001'")
);
});
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).mockResolvedValueOnce(ownerQueryResponse);
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 FROM Lead WHERE Email IN ('test@example.com')"
);
expect(querySpy).toHaveBeenNthCalledWith(
2,
expect.stringContaining("SELECT Id, Email, Name FROM User WHERE Id = 'owner001'")
);
});
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)
.mockResolvedValueOnce(ownerQueryResponse);
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: "Account",
},
]);
expect(querySpy).toHaveBeenNthCalledWith(
1,
"SELECT Id, Email, OwnerId, AccountId FROM Contact WHERE Email = 'test@example.com' AND AccountId != null"
);
expect(querySpy).toHaveBeenNthCalledWith(
2,
expect.stringContaining("SELECT Id, Email, Name FROM User WHERE Id = 'owner001'")
);
});
});
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
.mockResolvedValueOnce(ownerQueryResponse); // Owner 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 FROM Contact WHERE Email IN ('test@example.com')"
);
expect(querySpy).toHaveBeenNthCalledWith(
2,
expect.stringContaining("SELECT Id, Email, Name FROM User WHERE Id = 'owner001'")
);
});
it("checking against leads", async () => {
mockAppOptions({
roundRobinSkipCheckRecordOn: SalesforceRecordEnum.LEAD,
});
// Setup query spy with specific responses
const querySpy = vi.spyOn(mockConnection, "query");
querySpy.mockResolvedValueOnce(leadQueryResponse).mockResolvedValueOnce(ownerQueryResponse);
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 FROM Lead WHERE Email IN ('test@example.com')"
);
expect(querySpy).toHaveBeenNthCalledWith(
2,
expect.stringContaining("SELECT Id, Email, Name FROM User WHERE Id = 'owner001'")
);
});
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 FROM Contact WHERE Email = 'test@example.com' AND AccountId != null"
);
expect(querySpy).toHaveBeenNthCalledWith(2, "SELECT Id, OwnerId FROM Account WHERE Id = 'acc001'");
expect(querySpy).toHaveBeenNthCalledWith(
3,
expect.stringContaining("SELECT Id, Email, Name FROM User WHERE Id = 'owner001'")
);
});
});
});
});
+10 -22
View File
@@ -458,17 +458,15 @@ export default class SalesforceCRMService implements CRM {
});
}
if (ownerIds.size === 0) {
log.warn("No owner IDs found for records");
return [];
}
const ownersQuery = await Promise.all(
Array.from(ownerIds).map(async (ownerId) => {
const result = await this.getSalesforceUserFromUserId(ownerId);
return result;
})
);
const ownersQuery =
ownerIds.size > 0
? await Promise.all(
Array.from(ownerIds).map(async (ownerId) => {
const result = await this.getSalesforceUserFromUserId(ownerId);
return result;
})
)
: [];
// Filter out any undefined results and ensure records exist
const validOwnersQuery = ownersQuery.filter((query): query is jsforce.QueryResult<ContactRecord> => {
@@ -480,14 +478,9 @@ export default class SalesforceCRMService implements CRM {
);
});
if (validOwnersQuery.length === 0) {
log.warn("No valid owner records found");
return [];
}
return records
.map((record) => {
if (!record?.Id || !record?.OwnerId) {
if (!record?.Id) {
log.warn("Invalid record data", { record });
return null;
}
@@ -496,11 +489,6 @@ export default class SalesforceCRMService implements CRM {
? validOwnersQuery[0]?.records[0]?.Email
: validOwnersQuery.find((user) => user.records[0]?.Id === record.OwnerId)?.records[0]?.Email;
if (!ownerEmail) {
log.warn("Could not find owner email", { recordId: record.Id, ownerId: record.OwnerId });
return null;
}
return {
id: record.Id,
email: record.Email,