Fix an issue where null values were causing an error in automation loops (#14083)
* fixes an issue where nulls weren't being handled correctly in loops * remove log * update recursive gate to be more specific * use lodash for object check
This commit is contained in:
parent
f6360d42c8
commit
9809bf1a91
|
@ -1,4 +1,5 @@
|
||||||
import * as automationUtils from "./automationUtils"
|
import * as automationUtils from "./automationUtils"
|
||||||
|
import { isPlainObject } from "lodash"
|
||||||
|
|
||||||
type ObjValue = {
|
type ObjValue = {
|
||||||
[key: string]: string | ObjValue
|
[key: string]: string | ObjValue
|
||||||
|
@ -18,6 +19,10 @@ function replaceBindingsRecursive(
|
||||||
value: string | ObjValue,
|
value: string | ObjValue,
|
||||||
loopStepNumber: number
|
loopStepNumber: number
|
||||||
) {
|
) {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof value === "object") {
|
if (typeof value === "object") {
|
||||||
for (const [innerKey, innerValue] of Object.entries(value)) {
|
for (const [innerKey, innerValue] of Object.entries(value)) {
|
||||||
if (typeof innerValue === "string") {
|
if (typeof innerValue === "string") {
|
||||||
|
@ -25,7 +30,11 @@ function replaceBindingsRecursive(
|
||||||
innerValue,
|
innerValue,
|
||||||
`steps.${loopStepNumber}`
|
`steps.${loopStepNumber}`
|
||||||
)
|
)
|
||||||
} else if (typeof innerValue === "object") {
|
} else if (
|
||||||
|
innerValue &&
|
||||||
|
isPlainObject(innerValue) &&
|
||||||
|
Object.keys(innerValue).length > 0
|
||||||
|
) {
|
||||||
value[innerKey] = replaceBindingsRecursive(innerValue, loopStepNumber)
|
value[innerKey] = replaceBindingsRecursive(innerValue, loopStepNumber)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { loopAutomation } from "../../tests/utilities/structures"
|
||||||
import { context } from "@budibase/backend-core"
|
import { context } from "@budibase/backend-core"
|
||||||
import * as setup from "./utilities"
|
import * as setup from "./utilities"
|
||||||
import { Table } from "@budibase/types"
|
import { Table } from "@budibase/types"
|
||||||
|
import * as loopUtils from "../loopUtils"
|
||||||
import { LoopInput, LoopStepType } from "../../definitions/automations"
|
import { LoopInput, LoopStepType } from "../../definitions/automations"
|
||||||
|
|
||||||
describe("Attempt to run a basic loop automation", () => {
|
describe("Attempt to run a basic loop automation", () => {
|
||||||
|
@ -51,4 +52,98 @@ describe("Attempt to run a basic loop automation", () => {
|
||||||
})
|
})
|
||||||
expect(resp.steps[2].outputs.iterations).toBe(1)
|
expect(resp.steps[2].outputs.iterations).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("replaceFakeBindings", () => {
|
||||||
|
it("should replace loop bindings in nested objects", () => {
|
||||||
|
const originalStepInput = {
|
||||||
|
schema: {
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
length: { maximum: null },
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "name",
|
||||||
|
display: { type: "Text" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
tableId: "ta_aaad4296e9f74b12b1b90ef7a84afcad",
|
||||||
|
name: "{{ loop.currentItem.pokemon }}",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const loopStepNumber = 3
|
||||||
|
|
||||||
|
const result = loopUtils.replaceFakeBindings(
|
||||||
|
originalStepInput,
|
||||||
|
loopStepNumber
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
schema: {
|
||||||
|
name: {
|
||||||
|
type: "string",
|
||||||
|
constraints: {
|
||||||
|
type: "string",
|
||||||
|
length: { maximum: null },
|
||||||
|
presence: false,
|
||||||
|
},
|
||||||
|
name: "name",
|
||||||
|
display: { type: "Text" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
tableId: "ta_aaad4296e9f74b12b1b90ef7a84afcad",
|
||||||
|
name: "{{ steps.3.currentItem.pokemon }}",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle null values in nested objects", () => {
|
||||||
|
const originalStepInput = {
|
||||||
|
nullValue: null,
|
||||||
|
nestedNull: {
|
||||||
|
someKey: null,
|
||||||
|
},
|
||||||
|
validValue: "{{ loop.someValue }}",
|
||||||
|
}
|
||||||
|
|
||||||
|
const loopStepNumber = 2
|
||||||
|
|
||||||
|
const result = loopUtils.replaceFakeBindings(
|
||||||
|
originalStepInput,
|
||||||
|
loopStepNumber
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
nullValue: null,
|
||||||
|
nestedNull: {
|
||||||
|
someKey: null,
|
||||||
|
},
|
||||||
|
validValue: "{{ steps.2.someValue }}",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should handle empty objects and arrays", () => {
|
||||||
|
const originalStepInput = {
|
||||||
|
emptyObject: {},
|
||||||
|
emptyArray: [],
|
||||||
|
nestedEmpty: {
|
||||||
|
emptyObj: {},
|
||||||
|
emptyArr: [],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const loopStepNumber = 1
|
||||||
|
|
||||||
|
const result = loopUtils.replaceFakeBindings(
|
||||||
|
originalStepInput,
|
||||||
|
loopStepNumber
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).toEqual(originalStepInput)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue