1775 lines
44 KiB
TypeScript
1775 lines
44 KiB
TypeScript
import { expect, describe, it, vi } from "vitest";
|
|
|
|
import type { AttributesQueryValue, RaqbChild } from "@calcom/lib/raqb/types";
|
|
import type { Attribute } from "@calcom/lib/service/attribute/server/getAttributes";
|
|
import { AttributeType } from "@calcom/prisma/enums";
|
|
import { RoutingFormFieldType } from "@calcom/routing-forms/lib/FieldTypes";
|
|
|
|
import { getValueOfAttributeOption, acrossQueryValueCompatiblity } from "./raqbUtils";
|
|
|
|
const { resolveQueryValue } = acrossQueryValueCompatiblity;
|
|
|
|
// Mock the getFieldResponseValueAsLabel
|
|
vi.mock("@calcom/app-store/routing-forms/lib/getFieldResponseValueAsLabel", () => ({
|
|
getFieldResponseValueAsLabel: ({ fieldResponseValue }: { field: any; fieldResponseValue: any }) => {
|
|
// For testing, just return the value as-is
|
|
return fieldResponseValue;
|
|
},
|
|
}));
|
|
|
|
// Test Data Builders for AttributesQueryValue
|
|
const createQueryValueRule = (overrides?: Partial<RaqbChild>): RaqbChild => ({
|
|
type: "rule",
|
|
properties: {
|
|
field: "default-field",
|
|
operator: "select_equals",
|
|
value: ["default-value"],
|
|
valueSrc: ["value"],
|
|
valueError: [null],
|
|
valueType: ["select"],
|
|
},
|
|
...overrides,
|
|
});
|
|
|
|
const createAttributesQueryValue = (overrides?: {
|
|
id?: string;
|
|
type?: "group" | "switch_group";
|
|
children1?: Record<string, RaqbChild>;
|
|
properties?: any;
|
|
}): AttributesQueryValue => ({
|
|
id: overrides?.id || "test-id",
|
|
type: overrides?.type || "group",
|
|
children1: overrides?.children1 || {},
|
|
properties: overrides?.properties,
|
|
});
|
|
|
|
const createQueryValueWithRule = ({
|
|
ruleId,
|
|
field,
|
|
operator,
|
|
value,
|
|
valueSrc = ["value"],
|
|
valueError = [null],
|
|
valueType = ["select"],
|
|
}: {
|
|
ruleId: string;
|
|
field: string;
|
|
operator: string;
|
|
value: any[];
|
|
valueSrc?: string[];
|
|
valueError?: (string | null)[];
|
|
valueType?: string[];
|
|
}): AttributesQueryValue => {
|
|
return createAttributesQueryValue({
|
|
children1: {
|
|
[ruleId]: createQueryValueRule({
|
|
type: "rule",
|
|
properties: {
|
|
field,
|
|
operator,
|
|
value,
|
|
valueSrc,
|
|
valueError,
|
|
valueType,
|
|
},
|
|
}),
|
|
},
|
|
});
|
|
};
|
|
|
|
const createComplexQueryValue = ({
|
|
id,
|
|
rules,
|
|
}: {
|
|
id?: string;
|
|
rules: Array<{
|
|
ruleId: string;
|
|
field: string;
|
|
operator: string;
|
|
value: any[];
|
|
valueSrc?: string[];
|
|
valueError?: (string | null)[];
|
|
valueType?: string[];
|
|
}>;
|
|
}): AttributesQueryValue => {
|
|
const children1: Record<string, RaqbChild> = {};
|
|
|
|
rules.forEach((rule) => {
|
|
children1[rule.ruleId] = createQueryValueRule({
|
|
type: "rule",
|
|
properties: {
|
|
field: rule.field,
|
|
operator: rule.operator,
|
|
value: rule.value,
|
|
valueSrc: rule.valueSrc || ["value"],
|
|
valueError: rule.valueError || [null],
|
|
valueType: rule.valueType || ["select"],
|
|
},
|
|
});
|
|
});
|
|
|
|
return createAttributesQueryValue({
|
|
id,
|
|
children1,
|
|
});
|
|
};
|
|
|
|
const createNestedGroupQueryValue = ({
|
|
groups,
|
|
}: {
|
|
groups: Array<{
|
|
groupId: string;
|
|
rules: Array<{
|
|
ruleId: string;
|
|
field: string;
|
|
operator?: string;
|
|
value: any[];
|
|
valueSrc?: string[];
|
|
valueError?: (string | null)[];
|
|
valueType?: string[];
|
|
}>;
|
|
}>;
|
|
}): AttributesQueryValue => {
|
|
const children1: Record<string, RaqbChild> = {};
|
|
|
|
groups.forEach((group) => {
|
|
const groupChildren: Record<string, RaqbChild> = {};
|
|
|
|
group.rules.forEach((rule) => {
|
|
groupChildren[rule.ruleId] = createQueryValueRule({
|
|
type: "rule",
|
|
properties: {
|
|
field: rule.field,
|
|
operator: rule.operator || "select_equals",
|
|
value: rule.value,
|
|
valueSrc: rule.valueSrc || ["value"],
|
|
valueError: rule.valueError || [null],
|
|
valueType: rule.valueType || ["select"],
|
|
},
|
|
});
|
|
});
|
|
|
|
children1[group.groupId] = {
|
|
type: "group",
|
|
children1: groupChildren,
|
|
} as RaqbChild;
|
|
});
|
|
|
|
return createAttributesQueryValue({
|
|
type: "group",
|
|
children1,
|
|
});
|
|
};
|
|
|
|
describe("getValueOfAttributeOption", () => {
|
|
it("should return non-array value for non-array input - It is a requirement for RAQB to not unnecessarily transform single value to an array of one item", () => {
|
|
const input = { value: "option1", isGroup: false, contains: [] };
|
|
const result = getValueOfAttributeOption(input);
|
|
expect(result).toEqual("option1");
|
|
});
|
|
|
|
it("should return flat array of values for simple options", () => {
|
|
const input = [
|
|
{ value: "option1", isGroup: false, contains: [] },
|
|
{ value: "option2", isGroup: false, contains: [] },
|
|
];
|
|
|
|
const result = getValueOfAttributeOption(input);
|
|
expect(result).toEqual(["option1", "option2"]);
|
|
});
|
|
|
|
it("should flatten nested options from contains array", () => {
|
|
const input = [
|
|
{
|
|
value: "group1",
|
|
isGroup: true,
|
|
contains: [
|
|
{ value: "suboption1", id: "opt-1", slug: "option-1" },
|
|
{ value: "suboption2", id: "opt-2", slug: "option-2" },
|
|
],
|
|
},
|
|
];
|
|
|
|
const result = getValueOfAttributeOption(input);
|
|
expect(result).toEqual(["suboption1", "suboption2"]);
|
|
});
|
|
|
|
it("should handle mix of simple and nested options", () => {
|
|
const input = [
|
|
{ value: "option1", isGroup: false, contains: [] },
|
|
{
|
|
value: "group1",
|
|
isGroup: true,
|
|
contains: [
|
|
{ value: "suboption1", id: "opt-1", slug: "option-1" },
|
|
{ value: "suboption2", id: "opt-2", slug: "option-2" },
|
|
],
|
|
},
|
|
{ value: "option2", isGroup: false, contains: [] },
|
|
];
|
|
|
|
const result = getValueOfAttributeOption(input);
|
|
expect(result).toEqual(["option1", "suboption1", "suboption2", "option2"]);
|
|
});
|
|
|
|
it("should remove duplicate values", () => {
|
|
const input = [
|
|
{ value: "option1", isGroup: false, contains: [] },
|
|
{
|
|
value: "group1",
|
|
isGroup: true,
|
|
contains: [
|
|
{ value: "option1", id: "opt-1", slug: "option-1" },
|
|
{ value: "suboption2", id: "opt-2", slug: "option-2" },
|
|
],
|
|
},
|
|
];
|
|
|
|
const result = getValueOfAttributeOption(input);
|
|
expect(result).toEqual(["option1", "suboption2"]);
|
|
});
|
|
|
|
it("should handle empty input array", () => {
|
|
const input: {
|
|
value: string;
|
|
isGroup: boolean;
|
|
contains: { value: string; id: string; slug: string }[];
|
|
}[] = [];
|
|
|
|
const result = getValueOfAttributeOption(input);
|
|
expect(result).toEqual([]);
|
|
});
|
|
|
|
it("should still use contains if contains is empty and isGroup=true", () => {
|
|
const input = [{ value: "group1", isGroup: true, contains: [] }];
|
|
|
|
const result = getValueOfAttributeOption(input);
|
|
expect(result).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("resolveQueryValue", () => {
|
|
const mockFields = [
|
|
{ id: "location", type: RoutingFormFieldType.MULTI_SELECT, label: "Location", options: [] },
|
|
{ id: "city", type: RoutingFormFieldType.SINGLE_SELECT, label: "City", options: [] },
|
|
];
|
|
|
|
// Mock attributes for testing
|
|
const mockAttributes: Attribute[] = [
|
|
{
|
|
id: "attr-1",
|
|
name: "Location",
|
|
slug: "location",
|
|
type: AttributeType.MULTI_SELECT,
|
|
options: [
|
|
{ id: "opt-1", value: "New York", slug: "new-york" },
|
|
{ id: "opt-2", value: "London", slug: "london" },
|
|
],
|
|
},
|
|
{
|
|
id: "attr-2",
|
|
name: "City",
|
|
slug: "city",
|
|
type: AttributeType.SINGLE_SELECT,
|
|
options: [
|
|
{ id: "opt-3", value: "Mumbai", slug: "mumbai" },
|
|
{ id: "opt-4", value: "Delhi", slug: "delhi" },
|
|
],
|
|
},
|
|
];
|
|
|
|
describe("attribute option ID replacement", () => {
|
|
it("should replace attribute option IDs with lowercase values", () => {
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "attr-1",
|
|
operator: "select_equals",
|
|
value: ["opt-1"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
field: "attr-1",
|
|
operator: "select_equals",
|
|
value: ["new york"], // Should be lowercase
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should replace multiple attribute option IDs in the same value array", () => {
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "attr-1",
|
|
operator: "multiselect_some_in",
|
|
value: [["opt-1", "opt-2", "opt-3", "opt-4"]],
|
|
valueType: ["multiselect"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
field: "attr-1",
|
|
operator: "multiselect_some_in",
|
|
value: [["new york", "london", "mumbai", "delhi"]],
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle attribute option IDs in nested rules", () => {
|
|
const queryValue = createComplexQueryValue({
|
|
rules: [
|
|
{
|
|
ruleId: "rule1",
|
|
field: "attr-1",
|
|
operator: "select_equals",
|
|
value: ["opt-1"],
|
|
},
|
|
{
|
|
ruleId: "rule2",
|
|
field: "attr-2",
|
|
operator: "select_equals",
|
|
value: ["opt-3"],
|
|
},
|
|
],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: ["new york"],
|
|
}),
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: ["mumbai"],
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should replace attribute option IDs before processing field templates", () => {
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "attr-1",
|
|
operator: "multiselect_some_in",
|
|
value: [["opt-1", "{field:location}"]],
|
|
valueType: ["multiselect"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Paris"], label: "Paris" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: [["new york", "paris"]], // opt-1 replaced with "new york", field template with "paris"
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle attribute option IDs with special characters", () => {
|
|
const specialAttributes: Attribute[] = [
|
|
{
|
|
id: "attr-special",
|
|
name: "Special",
|
|
slug: "special",
|
|
type: AttributeType.SINGLE_SELECT,
|
|
options: [
|
|
{ id: "opt-special-1", value: "São Paulo", slug: "sao-paulo" },
|
|
{ id: "opt-special-2", value: "Zürich", slug: "zurich" },
|
|
],
|
|
},
|
|
];
|
|
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "attr-special",
|
|
operator: "select_equals",
|
|
value: ["opt-special-1"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: specialAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: ["são paulo"], // Should preserve special characters but be lowercase
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should not replace IDs that don't match any attribute options", () => {
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "attr-1",
|
|
operator: "select_equals",
|
|
value: ["non-existent-id", "opt-1"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: ["non-existent-id", "new york"], // Only opt-1 should be replaced
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle empty attributes array", () => {
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "attr-1",
|
|
operator: "select_equals",
|
|
value: ["opt-1"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: [], // No attributes
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: ["opt-1"], // Should remain unchanged
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle attributes with no options", () => {
|
|
const attributesWithoutOptions: Attribute[] = [
|
|
{
|
|
id: "attr-no-options",
|
|
name: "No Options",
|
|
slug: "no-options",
|
|
type: AttributeType.TEXT,
|
|
options: [], // Empty options array
|
|
},
|
|
];
|
|
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "attr-no-options",
|
|
operator: "text_equals",
|
|
value: ["some-value"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: attributesWithoutOptions,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: ["some-value"], // Should remain unchanged
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should replace option IDs in complex nested group structures", () => {
|
|
const queryValue = createNestedGroupQueryValue({
|
|
groups: [
|
|
{
|
|
groupId: "group1",
|
|
rules: [
|
|
{
|
|
ruleId: "rule1",
|
|
field: "attr-1",
|
|
operator: "multiselect_some_in",
|
|
value: [["opt-1", "opt-2"]],
|
|
valueType: ["multiselect"],
|
|
},
|
|
{
|
|
ruleId: "rule2",
|
|
field: "attr-2",
|
|
operator: "select_equals",
|
|
value: ["opt-3"],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
group1: {
|
|
type: "group",
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: [["new york", "london"]],
|
|
}),
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: ["mumbai"],
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle option IDs mixed with field templates in double-nested arrays", () => {
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "attr-1",
|
|
operator: "multiselect_some_in",
|
|
value: [["opt-1", "{field:city}", "opt-2", "{field:location}"]],
|
|
valueType: ["multiselect"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
city: { value: "Tokyo", label: "Tokyo" },
|
|
location: { value: ["Berlin", "Paris"], label: "Berlin, Paris" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
value: [["new york", "tokyo", "london", "berlin", "paris"]],
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
it("should handle simple field template replacement with single value", () => {
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "a8a89bba",
|
|
field: "city",
|
|
operator: "select_equals",
|
|
value: ["{field:city}"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
city: { label: "Mumbai", value: "Mumbai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
a8a89bba: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
field: "city",
|
|
operator: "select_equals",
|
|
value: ["mumbai"],
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle field template in double-nested array for multiselect", () => {
|
|
const queryValue = createQueryValueWithRule({
|
|
ruleId: "rule1",
|
|
field: "location",
|
|
operator: "multiselect_some_in",
|
|
value: [["{field:location}"]],
|
|
valueType: ["multiselect"],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { label: "Delhi", value: "Delhi" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
field: "location",
|
|
operator: "multiselect_some_in",
|
|
value: [["delhi"]],
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle mixed array with field template and regular values", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
operator: "multiselect_some_in",
|
|
value: [["{field:location}", "Chennai"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: "Delhi", label: "Delhi" }, // Single value, not array
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
operator: "multiselect_some_in",
|
|
value: [["delhi", "Chennai"]], // Single value replaced
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle multiple field templates in the same array", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "multifield",
|
|
operator: "multiselect_some_in",
|
|
value: [["{field:location}", "{field:city}"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi"], label: "Delhi" },
|
|
city: { value: "Mumbai", label: "Mumbai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "multifield",
|
|
operator: "multiselect_some_in",
|
|
value: [["delhi", "mumbai"]],
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle field template with no response value", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
operator: "select_equals",
|
|
value: ["{field:location}"],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {}, // No response for location field
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
operator: "select_equals",
|
|
value: ["{field:location}"], // Should remain unchanged
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle field template with unknown field", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "unknown",
|
|
operator: "select_equals",
|
|
value: ["{field:unknown}"],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
unknown: { value: "test", label: "test" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "unknown",
|
|
operator: "select_equals",
|
|
value: ["{field:unknown}"], // Should remain unchanged
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle complex nested structure", () => {
|
|
const queryValue = createAttributesQueryValue({
|
|
id: "test",
|
|
type: "group",
|
|
children1: {
|
|
rule1: createQueryValueRule({
|
|
type: "rule",
|
|
properties: {
|
|
field: "attr1",
|
|
operator: "multiselect_some_in",
|
|
value: [["{field:location}", "Fixed-Value"]],
|
|
valueType: ["multiselect"],
|
|
},
|
|
}),
|
|
},
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi", "Haryana"], label: "Delhi, Haryana" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
id: "test",
|
|
type: "group",
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
field: "attr1",
|
|
value: [["delhi", "haryana", "Fixed-Value"]],
|
|
operator: "multiselect_some_in",
|
|
}),
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle empty array values", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
operator: "multiselect_some_in",
|
|
value: [["{field:location}"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: [], label: "" }, // Empty array
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
operator: "multiselect_some_in",
|
|
value: [[]], // Should be empty array
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle no dynamicFieldValueOperands", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: ["{field:location}"],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: undefined,
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(queryValue); // Should return unchanged
|
|
});
|
|
|
|
it("should preserve case for non-template values in mixed arrays", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
operator: "multiselect_some_in",
|
|
value: [["{field:location}", "Chennai", "MUMBAI"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi"], label: "Delhi" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
operator: "multiselect_some_in",
|
|
value: [["delhi", "Chennai", "MUMBAI"]], // Only field template value is lowercased
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle deeply nested field templates", () => {
|
|
const queryValue = createNestedGroupQueryValue({
|
|
groups: [
|
|
{
|
|
groupId: "group1",
|
|
rules: [
|
|
{
|
|
ruleId: "rule1",
|
|
field: "location",
|
|
value: [["{field:location}", "Fixed1"]],
|
|
valueType: ["multiselect"],
|
|
},
|
|
{
|
|
ruleId: "rule2",
|
|
field: "city",
|
|
value: [["{field:city}", "Fixed2"]],
|
|
valueType: ["multiselect"],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
});
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi", "Mumbai"], label: "Delhi, Mumbai" },
|
|
city: { value: "Chennai", label: "Chennai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
type: "group",
|
|
children1: {
|
|
group1: {
|
|
type: "group",
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
field: "location",
|
|
value: [["delhi", "mumbai", "Fixed1"]],
|
|
}),
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: expect.objectContaining({
|
|
field: "city",
|
|
value: [["chennai", "Fixed2"]],
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle field template with array containing special characters", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["New York", "São Paulo", "Zürich"], label: "New York, São Paulo, Zürich" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["new york", "são paulo", "zürich"]],
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle field template in arrays at different nesting levels", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: ["{field:city}"], // Single nested
|
|
},
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}"]], // Double nested
|
|
},
|
|
},
|
|
rule3: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: [[["{field:city}"]]], // Triple nested
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi"], label: "Delhi" },
|
|
city: { value: "Mumbai", label: "Mumbai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: ["mumbai"],
|
|
},
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["delhi"]],
|
|
},
|
|
},
|
|
rule3: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: [[["mumbai"]]],
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle null and undefined values gracefully", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed",
|
|
value: [["{field:location}", null, "{field:city}"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi"], label: "Delhi" },
|
|
city: { value: null as any, label: "" }, // null value
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed",
|
|
value: [["delhi", null, "{field:city}"]], // city remains as template due to null value
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle numeric values from fields", () => {
|
|
const numericFields = [
|
|
{ id: "age", type: RoutingFormFieldType.NUMBER, label: "Age", options: [] },
|
|
{ id: "count", type: RoutingFormFieldType.NUMBER, label: "Count", options: [] },
|
|
];
|
|
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "numbers",
|
|
value: [["{field:age}", "{field:count}", 42]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: numericFields,
|
|
response: {
|
|
age: { value: 25, label: "25" },
|
|
count: { value: 100, label: "100" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "numbers",
|
|
value: [["25", "100", 42]],
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle very large arrays efficiently", () => {
|
|
const largeArray = new Array(100).fill("item");
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}", ...largeArray]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi", "Mumbai"], label: "Delhi, Mumbai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result.children1?.rule1.properties?.value[0]).toHaveLength(102); // 2 from field + 100 items
|
|
expect(result.children1?.rule1.properties?.value[0].slice(0, 2)).toEqual(["delhi", "mumbai"]);
|
|
});
|
|
|
|
it("should handle edge case with empty string field values", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["", " ", "Delhi"], label: ", , Delhi" }, // Empty and whitespace strings
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["", " ", "delhi"]],
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle field templates with hyphens and underscores in field names", () => {
|
|
const specialFields = [
|
|
{ id: "field-with-dashes", type: RoutingFormFieldType.TEXT, label: "Dashed Field", options: [] },
|
|
{
|
|
id: "field_with_underscores",
|
|
type: RoutingFormFieldType.TEXT,
|
|
label: "Underscored Field",
|
|
options: [],
|
|
},
|
|
];
|
|
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "special",
|
|
value: ["{field:field-with-dashes}", "{field:field_with_underscores}"],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: specialFields,
|
|
response: {
|
|
"field-with-dashes": { value: "Value2", label: "Value2" },
|
|
field_with_underscores: { value: "Value3", label: "Value3" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "special",
|
|
value: ["value2", "value3"],
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle mixed field templates and fixed values in complex scenarios", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
group1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed1",
|
|
value: [["{field:location}", "Fixed1", "{field:city}"]],
|
|
},
|
|
},
|
|
group2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed2",
|
|
value: [["Fixed2", "{field:location}"]],
|
|
},
|
|
},
|
|
group3: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed3",
|
|
value: [["{field:city}", "{field:location}", "Fixed3", "{field:city}"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi", "Mumbai"], label: "Delhi, Mumbai" },
|
|
city: { value: "Chennai", label: "Chennai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
group1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed1",
|
|
value: [["delhi", "mumbai", "Fixed1", "chennai"]],
|
|
},
|
|
},
|
|
group2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed2",
|
|
value: [["Fixed2", "delhi", "mumbai"]],
|
|
},
|
|
},
|
|
group3: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed3",
|
|
value: [["chennai", "delhi", "mumbai", "Fixed3", "chennai"]],
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle field templates in different JSON value types", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: "{field:city}",
|
|
},
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: ["{field:city}"],
|
|
},
|
|
},
|
|
rule3: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}"]],
|
|
},
|
|
},
|
|
rule4: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed",
|
|
customProp: "{field:city}",
|
|
nested: {
|
|
value: ["{field:location}"],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: { value: ["Delhi", "Mumbai"], label: "Delhi, Mumbai" },
|
|
city: { value: "Chennai", label: "Chennai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: "chennai",
|
|
},
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: ["chennai"],
|
|
},
|
|
},
|
|
rule3: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["delhi", "mumbai"]],
|
|
},
|
|
},
|
|
rule4: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "mixed",
|
|
customProp: "chennai",
|
|
nested: {
|
|
value: ["delhi", "mumbai"],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle empty response object", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}", "Fixed"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {}, // Empty response
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}", "Fixed"]], // Template unchanged
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle response with empty field value object", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
location: {} as any, // Empty object, no value property
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "location",
|
|
value: [["{field:location}"]], // Template unchanged
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle multiple occurrences of the same field template", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: ["{field:city}"],
|
|
},
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: ["{field:city}"],
|
|
},
|
|
},
|
|
rule3: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: [["{field:city}", "{field:city}"]],
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
city: { value: "Mumbai", label: "Mumbai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: ["mumbai"],
|
|
},
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: ["mumbai"],
|
|
},
|
|
},
|
|
rule3: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
value: [["mumbai", "mumbai"]],
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
it("should handle invalid query structure gracefully", () => {
|
|
// Test with an invalid query structure
|
|
const invalidQueryValue = null as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue: invalidQueryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
city: { value: "Mumbai", label: "Mumbai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it("should handle valid JSON that causes processing errors gracefully", () => {
|
|
const queryValue = {
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "nonexistent",
|
|
value: ["{field:nonexistent}"],
|
|
},
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
customField: "{field:city}",
|
|
},
|
|
},
|
|
},
|
|
} as unknown as AttributesQueryValue;
|
|
|
|
const result = resolveQueryValue({
|
|
queryValue,
|
|
dynamicFieldValueOperands: {
|
|
fields: mockFields,
|
|
response: {
|
|
city: { value: "Mumbai", label: "Mumbai" },
|
|
},
|
|
},
|
|
attributes: mockAttributes,
|
|
});
|
|
|
|
// Non-existent field should remain as-is, existing field should be resolved
|
|
expect(result).toEqual(
|
|
expect.objectContaining({
|
|
children1: {
|
|
rule1: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "nonexistent",
|
|
value: ["{field:nonexistent}"],
|
|
},
|
|
},
|
|
rule2: {
|
|
type: "rule",
|
|
properties: {
|
|
field: "city",
|
|
customField: "mumbai",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
);
|
|
});
|
|
});
|