fix(Salesforce Node): Quote numeric string filter values in SOQL conditions (#31128)

This commit is contained in:
Alexander Gekov 2026-05-27 09:52:28 +03:00 committed by GitHub
parent 1b9dfb20c4
commit 8dbcc8359a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 264 additions and 45 deletions

View File

@ -305,7 +305,13 @@ const SALESFORCE_DATE_LITERALS = new Set([
'NEXT_FISCAL_YEAR',
]);
export function getValue(value: any): string | number | boolean {
// Salesforce node typeVersion at which numeric-looking strings stopped being
// auto-coerced to unquoted SOQL numbers. See NODE-5116: string-typed Salesforce
// fields (e.g. external IDs) need quoted literals regardless of content. Older
// typeVersions keep the legacy coercion for backwards compatibility.
const NUMERIC_STRING_QUOTING_VERSION = 1.1;
export function getValue(value: any, nodeVersion = 1): string | number | boolean {
if (value === null || value === undefined) {
return 'null';
}
@ -379,22 +385,28 @@ export function getValue(value: any): string | number | boolean {
}
}
// Detect numeric strings and return them unquoted (leading zeros are preserved as strings)
if (/^-?(0|[1-9]\d*)(\.\d+)?$/.test(value)) {
// Legacy behavior (typeVersion < 1.1): auto-coerce numeric strings to unquoted
// SOQL numbers. Kept for existing workflows that rely on it for numeric SF fields
// (e.g. `AnnualRevenue > '0'`). Fixed in typeVersion 1.1 — see NODE-5116.
if (nodeVersion < NUMERIC_STRING_QUOTING_VERSION && /^-?(0|[1-9]\d*)(\.\d+)?$/.test(value)) {
const numericValue = Number(value);
if (Number.isFinite(numericValue)) {
return numericValue;
}
}
// All other strings are escaped and quoted
// All other strings are escaped and quoted. From typeVersion 1.1 onwards this
// includes numeric-looking strings — the value input has no field-type info,
// and string-typed Salesforce fields (e.g. external IDs) require quoted literals
// regardless of content. Users wanting a numeric comparison must pass a number
// via an expression.
return `'${escapeSoqlString(value)}'`;
}
throw new Error(`Unsupported value type: ${typeof value}`);
}
export function getConditions(options: IDataObject): string | undefined {
export function getConditions(options: IDataObject, nodeVersion = 1): string | undefined {
const conditions = (options.conditionsUi as IDataObject)?.conditionValues as IDataObject[];
if (!Array.isArray(conditions) || conditions.length === 0) {
@ -404,7 +416,7 @@ export function getConditions(options: IDataObject): string | undefined {
const conditionStrings = conditions.map((condition: IDataObject) => {
const field = validateSoqlFieldName(condition.field as string);
const operator = validateSoqlOperator(condition.operation as string);
const value = getValue(condition.value);
const value = getValue(condition.value, nodeVersion);
return `${field} ${operator} ${value}`;
});
@ -427,7 +439,13 @@ export function getDefaultFields(sobject: string) {
)[sobject];
}
export function getQuery(options: IDataObject, sobject: string, returnAll: boolean, limit = 0) {
export function getQuery(
options: IDataObject,
sobject: string,
returnAll: boolean,
limit = 0,
nodeVersion = 1,
) {
const validSobject = validateSoqlObjectName(sobject);
const fields: string[] = [];
@ -451,7 +469,7 @@ export function getQuery(options: IDataObject, sobject: string, returnAll: boole
((getDefaultFields(validSobject) as string) || 'id,LastModifiedDate').split(','),
);
}
const conditions = getConditions(options);
const conditions = getConditions(options, nodeVersion);
let query = `SELECT ${fields.join(',')} FROM ${validSobject} ${conditions ? conditions : ''}`;

View File

@ -46,7 +46,7 @@ export class Salesforce implements INodeType {
name: 'salesforce',
icon: 'file:salesforce.svg',
group: ['output'],
version: 1,
version: [1, 1.1],
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume Salesforce API',
defaults: {
@ -1049,6 +1049,7 @@ export class Salesforce implements INodeType {
const qs: IDataObject = {};
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
const nodeVersion = this.getNode().typeVersion;
this.logger.debug(
`Running "Salesforce" node named "${this.getNode.name}" resource "${resource}" operation "${operation}"`,
@ -1289,7 +1290,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, 'Lead', returnAll, 0);
qs.q = getQuery(options, 'Lead', returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -1300,7 +1301,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, 'Lead', returnAll, limit);
qs.q = getQuery(options, 'Lead', returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -1663,7 +1664,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, 'Contact', returnAll, 0);
qs.q = getQuery(options, 'Contact', returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -1674,7 +1675,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, 'Contact', returnAll, limit);
qs.q = getQuery(options, 'Contact', returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -1815,7 +1816,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, customObject, returnAll, 0);
qs.q = getQuery(options, customObject, returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -1826,7 +1827,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, customObject, returnAll, limit);
qs.q = getQuery(options, customObject, returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2049,7 +2050,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, 'Opportunity', returnAll, 0);
qs.q = getQuery(options, 'Opportunity', returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2060,7 +2061,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, 'Opportunity', returnAll, limit);
qs.q = getQuery(options, 'Opportunity', returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2337,7 +2338,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, 'Account', returnAll, 0);
qs.q = getQuery(options, 'Account', returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2348,7 +2349,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, 'Account', returnAll, limit);
qs.q = getQuery(options, 'Account', returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2552,7 +2553,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, 'Case', returnAll, 0);
qs.q = getQuery(options, 'Case', returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2563,7 +2564,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, 'Case', returnAll, limit);
qs.q = getQuery(options, 'Case', returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2815,7 +2816,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, 'Task', returnAll, 0);
qs.q = getQuery(options, 'Task', returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2826,7 +2827,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, 'Task', returnAll, limit);
qs.q = getQuery(options, 'Task', returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2947,7 +2948,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, 'Attachment', returnAll, 0);
qs.q = getQuery(options, 'Attachment', returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -2958,7 +2959,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, 'Attachment', returnAll, limit);
qs.q = getQuery(options, 'Attachment', returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -3002,7 +3003,7 @@ export class Salesforce implements INodeType {
const options = this.getNodeParameter('options', i);
try {
if (returnAll) {
qs.q = getQuery(options, 'User', returnAll, 0);
qs.q = getQuery(options, 'User', returnAll, 0, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',
@ -3013,7 +3014,7 @@ export class Salesforce implements INodeType {
);
} else {
const limit = this.getNodeParameter('limit', i);
qs.q = getQuery(options, 'User', returnAll, limit);
qs.q = getQuery(options, 'User', returnAll, limit, nodeVersion);
responseData = await salesforceApiRequestAllItems.call(
this,
'records',

View File

@ -26,7 +26,7 @@ export class SalesforceTrigger implements INodeType {
name: 'salesforceTrigger',
icon: 'file:salesforce.svg',
group: ['trigger'],
version: 1,
version: [1, 1.1],
description:
'Fetches data from Salesforce and starts the workflow on specified polling intervals.',
subtitle: '={{($parameter["triggerOn"])}}',
@ -194,6 +194,7 @@ export class SalesforceTrigger implements INodeType {
const triggerOn = this.getNodeParameter('triggerOn') as string;
let triggerResource = triggerOn.slice(0, 1).toUpperCase() + triggerOn.slice(1, -7);
const changeType = triggerOn.slice(-7);
const nodeVersion = this.getNode().typeVersion;
if (triggerResource === 'CustomObject') {
triggerResource = this.getNodeParameter('customObject') as string;
@ -249,9 +250,9 @@ export class SalesforceTrigger implements INodeType {
try {
if (this.getMode() === 'manual') {
qs.q = getQuery(options, triggerResource, false, 1);
qs.q = getQuery(options, triggerResource, false, 1, nodeVersion);
} else {
qs.q = getQuery(options, triggerResource, true, 0);
qs.q = getQuery(options, triggerResource, true, 0, nodeVersion);
}
responseData = await salesforceApiRequestAllItems.call(
this,

View File

@ -1371,15 +1371,50 @@ describe('Salesforce -> GenericFunctions', () => {
expect(result).toBe("'Bob\\' OR \\'1\\'=\\'1'");
});
it('should return numeric strings as numbers', () => {
expect(getValue('0')).toBe(0);
expect(getValue('123')).toBe(123);
expect(getValue('123.45')).toBe(123.45);
expect(getValue('-5')).toBe(-5);
describe('typeVersion 1 (legacy: numeric strings are coerced to unquoted SOQL numbers)', () => {
it('should return numeric strings as unquoted numbers', () => {
expect(getValue('0', 1)).toBe(0);
expect(getValue('123', 1)).toBe(123);
expect(getValue('123.45', 1)).toBe(123.45);
expect(getValue('-5', 1)).toBe(-5);
});
it('should preserve leading zeros as quoted strings', () => {
expect(getValue('00123', 1)).toBe("'00123'");
});
it('should default to legacy behavior when nodeVersion is omitted', () => {
// Safety net: callers that haven't passed nodeVersion must keep
// behaving as v1 so existing workflows are not impacted.
expect(getValue('123')).toBe(123);
});
});
it('should preserve leading zeros as quoted strings', () => {
expect(getValue('00123')).toBe("'00123'");
describe('typeVersion 1.1 (numeric strings are quoted — NODE-5116 fix)', () => {
it('should quote numeric-looking string values', () => {
expect(getValue('0', 1.1)).toBe("'0'");
expect(getValue('123', 1.1)).toBe("'123'");
expect(getValue('123.45', 1.1)).toBe("'123.45'");
expect(getValue('-5', 1.1)).toBe("'-5'");
});
it('should quote numeric strings without leading zero (regression: NODE-5116)', () => {
// String-typed Salesforce fields (e.g. external IDs) reject unquoted
// numeric literals: "must be of type string and should be enclosed in quotes".
expect(getValue('307795203', 1.1)).toBe("'307795203'");
});
it('should preserve leading zeros as quoted strings', () => {
expect(getValue('00123', 1.1)).toBe("'00123'");
expect(getValue('039381512', 1.1)).toBe("'039381512'");
});
it('should keep number-typed values unquoted', () => {
// Users wanting numeric SOQL comparisons pass numbers via expressions.
expect(getValue(307795203, 1.1)).toBe(307795203);
expect(getValue(0, 1.1)).toBe(0);
expect(getValue(-5, 1.1)).toBe(-5);
});
});
it('should return ISO datetime strings as-is', () => {
@ -1558,14 +1593,36 @@ describe('Salesforce -> GenericFunctions', () => {
expect(result).toBe("WHERE Name = 'Bob\\'s' AND Email LIKE '%test%'");
});
it('should return numeric string values unquoted', () => {
it('should keep numeric string values unquoted on typeVersion 1 (legacy)', () => {
const options: IDataObject = {
conditionsUi: {
conditionValues: [{ field: 'AnnualRevenue', operation: '>', value: '0' }],
},
};
const result = getConditions(options);
const result = getConditions(options, 1);
expect(result).toBe('WHERE AnnualRevenue > 0');
});
it('should quote numeric string values on typeVersion 1.1 (NODE-5116 fix)', () => {
const options: IDataObject = {
conditionsUi: {
conditionValues: [{ field: 'IdNumber__c', operation: 'equal', value: '307795203' }],
},
};
const result = getConditions(options, 1.1);
expect(result).toBe("WHERE IdNumber__c = '307795203'");
});
it('should keep number-typed values unquoted on typeVersion 1.1', () => {
const options: IDataObject = {
conditionsUi: {
conditionValues: [{ field: 'AnnualRevenue', operation: '>', value: 0 }],
},
};
const result = getConditions(options, 1.1);
expect(result).toBe('WHERE AnnualRevenue > 0');
});

View File

@ -1479,6 +1479,7 @@ describe('Salesforce', () => {
'Lead',
true,
0,
1,
);
expect(salesforceApiRequestAllItemsSpy).toHaveBeenCalledWith(
'records',
@ -1507,7 +1508,7 @@ describe('Salesforce', () => {
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Lead', false, 50);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Lead', false, 50, 1);
});
it('should handle lead delete operation', async () => {
@ -1858,7 +1859,7 @@ describe('Salesforce', () => {
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({ fields: 'Id,Subject,Type' }, 'Case', true, 0);
expect(getQuerySpy).toHaveBeenCalledWith({ fields: 'Id,Subject,Type' }, 'Case', true, 0, 1);
expect(salesforceApiRequestAllItemsSpy).toHaveBeenCalledWith(
'records',
'GET',
@ -1886,7 +1887,7 @@ describe('Salesforce', () => {
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Case', false, 25);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Case', false, 25, 1);
});
it('should handle case getAll operation error handling', async () => {
@ -2355,6 +2356,7 @@ describe('Salesforce', () => {
'Contact',
true,
0,
1,
);
expect(salesforceApiRequestAllItemsSpy).toHaveBeenCalledWith(
'records',
@ -2634,7 +2636,7 @@ describe('Salesforce', () => {
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'CustomObject__c', true, 0);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'CustomObject__c', true, 0, 1);
expect(salesforceApiRequestAllItemsSpy).toHaveBeenCalledWith(
'records',
'GET',
@ -3577,6 +3579,7 @@ describe('Salesforce', () => {
'Task',
false,
10,
1,
);
expect(salesforceApiRequestAllItemsSpy).toHaveBeenCalledWith(
'records',
@ -3898,6 +3901,7 @@ describe('Salesforce', () => {
'Attachment',
true,
0,
1,
);
expect(salesforceApiRequestAllItemsSpy).toHaveBeenCalledWith(
'records',
@ -3936,7 +3940,7 @@ describe('Salesforce', () => {
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Attachment', false, 5);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Attachment', false, 5, 1);
});
it('should handle attachment getAll operation error handling', async () => {
@ -4031,4 +4035,137 @@ describe('Salesforce', () => {
});
});
});
// Coverage for the 9 getAll call sites that previously had no test (Contact limit,
// CustomObject limit, Opportunity returnAll/limit, Account returnAll/limit, Task
// returnAll, User returnAll/limit) and end-to-end verification that the SF node's
// typeVersion is threaded into getQuery (NODE-5116 version-gate wiring).
describe('Execute Method - GetAll Query Wiring', () => {
const mockGetAll = (resource: string, returnAll: boolean, limit?: number, options = {}) => {
mockExecuteFunctions.getNodeParameter.mockImplementation((param: string): any => {
const params: Record<string, unknown> = {
resource,
operation: 'getAll',
returnAll,
...(returnAll ? {} : { limit }),
options,
customObject: 'CustomObject__c',
};
return params[param];
});
};
it('should call getQuery for contact getAll with limit', async () => {
mockGetAll('contact', false, 25);
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT * FROM Contact LIMIT 25');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Contact', false, 25, 1);
});
it('should call getQuery for customObject getAll with limit', async () => {
mockGetAll('customObject', false, 10);
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT * FROM CustomObject__c LIMIT 10');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'CustomObject__c', false, 10, 1);
});
it('should call getQuery for opportunity getAll with returnAll', async () => {
mockGetAll('opportunity', true, undefined, { fields: 'Id,Name' });
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT Id,Name FROM Opportunity');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({ fields: 'Id,Name' }, 'Opportunity', true, 0, 1);
});
it('should call getQuery for opportunity getAll with limit', async () => {
mockGetAll('opportunity', false, 5);
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT * FROM Opportunity LIMIT 5');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Opportunity', false, 5, 1);
});
it('should call getQuery for account getAll with returnAll', async () => {
mockGetAll('account', true, undefined, { fields: 'Id,Name,Type' });
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT Id,Name,Type FROM Account');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({ fields: 'Id,Name,Type' }, 'Account', true, 0, 1);
});
it('should call getQuery for account getAll with limit', async () => {
mockGetAll('account', false, 15);
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT * FROM Account LIMIT 15');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Account', false, 15, 1);
});
it('should call getQuery for task getAll with returnAll', async () => {
mockGetAll('task', true, undefined, { fields: 'Id,Subject' });
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT Id,Subject FROM Task');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({ fields: 'Id,Subject' }, 'Task', true, 0, 1);
});
it('should call getQuery for user getAll with returnAll', async () => {
mockGetAll('user', true, undefined, { fields: 'Id,Name,Email' });
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT Id,Name,Email FROM User');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({ fields: 'Id,Name,Email' }, 'User', true, 0, 1);
});
it('should call getQuery for user getAll with limit', async () => {
mockGetAll('user', false, 20);
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT * FROM User LIMIT 20');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'User', false, 20, 1);
});
it('should pass typeVersion 1.1 to getQuery when the node is on the new version', async () => {
// End-to-end proof that getNode().typeVersion is threaded into getQuery,
// so a workflow created on v1.1 actually gets the NODE-5116 fix at runtime.
mockNode.typeVersion = 1.1;
mockGetAll('lead', false, 10);
const getQuerySpy = jest.spyOn(GenericFunctions, 'getQuery');
getQuerySpy.mockReturnValue('SELECT * FROM Lead LIMIT 10');
salesforceApiRequestAllItemsSpy.mockResolvedValue([]);
await node.execute.call(mockExecuteFunctions);
expect(getQuerySpy).toHaveBeenCalledWith({}, 'Lead', false, 10, 1.1);
});
});
});

View File

@ -176,6 +176,7 @@ describe('SalesforceTrigger', () => {
'Account',
true,
0,
1,
);
expect(salesforceApiRequestAllItemsSpy).toHaveBeenCalledWith(
'records',
@ -236,6 +237,7 @@ describe('SalesforceTrigger', () => {
'Account',
true,
0,
1,
);
expect(result).toBeDefined();
@ -266,7 +268,7 @@ describe('SalesforceTrigger', () => {
const result = await trigger.poll.call(mockPollFunctions);
expect(getQuerySpy).toHaveBeenCalledWith(expect.any(Object), 'CustomObject__c', true, 0);
expect(getQuerySpy).toHaveBeenCalledWith(expect.any(Object), 'CustomObject__c', true, 0, 1);
expect(result).toBeDefined();
expect(result![0]).toHaveLength(1);
@ -341,6 +343,7 @@ describe('SalesforceTrigger', () => {
'Account',
false,
1,
1,
);
expect(result).toBeDefined();
@ -369,6 +372,7 @@ describe('SalesforceTrigger', () => {
'Account',
false,
1,
1,
);
});
});
@ -534,6 +538,7 @@ describe('SalesforceTrigger', () => {
'', // Empty resource name
true,
0,
1,
);
});
});